3 * Copyright (c) 2011-2015, ARM Limited. All rights reserved.
5 * SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "SataSiI3132.h"
11 #include <IndustryStandard/Atapi.h>
12 #include <Library/DevicePathLib.h>
16 IN SATA_SI3132_INSTANCE
* SataInstance
,
18 IN UINT16 PortMultiplierPort
21 SATA_SI3132_PORT
*SataPort
;
22 SATA_SI3132_DEVICE
*SataDevice
;
24 if (Port
>= SATA_SII3132_MAXPORT
) {
28 SataPort
= &(SataInstance
->Ports
[Port
]);
29 List
= SataPort
->Devices
.ForwardLink
;
31 while (List
!= &SataPort
->Devices
) {
32 SataDevice
= (SATA_SI3132_DEVICE
*)List
;
33 if (SataDevice
->Index
== PortMultiplierPort
) {
36 List
= List
->ForwardLink
;
42 SiI3132AtaPassThruCommand (
43 IN SATA_SI3132_INSTANCE
*SataSiI3132Instance
,
44 IN SATA_SI3132_PORT
*SataPort
,
45 IN UINT16 PortMultiplierPort
,
46 IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET
*Packet
,
47 IN EFI_EVENT Event OPTIONAL
50 SATA_SI3132_DEVICE
*SataDevice
;
51 EFI_PHYSICAL_ADDRESS PhysInDataBuffer
;
52 UINTN InDataBufferLength
= 0;
53 EFI_PHYSICAL_ADDRESS PhysOutDataBuffer
;
54 UINTN OutDataBufferLength
;
55 CONST UINTN EmptySlot
= 0;
56 UINTN Control
= PRB_CTRL_ATA
;
58 UINT32 Value32
, Error
, Timeout
= 0;
59 CONST UINT32 IrqMask
= (SII3132_PORT_INT_CMDCOMPL
| SII3132_PORT_INT_CMDERR
) << 16;
61 VOID
* PciAllocMapping
= NULL
;
62 EFI_PCI_IO_PROTOCOL
*PciIo
;
64 PciIo
= SataSiI3132Instance
->PciIo
;
65 ZeroMem (SataPort
->HostPRB
, sizeof (SATA_SI3132_PRB
));
67 // Construct Si3132 PRB
68 switch (Packet
->Protocol
) {
69 case EFI_ATA_PASS_THRU_PROTOCOL_ATA_HARDWARE_RESET
:
70 ASSERT (0); //TODO: Implement me!
72 case EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET
:
73 SATA_TRACE ("SiI3132AtaPassThru() EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET");
74 Control
= PRB_CTRL_SRST
;
76 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport
)) {
77 SataPort
->HostPRB
->Fis
.Control
= 0x0F;
80 case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA
:
81 ASSERT (0); //TODO: Implement me!
84 // There is no difference for SiI3132 between PIO and DMA invokation
85 case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN
:
86 case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN
:
87 // Fixup the size for block transfer. Following UEFI Specification, 'InTransferLength' should
88 // be in number of bytes. But for most data transfer commands, the value is in number of blocks
89 if (Packet
->Acb
->AtaCommand
== ATA_CMD_IDENTIFY_DRIVE
) {
90 InDataBufferLength
= Packet
->InTransferLength
;
92 SataDevice
= GetSataDevice (SataSiI3132Instance
, SataPort
->Index
, PortMultiplierPort
);
93 if (!SataDevice
|| (SataDevice
->BlockSize
== 0)) {
94 return EFI_INVALID_PARAMETER
;
97 InDataBufferLength
= Packet
->InTransferLength
* SataDevice
->BlockSize
;
100 Status
= PciIo
->Map (
101 PciIo
, EfiPciIoOperationBusMasterWrite
,
102 Packet
->InDataBuffer
, &InDataBufferLength
, &PhysInDataBuffer
, &PciAllocMapping
104 if (EFI_ERROR (Status
)) {
108 // Construct SGEs (32-bit system)
109 SataPort
->HostPRB
->Sge
[0].DataAddressLow
= (UINT32
)PhysInDataBuffer
;
110 SataPort
->HostPRB
->Sge
[0].DataAddressHigh
= (UINT32
)(PhysInDataBuffer
>> 32);
111 SataPort
->HostPRB
->Sge
[0].Attributes
= SGE_TRM
; // Only one SGE
112 SataPort
->HostPRB
->Sge
[0].DataCount
= InDataBufferLength
;
114 // Copy the Ata Command Block
115 CopyMem (&SataPort
->HostPRB
->Fis
, Packet
->Acb
, sizeof (EFI_ATA_COMMAND_BLOCK
));
118 SataPort
->HostPRB
->Fis
.FisType
= 0x27; // Register - Host to Device FIS
119 SataPort
->HostPRB
->Fis
.Control
= 1 << 7; // Is a command
120 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport
)) {
121 SataPort
->HostPRB
->Fis
.Control
|= PortMultiplierPort
& 0xFF;
124 case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT
:
125 case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
:
126 SataDevice
= GetSataDevice (SataSiI3132Instance
, SataPort
->Index
, PortMultiplierPort
);
127 if (!SataDevice
|| (SataDevice
->BlockSize
== 0)) {
128 return EFI_INVALID_PARAMETER
;
131 // Fixup the size for block transfer. Following UEFI Specification, 'InTransferLength' should
132 // be in number of bytes. But for most data transfer commands, the value is in number of blocks
133 OutDataBufferLength
= Packet
->OutTransferLength
* SataDevice
->BlockSize
;
135 Status
= PciIo
->Map (
136 PciIo
, EfiPciIoOperationBusMasterRead
,
137 Packet
->OutDataBuffer
, &OutDataBufferLength
, &PhysOutDataBuffer
, &PciAllocMapping
139 if (EFI_ERROR (Status
)) {
143 // Construct SGEs (32-bit system)
144 SataPort
->HostPRB
->Sge
[0].DataAddressLow
= (UINT32
)PhysOutDataBuffer
;
145 SataPort
->HostPRB
->Sge
[0].DataAddressHigh
= (UINT32
)(PhysOutDataBuffer
>> 32);
146 SataPort
->HostPRB
->Sge
[0].Attributes
= SGE_TRM
; // Only one SGE
147 SataPort
->HostPRB
->Sge
[0].DataCount
= OutDataBufferLength
;
149 // Copy the Ata Command Block
150 CopyMem (&SataPort
->HostPRB
->Fis
, Packet
->Acb
, sizeof (EFI_ATA_COMMAND_BLOCK
));
153 SataPort
->HostPRB
->Fis
.FisType
= 0x27; // Register - Host to Device FIS
154 SataPort
->HostPRB
->Fis
.Control
= 1 << 7; // Is a command
155 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport
)) {
156 SataPort
->HostPRB
->Fis
.Control
|= PortMultiplierPort
& 0xFF;
159 case EFI_ATA_PASS_THRU_PROTOCOL_DMA
:
160 ASSERT (0); //TODO: Implement me!
162 case EFI_ATA_PASS_THRU_PROTOCOL_DMA_QUEUED
:
163 ASSERT (0); //TODO: Implement me!
165 case EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_DIAGNOSTIC
:
166 ASSERT (0); //TODO: Implement me!
168 case EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_RESET
:
169 ASSERT (0); //TODO: Implement me!
171 case EFI_ATA_PASS_THRU_PROTOCOL_FPDMA
:
172 ASSERT (0); //TODO: Implement me!
174 case EFI_ATA_PASS_THRU_PROTOCOL_RETURN_RESPONSE
:
175 ASSERT (0); //TODO: Implement me!
182 SataPort
->HostPRB
->Control
= Control
;
183 SataPort
->HostPRB
->ProtocolOverride
= Protocol
;
186 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_INTSTATUS_REG
, IrqMask
);
188 if (!FeaturePcdGet (PcdSataSiI3132FeatureDirectCommandIssuing
)) {
189 // Indirect Command Issuance
191 //TODO: Find which slot is free (maybe use the Cmd FIFO)
192 //SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_CMDEXECFIFO_REG, &EmptySlot);
194 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_CMDACTIV_REG
+ (EmptySlot
* 8),
195 (UINT32
)(SataPort
->PhysAddrHostPRB
& 0xFFFFFFFF));
196 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_CMDACTIV_REG
+ (EmptySlot
* 8) + 4,
197 (UINT32
)((SataPort
->PhysAddrHostPRB
>> 32) & 0xFFFFFFFF));
199 // Direct Command Issuance
200 Status
= PciIo
->Mem
.Write (PciIo
, EfiPciIoWidthUint32
, 1, // Bar 1
201 SataPort
->RegBase
+ (EmptySlot
* 0x80),
202 sizeof (SATA_SI3132_PRB
) / 4,
204 ASSERT_EFI_ERROR (Status
);
206 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_CMDEXECFIFO_REG
, EmptySlot
);
210 // Could need to be implemented if we run multiple command in parallel to know which slot has been completed
211 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_SLOTSTATUS_REG
, &Value32
);
212 Timeout
= Packet
->Timeout
;
213 while (!Timeout
&& !Value32
) {
215 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_SLOTSTATUS_REG
, &Value32
);
219 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_INTSTATUS_REG
, &Value32
);
220 if (!Packet
->Timeout
) {
221 while (!(Value32
& IrqMask
)) {
223 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_INTSTATUS_REG
, &Value32
);
226 Timeout
= Packet
->Timeout
;
227 while (Timeout
&& !(Value32
& IrqMask
)) {
229 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_INTSTATUS_REG
, &Value32
);
234 // Fill Packet Ata Status Block
235 Status
= PciIo
->Mem
.Read (PciIo
, EfiPciIoWidthUint32
, 1, // Bar 1
236 SataPort
->RegBase
+ 0x08,
237 sizeof (EFI_ATA_STATUS_BLOCK
) / 4,
239 ASSERT_EFI_ERROR (Status
);
242 if ((Packet
->Timeout
!= 0) && (Timeout
== 0)) {
243 DEBUG ((EFI_D_ERROR
, "SiI3132AtaPassThru() Err:Timeout\n"));
246 } else if (Value32
& (SII3132_PORT_INT_CMDERR
<< 16)) {
247 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_CMDERROR_REG
, &Error
);
248 DEBUG ((EFI_D_ERROR
, "SiI3132AtaPassThru() CmdErr:0x%X (SiI3132 Err:0x%X)\n", Value32
, Error
));
250 return EFI_DEVICE_ERROR
;
251 } else if (Value32
& (SII3132_PORT_INT_CMDCOMPL
<< 16)) {
252 // Clear Command Complete
253 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_INTSTATUS_REG
, SII3132_PORT_INT_CMDCOMPL
<< 16);
255 if (PciAllocMapping
) {
256 Status
= PciIo
->Unmap (PciIo
, PciAllocMapping
);
257 ASSERT (!EFI_ERROR (Status
));
260 // If the command was ATA_CMD_IDENTIFY_DRIVE then we need to update the BlockSize
261 if (Packet
->Acb
->AtaCommand
== ATA_CMD_IDENTIFY_DRIVE
) {
262 ATA_IDENTIFY_DATA
*IdentifyData
= (ATA_IDENTIFY_DATA
*)Packet
->InDataBuffer
;
264 // Get the corresponding Block Device
265 SataDevice
= GetSataDevice (SataSiI3132Instance
, SataPort
->Index
, PortMultiplierPort
);
267 // Check logical block size
268 if ((IdentifyData
->phy_logic_sector_support
& BIT12
) != 0) {
269 ASSERT (SataDevice
!= NULL
);
270 SataDevice
->BlockSize
= (UINT32
) (((IdentifyData
->logic_sector_size_hi
<< 16) |
271 IdentifyData
->logic_sector_size_lo
) * sizeof (UINT16
));
273 SataDevice
->BlockSize
= 0x200;
279 return EFI_DEVICE_ERROR
;
284 Sends an ATA command to an ATA device that is attached to the ATA controller. This function
285 supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,
286 and the non-blocking I/O functionality is optional.
288 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
289 @param[in] Port The port number of the ATA device to send the command.
290 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
291 If there is no port multiplier, then specify 0.
292 @param[in,out] Packet A pointer to the ATA command to send to the ATA device specified by Port
293 and PortMultiplierPort.
294 @param[in] Event If non-blocking I/O is not supported then Event is ignored, and blocking
295 I/O is performed. If Event is NULL, then blocking I/O is performed. If
296 Event is not NULL and non blocking I/O is supported, then non-blocking
297 I/O is performed, and Event will be signaled when the ATA command completes.
299 @retval EFI_SUCCESS The ATA command was sent by the host. For bi-directional commands,
300 InTransferLength bytes were transferred from InDataBuffer. For write and
301 bi-directional commands, OutTransferLength bytes were transferred by OutDataBuffer.
302 @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number of bytes that could be transferred
303 is returned in InTransferLength. For write and bi-directional commands,
304 OutTransferLength bytes were transferred by OutDataBuffer.
305 @retval EFI_NOT_READY The ATA command could not be sent because there are too many ATA commands
306 already queued. The caller may retry again later.
307 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the ATA command.
308 @retval EFI_INVALID_PARAMETER Port, PortMultiplierPort, or the contents of Acb are invalid. The ATA
309 command was not sent, so no additional status information is available.
314 IN EFI_ATA_PASS_THRU_PROTOCOL
*This
,
316 IN UINT16 PortMultiplierPort
,
317 IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET
*Packet
,
318 IN EFI_EVENT Event OPTIONAL
321 SATA_SI3132_INSTANCE
*SataSiI3132Instance
;
322 SATA_SI3132_DEVICE
*SataDevice
;
323 SATA_SI3132_PORT
*SataPort
;
325 SataSiI3132Instance
= INSTANCE_FROM_ATAPASSTHRU_THIS (This
);
326 if (!SataSiI3132Instance
) {
327 return EFI_INVALID_PARAMETER
;
330 SataDevice
= GetSataDevice (SataSiI3132Instance
, Port
, PortMultiplierPort
);
332 return EFI_INVALID_PARAMETER
;
334 SataPort
= SataDevice
->Port
;
336 DEBUG ((EFI_D_INFO
, "SiI3132AtaPassThru(%d,%d) : AtaCmd:0x%X Prot:%d\n", Port
, PortMultiplierPort
,
337 Packet
->Acb
->AtaCommand
, Packet
->Protocol
));
339 return SiI3132AtaPassThruCommand (SataSiI3132Instance
, SataPort
, PortMultiplierPort
, Packet
, Event
);
343 Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
344 These can either be the list of ports where ATA devices are actually present or the
345 list of legal port numbers for the ATA controller. Regardless, the caller of this
346 function must probe the port number returned to see if an ATA device is actually
347 present at that location on the ATA controller.
349 The GetNextPort() function retrieves the port number on an ATA controller. If on input
350 Port is 0xFFFF, then the port number of the first port on the ATA controller is returned
351 in Port and EFI_SUCCESS is returned.
353 If Port is a port number that was returned on a previous call to GetNextPort(), then the
354 port number of the next port on the ATA controller is returned in Port, and EFI_SUCCESS
355 is returned. If Port is not 0xFFFF and Port was not returned on a previous call to
356 GetNextPort(), then EFI_INVALID_PARAMETER is returned.
358 If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND is
361 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
362 @param[in,out] Port On input, a pointer to the port number on the ATA controller.
363 On output, a pointer to the next port number on the ATA
364 controller. An input value of 0xFFFF retrieves the first port
365 number on the ATA controller.
367 @retval EFI_SUCCESS The next port number on the ATA controller was returned in Port.
368 @retval EFI_NOT_FOUND There are no more ports on this ATA controller.
369 @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned on a previous call
375 IN EFI_ATA_PASS_THRU_PROTOCOL
*This
,
379 SATA_SI3132_INSTANCE
*SataSiI3132Instance
;
381 EFI_STATUS Status
= EFI_SUCCESS
;
383 SataSiI3132Instance
= INSTANCE_FROM_ATAPASSTHRU_THIS (This
);
384 if (!SataSiI3132Instance
) {
385 return EFI_INVALID_PARAMETER
;
390 if (PrevPort
== 0xFFFF) {
393 if (PrevPort
< SATA_SII3132_MAXPORT
) {
394 *Port
= PrevPort
+ 1;
396 Status
= EFI_NOT_FOUND
;
403 Used to retrieve the list of legal port multiplier port numbers for ATA devices on a port of an ATA
404 controller. These can either be the list of port multiplier ports where ATA devices are actually
405 present on port or the list of legal port multiplier ports on that port. Regardless, the caller of this
406 function must probe the port number and port multiplier port number returned to see if an ATA
407 device is actually present.
409 The GetNextDevice() function retrieves the port multiplier port number of an ATA device
410 present on a port of an ATA controller.
412 If PortMultiplierPort points to a port multiplier port number value that was returned on a
413 previous call to GetNextDevice(), then the port multiplier port number of the next ATA device
414 on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is
417 If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first
418 ATA device on port of the ATA controller is returned in PortMultiplierPort and
419 EFI_SUCCESS is returned.
421 If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
422 was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
425 If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of
426 the ATA controller, then EFI_NOT_FOUND is returned.
428 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
429 @param[in] Port The port number present on the ATA controller.
430 @param[in,out] PortMultiplierPort On input, a pointer to the port multiplier port number of an
431 ATA device present on the ATA controller.
432 If on input a PortMultiplierPort of 0xFFFF is specified,
433 then the port multiplier port number of the first ATA device
434 is returned. On output, a pointer to the port multiplier port
435 number of the next ATA device present on an ATA controller.
437 @retval EFI_SUCCESS The port multiplier port number of the next ATA device on the port
438 of the ATA controller was returned in PortMultiplierPort.
439 @retval EFI_NOT_FOUND There are no more ATA devices on this port of the ATA controller.
440 @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and PortMultiplierPort was not
441 returned on a previous call to GetNextDevice().
445 SiI3132GetNextDevice (
446 IN EFI_ATA_PASS_THRU_PROTOCOL
*This
,
448 IN OUT UINT16
*PortMultiplierPort
451 SATA_SI3132_INSTANCE
*SataSiI3132Instance
;
452 SATA_SI3132_PORT
*SataPort
;
453 SATA_SI3132_DEVICE
*SataDevice
;
455 EFI_STATUS Status
= EFI_SUCCESS
;
457 SataSiI3132Instance
= INSTANCE_FROM_ATAPASSTHRU_THIS (This
);
458 if (!SataSiI3132Instance
) {
459 return EFI_INVALID_PARAMETER
;
462 if (Port
>= SATA_SII3132_MAXPORT
) {
463 return EFI_INVALID_PARAMETER
;
466 SataPort
= &(SataSiI3132Instance
->Ports
[Port
]);
468 if (*PortMultiplierPort
== 0xFFFF) {
469 List
= SataPort
->Devices
.ForwardLink
;
470 if (List
!= &SataPort
->Devices
) {
471 // The list is not empty, return the first device
472 *PortMultiplierPort
= ((SATA_SI3132_DEVICE
*)List
)->Index
;
474 Status
= EFI_NOT_FOUND
;
477 SataDevice
= GetSataDevice (SataSiI3132Instance
, Port
, *PortMultiplierPort
);
478 if (SataDevice
!= NULL
) {
479 // We have found the previous port multiplier, return the next one
480 List
= SataDevice
->Link
.ForwardLink
;
481 if (List
!= &SataPort
->Devices
) {
482 *PortMultiplierPort
= ((SATA_SI3132_DEVICE
*)List
)->Index
;
484 Status
= EFI_NOT_FOUND
;
487 Status
= EFI_NOT_FOUND
;
494 Used to allocate and build a device path node for an ATA device on an ATA controller.
496 The BuildDevicePath() function allocates and builds a single device node for the ATA
497 device specified by Port and PortMultiplierPort. If the ATA device specified by Port and
498 PortMultiplierPort is not present on the ATA controller, then EFI_NOT_FOUND is returned.
499 If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. If there are not enough
500 resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.
502 Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
503 DevicePath are initialized to describe the ATA device specified by Port and PortMultiplierPort,
504 and EFI_SUCCESS is returned.
506 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
507 @param[in] Port Port specifies the port number of the ATA device for which a
508 device path node is to be allocated and built.
509 @param[in] PortMultiplierPort The port multiplier port number of the ATA device for which a
510 device path node is to be allocated and built. If there is no
511 port multiplier, then specify 0.
512 @param[in,out] DevicePath A pointer to a single device path node that describes the ATA
513 device specified by Port and PortMultiplierPort. This function
514 is responsible for allocating the buffer DevicePath with the
515 boot service AllocatePool(). It is the caller's responsibility
516 to free DevicePath when the caller is finished with DevicePath.
517 @retval EFI_SUCCESS The device path node that describes the ATA device specified by
518 Port and PortMultiplierPort was allocated and returned in DevicePath.
519 @retval EFI_NOT_FOUND The ATA device specified by Port and PortMultiplierPort does not
520 exist on the ATA controller.
521 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
522 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
526 SiI3132BuildDevicePath (
527 IN EFI_ATA_PASS_THRU_PROTOCOL
*This
,
529 IN UINT16 PortMultiplierPort
,
530 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
533 SATA_SI3132_INSTANCE
*SataSiI3132Instance
;
534 SATA_SI3132_DEVICE
*SataDevice
;
535 EFI_DEVICE_PATH_PROTOCOL
*SiI3132DevicePath
;
537 SATA_TRACE ("SiI3132BuildDevicePath()");
539 SataSiI3132Instance
= INSTANCE_FROM_ATAPASSTHRU_THIS (This
);
540 if (!SataSiI3132Instance
) {
541 return EFI_INVALID_PARAMETER
;
544 SataDevice
= GetSataDevice (SataSiI3132Instance
, Port
, PortMultiplierPort
);
545 if (SataDevice
== NULL
) {
546 return EFI_NOT_FOUND
;
549 SiI3132DevicePath
= CreateDeviceNode (MESSAGING_DEVICE_PATH
, MSG_SATA_DP
, sizeof (SATA_DEVICE_PATH
));
550 if (SiI3132DevicePath
== NULL
) {
551 return EFI_OUT_OF_RESOURCES
;
554 ((SATA_DEVICE_PATH
*)SiI3132DevicePath
)->HBAPortNumber
= Port
;
555 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport
)) {
556 ((SATA_DEVICE_PATH
*)SiI3132DevicePath
)->PortMultiplierPortNumber
= PortMultiplierPort
;
558 //Temp:((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber = SATA_HBA_DIRECT_CONNECT_FLAG;
559 ((SATA_DEVICE_PATH
*)SiI3132DevicePath
)->PortMultiplierPortNumber
= 0;
561 ((SATA_DEVICE_PATH
*)SiI3132DevicePath
)->Lun
= Port
; //TODO: Search information how to define properly LUN (Logical Unit Number)
563 *DevicePath
= SiI3132DevicePath
;
568 Used to translate a device path node to a port number and port multiplier port number.
570 The GetDevice() function determines the port and port multiplier port number associated with
571 the ATA device described by DevicePath. If DevicePath is a device path node type that the
572 ATA Pass Thru driver supports, then the ATA Pass Thru driver will attempt to translate the contents
573 DevicePath into a port number and port multiplier port number.
575 If this translation is successful, then that port number and port multiplier port number are returned
576 in Port and PortMultiplierPort, and EFI_SUCCESS is returned.
578 If DevicePath, Port, or PortMultiplierPort are NULL, then EFI_INVALID_PARAMETER is returned.
580 If DevicePath is not a device path node type that the ATA Pass Thru driver supports, then
581 EFI_UNSUPPORTED is returned.
583 If DevicePath is a device path node type that the ATA Pass Thru driver supports, but there is not
584 a valid translation from DevicePath to a port number and port multiplier port number, then
585 EFI_NOT_FOUND is returned.
587 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
588 @param[in] DevicePath A pointer to the device path node that describes an ATA device on the
590 @param[out] Port On return, points to the port number of an ATA device on the ATA controller.
591 @param[out] PortMultiplierPort On return, points to the port multiplier port number of an ATA device
592 on the ATA controller.
594 @retval EFI_SUCCESS DevicePath was successfully translated to a port number and port multiplier
595 port number, and they were returned in Port and PortMultiplierPort.
596 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
597 @retval EFI_INVALID_PARAMETER Port is NULL.
598 @retval EFI_INVALID_PARAMETER PortMultiplierPort is NULL.
599 @retval EFI_UNSUPPORTED This driver does not support the device path node type in DevicePath.
600 @retval EFI_NOT_FOUND A valid translation from DevicePath to a port number and port multiplier
601 port number does not exist.
605 IN EFI_ATA_PASS_THRU_PROTOCOL
*This
,
606 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
608 OUT UINT16
*PortMultiplierPort
611 SATA_SI3132_INSTANCE
*SataSiI3132Instance
;
613 SATA_TRACE ("SiI3132GetDevice()");
615 if (!DevicePath
|| !Port
|| !PortMultiplierPort
) {
616 return EFI_INVALID_PARAMETER
;
619 if ((DevicePath
->Type
!= MESSAGING_DEVICE_PATH
) || (DevicePath
->SubType
!= MSG_SATA_DP
)) {
620 return EFI_UNSUPPORTED
;
623 SataSiI3132Instance
= INSTANCE_FROM_ATAPASSTHRU_THIS (This
);
624 if (!SataSiI3132Instance
) {
625 return EFI_INVALID_PARAMETER
;
628 if (((SATA_DEVICE_PATH
*)DevicePath
)->Lun
>= SATA_SII3132_MAXPORT
) {
629 return EFI_NOT_FOUND
;
632 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport
)) {
633 ASSERT (0); //TODO: Implement me!
634 return EFI_UNSUPPORTED
;
636 *Port
= ((SATA_DEVICE_PATH
*)DevicePath
)->Lun
;
637 // Return the first Sata Device as there should be only one directly connected
638 *PortMultiplierPort
= ((SATA_SI3132_DEVICE
*)SataSiI3132Instance
->Ports
[*Port
].Devices
.ForwardLink
)->Index
;
645 IN SATA_SI3132_PORT
*SataPort
648 EFI_PCI_IO_PROTOCOL
*PciIo
;
652 SATA_TRACE ("SiI3132HwResetPort()");
654 PciIo
= SataPort
->Instance
->PciIo
;
657 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_CONTROLCLEAR_REG
, SII3132_PORT_CONTROL_RESET
);
659 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_STATUS_REG
, &Value32
);
660 ASSERT (!(Value32
& SII3132_PORT_CONTROL_RESET
));
662 // Initialize error counters
663 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_ERRCOUNTDECODE
, 0);
664 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_ERRCOUNTCRC
, 0);
665 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_ERRCOUNTHANDSHAKE
, 0);
667 // Enable interrupts for command completion and command errors
668 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_ENABLEINT_REG
, SII3132_PORT_INT_CMDCOMPL
| SII3132_PORT_INT_CMDERR
);
671 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_ENABLEINT_REG
, SII3132_PORT_INT_CMDCOMPL
| SII3132_PORT_INT_CMDERR
| SII3132_PORT_INT_PORTRDY
| (1 << 3));
673 // Wait until Port Ready
674 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_INTSTATUS_REG
, &Value32
);
676 while ((Timeout
> 0) && ((Value32
& SII3132_PORT_INT_PORTRDY
) == 0)) {
679 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_INTSTATUS_REG
, &Value32
);
682 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_INTSTATUS_REG
, SII3132_PORT_INT_PORTRDY
);
685 SATA_TRACE ("SiI3132HwResetPort(): Timeout");
687 } else if ((Value32
& SII3132_PORT_INT_PORTRDY
) == 0) {
688 SATA_TRACE ("SiI3132HwResetPort(): Port Not Ready");
689 return EFI_DEVICE_ERROR
;
696 Resets a specific port on the ATA controller. This operation also resets all the ATA devices
697 connected to the port.
699 The ResetChannel() function resets an a specific port on an ATA controller. This operation
700 resets all the ATA devices connected to that port. If this ATA controller does not support
701 a reset port operation, then EFI_UNSUPPORTED is returned.
703 If a device error occurs while executing that port reset operation, then EFI_DEVICE_ERROR is
706 If a timeout occurs during the execution of the port reset operation, then EFI_TIMEOUT is returned.
708 If the port reset operation is completed, then EFI_SUCCESS is returned.
710 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
711 @param[in] Port The port number on the ATA controller.
713 @retval EFI_SUCCESS The ATA controller port was reset.
714 @retval EFI_UNSUPPORTED The ATA controller does not support a port reset operation.
715 @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the ATA port.
716 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the ATA port.
721 IN EFI_ATA_PASS_THRU_PROTOCOL
*This
,
725 SATA_SI3132_INSTANCE
*SataSiI3132Instance
;
726 SATA_SI3132_PORT
*SataPort
;
728 SATA_TRACE ("SiI3132ResetPort()");
730 SataSiI3132Instance
= INSTANCE_FROM_ATAPASSTHRU_THIS (This
);
731 if (!SataSiI3132Instance
) {
732 return EFI_INVALID_PARAMETER
;
735 if (Port
>= SATA_SII3132_MAXPORT
) {
736 return EFI_UNSUPPORTED
;
739 SataPort
= &(SataSiI3132Instance
->Ports
[Port
]);
740 return SiI3132HwResetPort (SataPort
);
744 Resets an ATA device that is connected to an ATA controller.
746 The ResetDevice() function resets the ATA device specified by Port and PortMultiplierPort.
747 If this ATA controller does not support a device reset operation, then EFI_UNSUPPORTED is
750 If Port or PortMultiplierPort are not in a valid range for this ATA controller, then
751 EFI_INVALID_PARAMETER is returned.
753 If a device error occurs while executing that device reset operation, then EFI_DEVICE_ERROR
756 If a timeout occurs during the execution of the device reset operation, then EFI_TIMEOUT is
759 If the device reset operation is completed, then EFI_SUCCESS is returned.
761 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
762 @param[in] Port Port represents the port number of the ATA device to be reset.
763 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to reset.
764 If there is no port multiplier, then specify 0.
765 @retval EFI_SUCCESS The ATA device specified by Port and PortMultiplierPort was reset.
766 @retval EFI_UNSUPPORTED The ATA controller does not support a device reset operation.
767 @retval EFI_INVALID_PARAMETER Port or PortMultiplierPort are invalid.
768 @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the ATA device
769 specified by Port and PortMultiplierPort.
770 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the ATA device
771 specified by Port and PortMultiplierPort.
776 IN EFI_ATA_PASS_THRU_PROTOCOL
*This
,
778 IN UINT16 PortMultiplierPort
781 EFI_PCI_IO_PROTOCOL
*PciIo
;
782 SATA_SI3132_INSTANCE
*SataSiI3132Instance
;
783 SATA_SI3132_PORT
*SataPort
;
784 SATA_SI3132_DEVICE
*SataDevice
;
788 SATA_TRACE ("SiI3132ResetDevice()");
790 SataSiI3132Instance
= INSTANCE_FROM_ATAPASSTHRU_THIS (This
);
791 if (!SataSiI3132Instance
) {
792 return EFI_INVALID_PARAMETER
;
795 PciIo
= SataSiI3132Instance
->PciIo
;
797 SataDevice
= GetSataDevice (SataSiI3132Instance
, Port
, PortMultiplierPort
);
799 return EFI_INVALID_PARAMETER
;
801 SataPort
= SataDevice
->Port
;
803 SATA_PORT_WRITE32 (SataPort
->RegBase
+ SII3132_PORT_CONTROLSET_REG
, SII3132_PORT_DEVICE_RESET
);
806 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_STATUS_REG
, &Value32
);
807 while ((Timeout
> 0) && ((Value32
& SII3132_PORT_DEVICE_RESET
) != 0)) {
809 SATA_PORT_READ32 (SataPort
->RegBase
+ SII3132_PORT_STATUS_REG
, &Value32
);
814 SATA_TRACE ("SiI3132ResetDevice(): Timeout");