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
= 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
= 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.
531 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
532 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
534 IN UINT8 PortMultiplier
,
535 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
536 IN UINT8 AtapiCommandLength
,
538 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
539 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
540 IN OUT VOID
*MemoryAddr
,
549 EFI_PHYSICAL_ADDRESS PhyAddr
;
552 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
554 EFI_AHCI_COMMAND_FIS CFis
;
555 EFI_AHCI_COMMAND_LIST CmdList
;
558 Flag
= EfiPciIoOperationBusMasterWrite
;
560 Flag
= EfiPciIoOperationBusMasterRead
;
564 // construct command list and command table with pci bus address
566 MapLength
= DataCount
;
567 Status
= PciIo
->Map (
576 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
577 return EFI_OUT_OF_RESOURCES
;
581 // Package read needed
583 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
585 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
587 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
588 CmdList
.AhciCmdW
= Read
? 0 : 1;
600 (VOID
*)(UINTN
)PhyAddr
,
604 Status
= AhciStartCommand (
610 if (EFI_ERROR (Status
)) {
615 // Checking the status and wait the driver sending data
617 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
619 // Wait device sends the PIO setup fis before data transfer
621 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
623 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_PIO_FIS_OFFSET
);
625 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_PIO_SETUP
) {
630 // Stall for 100 microseconds.
632 MicroSecondDelay(100);
638 Status
= EFI_TIMEOUT
;
643 // Wait for command compelte
645 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
646 Status
= AhciWaitMemSet (
654 if (EFI_ERROR (Status
)) {
658 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
659 Status
= AhciWaitMemSet (
662 EFI_AHCI_PORT_IS_PSS
,
663 EFI_AHCI_PORT_IS_PSS
,
666 if (EFI_ERROR (Status
)) {
677 AhciDisableFisReceive (
692 Start a DMA data transfer on specific port
694 @param PciIo The PCI IO protocol instance.
695 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
696 @param Port The number of port.
697 @param PortMultiplier The timeout value of stop.
698 @param AtapiCommand The atapi command will be used for the transfer.
699 @param AtapiCommandLength The length of the atapi command.
700 @param Read The transfer direction.
701 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
702 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
703 @param MemoryAddr The pointer to the data buffer.
704 @param DataCount The data count to be transferred.
705 @param Timeout The timeout value of non data transfer.
707 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
708 @retval EFI_TIMEOUT The operation is time out.
709 @retval EFI_UNSUPPORTED The device is not ready for transfer.
710 @retval EFI_SUCCESS The DMA data transfer executes successfully.
716 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
717 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
719 IN UINT8 PortMultiplier
,
720 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
721 IN UINT8 AtapiCommandLength
,
723 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
724 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
725 IN OUT VOID
*MemoryAddr
,
732 EFI_PHYSICAL_ADDRESS PhyAddr
;
735 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
736 EFI_AHCI_COMMAND_FIS CFis
;
737 EFI_AHCI_COMMAND_LIST CmdList
;
740 Flag
= EfiPciIoOperationBusMasterWrite
;
742 Flag
= EfiPciIoOperationBusMasterRead
;
746 // construct command list and command table with pci bus address
748 MapLength
= DataCount
;
749 Status
= PciIo
->Map (
758 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
759 return EFI_OUT_OF_RESOURCES
;
763 // Package read needed
765 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
767 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
769 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
770 CmdList
.AhciCmdW
= Read
? 0 : 1;
782 (VOID
*)(UINTN
)PhyAddr
,
786 Status
= AhciStartCommand (
792 if (EFI_ERROR (Status
)) {
797 // Wait device PRD processed
799 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
800 Status
= AhciWaitMemSet (
803 EFI_AHCI_PORT_IS_DPS
,
804 EFI_AHCI_PORT_IS_DPS
,
808 if (EFI_ERROR (Status
)) {
813 // Wait for command compelte
815 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
816 Status
= AhciWaitMemSet (
823 if (EFI_ERROR (Status
)) {
827 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
828 Status
= AhciWaitMemSet (
831 EFI_AHCI_PORT_IS_DHRS
,
832 EFI_AHCI_PORT_IS_DHRS
,
835 if (EFI_ERROR (Status
)) {
846 AhciDisableFisReceive (
861 Start a non data transfer on specific port.
863 @param PciIo The PCI IO protocol instance.
864 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
865 @param Port The number of port.
866 @param PortMultiplier The timeout value of stop.
867 @param AtapiCommand The atapi command will be used for the transfer.
868 @param AtapiCommandLength The length of the atapi command.
869 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
870 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
871 @param Timeout The timeout value of non data transfer.
873 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
874 @retval EFI_TIMEOUT The operation is time out.
875 @retval EFI_UNSUPPORTED The device is not ready for transfer.
876 @retval EFI_SUCCESS The non data transfer executes successfully.
881 AhciNonDataTransfer (
882 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
883 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
885 IN UINT8 PortMultiplier
,
886 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
887 IN UINT8 AtapiCommandLength
,
888 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
889 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
899 EFI_AHCI_COMMAND_FIS CFis
;
900 EFI_AHCI_COMMAND_LIST CmdList
;
903 // Package read needed
905 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
907 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
909 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
925 Status
= AhciStartCommand (
931 if (EFI_ERROR (Status
)) {
936 // Wait device sends the Response Fis
938 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
940 // Wait device sends the PIO setup fis before data transfer
942 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
944 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
946 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
951 // Stall for 100 microseconds.
953 MicroSecondDelay(100);
959 Status
= EFI_TIMEOUT
;
963 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
965 Status
= AhciWaitMemSet (
980 AhciDisableFisReceive (
990 Stop command running for giving port
992 @param PciIo The PCI IO protocol instance.
993 @param Port The number of port.
994 @param Timeout The timeout value of stop.
996 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
997 @retval EFI_TIMEOUT The operation is time out.
998 @retval EFI_SUCCESS The command stop successfully.
1004 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1012 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1013 Data
= AhciReadReg (PciIo
, Offset
);
1015 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) == 0) {
1019 if ((Data
& EFI_AHCI_PORT_CMD_ST
) != 0) {
1020 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_ST
));
1023 return AhciWaitMemSet (
1026 EFI_AHCI_PORT_CMD_CR
,
1033 Start command for give slot on specific port.
1035 @param PciIo The PCI IO protocol instance.
1036 @param Port The number of port.
1037 @param CommandSlot The number of CommandSlot.
1038 @param Timeout The timeout value of start.
1040 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
1041 @retval EFI_TIMEOUT The operation is time out.
1042 @retval EFI_SUCCESS The command start successfully.
1048 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1050 IN UINT8 CommandSlot
,
1063 // Collect AHCI controller information
1065 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1067 CmdSlotBit
= (UINT32
) (1 << CommandSlot
);
1069 AhciClearPortStatus (
1074 Status
= AhciEnableFisReceive (
1080 if (EFI_ERROR (Status
)) {
1085 // Setting the command
1087 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SACT
;
1088 AhciAndReg (PciIo
, Offset
, 0);
1089 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1091 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
1092 AhciAndReg (PciIo
, Offset
, 0);
1093 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1095 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1096 PortStatus
= AhciReadReg (PciIo
, Offset
);
1099 if ((PortStatus
& EFI_AHCI_PORT_CMD_ALPE
) != 0) {
1100 StartCmd
= AhciReadReg (PciIo
, Offset
);
1101 StartCmd
&= ~EFI_AHCI_PORT_CMD_ICC_MASK
;
1102 StartCmd
|= EFI_AHCI_PORT_CMD_ACTIVE
;
1105 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1106 PortTfd
= AhciReadReg (PciIo
, Offset
);
1108 if ((PortTfd
& (EFI_AHCI_PORT_TFD_BSY
| EFI_AHCI_PORT_TFD_DRQ
)) != 0) {
1109 if ((Capability
& BIT24
) != 0) {
1110 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1111 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_COL
);
1116 EFI_AHCI_PORT_CMD_COL
,
1123 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1124 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_ST
| StartCmd
);
1132 @param PciIo The PCI IO protocol instance.
1133 @param Port The number of port.
1134 @param Timeout The timeout value of reset.
1136 @retval EFI_DEVICE_ERROR The port reset unsuccessfully
1137 @retval EFI_TIMEOUT The reset operation is time out.
1138 @retval EFI_SUCCESS The port reset successfully.
1144 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1152 AhciClearPortStatus (PciIo
, Port
);
1154 AhciStopCommand (PciIo
, Port
, Timeout
);
1156 AhciDisableFisReceive (PciIo
, Port
, Timeout
);
1158 AhciEnableFisReceive (PciIo
, Port
, Timeout
);
1160 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
1162 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_DET_INIT
);
1165 // wait 5 milliseceond before de-assert DET
1167 MicroSecondDelay (5000);
1169 AhciAndReg (PciIo
, Offset
, (UINT32
)EFI_AHCI_PORT_SCTL_MASK
);
1172 // wait 5 milliseceond before de-assert DET
1174 MicroSecondDelay (5000);
1177 // Wait for communication to be re-established
1179 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
1180 Status
= AhciWaitMemSet (
1183 EFI_AHCI_PORT_SSTS_DET_MASK
,
1184 EFI_AHCI_PORT_SSTS_DET_PCE
,
1188 if (EFI_ERROR (Status
)) {
1192 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
1193 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_ERR_CLEAR
);
1201 @param PciIo The PCI IO protocol instance.
1202 @param Timeout The timeout value of reset.
1205 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
1206 @retval EFI_TIMEOUT The reset operation is time out.
1207 @retval EFI_SUCCESS AHCI controller is reset successfully.
1213 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1221 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
1223 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_RESET
);
1225 Status
= EFI_TIMEOUT
;
1227 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
1230 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1232 if ((Value
& EFI_AHCI_GHC_RESET
) == 0) {
1237 // Stall for 100 microseconds.
1239 MicroSecondDelay(100);
1242 } while (Delay
> 0);
1252 Send Buffer cmd to specific device.
1254 @param PciIo The PCI IO protocol instance.
1255 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1256 @param Port The number of port.
1257 @param PortMultiplier The timeout value of stop.
1258 @param Buffer The data buffer to store IDENTIFY PACKET data.
1260 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1261 @retval EFI_TIMEOUT The operation is time out.
1262 @retval EFI_UNSUPPORTED The device is not ready for executing.
1263 @retval EFI_SUCCESS The cmd executes successfully.
1269 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1270 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1272 IN UINT8 PortMultiplier
,
1273 IN OUT EFI_IDENTIFY_DATA
*Buffer
1277 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1278 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1280 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
1281 return EFI_INVALID_PARAMETER
;
1284 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1285 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1287 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DRIVE
;
1288 AtaCommandBlock
.AtaSectorCount
= 1;
1290 Status
= AhciPioTransfer (
1301 sizeof (EFI_IDENTIFY_DATA
),
1309 Send Buffer cmd to specific device.
1311 @param PciIo The PCI IO protocol instance.
1312 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1313 @param Port The number of port.
1314 @param PortMultiplier The timeout value of stop.
1315 @param Buffer The data buffer to store IDENTIFY PACKET data.
1317 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1318 @retval EFI_TIMEOUT The operation is time out.
1319 @retval EFI_UNSUPPORTED The device is not ready for executing.
1320 @retval EFI_SUCCESS The cmd executes successfully.
1325 AhciIdentifyPacket (
1326 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1327 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1329 IN UINT8 PortMultiplier
,
1330 IN OUT EFI_IDENTIFY_DATA
*Buffer
1334 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1335 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1337 if (PciIo
== NULL
|| AhciRegisters
== NULL
) {
1338 return EFI_INVALID_PARAMETER
;
1341 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1342 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1344 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DEVICE
;
1345 AtaCommandBlock
.AtaSectorCount
= 1;
1347 Status
= AhciPioTransfer (
1358 sizeof (EFI_IDENTIFY_DATA
),
1366 Send SET FEATURE cmd on specific device.
1368 @param PciIo The PCI IO protocol instance.
1369 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1370 @param Port The number of port.
1371 @param PortMultiplier The timeout value of stop.
1372 @param Feature The data to send Feature register.
1373 @param FeatureSpecificData The specific data for SET FEATURE cmd.
1375 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1376 @retval EFI_TIMEOUT The operation is time out.
1377 @retval EFI_UNSUPPORTED The device is not ready for executing.
1378 @retval EFI_SUCCESS The cmd executes successfully.
1383 AhciDeviceSetFeature (
1384 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1385 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1387 IN UINT8 PortMultiplier
,
1389 IN UINT32 FeatureSpecificData
1393 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1394 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1396 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1397 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1399 AtaCommandBlock
.AtaCommand
= ATA_CMD_SET_FEATURES
;
1400 AtaCommandBlock
.AtaFeatures
= (UINT8
) Feature
;
1401 AtaCommandBlock
.AtaFeaturesExp
= (UINT8
) (Feature
>> 8);
1402 AtaCommandBlock
.AtaSectorCount
= (UINT8
) FeatureSpecificData
;
1403 AtaCommandBlock
.AtaSectorNumber
= (UINT8
) (FeatureSpecificData
>> 8);
1404 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (FeatureSpecificData
>> 16);
1405 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (FeatureSpecificData
>> 24);
1407 Status
= AhciNonDataTransfer (
1411 (UINT8
)PortMultiplier
,
1423 This function is used to send out ATAPI commands conforms to the Packet Command
1426 @param PciIo The PCI IO protocol instance.
1427 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1428 @param Port The number of port.
1429 @param PortMultiplier The number of port multiplier.
1430 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
1432 @retval EFI_SUCCESS send out the ATAPI packet command successfully
1433 and device sends data successfully.
1434 @retval EFI_DEVICE_ERROR the device failed to send data.
1439 AhciPacketCommandExecute (
1440 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1441 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1443 IN UINT8 PortMultiplier
,
1444 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1450 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1451 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1455 if (Packet
== NULL
|| Packet
->Cdb
== NULL
) {
1456 return EFI_INVALID_PARAMETER
;
1459 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1460 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1461 AtaCommandBlock
.AtaCommand
= ATA_CMD_PACKET
;
1465 AtaCommandBlock
.AtaFeatures
= 0x00;
1467 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
1468 // determine how many data should be transferred.
1470 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
& 0x00ff);
1471 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
>> 8);
1473 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1474 Buffer
= Packet
->InDataBuffer
;
1475 Length
= Packet
->InTransferLength
;
1478 Buffer
= Packet
->OutDataBuffer
;
1479 Length
= Packet
->OutTransferLength
;
1484 Status
= AhciNonDataTransfer (
1497 // READ_CAPACITY cmd may execute failure. Retry 5 times
1499 if (((UINT8
*)Packet
->Cdb
)[0] == ATA_CMD_READ_CAPACITY
) {
1505 Status
= AhciPioTransfer (
1519 if (!EFI_ERROR (Status
)) {
1523 } while (Retry
!= 0);
1529 Allocate transfer-related data struct which is used at AHCI mode.
1531 @param PciIo The PCI IO protocol instance.
1532 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1537 AhciCreateTransferDescriptor (
1538 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1539 IN OUT EFI_AHCI_REGISTERS
*AhciRegisters
1547 UINT8 MaxPortNumber
;
1548 UINT8 MaxCommandSlotNumber
;
1549 BOOLEAN Support64Bit
;
1550 UINT64 MaxReceiveFisSize
;
1551 UINT64 MaxCommandListSize
;
1552 UINT64 MaxCommandTableSize
;
1556 // Collect AHCI controller information
1558 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1559 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
1561 // Get the number of command slots per port supported by this HBA.
1563 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1564 Support64Bit
= ((Capability
& BIT31
) != 0) ? TRUE
: FALSE
;
1566 MaxReceiveFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1567 Status
= PciIo
->AllocateBuffer (
1570 EfiBootServicesData
,
1571 EFI_SIZE_TO_PAGES (MaxReceiveFisSize
),
1576 if (EFI_ERROR (Status
)) {
1577 return EFI_OUT_OF_RESOURCES
;
1580 ZeroMem (Buffer
, MaxReceiveFisSize
);
1582 AhciRegisters
->AhciRFis
= Buffer
;
1583 AhciRegisters
->MaxReceiveFisSize
= MaxReceiveFisSize
;
1584 Bytes
= MaxReceiveFisSize
;
1586 Status
= PciIo
->Map (
1588 EfiPciIoOperationBusMasterCommonBuffer
,
1591 &(EFI_PHYSICAL_ADDRESS
)AhciRegisters
->AhciRFisPciAddr
,
1592 &AhciRegisters
->MapRFis
1595 if (EFI_ERROR (Status
) || (Bytes
!= MaxReceiveFisSize
)) {
1597 // Map error or unable to map the whole RFis buffer into a contiguous region.
1599 Status
= EFI_OUT_OF_RESOURCES
;
1603 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)AhciRegisters
->AhciRFisPciAddr
> 0x100000000UL
)) {
1605 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1607 Status
= EFI_DEVICE_ERROR
;
1612 // Allocate memory for command list
1613 // Note that the implemenation is a single task model which only use a command list for all ports.
1616 MaxCommandListSize
= MaxCommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
);
1617 Status
= PciIo
->AllocateBuffer (
1620 EfiBootServicesData
,
1621 EFI_SIZE_TO_PAGES (MaxCommandListSize
),
1626 if (EFI_ERROR (Status
)) {
1628 // Free mapped resource.
1630 Status
= EFI_OUT_OF_RESOURCES
;
1634 ZeroMem (Buffer
, MaxCommandListSize
);
1636 AhciRegisters
->AhciCmdList
= Buffer
;
1637 AhciRegisters
->MaxCommandListSize
= MaxCommandListSize
;
1638 Bytes
= MaxCommandListSize
;
1640 Status
= PciIo
->Map (
1642 EfiPciIoOperationBusMasterCommonBuffer
,
1645 &(EFI_PHYSICAL_ADDRESS
)AhciRegisters
->AhciCmdListPciAddr
,
1646 &AhciRegisters
->MapCmdList
1649 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandListSize
)) {
1651 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1653 Status
= EFI_OUT_OF_RESOURCES
;
1657 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)AhciRegisters
->AhciCmdListPciAddr
> 0x100000000UL
)) {
1659 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1661 Status
= EFI_DEVICE_ERROR
;
1666 // Allocate memory for command table
1667 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
1670 MaxCommandTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
1672 Status
= PciIo
->AllocateBuffer (
1675 EfiBootServicesData
,
1676 EFI_SIZE_TO_PAGES (MaxCommandTableSize
),
1681 if (EFI_ERROR (Status
)) {
1683 // Free mapped resource.
1685 Status
= EFI_OUT_OF_RESOURCES
;
1689 ZeroMem (Buffer
, MaxCommandTableSize
);
1691 AhciRegisters
->AhciCommandTable
= Buffer
;
1692 AhciRegisters
->MaxCommandTableSize
= MaxCommandTableSize
;
1693 Bytes
= MaxCommandTableSize
;
1695 Status
= PciIo
->Map (
1697 EfiPciIoOperationBusMasterCommonBuffer
,
1700 &(EFI_PHYSICAL_ADDRESS
)AhciRegisters
->AhciCommandTablePciAddr
,
1701 &AhciRegisters
->MapCommandTable
1704 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandTableSize
)) {
1706 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1708 Status
= EFI_OUT_OF_RESOURCES
;
1712 if ((!Support64Bit
) && ((EFI_PHYSICAL_ADDRESS
)AhciRegisters
->AhciCommandTablePciAddr
> 0x100000000UL
)) {
1714 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1716 Status
= EFI_DEVICE_ERROR
;
1722 // Map error or unable to map the whole CmdList buffer into a contiguous region.
1727 AhciRegisters
->MapCommandTable
1732 EFI_SIZE_TO_PAGES (MaxCommandTableSize
),
1733 AhciRegisters
->AhciCommandTable
1738 AhciRegisters
->MapCmdList
1743 EFI_SIZE_TO_PAGES (MaxCommandListSize
),
1744 AhciRegisters
->AhciCmdList
1749 AhciRegisters
->MapRFis
1754 EFI_SIZE_TO_PAGES (MaxReceiveFisSize
),
1755 AhciRegisters
->AhciRFis
1762 Initialize ATA host controller at AHCI mode.
1764 The function is designed to initialize ATA host controller.
1766 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
1771 AhciModeInitialization (
1772 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
1776 EFI_PCI_IO_PROTOCOL
*PciIo
;
1777 EFI_IDE_CONTROLLER_INIT_PROTOCOL
*IdeInit
;
1779 UINT8 MaxPortNumber
;
1780 UINT32 PortImplementBitMap
;
1781 UINT8 MaxCommandSlotNumber
;
1782 BOOLEAN Support64Bit
;
1784 EFI_AHCI_REGISTERS
*AhciRegisters
;
1790 EFI_IDENTIFY_DATA Buffer
;
1791 EFI_ATA_DEVICE_TYPE DeviceType
;
1792 EFI_ATA_COLLECTIVE_MODE
*SupportedModes
;
1793 EFI_ATA_TRANSFER_MODE TransferMode
;
1795 if (Instance
== NULL
) {
1796 return EFI_INVALID_PARAMETER
;
1799 PciIo
= Instance
->PciIo
;
1800 IdeInit
= Instance
->IdeControllerInit
;
1802 Status
= AhciReset (PciIo
, ATA_ATAPI_TIMEOUT
);
1804 if (EFI_ERROR (Status
)) {
1805 return EFI_DEVICE_ERROR
;
1809 // Enable AE before accessing any AHCI registers
1811 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
1814 // Collect AHCI controller information
1816 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1819 // Get the number of command slots per port supported by this HBA.
1821 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1822 Support64Bit
= ((Capability
& BIT31
) != 0) ? TRUE
: FALSE
;
1825 // Get the bit map of those ports exposed by this HBA.
1826 // It indicates which ports that the HBA supports are available for software to use.
1828 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
1829 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
1831 AhciRegisters
= &Instance
->AhciRegisters
;
1832 Status
= AhciCreateTransferDescriptor (PciIo
, AhciRegisters
);
1834 if (EFI_ERROR (Status
)) {
1835 return EFI_OUT_OF_RESOURCES
;
1838 for (Port
= 0; Port
< MaxPortNumber
; Port
++) {
1839 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFisPciAddr
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
1841 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FB
;
1842 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
1843 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FBU
;
1844 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
1847 // Single task envrionment, we only use one command table for all port
1849 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdListPciAddr
);
1851 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLB
;
1852 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
1853 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLBU
;
1854 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
1856 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
1857 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1859 if ((Capability
& EFI_AHCI_PORT_CMD_ASP
) != 0) {
1860 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_SUD
);
1862 Data
= AhciReadReg (PciIo
, Offset
);
1863 if ((Data
& EFI_AHCI_PORT_CMD_CPD
) != 0) {
1864 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_POD
);
1867 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
|EFI_AHCI_PORT_CMD_COL
|EFI_AHCI_PORT_CMD_ST
));
1870 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
1871 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_SCTL_IPM_MASK
));
1873 AhciAndReg (PciIo
, Offset
,(UINT32
) ~(EFI_AHCI_PORT_SCTL_IPM_PSD
));
1874 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_PSD
);
1876 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_SCTL_IPM_SSD
));
1877 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_SSD
);
1879 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IE
;
1880 AhciAndReg (PciIo
, Offset
, 0);
1882 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
1883 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
1887 // Stall for 100 milliseconds.
1889 MicroSecondDelay(100000);
1891 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBeforeChannelEnumeration
, Port
);
1893 for (Port
= 0; Port
< MaxPortNumber
; Port
++) {
1894 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
1896 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
1897 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
1903 // Found device in the port
1905 if (Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) {
1906 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SIG
;
1908 Status
= AhciWaitMemSet (
1915 if (EFI_ERROR (Status
)) {
1920 // Now inform the IDE Controller Init Module.
1922 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBusBeforeDevicePresenceDetection
, Port
);
1924 Data
= AhciReadReg (PciIo
, Offset
);
1926 if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATAPI_DEVICE_SIG
) {
1927 Status
= AhciIdentifyPacket (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
1929 if (EFI_ERROR (Status
)) {
1933 DeviceType
= EfiIdeCdrom
;
1934 } else if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATA_DEVICE_SIG
) {
1935 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
1937 if (EFI_ERROR (Status
)) {
1941 DeviceType
= EfiIdeHarddisk
;
1946 DEBUG ((EFI_D_INFO
, "port [%d] port mulitplier [%d] has a [%a]\n",
1947 Port
, 0, DeviceType
== EfiIdeCdrom
? "cdrom" : "harddisk"));
1950 // Submit identify data to IDE controller init driver
1952 IdeInit
->SubmitData (IdeInit
, Port
, 0, &Buffer
);
1955 // Now start to config ide device parameter and transfer mode.
1957 Status
= IdeInit
->CalculateMode (
1963 if (EFI_ERROR (Status
)) {
1964 DEBUG ((EFI_D_ERROR
, "Calculate Mode Fail, Status = %r\n", Status
));
1969 // Set best supported PIO mode on this IDE device
1971 if (SupportedModes
->PioMode
.Mode
<= EfiAtaPioMode2
) {
1972 TransferMode
.ModeCategory
= EFI_ATA_MODE_DEFAULT_PIO
;
1974 TransferMode
.ModeCategory
= EFI_ATA_MODE_FLOW_PIO
;
1977 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->PioMode
.Mode
);
1980 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
1981 // be set together. Only one DMA mode can be set to a device. If setting
1982 // DMA mode operation fails, we can continue moving on because we only use
1983 // PIO mode at boot time. DMA modes are used by certain kind of OS booting
1985 if (SupportedModes
->UdmaMode
.Valid
) {
1986 TransferMode
.ModeCategory
= EFI_ATA_MODE_UDMA
;
1987 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->UdmaMode
.Mode
);
1988 } else if (SupportedModes
->MultiWordDmaMode
.Valid
) {
1989 TransferMode
.ModeCategory
= EFI_ATA_MODE_MDMA
;
1990 TransferMode
.ModeNumber
= (UINT8
) SupportedModes
->MultiWordDmaMode
.Mode
;
1993 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, 0, 0x03, (UINT32
)(*(UINT8
*)&TransferMode
));
1995 if (EFI_ERROR (Status
)) {
1996 DEBUG ((EFI_D_ERROR
, "Set transfer Mode Fail, Status = %r\n", Status
));
2000 // Found a ATA or ATAPI device, add it into the device list.
2002 CreateNewDeviceInfo (Instance
, Port
, 0, DeviceType
, &Buffer
);