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
;
1781 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr
;
1782 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr
;
1783 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr
;
1787 // Collect AHCI controller information
1789 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1790 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
1792 // Get the number of command slots per port supported by this HBA.
1794 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1795 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
1797 MaxReceiveFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1798 Status
= PciIo
->AllocateBuffer (
1801 EfiBootServicesData
,
1802 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
1807 if (EFI_ERROR (Status
)) {
1808 return EFI_OUT_OF_RESOURCES
;
1811 ZeroMem (Buffer
, (UINTN
)MaxReceiveFisSize
);
1813 AhciRegisters
->AhciRFis
= Buffer
;
1814 AhciRegisters
->MaxReceiveFisSize
= MaxReceiveFisSize
;
1815 Bytes
= (UINTN
)MaxReceiveFisSize
;
1817 Status
= PciIo
->Map (
1819 EfiPciIoOperationBusMasterCommonBuffer
,
1823 &AhciRegisters
->MapRFis
1826 if (EFI_ERROR (Status
) || (Bytes
!= MaxReceiveFisSize
)) {
1828 // Map error or unable to map the whole RFis buffer into a contiguous region.
1830 Status
= EFI_OUT_OF_RESOURCES
;
1834 if ((!Support64Bit
) && (AhciRFisPciAddr
> 0x100000000ULL
)) {
1836 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1838 Status
= EFI_DEVICE_ERROR
;
1841 AhciRegisters
->AhciRFisPciAddr
= (EFI_AHCI_RECEIVED_FIS
*)(UINTN
)AhciRFisPciAddr
;
1844 // Allocate memory for command list
1845 // Note that the implemenation is a single task model which only use a command list for all ports.
1848 MaxCommandListSize
= MaxCommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
);
1849 Status
= PciIo
->AllocateBuffer (
1852 EfiBootServicesData
,
1853 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
1858 if (EFI_ERROR (Status
)) {
1860 // Free mapped resource.
1862 Status
= EFI_OUT_OF_RESOURCES
;
1866 ZeroMem (Buffer
, (UINTN
)MaxCommandListSize
);
1868 AhciRegisters
->AhciCmdList
= Buffer
;
1869 AhciRegisters
->MaxCommandListSize
= MaxCommandListSize
;
1870 Bytes
= (UINTN
)MaxCommandListSize
;
1872 Status
= PciIo
->Map (
1874 EfiPciIoOperationBusMasterCommonBuffer
,
1877 &AhciCmdListPciAddr
,
1878 &AhciRegisters
->MapCmdList
1881 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandListSize
)) {
1883 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1885 Status
= EFI_OUT_OF_RESOURCES
;
1889 if ((!Support64Bit
) && (AhciCmdListPciAddr
> 0x100000000ULL
)) {
1891 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1893 Status
= EFI_DEVICE_ERROR
;
1896 AhciRegisters
->AhciCmdListPciAddr
= (EFI_AHCI_COMMAND_LIST
*)(UINTN
)AhciCmdListPciAddr
;
1899 // Allocate memory for command table
1900 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
1903 MaxCommandTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
1905 Status
= PciIo
->AllocateBuffer (
1908 EfiBootServicesData
,
1909 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
1914 if (EFI_ERROR (Status
)) {
1916 // Free mapped resource.
1918 Status
= EFI_OUT_OF_RESOURCES
;
1922 ZeroMem (Buffer
, (UINTN
)MaxCommandTableSize
);
1924 AhciRegisters
->AhciCommandTable
= Buffer
;
1925 AhciRegisters
->MaxCommandTableSize
= MaxCommandTableSize
;
1926 Bytes
= (UINTN
)MaxCommandTableSize
;
1928 Status
= PciIo
->Map (
1930 EfiPciIoOperationBusMasterCommonBuffer
,
1933 &AhciCommandTablePciAddr
,
1934 &AhciRegisters
->MapCommandTable
1937 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandTableSize
)) {
1939 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1941 Status
= EFI_OUT_OF_RESOURCES
;
1945 if ((!Support64Bit
) && (AhciCommandTablePciAddr
> 0x100000000ULL
)) {
1947 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1949 Status
= EFI_DEVICE_ERROR
;
1952 AhciRegisters
->AhciCommandTablePciAddr
= (EFI_AHCI_COMMAND_TABLE
*)(UINTN
)AhciCommandTablePciAddr
;
1956 // Map error or unable to map the whole CmdList buffer into a contiguous region.
1961 AhciRegisters
->MapCommandTable
1966 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
1967 AhciRegisters
->AhciCommandTable
1972 AhciRegisters
->MapCmdList
1977 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
1978 AhciRegisters
->AhciCmdList
1983 AhciRegisters
->MapRFis
1988 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
1989 AhciRegisters
->AhciRFis
1996 Initialize ATA host controller at AHCI mode.
1998 The function is designed to initialize ATA host controller.
2000 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
2005 AhciModeInitialization (
2006 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
2010 EFI_PCI_IO_PROTOCOL
*PciIo
;
2011 EFI_IDE_CONTROLLER_INIT_PROTOCOL
*IdeInit
;
2013 UINT8 MaxPortNumber
;
2014 UINT32 PortImplementBitMap
;
2015 UINT8 MaxCommandSlotNumber
;
2016 BOOLEAN Support64Bit
;
2018 EFI_AHCI_REGISTERS
*AhciRegisters
;
2024 EFI_IDENTIFY_DATA Buffer
;
2025 EFI_ATA_DEVICE_TYPE DeviceType
;
2026 EFI_ATA_COLLECTIVE_MODE
*SupportedModes
;
2027 EFI_ATA_TRANSFER_MODE TransferMode
;
2029 if (Instance
== NULL
) {
2030 return EFI_INVALID_PARAMETER
;
2033 PciIo
= Instance
->PciIo
;
2034 IdeInit
= Instance
->IdeControllerInit
;
2036 Status
= AhciReset (PciIo
, ATA_ATAPI_TIMEOUT
);
2038 if (EFI_ERROR (Status
)) {
2039 return EFI_DEVICE_ERROR
;
2043 // Enable AE before accessing any AHCI registers
2045 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
2048 // Collect AHCI controller information
2050 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
2053 // Get the number of command slots per port supported by this HBA.
2055 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
2056 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
2059 // Get the bit map of those ports exposed by this HBA.
2060 // It indicates which ports that the HBA supports are available for software to use.
2062 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
2063 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
2065 AhciRegisters
= &Instance
->AhciRegisters
;
2066 Status
= AhciCreateTransferDescriptor (PciIo
, AhciRegisters
);
2068 if (EFI_ERROR (Status
)) {
2069 return EFI_OUT_OF_RESOURCES
;
2072 for (Port
= 0; Port
< MaxPortNumber
; Port
++) {
2073 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFisPciAddr
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
2075 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FB
;
2076 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2077 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FBU
;
2078 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2081 // Single task envrionment, we only use one command table for all port
2083 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdListPciAddr
);
2085 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLB
;
2086 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2087 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLBU
;
2088 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2090 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
2091 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2093 if ((Capability
& EFI_AHCI_PORT_CMD_ASP
) != 0) {
2094 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_SUD
);
2096 Data
= AhciReadReg (PciIo
, Offset
);
2097 if ((Data
& EFI_AHCI_PORT_CMD_CPD
) != 0) {
2098 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_POD
);
2101 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
|EFI_AHCI_PORT_CMD_COL
|EFI_AHCI_PORT_CMD_ST
));
2104 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
2105 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_SCTL_IPM_MASK
));
2107 AhciAndReg (PciIo
, Offset
,(UINT32
) ~(EFI_AHCI_PORT_SCTL_IPM_PSD
));
2108 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_PSD
);
2110 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_SCTL_IPM_SSD
));
2111 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_SSD
);
2113 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IE
;
2114 AhciAndReg (PciIo
, Offset
, 0);
2116 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
2117 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
2121 // Stall for 100 milliseconds.
2123 MicroSecondDelay(100000);
2125 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBeforeChannelEnumeration
, Port
);
2127 for (Port
= 0; Port
< MaxPortNumber
; Port
++) {
2128 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
2130 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
2131 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
2137 // Found device in the port
2139 if (Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) {
2140 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SIG
;
2142 Status
= AhciWaitMemSet (
2149 if (EFI_ERROR (Status
)) {
2154 // Now inform the IDE Controller Init Module.
2156 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBusBeforeDevicePresenceDetection
, Port
);
2158 Data
= AhciReadReg (PciIo
, Offset
);
2160 if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATAPI_DEVICE_SIG
) {
2161 Status
= AhciIdentifyPacket (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2163 if (EFI_ERROR (Status
)) {
2167 DeviceType
= EfiIdeCdrom
;
2168 } else if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATA_DEVICE_SIG
) {
2169 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2171 if (EFI_ERROR (Status
)) {
2175 DeviceType
= EfiIdeHarddisk
;
2180 DEBUG ((EFI_D_INFO
, "port [%d] port mulitplier [%d] has a [%a]\n",
2181 Port
, 0, DeviceType
== EfiIdeCdrom
? "cdrom" : "harddisk"));
2184 // If the device is a hard disk, then try to enable S.M.A.R.T feature
2186 if (DeviceType
== EfiIdeHarddisk
) {
2187 AhciAtaSmartSupport (
2198 // Submit identify data to IDE controller init driver
2200 IdeInit
->SubmitData (IdeInit
, Port
, 0, &Buffer
);
2203 // Now start to config ide device parameter and transfer mode.
2205 Status
= IdeInit
->CalculateMode (
2211 if (EFI_ERROR (Status
)) {
2212 DEBUG ((EFI_D_ERROR
, "Calculate Mode Fail, Status = %r\n", Status
));
2217 // Set best supported PIO mode on this IDE device
2219 if (SupportedModes
->PioMode
.Mode
<= EfiAtaPioMode2
) {
2220 TransferMode
.ModeCategory
= EFI_ATA_MODE_DEFAULT_PIO
;
2222 TransferMode
.ModeCategory
= EFI_ATA_MODE_FLOW_PIO
;
2225 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->PioMode
.Mode
);
2228 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
2229 // be set together. Only one DMA mode can be set to a device. If setting
2230 // DMA mode operation fails, we can continue moving on because we only use
2231 // PIO mode at boot time. DMA modes are used by certain kind of OS booting
2233 if (SupportedModes
->UdmaMode
.Valid
) {
2234 TransferMode
.ModeCategory
= EFI_ATA_MODE_UDMA
;
2235 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->UdmaMode
.Mode
);
2236 } else if (SupportedModes
->MultiWordDmaMode
.Valid
) {
2237 TransferMode
.ModeCategory
= EFI_ATA_MODE_MDMA
;
2238 TransferMode
.ModeNumber
= (UINT8
) SupportedModes
->MultiWordDmaMode
.Mode
;
2241 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, 0, 0x03, (UINT32
)(*(UINT8
*)&TransferMode
));
2243 if (EFI_ERROR (Status
)) {
2244 DEBUG ((EFI_D_ERROR
, "Set transfer Mode Fail, Status = %r\n", Status
));
2248 // Found a ATA or ATAPI device, add it into the device list.
2250 CreateNewDeviceInfo (Instance
, Port
, 0, DeviceType
, &Buffer
);