2 The file for AHCI mode of ATA host controller.
4 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "AtaAtapiPassThru.h"
18 Read AHCI Operation register.
20 @param PciIo The PCI IO protocol instance.
21 @param Offset The operation register offset.
23 @return The register content read.
29 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
35 ASSERT (PciIo
!= NULL
);
52 Write AHCI Operation register.
54 @param PciIo The PCI IO protocol instance.
55 @param Offset The operation register offset.
56 @param Data The data used to write down.
62 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
67 ASSERT (PciIo
!= NULL
);
82 Do AND operation with the value of AHCI Operation register.
84 @param PciIo The PCI IO protocol instance.
85 @param Offset The operation register offset.
86 @param AndData The data used to do AND operation.
92 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
99 ASSERT (PciIo
!= NULL
);
101 Data
= AhciReadReg (PciIo
, Offset
);
105 AhciWriteReg (PciIo
, Offset
, Data
);
109 Do OR operation with the value of AHCI Operation register.
111 @param PciIo The PCI IO protocol instance.
112 @param Offset The operation register offset.
113 @param OrData The data used to do OR operation.
119 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
126 ASSERT (PciIo
!= NULL
);
128 Data
= AhciReadReg (PciIo
, Offset
);
132 AhciWriteReg (PciIo
, Offset
, Data
);
136 Wait for memory set to the test value.
138 @param PciIo The PCI IO protocol instance.
139 @param Offset The memory address to test.
140 @param MaskValue The mask value of memory.
141 @param TestValue The test value of memory.
142 @param Timeout The time out value for wait memory set.
144 @retval EFI_DEVICE_ERROR The memory is not set.
145 @retval EFI_TIMEOUT The memory setting is time out.
146 @retval EFI_SUCCESS The memory is correct set.
152 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
162 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
165 Value
= AhciReadReg (PciIo
, Offset
) & MaskValue
;
167 if (Value
== TestValue
) {
172 // Stall for 100 microseconds.
174 MicroSecondDelay (100);
184 return EFI_DEVICE_ERROR
;
188 Check if the device is still on port. It also checks if the AHCI controller
189 supports the address and data count will be transfered.
191 @param PciIo The PCI IO protocol instance.
192 @param Port The number of port.
194 @retval EFI_SUCCESS The device is attached to port and the transfer data is
195 supported by AHCI controller.
196 @retval EFI_UNSUPPORTED The transfer address and count is not supported by AHCI
198 @retval EFI_NOT_READY The physical communication between AHCI controller and device
204 AhciCheckDeviceStatus (
205 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
212 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
214 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
216 if (Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) {
220 return EFI_NOT_READY
;
225 Clear the port interrupt and error status. It will also clear
226 HBA interrupt status.
228 @param PciIo The PCI IO protocol instance.
229 @param Port The number of port.
234 AhciClearPortStatus (
235 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
242 // Clear any error status
244 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
245 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
248 // Clear any port interrupt status
250 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
251 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
254 // Clear any HBA interrupt status
256 AhciWriteReg (PciIo
, EFI_AHCI_IS_OFFSET
, AhciReadReg (PciIo
, EFI_AHCI_IS_OFFSET
));
260 This function is used to dump the Status Registers and if there is ERR bit set
261 in the Status Register, the Error Register's value is also be dumped.
263 @param PciIo The PCI IO protocol instance.
264 @param Port The number of port.
265 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
271 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
273 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
279 ASSERT (PciIo
!= NULL
);
281 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
282 Data
= AhciReadReg (PciIo
, Offset
);
284 if (AtaStatusBlock
!= NULL
) {
285 ZeroMem (AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
287 AtaStatusBlock
->AtaStatus
= (UINT8
)Data
;
288 if ((AtaStatusBlock
->AtaStatus
& BIT0
) != 0) {
289 AtaStatusBlock
->AtaError
= (UINT8
)(Data
>> 8);
296 Enable the FIS running for giving port.
298 @param PciIo The PCI IO protocol instance.
299 @param Port The number of port.
300 @param Timeout The timeout value of enabling FIS.
302 @retval EFI_DEVICE_ERROR The FIS enable setting fails.
303 @retval EFI_TIMEOUT The FIS enable setting is time out.
304 @retval EFI_SUCCESS The FIS enable successfully.
309 AhciEnableFisReceive (
310 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
317 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
318 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
320 return AhciWaitMemSet (
323 EFI_AHCI_PORT_CMD_FR
,
324 EFI_AHCI_PORT_CMD_FR
,
330 Disable the FIS running for giving port.
332 @param PciIo The PCI IO protocol instance.
333 @param Port The number of port.
334 @param Timeout The timeout value of disabling FIS.
336 @retval EFI_DEVICE_ERROR The FIS disable setting fails.
337 @retval EFI_TIMEOUT The FIS disable setting is time out.
338 @retval EFI_UNSUPPORTED The port is in running state.
339 @retval EFI_SUCCESS The FIS disable successfully.
344 AhciDisableFisReceive (
345 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
353 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
354 Data
= AhciReadReg (PciIo
, Offset
);
357 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
359 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) != 0) {
360 return EFI_UNSUPPORTED
;
364 // Check if the Fis receive DMA engine for the port is running.
366 if ((Data
& EFI_AHCI_PORT_CMD_FR
) != EFI_AHCI_PORT_CMD_FR
) {
370 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
));
372 return AhciWaitMemSet (
375 EFI_AHCI_PORT_CMD_FR
,
384 Build the command list, command table and prepare the fis receiver.
386 @param PciIo The PCI IO protocol instance.
387 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
388 @param Port The number of port.
389 @param PortMultiplier The timeout value of stop.
390 @param CommandFis The control fis will be used for the transfer.
391 @param CommandList The command list will be used for the transfer.
392 @param AtapiCommand The atapi command will be used for the transfer.
393 @param AtapiCommandLength The length of the atapi command.
394 @param CommandSlotNumber The command slot will be used for the transfer.
395 @param DataPhysicalAddr The pointer to the data buffer pci bus master address.
396 @param DataLength The data count to be transferred.
402 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
403 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
405 IN UINT8 PortMultiplier
,
406 IN EFI_AHCI_COMMAND_FIS
*CommandFis
,
407 IN EFI_AHCI_COMMAND_LIST
*CommandList
,
408 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
409 IN UINT8 AtapiCommandLength
,
410 IN UINT8 CommandSlotNumber
,
411 IN OUT VOID
*DataPhysicalAddr
,
426 PrdtNumber
= (DataLength
+ EFI_AHCI_MAX_DATA_PER_PRDT
- 1) / EFI_AHCI_MAX_DATA_PER_PRDT
;
429 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
430 // It also limits that the maximum amount of the PRDT entry in the command table
433 ASSERT (PrdtNumber
<= 65535);
435 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFis
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
437 BaseAddr
= Data64
.Uint64
;
439 ZeroMem ((VOID
*)((UINTN
) BaseAddr
), sizeof (EFI_AHCI_RECEIVED_FIS
));
441 ZeroMem (AhciRegisters
->AhciCommandTable
, sizeof (EFI_AHCI_COMMAND_TABLE
));
443 CommandFis
->AhciCFisPmNum
= PortMultiplier
;
445 CopyMem (&AhciRegisters
->AhciCommandTable
->CommandFis
, CommandFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
447 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
448 if (AtapiCommand
!= NULL
) {
450 &AhciRegisters
->AhciCommandTable
->AtapiCmd
,
455 CommandList
->AhciCmdA
= 1;
456 CommandList
->AhciCmdP
= 1;
457 CommandList
->AhciCmdC
= (DataLength
== 0) ? 1 : 0;
459 AhciOrReg (PciIo
, Offset
, (EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
461 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
464 RemainedData
= (UINTN
) DataLength
;
465 MemAddr
= (UINTN
) DataPhysicalAddr
;
466 CommandList
->AhciCmdPrdtl
= (UINT32
)PrdtNumber
;
468 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
469 if (RemainedData
< EFI_AHCI_MAX_DATA_PER_PRDT
) {
470 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= (UINT32
)RemainedData
- 1;
472 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= EFI_AHCI_MAX_DATA_PER_PRDT
- 1;
475 Data64
.Uint64
= (UINT64
)MemAddr
;
476 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDba
= Data64
.Uint32
.Lower32
;
477 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbau
= Data64
.Uint32
.Upper32
;
478 RemainedData
-= EFI_AHCI_MAX_DATA_PER_PRDT
;
479 MemAddr
+= EFI_AHCI_MAX_DATA_PER_PRDT
;
483 // Set the last PRDT to Interrupt On Complete
485 if (PrdtNumber
> 0) {
486 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtNumber
- 1].AhciPrdtIoc
= 1;
490 (VOID
*) ((UINTN
) AhciRegisters
->AhciCmdList
+ (UINTN
) CommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
)),
492 sizeof (EFI_AHCI_COMMAND_LIST
)
495 Data64
.Uint64
= (UINT64
)(UINTN
) AhciRegisters
->AhciCommandTablePciAddr
;
496 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtba
= Data64
.Uint32
.Lower32
;
497 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtbau
= Data64
.Uint32
.Upper32
;
498 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdPmp
= PortMultiplier
;
505 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.
506 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.
511 AhciBuildCommandFis (
512 IN OUT EFI_AHCI_COMMAND_FIS
*CmdFis
,
513 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
516 ZeroMem (CmdFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
518 CmdFis
->AhciCFisType
= EFI_AHCI_FIS_REGISTER_H2D
;
520 // Indicator it's a command
522 CmdFis
->AhciCFisCmdInd
= 0x1;
523 CmdFis
->AhciCFisCmd
= AtaCommandBlock
->AtaCommand
;
525 CmdFis
->AhciCFisFeature
= AtaCommandBlock
->AtaFeatures
;
526 CmdFis
->AhciCFisFeatureExp
= AtaCommandBlock
->AtaFeaturesExp
;
528 CmdFis
->AhciCFisSecNum
= AtaCommandBlock
->AtaSectorNumber
;
529 CmdFis
->AhciCFisSecNumExp
= AtaCommandBlock
->AtaSectorNumberExp
;
531 CmdFis
->AhciCFisClyLow
= AtaCommandBlock
->AtaCylinderLow
;
532 CmdFis
->AhciCFisClyLowExp
= AtaCommandBlock
->AtaCylinderLowExp
;
534 CmdFis
->AhciCFisClyHigh
= AtaCommandBlock
->AtaCylinderHigh
;
535 CmdFis
->AhciCFisClyHighExp
= AtaCommandBlock
->AtaCylinderHighExp
;
537 CmdFis
->AhciCFisSecCount
= AtaCommandBlock
->AtaSectorCount
;
538 CmdFis
->AhciCFisSecCountExp
= AtaCommandBlock
->AtaSectorCountExp
;
540 CmdFis
->AhciCFisDevHead
= (UINT8
) (AtaCommandBlock
->AtaDeviceHead
| 0xE0);
544 Start a PIO data transfer on specific port.
546 @param PciIo The PCI IO protocol instance.
547 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
548 @param Port The number of port.
549 @param PortMultiplier The timeout value of stop.
550 @param AtapiCommand The atapi command will be used for the transfer.
551 @param AtapiCommandLength The length of the atapi command.
552 @param Read The transfer direction.
553 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
554 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
555 @param MemoryAddr The pointer to the data buffer.
556 @param DataCount The data count to be transferred.
557 @param Timeout The timeout value of non data transfer.
559 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
560 @retval EFI_TIMEOUT The operation is time out.
561 @retval EFI_UNSUPPORTED The device is not ready for transfer.
562 @retval EFI_SUCCESS The PIO data transfer executes successfully.
568 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
569 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
571 IN UINT8 PortMultiplier
,
572 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
573 IN UINT8 AtapiCommandLength
,
575 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
576 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
577 IN OUT VOID
*MemoryAddr
,
586 EFI_PHYSICAL_ADDRESS PhyAddr
;
589 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
591 EFI_AHCI_COMMAND_FIS CFis
;
592 EFI_AHCI_COMMAND_LIST CmdList
;
595 Flag
= EfiPciIoOperationBusMasterWrite
;
597 Flag
= EfiPciIoOperationBusMasterRead
;
601 // construct command list and command table with pci bus address
603 MapLength
= DataCount
;
604 Status
= PciIo
->Map (
613 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
614 return EFI_OUT_OF_RESOURCES
;
618 // Package read needed
620 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
622 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
624 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
625 CmdList
.AhciCmdW
= Read
? 0 : 1;
637 (VOID
*)(UINTN
)PhyAddr
,
641 Status
= AhciStartCommand (
647 if (EFI_ERROR (Status
)) {
652 // Checking the status and wait the driver sending data
654 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
656 // Wait device sends the PIO setup fis before data transfer
658 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
660 Value
= *(volatile UINT32
*) (FisBaseAddr
+ EFI_AHCI_PIO_FIS_OFFSET
);
662 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_PIO_SETUP
) {
667 // Stall for 100 microseconds.
669 MicroSecondDelay(100);
675 Status
= EFI_TIMEOUT
;
680 // Wait for command compelte
682 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
683 Status
= AhciWaitMemSet (
691 if (EFI_ERROR (Status
)) {
695 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
696 Status
= AhciWaitMemSet (
699 EFI_AHCI_PORT_IS_PSS
,
700 EFI_AHCI_PORT_IS_PSS
,
703 if (EFI_ERROR (Status
)) {
714 AhciDisableFisReceive (
725 AhciDumpPortStatus (PciIo
, Port
, AtaStatusBlock
);
731 Start a DMA data transfer on specific port
733 @param PciIo The PCI IO protocol instance.
734 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
735 @param Port The number of port.
736 @param PortMultiplier The timeout value of stop.
737 @param AtapiCommand The atapi command will be used for the transfer.
738 @param AtapiCommandLength The length of the atapi command.
739 @param Read The transfer direction.
740 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
741 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
742 @param MemoryAddr The pointer to the data buffer.
743 @param DataCount The data count to be transferred.
744 @param Timeout The timeout value of non data transfer.
746 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
747 @retval EFI_TIMEOUT The operation is time out.
748 @retval EFI_UNSUPPORTED The device is not ready for transfer.
749 @retval EFI_SUCCESS The DMA data transfer executes successfully.
755 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
756 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
758 IN UINT8 PortMultiplier
,
759 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
760 IN UINT8 AtapiCommandLength
,
762 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
763 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
764 IN OUT VOID
*MemoryAddr
,
771 EFI_PHYSICAL_ADDRESS PhyAddr
;
774 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
775 EFI_AHCI_COMMAND_FIS CFis
;
776 EFI_AHCI_COMMAND_LIST CmdList
;
779 Flag
= EfiPciIoOperationBusMasterWrite
;
781 Flag
= EfiPciIoOperationBusMasterRead
;
785 // construct command list and command table with pci bus address
787 MapLength
= DataCount
;
788 Status
= PciIo
->Map (
797 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
798 return EFI_OUT_OF_RESOURCES
;
802 // Package read needed
804 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
806 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
808 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
809 CmdList
.AhciCmdW
= Read
? 0 : 1;
821 (VOID
*)(UINTN
)PhyAddr
,
825 Status
= AhciStartCommand (
831 if (EFI_ERROR (Status
)) {
836 // Wait device PRD processed
838 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
839 Status
= AhciWaitMemSet (
842 EFI_AHCI_PORT_IS_DPS
,
843 EFI_AHCI_PORT_IS_DPS
,
847 if (EFI_ERROR (Status
)) {
852 // Wait for command compelte
854 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
855 Status
= AhciWaitMemSet (
862 if (EFI_ERROR (Status
)) {
866 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
867 Status
= AhciWaitMemSet (
870 EFI_AHCI_PORT_IS_DHRS
,
871 EFI_AHCI_PORT_IS_DHRS
,
874 if (EFI_ERROR (Status
)) {
885 AhciDisableFisReceive (
896 AhciDumpPortStatus (PciIo
, Port
, AtaStatusBlock
);
902 Start a non data transfer on specific port.
904 @param PciIo The PCI IO protocol instance.
905 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
906 @param Port The number of port.
907 @param PortMultiplier The timeout value of stop.
908 @param AtapiCommand The atapi command will be used for the transfer.
909 @param AtapiCommandLength The length of the atapi command.
910 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
911 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
912 @param Timeout The timeout value of non data transfer.
914 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
915 @retval EFI_TIMEOUT The operation is time out.
916 @retval EFI_UNSUPPORTED The device is not ready for transfer.
917 @retval EFI_SUCCESS The non data transfer executes successfully.
922 AhciNonDataTransfer (
923 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
924 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
926 IN UINT8 PortMultiplier
,
927 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
928 IN UINT8 AtapiCommandLength
,
929 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
930 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
940 EFI_AHCI_COMMAND_FIS CFis
;
941 EFI_AHCI_COMMAND_LIST CmdList
;
944 // Package read needed
946 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
948 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
950 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
966 Status
= AhciStartCommand (
972 if (EFI_ERROR (Status
)) {
977 // Wait device sends the Response Fis
979 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
981 // Wait device sends the PIO setup fis before data transfer
983 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
985 Value
= *(volatile UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
987 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
992 // Stall for 100 microseconds.
994 MicroSecondDelay(100);
1000 Status
= EFI_TIMEOUT
;
1004 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
1006 Status
= AhciWaitMemSet (
1021 AhciDisableFisReceive (
1027 AhciDumpPortStatus (PciIo
, Port
, AtaStatusBlock
);
1033 Stop command running for giving port
1035 @param PciIo The PCI IO protocol instance.
1036 @param Port The number of port.
1037 @param Timeout The timeout value of stop.
1039 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
1040 @retval EFI_TIMEOUT The operation is time out.
1041 @retval EFI_SUCCESS The command stop successfully.
1047 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1055 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1056 Data
= AhciReadReg (PciIo
, Offset
);
1058 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) == 0) {
1062 if ((Data
& EFI_AHCI_PORT_CMD_ST
) != 0) {
1063 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_ST
));
1066 return AhciWaitMemSet (
1069 EFI_AHCI_PORT_CMD_CR
,
1076 Start command for give slot on specific port.
1078 @param PciIo The PCI IO protocol instance.
1079 @param Port The number of port.
1080 @param CommandSlot The number of CommandSlot.
1081 @param Timeout The timeout value of start.
1083 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
1084 @retval EFI_TIMEOUT The operation is time out.
1085 @retval EFI_SUCCESS The command start successfully.
1091 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1093 IN UINT8 CommandSlot
,
1106 // Collect AHCI controller information
1108 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1110 CmdSlotBit
= (UINT32
) (1 << CommandSlot
);
1112 AhciClearPortStatus (
1117 Status
= AhciEnableFisReceive (
1123 if (EFI_ERROR (Status
)) {
1127 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1128 PortStatus
= AhciReadReg (PciIo
, Offset
);
1131 if ((PortStatus
& EFI_AHCI_PORT_CMD_ALPE
) != 0) {
1132 StartCmd
= AhciReadReg (PciIo
, Offset
);
1133 StartCmd
&= ~EFI_AHCI_PORT_CMD_ICC_MASK
;
1134 StartCmd
|= EFI_AHCI_PORT_CMD_ACTIVE
;
1137 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1138 PortTfd
= AhciReadReg (PciIo
, Offset
);
1140 if ((PortTfd
& (EFI_AHCI_PORT_TFD_BSY
| EFI_AHCI_PORT_TFD_DRQ
)) != 0) {
1141 if ((Capability
& BIT24
) != 0) {
1142 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1143 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_COL
);
1148 EFI_AHCI_PORT_CMD_COL
,
1155 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1156 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_ST
| StartCmd
);
1159 // Setting the command
1161 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SACT
;
1162 AhciAndReg (PciIo
, Offset
, 0);
1163 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1165 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
1166 AhciAndReg (PciIo
, Offset
, 0);
1167 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1175 @param PciIo The PCI IO protocol instance.
1176 @param Port The number of port.
1177 @param Timeout The timeout value of reset.
1179 @retval EFI_DEVICE_ERROR The port reset unsuccessfully
1180 @retval EFI_TIMEOUT The reset operation is time out.
1181 @retval EFI_SUCCESS The port reset successfully.
1187 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1195 AhciClearPortStatus (PciIo
, Port
);
1197 AhciStopCommand (PciIo
, Port
, Timeout
);
1199 AhciDisableFisReceive (PciIo
, Port
, Timeout
);
1201 AhciEnableFisReceive (PciIo
, Port
, Timeout
);
1203 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
1205 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_DET_INIT
);
1208 // wait 5 milliseceond before de-assert DET
1210 MicroSecondDelay (5000);
1212 AhciAndReg (PciIo
, Offset
, (UINT32
)EFI_AHCI_PORT_SCTL_MASK
);
1215 // wait 5 milliseceond before de-assert DET
1217 MicroSecondDelay (5000);
1220 // Wait for communication to be re-established
1222 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
1223 Status
= AhciWaitMemSet (
1226 EFI_AHCI_PORT_SSTS_DET_MASK
,
1227 EFI_AHCI_PORT_SSTS_DET_PCE
,
1231 if (EFI_ERROR (Status
)) {
1235 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
1236 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_ERR_CLEAR
);
1244 @param PciIo The PCI IO protocol instance.
1245 @param Timeout The timeout value of reset.
1248 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
1249 @retval EFI_TIMEOUT The reset operation is time out.
1250 @retval EFI_SUCCESS AHCI controller is reset successfully.
1256 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1264 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
1266 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_RESET
);
1268 Status
= EFI_TIMEOUT
;
1270 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
1273 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1275 if ((Value
& EFI_AHCI_GHC_RESET
) == 0) {
1280 // Stall for 100 microseconds.
1282 MicroSecondDelay(100);
1285 } while (Delay
> 0);
1295 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
1297 @param PciIo The PCI IO protocol instance.
1298 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1299 @param Port The number of port.
1300 @param PortMultiplier The timeout value of stop.
1301 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1303 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
1304 @retval Others Fail to get return status data.
1309 AhciAtaSmartReturnStatusCheck (
1310 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1311 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1313 IN UINT8 PortMultiplier
,
1314 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1318 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1324 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1326 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1327 AtaCommandBlock
.AtaFeatures
= ATA_SMART_RETURN_STATUS
;
1328 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1329 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1332 // Send S.M.A.R.T Read Return Status command to device
1334 Status
= AhciNonDataTransfer (
1338 (UINT8
)PortMultiplier
,
1346 if (EFI_ERROR (Status
)) {
1347 return EFI_DEVICE_ERROR
;
1350 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1352 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
1354 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
1355 LBAMid
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[5];
1356 LBAHigh
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[6];
1358 if ((LBAMid
== 0x4f) && (LBAHigh
== 0xc2)) {
1360 // The threshold exceeded condition is not detected by the device
1362 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
1364 } else if ((LBAMid
== 0xf4) && (LBAHigh
== 0x2c)) {
1366 // The threshold exceeded condition is detected by the device
1368 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is detected\n"));
1376 Enable SMART command of the disk if supported.
1378 @param PciIo The PCI IO protocol instance.
1379 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1380 @param Port The number of port.
1381 @param PortMultiplier The timeout value of stop.
1382 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
1383 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1388 AhciAtaSmartSupport (
1389 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1390 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1392 IN UINT8 PortMultiplier
,
1393 IN EFI_IDENTIFY_DATA
*IdentifyData
,
1394 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1398 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1401 // Detect if the device supports S.M.A.R.T.
1403 if ((IdentifyData
->AtaData
.command_set_supported_82
& 0x0001) != 0x0001) {
1405 // S.M.A.R.T is not supported by the device
1407 DEBUG ((EFI_D_INFO
, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
1408 Port
, PortMultiplier
));
1411 // Check if the feature is enabled. If not, then enable S.M.A.R.T.
1413 if ((IdentifyData
->AtaData
.command_set_feature_enb_85
& 0x0001) != 0x0001) {
1414 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1416 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1417 AtaCommandBlock
.AtaFeatures
= ATA_SMART_ENABLE_OPERATION
;
1418 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1419 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1422 // Send S.M.A.R.T Enable command to device
1424 Status
= AhciNonDataTransfer (
1428 (UINT8
)PortMultiplier
,
1437 if (!EFI_ERROR (Status
)) {
1439 // Send S.M.A.R.T AutoSave command to device
1441 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1443 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1444 AtaCommandBlock
.AtaFeatures
= 0xD2;
1445 AtaCommandBlock
.AtaSectorCount
= 0xF1;
1446 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1447 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1449 Status
= AhciNonDataTransfer (
1453 (UINT8
)PortMultiplier
,
1461 if (!EFI_ERROR (Status
)) {
1462 Status
= AhciAtaSmartReturnStatusCheck (
1466 (UINT8
)PortMultiplier
,
1472 DEBUG ((EFI_D_INFO
, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
1473 Port
, PortMultiplier
));
1480 Send Buffer cmd to specific device.
1482 @param PciIo The PCI IO protocol instance.
1483 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1484 @param Port The number of port.
1485 @param PortMultiplier The timeout value of stop.
1486 @param Buffer The data buffer to store IDENTIFY PACKET data.
1488 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1489 @retval EFI_TIMEOUT The operation is time out.
1490 @retval EFI_UNSUPPORTED The device is not ready for executing.
1491 @retval EFI_SUCCESS The cmd executes successfully.
1497 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1498 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1500 IN UINT8 PortMultiplier
,
1501 IN OUT EFI_IDENTIFY_DATA
*Buffer
1505 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1506 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1508 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
1509 return EFI_INVALID_PARAMETER
;
1512 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1513 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1515 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DRIVE
;
1516 AtaCommandBlock
.AtaSectorCount
= 1;
1518 Status
= AhciPioTransfer (
1529 sizeof (EFI_IDENTIFY_DATA
),
1537 Send Buffer cmd to specific device.
1539 @param PciIo The PCI IO protocol instance.
1540 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1541 @param Port The number of port.
1542 @param PortMultiplier The timeout value of stop.
1543 @param Buffer The data buffer to store IDENTIFY PACKET data.
1545 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1546 @retval EFI_TIMEOUT The operation is time out.
1547 @retval EFI_UNSUPPORTED The device is not ready for executing.
1548 @retval EFI_SUCCESS The cmd executes successfully.
1553 AhciIdentifyPacket (
1554 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1555 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1557 IN UINT8 PortMultiplier
,
1558 IN OUT EFI_IDENTIFY_DATA
*Buffer
1562 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1563 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1565 if (PciIo
== NULL
|| AhciRegisters
== NULL
) {
1566 return EFI_INVALID_PARAMETER
;
1569 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1570 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1572 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DEVICE
;
1573 AtaCommandBlock
.AtaSectorCount
= 1;
1575 Status
= AhciPioTransfer (
1586 sizeof (EFI_IDENTIFY_DATA
),
1594 Send SET FEATURE cmd on specific device.
1596 @param PciIo The PCI IO protocol instance.
1597 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1598 @param Port The number of port.
1599 @param PortMultiplier The timeout value of stop.
1600 @param Feature The data to send Feature register.
1601 @param FeatureSpecificData The specific data for SET FEATURE cmd.
1603 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1604 @retval EFI_TIMEOUT The operation is time out.
1605 @retval EFI_UNSUPPORTED The device is not ready for executing.
1606 @retval EFI_SUCCESS The cmd executes successfully.
1611 AhciDeviceSetFeature (
1612 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1613 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1615 IN UINT8 PortMultiplier
,
1617 IN UINT32 FeatureSpecificData
1621 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1622 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1624 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1625 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1627 AtaCommandBlock
.AtaCommand
= ATA_CMD_SET_FEATURES
;
1628 AtaCommandBlock
.AtaFeatures
= (UINT8
) Feature
;
1629 AtaCommandBlock
.AtaFeaturesExp
= (UINT8
) (Feature
>> 8);
1630 AtaCommandBlock
.AtaSectorCount
= (UINT8
) FeatureSpecificData
;
1631 AtaCommandBlock
.AtaSectorNumber
= (UINT8
) (FeatureSpecificData
>> 8);
1632 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (FeatureSpecificData
>> 16);
1633 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (FeatureSpecificData
>> 24);
1635 Status
= AhciNonDataTransfer (
1639 (UINT8
)PortMultiplier
,
1651 This function is used to send out ATAPI commands conforms to the Packet Command
1654 @param PciIo The PCI IO protocol instance.
1655 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1656 @param Port The number of port.
1657 @param PortMultiplier The number of port multiplier.
1658 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
1660 @retval EFI_SUCCESS send out the ATAPI packet command successfully
1661 and device sends data successfully.
1662 @retval EFI_DEVICE_ERROR the device failed to send data.
1667 AhciPacketCommandExecute (
1668 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1669 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1671 IN UINT8 PortMultiplier
,
1672 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1678 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1679 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1683 if (Packet
== NULL
|| Packet
->Cdb
== NULL
) {
1684 return EFI_INVALID_PARAMETER
;
1687 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1688 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1689 AtaCommandBlock
.AtaCommand
= ATA_CMD_PACKET
;
1693 AtaCommandBlock
.AtaFeatures
= 0x00;
1695 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
1696 // determine how many data should be transferred.
1698 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
& 0x00ff);
1699 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
>> 8);
1701 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1702 Buffer
= Packet
->InDataBuffer
;
1703 Length
= Packet
->InTransferLength
;
1706 Buffer
= Packet
->OutDataBuffer
;
1707 Length
= Packet
->OutTransferLength
;
1712 Status
= AhciNonDataTransfer (
1725 // READ_CAPACITY cmd may execute failure. Retry 5 times
1727 if (((UINT8
*)Packet
->Cdb
)[0] == ATA_CMD_READ_CAPACITY
) {
1733 Status
= AhciPioTransfer (
1747 if (!EFI_ERROR (Status
)) {
1751 } while (Retry
!= 0);
1757 Allocate transfer-related data struct which is used at AHCI mode.
1759 @param PciIo The PCI IO protocol instance.
1760 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1765 AhciCreateTransferDescriptor (
1766 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1767 IN OUT EFI_AHCI_REGISTERS
*AhciRegisters
1775 UINT8 MaxPortNumber
;
1776 UINT8 MaxCommandSlotNumber
;
1777 BOOLEAN Support64Bit
;
1778 UINT64 MaxReceiveFisSize
;
1779 UINT64 MaxCommandListSize
;
1780 UINT64 MaxCommandTableSize
;
1784 // Collect AHCI controller information
1786 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1787 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
1789 // Get the number of command slots per port supported by this HBA.
1791 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1792 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
1794 MaxReceiveFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1795 Status
= PciIo
->AllocateBuffer (
1798 EfiBootServicesData
,
1799 (UINTN
)EFI_SIZE_TO_PAGES (MaxReceiveFisSize
),
1804 if (EFI_ERROR (Status
)) {
1805 return EFI_OUT_OF_RESOURCES
;
1808 ZeroMem (Buffer
, (UINTN
)MaxReceiveFisSize
);
1810 AhciRegisters
->AhciRFis
= Buffer
;
1811 AhciRegisters
->MaxReceiveFisSize
= MaxReceiveFisSize
;
1812 Bytes
= (UINTN
)MaxReceiveFisSize
;
1814 Status
= PciIo
->Map (
1816 EfiPciIoOperationBusMasterCommonBuffer
,
1819 (EFI_PHYSICAL_ADDRESS
*) &AhciRegisters
->AhciRFisPciAddr
,
1820 &AhciRegisters
->MapRFis
1823 if (EFI_ERROR (Status
) || (Bytes
!= MaxReceiveFisSize
)) {
1825 // Map error or unable to map the whole RFis buffer into a contiguous region.
1827 Status
= EFI_OUT_OF_RESOURCES
;
1831 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)(UINTN
)AhciRegisters
->AhciRFisPciAddr
> 0x100000000ULL
)) {
1833 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1835 Status
= EFI_DEVICE_ERROR
;
1840 // Allocate memory for command list
1841 // Note that the implemenation is a single task model which only use a command list for all ports.
1844 MaxCommandListSize
= MaxCommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
);
1845 Status
= PciIo
->AllocateBuffer (
1848 EfiBootServicesData
,
1849 (UINTN
)EFI_SIZE_TO_PAGES (MaxCommandListSize
),
1854 if (EFI_ERROR (Status
)) {
1856 // Free mapped resource.
1858 Status
= EFI_OUT_OF_RESOURCES
;
1862 ZeroMem (Buffer
, (UINTN
)MaxCommandListSize
);
1864 AhciRegisters
->AhciCmdList
= Buffer
;
1865 AhciRegisters
->MaxCommandListSize
= MaxCommandListSize
;
1866 Bytes
= (UINTN
)MaxCommandListSize
;
1868 Status
= PciIo
->Map (
1870 EfiPciIoOperationBusMasterCommonBuffer
,
1873 (EFI_PHYSICAL_ADDRESS
*)&AhciRegisters
->AhciCmdListPciAddr
,
1874 &AhciRegisters
->MapCmdList
1877 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandListSize
)) {
1879 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1881 Status
= EFI_OUT_OF_RESOURCES
;
1885 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)(UINTN
)AhciRegisters
->AhciCmdListPciAddr
> 0x100000000ULL
)) {
1887 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1889 Status
= EFI_DEVICE_ERROR
;
1894 // Allocate memory for command table
1895 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
1898 MaxCommandTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
1900 Status
= PciIo
->AllocateBuffer (
1903 EfiBootServicesData
,
1904 (UINTN
)EFI_SIZE_TO_PAGES (MaxCommandTableSize
),
1909 if (EFI_ERROR (Status
)) {
1911 // Free mapped resource.
1913 Status
= EFI_OUT_OF_RESOURCES
;
1917 ZeroMem (Buffer
, (UINTN
)MaxCommandTableSize
);
1919 AhciRegisters
->AhciCommandTable
= Buffer
;
1920 AhciRegisters
->MaxCommandTableSize
= MaxCommandTableSize
;
1921 Bytes
= (UINTN
)MaxCommandTableSize
;
1923 Status
= PciIo
->Map (
1925 EfiPciIoOperationBusMasterCommonBuffer
,
1928 (EFI_PHYSICAL_ADDRESS
*)&AhciRegisters
->AhciCommandTablePciAddr
,
1929 &AhciRegisters
->MapCommandTable
1932 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandTableSize
)) {
1934 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1936 Status
= EFI_OUT_OF_RESOURCES
;
1940 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)(UINTN
)AhciRegisters
->AhciCommandTablePciAddr
> 0x100000000ULL
)) {
1942 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1944 Status
= EFI_DEVICE_ERROR
;
1950 // Map error or unable to map the whole CmdList buffer into a contiguous region.
1955 AhciRegisters
->MapCommandTable
1960 (UINTN
)EFI_SIZE_TO_PAGES (MaxCommandTableSize
),
1961 AhciRegisters
->AhciCommandTable
1966 AhciRegisters
->MapCmdList
1971 (UINTN
)EFI_SIZE_TO_PAGES (MaxCommandListSize
),
1972 AhciRegisters
->AhciCmdList
1977 AhciRegisters
->MapRFis
1982 (UINTN
)EFI_SIZE_TO_PAGES (MaxReceiveFisSize
),
1983 AhciRegisters
->AhciRFis
1990 Initialize ATA host controller at AHCI mode.
1992 The function is designed to initialize ATA host controller.
1994 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
1999 AhciModeInitialization (
2000 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
2004 EFI_PCI_IO_PROTOCOL
*PciIo
;
2005 EFI_IDE_CONTROLLER_INIT_PROTOCOL
*IdeInit
;
2007 UINT8 MaxPortNumber
;
2008 UINT32 PortImplementBitMap
;
2009 UINT8 MaxCommandSlotNumber
;
2010 BOOLEAN Support64Bit
;
2012 EFI_AHCI_REGISTERS
*AhciRegisters
;
2018 EFI_IDENTIFY_DATA Buffer
;
2019 EFI_ATA_DEVICE_TYPE DeviceType
;
2020 EFI_ATA_COLLECTIVE_MODE
*SupportedModes
;
2021 EFI_ATA_TRANSFER_MODE TransferMode
;
2023 if (Instance
== NULL
) {
2024 return EFI_INVALID_PARAMETER
;
2027 PciIo
= Instance
->PciIo
;
2028 IdeInit
= Instance
->IdeControllerInit
;
2030 Status
= AhciReset (PciIo
, ATA_ATAPI_TIMEOUT
);
2032 if (EFI_ERROR (Status
)) {
2033 return EFI_DEVICE_ERROR
;
2037 // Enable AE before accessing any AHCI registers
2039 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
2042 // Collect AHCI controller information
2044 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
2047 // Get the number of command slots per port supported by this HBA.
2049 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
2050 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
2053 // Get the bit map of those ports exposed by this HBA.
2054 // It indicates which ports that the HBA supports are available for software to use.
2056 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
2057 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
2059 AhciRegisters
= &Instance
->AhciRegisters
;
2060 Status
= AhciCreateTransferDescriptor (PciIo
, AhciRegisters
);
2062 if (EFI_ERROR (Status
)) {
2063 return EFI_OUT_OF_RESOURCES
;
2066 for (Port
= 0; Port
< MaxPortNumber
; Port
++) {
2067 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFisPciAddr
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
2069 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FB
;
2070 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2071 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FBU
;
2072 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2075 // Single task envrionment, we only use one command table for all port
2077 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdListPciAddr
);
2079 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLB
;
2080 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2081 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLBU
;
2082 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2084 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
2085 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2087 if ((Capability
& EFI_AHCI_PORT_CMD_ASP
) != 0) {
2088 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_SUD
);
2090 Data
= AhciReadReg (PciIo
, Offset
);
2091 if ((Data
& EFI_AHCI_PORT_CMD_CPD
) != 0) {
2092 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_POD
);
2095 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
|EFI_AHCI_PORT_CMD_COL
|EFI_AHCI_PORT_CMD_ST
));
2098 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
2099 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_SCTL_IPM_MASK
));
2101 AhciAndReg (PciIo
, Offset
,(UINT32
) ~(EFI_AHCI_PORT_SCTL_IPM_PSD
));
2102 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_PSD
);
2104 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_SCTL_IPM_SSD
));
2105 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_SSD
);
2107 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IE
;
2108 AhciAndReg (PciIo
, Offset
, 0);
2110 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
2111 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
2115 // Stall for 100 milliseconds.
2117 MicroSecondDelay(100000);
2119 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBeforeChannelEnumeration
, Port
);
2121 for (Port
= 0; Port
< MaxPortNumber
; Port
++) {
2122 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
2124 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
2125 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
2131 // Found device in the port
2133 if (Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) {
2134 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SIG
;
2136 Status
= AhciWaitMemSet (
2143 if (EFI_ERROR (Status
)) {
2148 // Now inform the IDE Controller Init Module.
2150 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBusBeforeDevicePresenceDetection
, Port
);
2152 Data
= AhciReadReg (PciIo
, Offset
);
2154 if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATAPI_DEVICE_SIG
) {
2155 Status
= AhciIdentifyPacket (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2157 if (EFI_ERROR (Status
)) {
2161 DeviceType
= EfiIdeCdrom
;
2162 } else if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATA_DEVICE_SIG
) {
2163 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2165 if (EFI_ERROR (Status
)) {
2169 DeviceType
= EfiIdeHarddisk
;
2174 DEBUG ((EFI_D_INFO
, "port [%d] port mulitplier [%d] has a [%a]\n",
2175 Port
, 0, DeviceType
== EfiIdeCdrom
? "cdrom" : "harddisk"));
2178 // If the device is a hard disk, then try to enable S.M.A.R.T feature
2180 if (DeviceType
== EfiIdeHarddisk
) {
2181 AhciAtaSmartSupport (
2192 // Submit identify data to IDE controller init driver
2194 IdeInit
->SubmitData (IdeInit
, Port
, 0, &Buffer
);
2197 // Now start to config ide device parameter and transfer mode.
2199 Status
= IdeInit
->CalculateMode (
2205 if (EFI_ERROR (Status
)) {
2206 DEBUG ((EFI_D_ERROR
, "Calculate Mode Fail, Status = %r\n", Status
));
2211 // Set best supported PIO mode on this IDE device
2213 if (SupportedModes
->PioMode
.Mode
<= EfiAtaPioMode2
) {
2214 TransferMode
.ModeCategory
= EFI_ATA_MODE_DEFAULT_PIO
;
2216 TransferMode
.ModeCategory
= EFI_ATA_MODE_FLOW_PIO
;
2219 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->PioMode
.Mode
);
2222 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
2223 // be set together. Only one DMA mode can be set to a device. If setting
2224 // DMA mode operation fails, we can continue moving on because we only use
2225 // PIO mode at boot time. DMA modes are used by certain kind of OS booting
2227 if (SupportedModes
->UdmaMode
.Valid
) {
2228 TransferMode
.ModeCategory
= EFI_ATA_MODE_UDMA
;
2229 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->UdmaMode
.Mode
);
2230 } else if (SupportedModes
->MultiWordDmaMode
.Valid
) {
2231 TransferMode
.ModeCategory
= EFI_ATA_MODE_MDMA
;
2232 TransferMode
.ModeNumber
= (UINT8
) SupportedModes
->MultiWordDmaMode
.Mode
;
2235 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, 0, 0x03, (UINT32
)(*(UINT8
*)&TransferMode
));
2237 if (EFI_ERROR (Status
)) {
2238 DEBUG ((EFI_D_ERROR
, "Set transfer Mode Fail, Status = %r\n", Status
));
2242 // Found a ATA or ATAPI device, add it into the device list.
2244 CreateNewDeviceInfo (Instance
, Port
, 0, DeviceType
, &Buffer
);