2 The file for AHCI mode of ATA host controller.
4 Copyright (c) 2010, 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 Enable the FIS running for giving port.
262 @param PciIo The PCI IO protocol instance.
263 @param Port The number of port.
264 @param Timeout The timeout value of enabling FIS.
266 @retval EFI_DEVICE_ERROR The FIS enable setting fails.
267 @retval EFI_TIMEOUT The FIS enable setting is time out.
268 @retval EFI_SUCCESS The FIS enable successfully.
273 AhciEnableFisReceive (
274 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
281 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
282 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
284 return AhciWaitMemSet (
287 EFI_AHCI_PORT_CMD_FR
,
288 EFI_AHCI_PORT_CMD_FR
,
294 Disable the FIS running for giving port.
296 @param PciIo The PCI IO protocol instance.
297 @param Port The number of port.
298 @param Timeout The timeout value of disabling FIS.
300 @retval EFI_DEVICE_ERROR The FIS disable setting fails.
301 @retval EFI_TIMEOUT The FIS disable setting is time out.
302 @retval EFI_UNSUPPORTED The port is in running state.
303 @retval EFI_SUCCESS The FIS disable successfully.
308 AhciDisableFisReceive (
309 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
317 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
318 Data
= AhciReadReg (PciIo
, Offset
);
321 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
323 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) != 0) {
324 return EFI_UNSUPPORTED
;
328 // Check if the Fis receive DMA engine for the port is running.
330 if ((Data
& EFI_AHCI_PORT_CMD_FR
) != EFI_AHCI_PORT_CMD_FR
) {
334 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
));
336 return AhciWaitMemSet (
339 EFI_AHCI_PORT_CMD_FR
,
348 Build the command list, command table and prepare the fis receiver.
350 @param PciIo The PCI IO protocol instance.
351 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
352 @param Port The number of port.
353 @param PortMultiplier The timeout value of stop.
354 @param CommandFis The control fis will be used for the transfer.
355 @param CommandList The command list will be used for the transfer.
356 @param AtapiCommand The atapi command will be used for the transfer.
357 @param AtapiCommandLength The length of the atapi command.
358 @param CommandSlotNumber The command slot will be used for the transfer.
359 @param DataPhysicalAddr The pointer to the data buffer pci bus master address.
360 @param DataLength The data count to be transferred.
366 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
367 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
369 IN UINT8 PortMultiplier
,
370 IN EFI_AHCI_COMMAND_FIS
*CommandFis
,
371 IN EFI_AHCI_COMMAND_LIST
*CommandList
,
372 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
373 IN UINT8 AtapiCommandLength
,
374 IN UINT8 CommandSlotNumber
,
375 IN OUT VOID
*DataPhysicalAddr
,
390 PrdtNumber
= (DataLength
+ EFI_AHCI_MAX_DATA_PER_PRDT
- 1) / EFI_AHCI_MAX_DATA_PER_PRDT
;
393 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
394 // It also limits that the maximum amount of the PRDT entry in the command table
397 ASSERT (PrdtNumber
<= 65535);
399 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFis
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
401 BaseAddr
= Data64
.Uint64
;
403 ZeroMem ((VOID
*)((UINTN
) BaseAddr
), sizeof (EFI_AHCI_RECEIVED_FIS
));
405 ZeroMem (AhciRegisters
->AhciCommandTable
, sizeof (EFI_AHCI_COMMAND_TABLE
));
407 CommandFis
->AhciCFisPmNum
= PortMultiplier
;
409 CopyMem (&AhciRegisters
->AhciCommandTable
->CommandFis
, CommandFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
411 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
412 if (AtapiCommand
!= NULL
) {
414 &AhciRegisters
->AhciCommandTable
->AtapiCmd
,
419 CommandList
->AhciCmdA
= 1;
420 CommandList
->AhciCmdP
= 1;
421 CommandList
->AhciCmdC
= (DataLength
== 0) ? 1 : 0;
423 AhciOrReg (PciIo
, Offset
, (EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
425 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
428 RemainedData
= (UINTN
) DataLength
;
429 MemAddr
= (UINTN
) DataPhysicalAddr
;
430 CommandList
->AhciCmdPrdtl
= (UINT32
)PrdtNumber
;
432 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
433 if (RemainedData
< EFI_AHCI_MAX_DATA_PER_PRDT
) {
434 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= (UINT32
)RemainedData
- 1;
436 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= EFI_AHCI_MAX_DATA_PER_PRDT
- 1;
439 Data64
.Uint64
= (UINT64
)MemAddr
;
440 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDba
= Data64
.Uint32
.Lower32
;
441 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbau
= Data64
.Uint32
.Upper32
;
442 RemainedData
-= EFI_AHCI_MAX_DATA_PER_PRDT
;
443 MemAddr
+= EFI_AHCI_MAX_DATA_PER_PRDT
;
447 // Set the last PRDT to Interrupt On Complete
449 if (PrdtNumber
> 0) {
450 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtNumber
- 1].AhciPrdtIoc
= 1;
454 (VOID
*) ((UINTN
) AhciRegisters
->AhciCmdList
+ (UINTN
) CommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
)),
456 sizeof (EFI_AHCI_COMMAND_LIST
)
459 Data64
.Uint64
= (UINT64
)(UINTN
) AhciRegisters
->AhciCommandTablePciAddr
;
460 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtba
= Data64
.Uint32
.Lower32
;
461 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtbau
= Data64
.Uint32
.Upper32
;
462 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdPmp
= PortMultiplier
;
469 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.
470 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.
475 AhciBuildCommandFis (
476 IN OUT EFI_AHCI_COMMAND_FIS
*CmdFis
,
477 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
480 ZeroMem (CmdFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
482 CmdFis
->AhciCFisType
= EFI_AHCI_FIS_REGISTER_H2D
;
484 // Indicator it's a command
486 CmdFis
->AhciCFisCmdInd
= 0x1;
487 CmdFis
->AhciCFisCmd
= AtaCommandBlock
->AtaCommand
;
489 CmdFis
->AhciCFisFeature
= AtaCommandBlock
->AtaFeatures
;
490 CmdFis
->AhciCFisFeatureExp
= AtaCommandBlock
->AtaFeaturesExp
;
492 CmdFis
->AhciCFisSecNum
= AtaCommandBlock
->AtaSectorNumber
;
493 CmdFis
->AhciCFisSecNumExp
= AtaCommandBlock
->AtaSectorNumberExp
;
495 CmdFis
->AhciCFisClyLow
= AtaCommandBlock
->AtaCylinderLow
;
496 CmdFis
->AhciCFisClyLowExp
= AtaCommandBlock
->AtaCylinderLowExp
;
498 CmdFis
->AhciCFisClyHigh
= AtaCommandBlock
->AtaCylinderHigh
;
499 CmdFis
->AhciCFisClyHighExp
= AtaCommandBlock
->AtaCylinderHighExp
;
501 CmdFis
->AhciCFisSecCount
= AtaCommandBlock
->AtaSectorCount
;
502 CmdFis
->AhciCFisSecCountExp
= AtaCommandBlock
->AtaSectorCountExp
;
504 CmdFis
->AhciCFisDevHead
= (UINT8
) (AtaCommandBlock
->AtaDeviceHead
| 0xE0);
508 Start a PIO data transfer on specific port.
510 @param PciIo The PCI IO protocol instance.
511 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
512 @param Port The number of port.
513 @param PortMultiplier The timeout value of stop.
514 @param AtapiCommand The atapi command will be used for the transfer.
515 @param AtapiCommandLength The length of the atapi command.
516 @param Read The transfer direction.
517 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
518 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
519 @param MemoryAddr The pointer to the data buffer.
520 @param DataCount The data count to be transferred.
521 @param Timeout The timeout value of non data transfer.
523 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
524 @retval EFI_TIMEOUT The operation is time out.
525 @retval EFI_UNSUPPORTED The device is not ready for transfer.
526 @retval EFI_SUCCESS The PIO data transfer executes successfully.
532 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
533 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
535 IN UINT8 PortMultiplier
,
536 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
537 IN UINT8 AtapiCommandLength
,
539 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
540 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
541 IN OUT VOID
*MemoryAddr
,
550 EFI_PHYSICAL_ADDRESS PhyAddr
;
553 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
555 EFI_AHCI_COMMAND_FIS CFis
;
556 EFI_AHCI_COMMAND_LIST CmdList
;
559 Flag
= EfiPciIoOperationBusMasterWrite
;
561 Flag
= EfiPciIoOperationBusMasterRead
;
565 // construct command list and command table with pci bus address
567 MapLength
= DataCount
;
568 Status
= PciIo
->Map (
577 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
578 return EFI_OUT_OF_RESOURCES
;
582 // Package read needed
584 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
586 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
588 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
589 CmdList
.AhciCmdW
= Read
? 0 : 1;
601 (VOID
*)(UINTN
)PhyAddr
,
605 Status
= AhciStartCommand (
611 if (EFI_ERROR (Status
)) {
616 // Checking the status and wait the driver sending data
618 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
620 // Wait device sends the PIO setup fis before data transfer
622 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
624 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_PIO_FIS_OFFSET
);
626 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_PIO_SETUP
) {
631 // Stall for 100 microseconds.
633 MicroSecondDelay(100);
639 Status
= EFI_TIMEOUT
;
644 // Wait for command compelte
646 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
647 Status
= AhciWaitMemSet (
655 if (EFI_ERROR (Status
)) {
659 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
660 Status
= AhciWaitMemSet (
663 EFI_AHCI_PORT_IS_PSS
,
664 EFI_AHCI_PORT_IS_PSS
,
667 if (EFI_ERROR (Status
)) {
678 AhciDisableFisReceive (
693 Start a DMA data transfer on specific port
695 @param PciIo The PCI IO protocol instance.
696 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
697 @param Port The number of port.
698 @param PortMultiplier The timeout value of stop.
699 @param AtapiCommand The atapi command will be used for the transfer.
700 @param AtapiCommandLength The length of the atapi command.
701 @param Read The transfer direction.
702 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
703 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
704 @param MemoryAddr The pointer to the data buffer.
705 @param DataCount The data count to be transferred.
706 @param Timeout The timeout value of non data transfer.
708 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
709 @retval EFI_TIMEOUT The operation is time out.
710 @retval EFI_UNSUPPORTED The device is not ready for transfer.
711 @retval EFI_SUCCESS The DMA data transfer executes successfully.
717 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
718 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
720 IN UINT8 PortMultiplier
,
721 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
722 IN UINT8 AtapiCommandLength
,
724 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
725 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
726 IN OUT VOID
*MemoryAddr
,
733 EFI_PHYSICAL_ADDRESS PhyAddr
;
736 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
737 EFI_AHCI_COMMAND_FIS CFis
;
738 EFI_AHCI_COMMAND_LIST CmdList
;
741 Flag
= EfiPciIoOperationBusMasterWrite
;
743 Flag
= EfiPciIoOperationBusMasterRead
;
747 // construct command list and command table with pci bus address
749 MapLength
= DataCount
;
750 Status
= PciIo
->Map (
759 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
760 return EFI_OUT_OF_RESOURCES
;
764 // Package read needed
766 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
768 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
770 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
771 CmdList
.AhciCmdW
= Read
? 0 : 1;
783 (VOID
*)(UINTN
)PhyAddr
,
787 Status
= AhciStartCommand (
793 if (EFI_ERROR (Status
)) {
798 // Wait device PRD processed
800 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
801 Status
= AhciWaitMemSet (
804 EFI_AHCI_PORT_IS_DPS
,
805 EFI_AHCI_PORT_IS_DPS
,
809 if (EFI_ERROR (Status
)) {
814 // Wait for command compelte
816 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
817 Status
= AhciWaitMemSet (
824 if (EFI_ERROR (Status
)) {
828 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
829 Status
= AhciWaitMemSet (
832 EFI_AHCI_PORT_IS_DHRS
,
833 EFI_AHCI_PORT_IS_DHRS
,
836 if (EFI_ERROR (Status
)) {
847 AhciDisableFisReceive (
862 Start a non data transfer on specific port.
864 @param PciIo The PCI IO protocol instance.
865 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
866 @param Port The number of port.
867 @param PortMultiplier The timeout value of stop.
868 @param AtapiCommand The atapi command will be used for the transfer.
869 @param AtapiCommandLength The length of the atapi command.
870 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
871 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
872 @param Timeout The timeout value of non data transfer.
874 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
875 @retval EFI_TIMEOUT The operation is time out.
876 @retval EFI_UNSUPPORTED The device is not ready for transfer.
877 @retval EFI_SUCCESS The non data transfer executes successfully.
882 AhciNonDataTransfer (
883 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
884 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
886 IN UINT8 PortMultiplier
,
887 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
888 IN UINT8 AtapiCommandLength
,
889 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
890 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
900 EFI_AHCI_COMMAND_FIS CFis
;
901 EFI_AHCI_COMMAND_LIST CmdList
;
904 // Package read needed
906 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
908 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
910 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
926 Status
= AhciStartCommand (
932 if (EFI_ERROR (Status
)) {
937 // Wait device sends the Response Fis
939 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
941 // Wait device sends the PIO setup fis before data transfer
943 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
945 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
947 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
952 // Stall for 100 microseconds.
954 MicroSecondDelay(100);
960 Status
= EFI_TIMEOUT
;
964 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
966 Status
= AhciWaitMemSet (
981 AhciDisableFisReceive (
991 Stop command running for giving port
993 @param PciIo The PCI IO protocol instance.
994 @param Port The number of port.
995 @param Timeout The timeout value of stop.
997 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
998 @retval EFI_TIMEOUT The operation is time out.
999 @retval EFI_SUCCESS The command stop successfully.
1005 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1013 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1014 Data
= AhciReadReg (PciIo
, Offset
);
1016 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) == 0) {
1020 if ((Data
& EFI_AHCI_PORT_CMD_ST
) != 0) {
1021 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_ST
));
1024 return AhciWaitMemSet (
1027 EFI_AHCI_PORT_CMD_CR
,
1034 Start command for give slot on specific port.
1036 @param PciIo The PCI IO protocol instance.
1037 @param Port The number of port.
1038 @param CommandSlot The number of CommandSlot.
1039 @param Timeout The timeout value of start.
1041 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
1042 @retval EFI_TIMEOUT The operation is time out.
1043 @retval EFI_SUCCESS The command start successfully.
1049 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1051 IN UINT8 CommandSlot
,
1064 // Collect AHCI controller information
1066 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1068 CmdSlotBit
= (UINT32
) (1 << CommandSlot
);
1070 AhciClearPortStatus (
1075 Status
= AhciEnableFisReceive (
1081 if (EFI_ERROR (Status
)) {
1086 // Setting the command
1088 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SACT
;
1089 AhciAndReg (PciIo
, Offset
, 0);
1090 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1092 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
1093 AhciAndReg (PciIo
, Offset
, 0);
1094 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1096 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1097 PortStatus
= AhciReadReg (PciIo
, Offset
);
1100 if ((PortStatus
& EFI_AHCI_PORT_CMD_ALPE
) != 0) {
1101 StartCmd
= AhciReadReg (PciIo
, Offset
);
1102 StartCmd
&= ~EFI_AHCI_PORT_CMD_ICC_MASK
;
1103 StartCmd
|= EFI_AHCI_PORT_CMD_ACTIVE
;
1106 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1107 PortTfd
= AhciReadReg (PciIo
, Offset
);
1109 if ((PortTfd
& (EFI_AHCI_PORT_TFD_BSY
| EFI_AHCI_PORT_TFD_DRQ
)) != 0) {
1110 if ((Capability
& BIT24
) != 0) {
1111 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1112 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_COL
);
1117 EFI_AHCI_PORT_CMD_COL
,
1124 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1125 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_ST
| StartCmd
);
1133 @param PciIo The PCI IO protocol instance.
1134 @param Port The number of port.
1135 @param Timeout The timeout value of reset.
1137 @retval EFI_DEVICE_ERROR The port reset unsuccessfully
1138 @retval EFI_TIMEOUT The reset operation is time out.
1139 @retval EFI_SUCCESS The port reset successfully.
1145 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1153 AhciClearPortStatus (PciIo
, Port
);
1155 AhciStopCommand (PciIo
, Port
, Timeout
);
1157 AhciDisableFisReceive (PciIo
, Port
, Timeout
);
1159 AhciEnableFisReceive (PciIo
, Port
, Timeout
);
1161 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
1163 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_DET_INIT
);
1166 // wait 5 milliseceond before de-assert DET
1168 MicroSecondDelay (5000);
1170 AhciAndReg (PciIo
, Offset
, (UINT32
)EFI_AHCI_PORT_SCTL_MASK
);
1173 // wait 5 milliseceond before de-assert DET
1175 MicroSecondDelay (5000);
1178 // Wait for communication to be re-established
1180 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
1181 Status
= AhciWaitMemSet (
1184 EFI_AHCI_PORT_SSTS_DET_MASK
,
1185 EFI_AHCI_PORT_SSTS_DET_PCE
,
1189 if (EFI_ERROR (Status
)) {
1193 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
1194 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_ERR_CLEAR
);
1202 @param PciIo The PCI IO protocol instance.
1203 @param Timeout The timeout value of reset.
1206 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
1207 @retval EFI_TIMEOUT The reset operation is time out.
1208 @retval EFI_SUCCESS AHCI controller is reset successfully.
1214 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1222 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
1224 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_RESET
);
1226 Status
= EFI_TIMEOUT
;
1228 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
1231 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1233 if ((Value
& EFI_AHCI_GHC_RESET
) == 0) {
1238 // Stall for 100 microseconds.
1240 MicroSecondDelay(100);
1243 } while (Delay
> 0);
1253 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
1255 @param PciIo The PCI IO protocol instance.
1256 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1257 @param Port The number of port.
1258 @param PortMultiplier The timeout value of stop.
1259 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1261 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
1262 @retval Others Fail to get return status data.
1267 AhciAtaSmartReturnStatusCheck (
1268 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1269 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1271 IN UINT8 PortMultiplier
,
1272 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1276 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1282 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1284 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1285 AtaCommandBlock
.AtaFeatures
= ATA_SMART_RETURN_STATUS
;
1286 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1287 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1290 // Send S.M.A.R.T Read Return Status command to device
1292 Status
= AhciNonDataTransfer (
1296 (UINT8
)PortMultiplier
,
1304 if (EFI_ERROR (Status
)) {
1305 return EFI_DEVICE_ERROR
;
1308 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1310 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
1312 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
1313 LBAMid
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[5];
1314 LBAHigh
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[6];
1316 if ((LBAMid
== 0x4f) && (LBAHigh
== 0xc2)) {
1318 // The threshold exceeded condition is not detected by the device
1320 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
1322 } else if ((LBAMid
== 0xf4) && (LBAHigh
== 0x2c)) {
1324 // The threshold exceeded condition is detected by the device
1326 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is detected\n"));
1334 Enable SMART command of the disk if supported.
1336 @param PciIo The PCI IO protocol instance.
1337 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1338 @param Port The number of port.
1339 @param PortMultiplier The timeout value of stop.
1340 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
1341 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1346 AhciAtaSmartSupport (
1347 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1348 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1350 IN UINT8 PortMultiplier
,
1351 IN EFI_IDENTIFY_DATA
*IdentifyData
,
1352 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1356 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1359 // Detect if the device supports S.M.A.R.T.
1361 if ((IdentifyData
->AtaData
.command_set_supported_82
& 0x0001) != 0x0001) {
1363 // S.M.A.R.T is not supported by the device
1365 DEBUG ((EFI_D_INFO
, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
1366 Port
, PortMultiplier
));
1369 // Check if the feature is enabled. If not, then enable S.M.A.R.T.
1371 if ((IdentifyData
->AtaData
.command_set_feature_enb_85
& 0x0001) != 0x0001) {
1372 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1374 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1375 AtaCommandBlock
.AtaFeatures
= ATA_SMART_ENABLE_OPERATION
;
1376 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1377 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1380 // Send S.M.A.R.T Enable command to device
1382 Status
= AhciNonDataTransfer (
1386 (UINT8
)PortMultiplier
,
1395 if (!EFI_ERROR (Status
)) {
1397 // Send S.M.A.R.T AutoSave command to device
1399 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1401 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1402 AtaCommandBlock
.AtaFeatures
= 0xD2;
1403 AtaCommandBlock
.AtaSectorCount
= 0xF1;
1404 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1405 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1407 Status
= AhciNonDataTransfer (
1411 (UINT8
)PortMultiplier
,
1419 if (!EFI_ERROR (Status
)) {
1420 Status
= AhciAtaSmartReturnStatusCheck (
1424 (UINT8
)PortMultiplier
,
1430 DEBUG ((EFI_D_INFO
, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
1431 Port
, PortMultiplier
));
1438 Send Buffer cmd to specific device.
1440 @param PciIo The PCI IO protocol instance.
1441 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1442 @param Port The number of port.
1443 @param PortMultiplier The timeout value of stop.
1444 @param Buffer The data buffer to store IDENTIFY PACKET data.
1446 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1447 @retval EFI_TIMEOUT The operation is time out.
1448 @retval EFI_UNSUPPORTED The device is not ready for executing.
1449 @retval EFI_SUCCESS The cmd executes successfully.
1455 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1456 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1458 IN UINT8 PortMultiplier
,
1459 IN OUT EFI_IDENTIFY_DATA
*Buffer
1463 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1464 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1466 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
1467 return EFI_INVALID_PARAMETER
;
1470 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1471 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1473 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DRIVE
;
1474 AtaCommandBlock
.AtaSectorCount
= 1;
1476 Status
= AhciPioTransfer (
1487 sizeof (EFI_IDENTIFY_DATA
),
1495 Send Buffer cmd to specific device.
1497 @param PciIo The PCI IO protocol instance.
1498 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1499 @param Port The number of port.
1500 @param PortMultiplier The timeout value of stop.
1501 @param Buffer The data buffer to store IDENTIFY PACKET data.
1503 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1504 @retval EFI_TIMEOUT The operation is time out.
1505 @retval EFI_UNSUPPORTED The device is not ready for executing.
1506 @retval EFI_SUCCESS The cmd executes successfully.
1511 AhciIdentifyPacket (
1512 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1513 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1515 IN UINT8 PortMultiplier
,
1516 IN OUT EFI_IDENTIFY_DATA
*Buffer
1520 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1521 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1523 if (PciIo
== NULL
|| AhciRegisters
== NULL
) {
1524 return EFI_INVALID_PARAMETER
;
1527 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1528 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1530 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DEVICE
;
1531 AtaCommandBlock
.AtaSectorCount
= 1;
1533 Status
= AhciPioTransfer (
1544 sizeof (EFI_IDENTIFY_DATA
),
1552 Send SET FEATURE cmd on specific device.
1554 @param PciIo The PCI IO protocol instance.
1555 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1556 @param Port The number of port.
1557 @param PortMultiplier The timeout value of stop.
1558 @param Feature The data to send Feature register.
1559 @param FeatureSpecificData The specific data for SET FEATURE cmd.
1561 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1562 @retval EFI_TIMEOUT The operation is time out.
1563 @retval EFI_UNSUPPORTED The device is not ready for executing.
1564 @retval EFI_SUCCESS The cmd executes successfully.
1569 AhciDeviceSetFeature (
1570 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1571 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1573 IN UINT8 PortMultiplier
,
1575 IN UINT32 FeatureSpecificData
1579 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1580 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1582 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1583 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1585 AtaCommandBlock
.AtaCommand
= ATA_CMD_SET_FEATURES
;
1586 AtaCommandBlock
.AtaFeatures
= (UINT8
) Feature
;
1587 AtaCommandBlock
.AtaFeaturesExp
= (UINT8
) (Feature
>> 8);
1588 AtaCommandBlock
.AtaSectorCount
= (UINT8
) FeatureSpecificData
;
1589 AtaCommandBlock
.AtaSectorNumber
= (UINT8
) (FeatureSpecificData
>> 8);
1590 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (FeatureSpecificData
>> 16);
1591 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (FeatureSpecificData
>> 24);
1593 Status
= AhciNonDataTransfer (
1597 (UINT8
)PortMultiplier
,
1609 This function is used to send out ATAPI commands conforms to the Packet Command
1612 @param PciIo The PCI IO protocol instance.
1613 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1614 @param Port The number of port.
1615 @param PortMultiplier The number of port multiplier.
1616 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
1618 @retval EFI_SUCCESS send out the ATAPI packet command successfully
1619 and device sends data successfully.
1620 @retval EFI_DEVICE_ERROR the device failed to send data.
1625 AhciPacketCommandExecute (
1626 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1627 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1629 IN UINT8 PortMultiplier
,
1630 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1636 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1637 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1641 if (Packet
== NULL
|| Packet
->Cdb
== NULL
) {
1642 return EFI_INVALID_PARAMETER
;
1645 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1646 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1647 AtaCommandBlock
.AtaCommand
= ATA_CMD_PACKET
;
1651 AtaCommandBlock
.AtaFeatures
= 0x00;
1653 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
1654 // determine how many data should be transferred.
1656 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
& 0x00ff);
1657 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
>> 8);
1659 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1660 Buffer
= Packet
->InDataBuffer
;
1661 Length
= Packet
->InTransferLength
;
1664 Buffer
= Packet
->OutDataBuffer
;
1665 Length
= Packet
->OutTransferLength
;
1670 Status
= AhciNonDataTransfer (
1683 // READ_CAPACITY cmd may execute failure. Retry 5 times
1685 if (((UINT8
*)Packet
->Cdb
)[0] == ATA_CMD_READ_CAPACITY
) {
1691 Status
= AhciPioTransfer (
1705 if (!EFI_ERROR (Status
)) {
1709 } while (Retry
!= 0);
1715 Allocate transfer-related data struct which is used at AHCI mode.
1717 @param PciIo The PCI IO protocol instance.
1718 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1723 AhciCreateTransferDescriptor (
1724 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1725 IN OUT EFI_AHCI_REGISTERS
*AhciRegisters
1733 UINT8 MaxPortNumber
;
1734 UINT8 MaxCommandSlotNumber
;
1735 BOOLEAN Support64Bit
;
1736 UINT64 MaxReceiveFisSize
;
1737 UINT64 MaxCommandListSize
;
1738 UINT64 MaxCommandTableSize
;
1742 // Collect AHCI controller information
1744 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1745 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
1747 // Get the number of command slots per port supported by this HBA.
1749 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1750 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
1752 MaxReceiveFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1753 Status
= PciIo
->AllocateBuffer (
1756 EfiBootServicesData
,
1757 (UINTN
)EFI_SIZE_TO_PAGES (MaxReceiveFisSize
),
1762 if (EFI_ERROR (Status
)) {
1763 return EFI_OUT_OF_RESOURCES
;
1766 ZeroMem (Buffer
, (UINTN
)MaxReceiveFisSize
);
1768 AhciRegisters
->AhciRFis
= Buffer
;
1769 AhciRegisters
->MaxReceiveFisSize
= MaxReceiveFisSize
;
1770 Bytes
= (UINTN
)MaxReceiveFisSize
;
1772 Status
= PciIo
->Map (
1774 EfiPciIoOperationBusMasterCommonBuffer
,
1777 (EFI_PHYSICAL_ADDRESS
*) &AhciRegisters
->AhciRFisPciAddr
,
1778 &AhciRegisters
->MapRFis
1781 if (EFI_ERROR (Status
) || (Bytes
!= MaxReceiveFisSize
)) {
1783 // Map error or unable to map the whole RFis buffer into a contiguous region.
1785 Status
= EFI_OUT_OF_RESOURCES
;
1789 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)(UINTN
)AhciRegisters
->AhciRFisPciAddr
> 0x100000000ULL
)) {
1791 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1793 Status
= EFI_DEVICE_ERROR
;
1798 // Allocate memory for command list
1799 // Note that the implemenation is a single task model which only use a command list for all ports.
1802 MaxCommandListSize
= MaxCommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
);
1803 Status
= PciIo
->AllocateBuffer (
1806 EfiBootServicesData
,
1807 (UINTN
)EFI_SIZE_TO_PAGES (MaxCommandListSize
),
1812 if (EFI_ERROR (Status
)) {
1814 // Free mapped resource.
1816 Status
= EFI_OUT_OF_RESOURCES
;
1820 ZeroMem (Buffer
, (UINTN
)MaxCommandListSize
);
1822 AhciRegisters
->AhciCmdList
= Buffer
;
1823 AhciRegisters
->MaxCommandListSize
= MaxCommandListSize
;
1824 Bytes
= (UINTN
)MaxCommandListSize
;
1826 Status
= PciIo
->Map (
1828 EfiPciIoOperationBusMasterCommonBuffer
,
1831 (EFI_PHYSICAL_ADDRESS
*)&AhciRegisters
->AhciCmdListPciAddr
,
1832 &AhciRegisters
->MapCmdList
1835 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandListSize
)) {
1837 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1839 Status
= EFI_OUT_OF_RESOURCES
;
1843 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)(UINTN
)AhciRegisters
->AhciCmdListPciAddr
> 0x100000000ULL
)) {
1845 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1847 Status
= EFI_DEVICE_ERROR
;
1852 // Allocate memory for command table
1853 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
1856 MaxCommandTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
1858 Status
= PciIo
->AllocateBuffer (
1861 EfiBootServicesData
,
1862 (UINTN
)EFI_SIZE_TO_PAGES (MaxCommandTableSize
),
1867 if (EFI_ERROR (Status
)) {
1869 // Free mapped resource.
1871 Status
= EFI_OUT_OF_RESOURCES
;
1875 ZeroMem (Buffer
, (UINTN
)MaxCommandTableSize
);
1877 AhciRegisters
->AhciCommandTable
= Buffer
;
1878 AhciRegisters
->MaxCommandTableSize
= MaxCommandTableSize
;
1879 Bytes
= (UINTN
)MaxCommandTableSize
;
1881 Status
= PciIo
->Map (
1883 EfiPciIoOperationBusMasterCommonBuffer
,
1886 (EFI_PHYSICAL_ADDRESS
*)&AhciRegisters
->AhciCommandTablePciAddr
,
1887 &AhciRegisters
->MapCommandTable
1890 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandTableSize
)) {
1892 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1894 Status
= EFI_OUT_OF_RESOURCES
;
1898 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)(UINTN
)AhciRegisters
->AhciCommandTablePciAddr
> 0x100000000ULL
)) {
1900 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1902 Status
= EFI_DEVICE_ERROR
;
1908 // Map error or unable to map the whole CmdList buffer into a contiguous region.
1913 AhciRegisters
->MapCommandTable
1918 (UINTN
)EFI_SIZE_TO_PAGES (MaxCommandTableSize
),
1919 AhciRegisters
->AhciCommandTable
1924 AhciRegisters
->MapCmdList
1929 (UINTN
)EFI_SIZE_TO_PAGES (MaxCommandListSize
),
1930 AhciRegisters
->AhciCmdList
1935 AhciRegisters
->MapRFis
1940 (UINTN
)EFI_SIZE_TO_PAGES (MaxReceiveFisSize
),
1941 AhciRegisters
->AhciRFis
1948 Initialize ATA host controller at AHCI mode.
1950 The function is designed to initialize ATA host controller.
1952 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
1957 AhciModeInitialization (
1958 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
1962 EFI_PCI_IO_PROTOCOL
*PciIo
;
1963 EFI_IDE_CONTROLLER_INIT_PROTOCOL
*IdeInit
;
1965 UINT8 MaxPortNumber
;
1966 UINT32 PortImplementBitMap
;
1967 UINT8 MaxCommandSlotNumber
;
1968 BOOLEAN Support64Bit
;
1970 EFI_AHCI_REGISTERS
*AhciRegisters
;
1976 EFI_IDENTIFY_DATA Buffer
;
1977 EFI_ATA_DEVICE_TYPE DeviceType
;
1978 EFI_ATA_COLLECTIVE_MODE
*SupportedModes
;
1979 EFI_ATA_TRANSFER_MODE TransferMode
;
1981 if (Instance
== NULL
) {
1982 return EFI_INVALID_PARAMETER
;
1985 PciIo
= Instance
->PciIo
;
1986 IdeInit
= Instance
->IdeControllerInit
;
1988 Status
= AhciReset (PciIo
, ATA_ATAPI_TIMEOUT
);
1990 if (EFI_ERROR (Status
)) {
1991 return EFI_DEVICE_ERROR
;
1995 // Enable AE before accessing any AHCI registers
1997 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
2000 // Collect AHCI controller information
2002 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
2005 // Get the number of command slots per port supported by this HBA.
2007 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
2008 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
2011 // Get the bit map of those ports exposed by this HBA.
2012 // It indicates which ports that the HBA supports are available for software to use.
2014 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
2015 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
2017 AhciRegisters
= &Instance
->AhciRegisters
;
2018 Status
= AhciCreateTransferDescriptor (PciIo
, AhciRegisters
);
2020 if (EFI_ERROR (Status
)) {
2021 return EFI_OUT_OF_RESOURCES
;
2024 for (Port
= 0; Port
< MaxPortNumber
; Port
++) {
2025 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFisPciAddr
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
2027 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FB
;
2028 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2029 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FBU
;
2030 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2033 // Single task envrionment, we only use one command table for all port
2035 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdListPciAddr
);
2037 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLB
;
2038 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2039 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLBU
;
2040 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2042 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
2043 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2045 if ((Capability
& EFI_AHCI_PORT_CMD_ASP
) != 0) {
2046 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_SUD
);
2048 Data
= AhciReadReg (PciIo
, Offset
);
2049 if ((Data
& EFI_AHCI_PORT_CMD_CPD
) != 0) {
2050 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_POD
);
2053 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
|EFI_AHCI_PORT_CMD_COL
|EFI_AHCI_PORT_CMD_ST
));
2056 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
2057 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_SCTL_IPM_MASK
));
2059 AhciAndReg (PciIo
, Offset
,(UINT32
) ~(EFI_AHCI_PORT_SCTL_IPM_PSD
));
2060 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_PSD
);
2062 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_SCTL_IPM_SSD
));
2063 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_SSD
);
2065 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IE
;
2066 AhciAndReg (PciIo
, Offset
, 0);
2068 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
2069 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
2073 // Stall for 100 milliseconds.
2075 MicroSecondDelay(100000);
2077 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBeforeChannelEnumeration
, Port
);
2079 for (Port
= 0; Port
< MaxPortNumber
; Port
++) {
2080 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
2082 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
2083 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
2089 // Found device in the port
2091 if (Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) {
2092 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SIG
;
2094 Status
= AhciWaitMemSet (
2101 if (EFI_ERROR (Status
)) {
2106 // Now inform the IDE Controller Init Module.
2108 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBusBeforeDevicePresenceDetection
, Port
);
2110 Data
= AhciReadReg (PciIo
, Offset
);
2112 if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATAPI_DEVICE_SIG
) {
2113 Status
= AhciIdentifyPacket (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2115 if (EFI_ERROR (Status
)) {
2119 DeviceType
= EfiIdeCdrom
;
2120 } else if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATA_DEVICE_SIG
) {
2121 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2123 if (EFI_ERROR (Status
)) {
2127 DeviceType
= EfiIdeHarddisk
;
2132 DEBUG ((EFI_D_INFO
, "port [%d] port mulitplier [%d] has a [%a]\n",
2133 Port
, 0, DeviceType
== EfiIdeCdrom
? "cdrom" : "harddisk"));
2136 // If the device is a hard disk, then try to enable S.M.A.R.T feature
2138 if (DeviceType
== EfiIdeHarddisk
) {
2139 AhciAtaSmartSupport (
2150 // Submit identify data to IDE controller init driver
2152 IdeInit
->SubmitData (IdeInit
, Port
, 0, &Buffer
);
2155 // Now start to config ide device parameter and transfer mode.
2157 Status
= IdeInit
->CalculateMode (
2163 if (EFI_ERROR (Status
)) {
2164 DEBUG ((EFI_D_ERROR
, "Calculate Mode Fail, Status = %r\n", Status
));
2169 // Set best supported PIO mode on this IDE device
2171 if (SupportedModes
->PioMode
.Mode
<= EfiAtaPioMode2
) {
2172 TransferMode
.ModeCategory
= EFI_ATA_MODE_DEFAULT_PIO
;
2174 TransferMode
.ModeCategory
= EFI_ATA_MODE_FLOW_PIO
;
2177 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->PioMode
.Mode
);
2180 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
2181 // be set together. Only one DMA mode can be set to a device. If setting
2182 // DMA mode operation fails, we can continue moving on because we only use
2183 // PIO mode at boot time. DMA modes are used by certain kind of OS booting
2185 if (SupportedModes
->UdmaMode
.Valid
) {
2186 TransferMode
.ModeCategory
= EFI_ATA_MODE_UDMA
;
2187 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->UdmaMode
.Mode
);
2188 } else if (SupportedModes
->MultiWordDmaMode
.Valid
) {
2189 TransferMode
.ModeCategory
= EFI_ATA_MODE_MDMA
;
2190 TransferMode
.ModeNumber
= (UINT8
) SupportedModes
->MultiWordDmaMode
.Mode
;
2193 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, 0, 0x03, (UINT32
)(*(UINT8
*)&TransferMode
));
2195 if (EFI_ERROR (Status
)) {
2196 DEBUG ((EFI_D_ERROR
, "Set transfer Mode Fail, Status = %r\n", Status
));
2200 // Found a ATA or ATAPI device, add it into the device list.
2202 CreateNewDeviceInfo (Instance
, Port
, 0, DeviceType
, &Buffer
);