2 The AhciPei driver is used to manage ATA hard disk device working under AHCI
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #define ATA_CMD_TRUST_NON_DATA 0x5B
21 #define ATA_CMD_TRUST_RECEIVE 0x5C
22 #define ATA_CMD_TRUST_SEND 0x5E
25 // Look up table (IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL
27 EFI_ATA_PASS_THRU_CMD_PROTOCOL mAtaPassThruCmdProtocols
[2] = {
28 EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN
,
29 EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
33 // Look up table (Lba48Bit, IsIsWrite) for ATA_CMD
35 UINT8 mAtaCommands
[2][2] = {
37 ATA_CMD_READ_SECTORS
, // 28-bit LBA; PIO read
38 ATA_CMD_WRITE_SECTORS
// 28-bit LBA; PIO write
41 ATA_CMD_READ_SECTORS_EXT
, // 48-bit LBA; PIO read
42 ATA_CMD_WRITE_SECTORS_EXT
// 48-bit LBA; PIO write
47 // Look up table (IsTrustSend) for ATA_CMD
49 UINT8 mAtaTrustCommands
[2] = {
50 ATA_CMD_TRUST_RECEIVE
, // PIO read
51 ATA_CMD_TRUST_SEND
// PIO write
55 // Look up table (Lba48Bit) for maximum transfer block number
57 #define MAX_28BIT_TRANSFER_BLOCK_NUM 0x100
58 #define MAX_48BIT_TRANSFER_BLOCK_NUM 0xFFFF
60 UINT32 mMaxTransferBlockNumber
[2] = {
61 MAX_28BIT_TRANSFER_BLOCK_NUM
,
62 MAX_48BIT_TRANSFER_BLOCK_NUM
66 // The maximum total sectors count in 28 bit addressing mode
68 #define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff
72 Read AHCI Operation register.
74 @param[in] AhciBar AHCI bar address.
75 @param[in] Offset The operation register offset.
77 @return The register content read.
89 Data
= MmioRead32 (AhciBar
+ Offset
);
95 Write AHCI Operation register.
97 @param[in] AhciBar AHCI bar address.
98 @param[in] Offset The operation register offset.
99 @param[in] Data The Data used to write down.
109 MmioWrite32 (AhciBar
+ Offset
, Data
);
113 Do AND operation with the value of AHCI Operation register.
115 @param[in] AhciBar AHCI bar address.
116 @param[in] Offset The operation register offset.
117 @param[in] AndData The data used to do AND operation.
129 Data
= AhciReadReg (AhciBar
, Offset
);
132 AhciWriteReg (AhciBar
, Offset
, Data
);
136 Do OR operation with the Value of AHCI Operation register.
138 @param[in] AhciBar AHCI bar address.
139 @param[in] Offset The operation register offset.
140 @param[in] OrData The Data used to do OR operation.
152 Data
= AhciReadReg (AhciBar
, Offset
);
155 AhciWriteReg (AhciBar
, Offset
, Data
);
159 Wait for memory set to the test Value.
161 @param[in] AhciBar AHCI bar address.
162 @param[in] Offset The memory offset to test.
163 @param[in] MaskValue The mask Value of memory.
164 @param[in] TestValue The test Value of memory.
165 @param[in] Timeout The timeout, in 100ns units, for wait memory set.
167 @retval EFI_DEVICE_ERROR The memory is not set.
168 @retval EFI_TIMEOUT The memory setting is time out.
169 @retval EFI_SUCCESS The memory is correct set.
185 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
188 Value
= AhciReadReg (AhciBar
, Offset
) & MaskValue
;
190 if (Value
== TestValue
) {
195 // Stall for 100 microseconds.
197 MicroSecondDelay (100);
207 Check the memory status to the test value.
209 @param[in] Address The memory address to test.
210 @param[in] MaskValue The mask value of memory.
211 @param[in] TestValue The test value of memory.
213 @retval EFI_NOT_READY The memory is not set.
214 @retval EFI_SUCCESS The memory is correct set.
226 Value
= *(volatile UINT32
*) Address
;
229 if (Value
== TestValue
) {
232 return EFI_NOT_READY
;
237 Wait for the value of the specified system memory set to the test value.
239 @param[in] Address The system memory address to test.
240 @param[in] MaskValue The mask value of memory.
241 @param[in] TestValue The test value of memory.
242 @param[in] Timeout The timeout, in 100ns units, for wait memory set.
244 @retval EFI_TIMEOUT The system memory setting is time out.
245 @retval EFI_SUCCESS The system memory is correct set.
250 IN EFI_PHYSICAL_ADDRESS Address
,
258 BOOLEAN InfiniteWait
;
263 InfiniteWait
= FALSE
;
266 Delay
= DivU64x32 (Timeout
, 1000) + 1;
270 // Access sytem memory to see if the value is the tested one.
272 // The system memory pointed by Address will be updated by the
273 // SATA Host Controller, "volatile" is introduced to prevent
274 // compiler from optimizing the access to the memory address
275 // to only read once.
277 Value
= *(volatile UINT32
*) (UINTN
) Address
;
280 if (Value
== TestValue
) {
285 // Stall for 100 microseconds.
287 MicroSecondDelay (100);
291 } while (InfiniteWait
|| (Delay
> 0));
298 Clear the port interrupt and error status. It will also clear HBA interrupt
301 @param[in] AhciBar AHCI bar address.
302 @param[in] Port The number of port.
306 AhciClearPortStatus (
314 // Clear any error status
316 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_SERR
;
317 AhciWriteReg (AhciBar
, Offset
, AhciReadReg (AhciBar
, Offset
));
320 // Clear any port interrupt status
322 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_IS
;
323 AhciWriteReg (AhciBar
, Offset
, AhciReadReg (AhciBar
, Offset
));
326 // Clear any HBA interrupt status
328 AhciWriteReg (AhciBar
, AHCI_IS_OFFSET
, AhciReadReg (AhciBar
, AHCI_IS_OFFSET
));
332 Enable the FIS running for giving port.
334 @param[in] AhciBar AHCI bar address.
335 @param[in] Port The number of port.
336 @param[in] Timeout The timeout, in 100ns units, to enabling FIS.
338 @retval EFI_DEVICE_ERROR The FIS enable setting fails.
339 @retval EFI_TIMEOUT The FIS enable setting is time out.
340 @retval EFI_SUCCESS The FIS enable successfully.
344 AhciEnableFisReceive (
352 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
353 AhciOrReg (AhciBar
, Offset
, AHCI_PORT_CMD_FRE
);
359 Disable the FIS running for giving port.
361 @param[in] AhciBar AHCI bar address.
362 @param[in] Port The number of port.
363 @param[in] Timeout The timeout value of disabling FIS, uses 100ns as a unit.
365 @retval EFI_DEVICE_ERROR The FIS disable setting fails.
366 @retval EFI_TIMEOUT The FIS disable setting is time out.
367 @retval EFI_UNSUPPORTED The port is in running state.
368 @retval EFI_SUCCESS The FIS disable successfully.
372 AhciDisableFisReceive (
381 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
382 Data
= AhciReadReg (AhciBar
, Offset
);
385 // Before disabling Fis receive, the DMA engine of the port should NOT be in
388 if ((Data
& (AHCI_PORT_CMD_ST
| AHCI_PORT_CMD_CR
)) != 0) {
389 return EFI_UNSUPPORTED
;
393 // Check if the Fis receive DMA engine for the port is running.
395 if ((Data
& AHCI_PORT_CMD_FR
) != AHCI_PORT_CMD_FR
) {
399 AhciAndReg (AhciBar
, Offset
, (UINT32
)~(AHCI_PORT_CMD_FRE
));
401 return AhciWaitMmioSet (
411 Build the command list, command table and prepare the fis receiver.
413 @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
414 @param[in] Port The number of port.
415 @param[in] PortMultiplier The number of port multiplier.
416 @param[in] FisIndex The offset index of the FIS base address.
417 @param[in] CommandFis The control fis will be used for the transfer.
418 @param[in] CommandList The command list will be used for the transfer.
419 @param[in] CommandSlotNumber The command slot will be used for the transfer.
420 @param[in,out] DataPhysicalAddr The pointer to the data buffer pci bus master
422 @param[in] DataLength The data count to be transferred.
427 IN PEI_AHCI_CONTROLLER_PRIVATE_DATA
*Private
,
429 IN UINT8 PortMultiplier
,
431 IN EFI_AHCI_COMMAND_FIS
*CommandFis
,
432 IN EFI_AHCI_COMMAND_LIST
*CommandList
,
433 IN UINT8 CommandSlotNumber
,
434 IN OUT VOID
*DataPhysicalAddr
,
438 EFI_AHCI_REGISTERS
*AhciRegisters
;
448 AhciRegisters
= &Private
->AhciRegisters
;
449 AhciBar
= Private
->MmioBase
;
454 PrdtNumber
= (UINT32
)DivU64x32 (
455 (UINT64
)DataLength
+ AHCI_MAX_DATA_PER_PRDT
- 1,
456 AHCI_MAX_DATA_PER_PRDT
460 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
461 // It also limits that the maximum amount of the PRDT entry in the command table
463 // Current driver implementation supports up to a maximum of AHCI_MAX_PRDT_NUMBER
466 ASSERT (PrdtNumber
<= AHCI_MAX_PRDT_NUMBER
);
467 if (PrdtNumber
> AHCI_MAX_PRDT_NUMBER
) {
471 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFis
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * FisIndex
;
473 BaseAddr
= Data64
.Uint64
;
475 ZeroMem ((VOID
*)((UINTN
) BaseAddr
), sizeof (EFI_AHCI_RECEIVED_FIS
));
477 ZeroMem (AhciRegisters
->AhciCmdTable
, sizeof (EFI_AHCI_COMMAND_TABLE
));
479 CommandFis
->AhciCFisPmNum
= PortMultiplier
;
481 CopyMem (&AhciRegisters
->AhciCmdTable
->CommandFis
, CommandFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
483 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
484 AhciAndReg (AhciBar
, Offset
, (UINT32
)~(AHCI_PORT_CMD_DLAE
| AHCI_PORT_CMD_ATAPI
));
486 RemainedData
= (UINTN
) DataLength
;
487 MemAddr
= (UINTN
) DataPhysicalAddr
;
488 CommandList
->AhciCmdPrdtl
= PrdtNumber
;
490 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
491 if (RemainedData
< AHCI_MAX_DATA_PER_PRDT
) {
492 AhciRegisters
->AhciCmdTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= (UINT32
)RemainedData
- 1;
494 AhciRegisters
->AhciCmdTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= AHCI_MAX_DATA_PER_PRDT
- 1;
497 Data64
.Uint64
= (UINT64
)MemAddr
;
498 AhciRegisters
->AhciCmdTable
->PrdtTable
[PrdtIndex
].AhciPrdtDba
= Data64
.Uint32
.Lower32
;
499 AhciRegisters
->AhciCmdTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbau
= Data64
.Uint32
.Upper32
;
500 RemainedData
-= AHCI_MAX_DATA_PER_PRDT
;
501 MemAddr
+= AHCI_MAX_DATA_PER_PRDT
;
505 // Set the last PRDT to Interrupt On Complete
507 if (PrdtNumber
> 0) {
508 AhciRegisters
->AhciCmdTable
->PrdtTable
[PrdtNumber
- 1].AhciPrdtIoc
= 1;
512 (VOID
*) ((UINTN
) AhciRegisters
->AhciCmdList
+ (UINTN
) CommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
)),
514 sizeof (EFI_AHCI_COMMAND_LIST
)
517 Data64
.Uint64
= (UINT64
)(UINTN
) AhciRegisters
->AhciCmdTable
;
518 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtba
= Data64
.Uint32
.Lower32
;
519 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtbau
= Data64
.Uint32
.Upper32
;
520 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdPmp
= PortMultiplier
;
526 @param[in,out] CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data
528 @param[in] AtaCommandBlock A pointer to the EFI_ATA_COMMAND_BLOCK data
533 AhciBuildCommandFis (
534 IN OUT EFI_AHCI_COMMAND_FIS
*CmdFis
,
535 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
538 ZeroMem (CmdFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
540 CmdFis
->AhciCFisType
= AHCI_FIS_REGISTER_H2D
;
542 // Indicator it's a command
544 CmdFis
->AhciCFisCmdInd
= 0x1;
545 CmdFis
->AhciCFisCmd
= AtaCommandBlock
->AtaCommand
;
547 CmdFis
->AhciCFisFeature
= AtaCommandBlock
->AtaFeatures
;
548 CmdFis
->AhciCFisFeatureExp
= AtaCommandBlock
->AtaFeaturesExp
;
550 CmdFis
->AhciCFisSecNum
= AtaCommandBlock
->AtaSectorNumber
;
551 CmdFis
->AhciCFisSecNumExp
= AtaCommandBlock
->AtaSectorNumberExp
;
553 CmdFis
->AhciCFisClyLow
= AtaCommandBlock
->AtaCylinderLow
;
554 CmdFis
->AhciCFisClyLowExp
= AtaCommandBlock
->AtaCylinderLowExp
;
556 CmdFis
->AhciCFisClyHigh
= AtaCommandBlock
->AtaCylinderHigh
;
557 CmdFis
->AhciCFisClyHighExp
= AtaCommandBlock
->AtaCylinderHighExp
;
559 CmdFis
->AhciCFisSecCount
= AtaCommandBlock
->AtaSectorCount
;
560 CmdFis
->AhciCFisSecCountExp
= AtaCommandBlock
->AtaSectorCountExp
;
562 CmdFis
->AhciCFisDevHead
= (UINT8
) (AtaCommandBlock
->AtaDeviceHead
| 0xE0);
566 Stop command running for giving port
568 @param[in] AhciBar AHCI bar address.
569 @param[in] Port The number of port.
570 @param[in] Timeout The timeout value, in 100ns units, to stop.
572 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
573 @retval EFI_TIMEOUT The operation is time out.
574 @retval EFI_SUCCESS The command stop successfully.
587 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
588 Data
= AhciReadReg (AhciBar
, Offset
);
590 if ((Data
& (AHCI_PORT_CMD_ST
| AHCI_PORT_CMD_CR
)) == 0) {
594 if ((Data
& AHCI_PORT_CMD_ST
) != 0) {
595 AhciAndReg (AhciBar
, Offset
, (UINT32
)~(AHCI_PORT_CMD_ST
));
598 return AhciWaitMmioSet (
608 Start command for give slot on specific port.
610 @param[in] AhciBar AHCI bar address.
611 @param[in] Port The number of port.
612 @param[in] CommandSlot The number of Command Slot.
613 @param[in] Timeout The timeout value, in 100ns units, to start.
615 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
616 @retval EFI_TIMEOUT The operation is time out.
617 @retval EFI_SUCCESS The command start successfully.
624 IN UINT8 CommandSlot
,
637 // Collect AHCI controller information
639 Capability
= AhciReadReg (AhciBar
, AHCI_CAPABILITY_OFFSET
);
641 CmdSlotBit
= (UINT32
) (1 << CommandSlot
);
643 AhciClearPortStatus (
648 Status
= AhciEnableFisReceive (
653 if (EFI_ERROR (Status
)) {
657 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
658 PortStatus
= AhciReadReg (AhciBar
, Offset
);
661 if ((PortStatus
& AHCI_PORT_CMD_ALPE
) != 0) {
662 StartCmd
= AhciReadReg (AhciBar
, Offset
);
663 StartCmd
&= ~AHCI_PORT_CMD_ICC_MASK
;
664 StartCmd
|= AHCI_PORT_CMD_ACTIVE
;
667 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_TFD
;
668 PortTfd
= AhciReadReg (AhciBar
, Offset
);
670 if ((PortTfd
& (AHCI_PORT_TFD_BSY
| AHCI_PORT_TFD_DRQ
)) != 0) {
671 if ((Capability
& BIT24
) != 0) {
672 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
673 AhciOrReg (AhciBar
, Offset
, AHCI_PORT_CMD_CLO
);
685 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
686 AhciOrReg (AhciBar
, Offset
, AHCI_PORT_CMD_ST
| StartCmd
);
689 // Setting the command
691 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CI
;
692 AhciAndReg (AhciBar
, Offset
, 0);
693 AhciOrReg (AhciBar
, Offset
, CmdSlotBit
);
699 Start a PIO Data transfer on specific port.
701 @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
702 @param[in] Port The number of port.
703 @param[in] PortMultiplier The number of port multiplier.
704 @param[in] FisIndex The offset index of the FIS base address.
705 @param[in] Read The transfer direction.
706 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
707 @param[in,out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
708 @param[in,out] MemoryAddr The pointer to the data buffer.
709 @param[in] DataCount The data count to be transferred.
710 @param[in] Timeout The timeout value of PIO data transfer, uses
713 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
714 @retval EFI_TIMEOUT The operation is time out.
715 @retval EFI_UNSUPPORTED The device is not ready for transfer.
716 @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
717 @retval EFI_SUCCESS The PIO data transfer executes successfully.
722 IN PEI_AHCI_CONTROLLER_PRIVATE_DATA
*Private
,
724 IN UINT8 PortMultiplier
,
727 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
728 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
729 IN OUT VOID
*MemoryAddr
,
735 EDKII_IOMMU_OPERATION MapOp
;
737 EFI_PHYSICAL_ADDRESS PhyAddr
;
739 EFI_AHCI_REGISTERS
*AhciRegisters
;
741 BOOLEAN InfiniteWait
;
750 EFI_AHCI_COMMAND_FIS CFis
;
751 EFI_AHCI_COMMAND_LIST CmdList
;
754 BOOLEAN PioFisReceived
;
755 BOOLEAN D2hFisReceived
;
758 // Current driver implementation supports up to a maximum of AHCI_MAX_PRDT_NUMBER
761 if (DataCount
/ (UINT32
)AHCI_MAX_PRDT_NUMBER
> AHCI_MAX_DATA_PER_PRDT
) {
764 "%a: Driver only support a maximum of 0x%x PRDT entries, "
765 "current number of data byte 0x%x is too large, maximum allowed is 0x%x.\n",
766 __FUNCTION__
, AHCI_MAX_PRDT_NUMBER
, DataCount
,
767 AHCI_MAX_PRDT_NUMBER
* AHCI_MAX_DATA_PER_PRDT
769 return EFI_UNSUPPORTED
;
772 MapOp
= Read
? EdkiiIoMmuOperationBusMasterWrite
:
773 EdkiiIoMmuOperationBusMasterRead
;
774 MapLength
= DataCount
;
782 if (EFI_ERROR (Status
) || (MapLength
!= DataCount
)) {
783 DEBUG ((DEBUG_ERROR
, "%a: Fail to map data buffer.\n", __FUNCTION__
));
784 return EFI_OUT_OF_RESOURCES
;
787 AhciRegisters
= &Private
->AhciRegisters
;
788 AhciBar
= Private
->MmioBase
;
789 InfiniteWait
= (Timeout
== 0) ? TRUE
: FALSE
;
792 // Fill FIS base address register
794 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_FB
;
795 OldRfisLo
= AhciReadReg (AhciBar
, Offset
);
796 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_FBU
;
797 OldRfisHi
= AhciReadReg (AhciBar
, Offset
);
798 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFis
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * FisIndex
;
799 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_FB
;
800 AhciWriteReg (AhciBar
, Offset
, Data64
.Uint32
.Lower32
);
801 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_FBU
;
802 AhciWriteReg (AhciBar
, Offset
, Data64
.Uint32
.Upper32
);
805 // Single task envrionment, we only use one command table for all port
807 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CLB
;
808 OldCmdListLo
= AhciReadReg (AhciBar
, Offset
);
809 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CLBU
;
810 OldCmdListHi
= AhciReadReg (AhciBar
, Offset
);
811 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdList
);
812 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CLB
;
813 AhciWriteReg (AhciBar
, Offset
, Data64
.Uint32
.Lower32
);
814 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CLBU
;
815 AhciWriteReg (AhciBar
, Offset
, Data64
.Uint32
.Upper32
);
818 // Package read needed
820 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
822 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
824 CmdList
.AhciCmdCfl
= AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
825 CmdList
.AhciCmdW
= Read
? 0 : 1;
835 (VOID
*)(UINTN
)PhyAddr
,
839 Status
= AhciStartCommand (
845 if (EFI_ERROR (Status
)) {
850 // Checking the status and wait the driver sending Data
852 FisBaseAddr
= (UINT32
)(UINTN
)AhciRegisters
->AhciRFis
+ sizeof (EFI_AHCI_RECEIVED_FIS
) * FisIndex
;
855 // Wait device sends the PIO setup fis before data transfer
857 Status
= EFI_TIMEOUT
;
858 Delay
= (UINT32
) DivU64x32 (Timeout
, 1000) + 1;
860 PioFisReceived
= FALSE
;
861 D2hFisReceived
= FALSE
;
862 Offset
= FisBaseAddr
+ AHCI_PIO_FIS_OFFSET
;
863 Status
= AhciCheckMemSet (Offset
, AHCI_FIS_TYPE_MASK
, AHCI_FIS_PIO_SETUP
);
864 if (!EFI_ERROR (Status
)) {
865 DEBUG ((DEBUG_INFO
, "%a: PioFisReceived.\n", __FUNCTION__
));
866 PioFisReceived
= TRUE
;
869 // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
870 // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from
871 // device after the transaction is finished successfully.
872 // To get better device compatibilities, we further check if the PxTFD's
873 // ERR bit is set. By this way, we can know if there is a real error happened.
875 Offset
= FisBaseAddr
+ AHCI_D2H_FIS_OFFSET
;
876 Status
= AhciCheckMemSet (Offset
, AHCI_FIS_TYPE_MASK
, AHCI_FIS_REGISTER_D2H
);
877 if (!EFI_ERROR (Status
)) {
878 DEBUG ((DEBUG_INFO
, "%a: D2hFisReceived.\n", __FUNCTION__
));
879 D2hFisReceived
= TRUE
;
882 if (PioFisReceived
|| D2hFisReceived
) {
883 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_TFD
;
884 PortTfd
= AhciReadReg (AhciBar
, (UINT32
) Offset
);
886 // PxTFD will be updated if there is a D2H or SetupFIS received.
888 if ((PortTfd
& AHCI_PORT_TFD_ERR
) != 0) {
889 Status
= EFI_DEVICE_ERROR
;
893 PrdCount
= *(volatile UINT32
*) (&(AhciRegisters
->AhciCmdList
[0].AhciCmdPrdbc
));
894 if (PrdCount
== DataCount
) {
895 Status
= EFI_SUCCESS
;
901 // Stall for 100 microseconds.
903 MicroSecondDelay(100);
907 Status
= EFI_TIMEOUT
;
909 } while (InfiniteWait
|| (Delay
> 0));
912 // Wait for D2H Fis is received
914 Offset
= FisBaseAddr
+ AHCI_D2H_FIS_OFFSET
;
915 Status
= AhciWaitMemSet (
918 AHCI_FIS_REGISTER_D2H
,
921 if (EFI_ERROR (Status
)) {
922 DEBUG ((DEBUG_ERROR
, "%a: AhciWaitMemSet (%r)\n", __FUNCTION__
, Status
));
926 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_TFD
;
927 PortTfd
= AhciReadReg (AhciBar
, (UINT32
) Offset
);
928 if ((PortTfd
& AHCI_PORT_TFD_ERR
) != 0) {
929 Status
= EFI_DEVICE_ERROR
;
940 AhciDisableFisReceive (
946 if (MapData
!= NULL
) {
947 IoMmuUnmap (MapData
);
950 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_FB
;
951 AhciWriteReg (AhciBar
, Offset
, OldRfisLo
);
952 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_FBU
;
953 AhciWriteReg (AhciBar
, Offset
, OldRfisHi
);
955 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CLB
;
956 AhciWriteReg (AhciBar
, Offset
, OldCmdListLo
);
957 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CLBU
;
958 AhciWriteReg (AhciBar
, Offset
, OldCmdListHi
);
964 Start a non data transfer on specific port.
966 @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
967 @param[in] Port The number of port.
968 @param[in] PortMultiplier The number of port multiplier.
969 @param[in] FisIndex The offset index of the FIS base address.
970 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
971 @param[in,out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
972 @param[in] Timeout The timeout value of non data transfer, uses
975 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
976 @retval EFI_TIMEOUT The operation is time out.
977 @retval EFI_UNSUPPORTED The device is not ready for transfer.
978 @retval EFI_SUCCESS The non data transfer executes successfully.
982 AhciNonDataTransfer (
983 IN PEI_AHCI_CONTROLLER_PRIVATE_DATA
*Private
,
985 IN UINT8 PortMultiplier
,
987 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
988 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
994 EFI_AHCI_REGISTERS
*AhciRegisters
;
998 EFI_AHCI_COMMAND_FIS CFis
;
999 EFI_AHCI_COMMAND_LIST CmdList
;
1001 AhciBar
= Private
->MmioBase
;
1002 AhciRegisters
= &Private
->AhciRegisters
;
1005 // Package read needed
1007 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
1009 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
1011 CmdList
.AhciCmdCfl
= AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
1025 Status
= AhciStartCommand (
1031 if (EFI_ERROR (Status
)) {
1036 // Wait device sends the Response Fis
1038 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ sizeof (EFI_AHCI_RECEIVED_FIS
) * FisIndex
;
1039 Offset
= FisBaseAddr
+ AHCI_D2H_FIS_OFFSET
;
1040 Status
= AhciWaitMemSet (
1043 AHCI_FIS_REGISTER_D2H
,
1047 if (EFI_ERROR (Status
)) {
1051 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_TFD
;
1052 PortTfd
= AhciReadReg (AhciBar
, (UINT32
) Offset
);
1053 if ((PortTfd
& AHCI_PORT_TFD_ERR
) != 0) {
1054 Status
= EFI_DEVICE_ERROR
;
1064 AhciDisableFisReceive (
1076 @param[in] AhciBar AHCI bar address.
1077 @param[in] Timeout The timeout, in 100ns units, to reset.
1079 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
1080 @retval EFI_TIMEOUT The reset operation is time out.
1081 @retval EFI_SUCCESS AHCI controller is reset successfully.
1095 // Collect AHCI controller information
1097 Capability
= AhciReadReg (AhciBar
, AHCI_CAPABILITY_OFFSET
);
1100 // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
1102 if ((Capability
& AHCI_CAP_SAM
) == 0) {
1103 AhciOrReg (AhciBar
, AHCI_GHC_OFFSET
, AHCI_GHC_ENABLE
);
1106 AhciOrReg (AhciBar
, AHCI_GHC_OFFSET
, AHCI_GHC_RESET
);
1108 Delay
= (UINT32
) (DivU64x32(Timeout
, 1000) + 1);
1111 Value
= AhciReadReg(AhciBar
, AHCI_GHC_OFFSET
);
1112 if ((Value
& AHCI_GHC_RESET
) == 0) {
1117 // Stall for 100 microseconds.
1119 MicroSecondDelay(100);
1122 } while (Delay
> 0);
1128 Send Identify Drive command to a specific device.
1130 @param[in] Private The pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
1131 @param[in] Port The number of port.
1132 @param[in] PortMultiplier The port multiplier port number.
1133 @param[in] FisIndex The offset index of the FIS base address.
1134 @param[in] Buffer The data buffer to store IDENTIFY PACKET data.
1136 @retval EFI_SUCCESS The cmd executes successfully.
1137 @retval EFI_INVALID_PARAMETER Buffer is NULL.
1138 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1139 @retval EFI_TIMEOUT The operation is time out.
1140 @retval EFI_UNSUPPORTED The device is not ready for executing.
1145 IN PEI_AHCI_CONTROLLER_PRIVATE_DATA
*Private
,
1147 IN UINT8 PortMultiplier
,
1149 IN ATA_IDENTIFY_DATA
*Buffer
1153 EFI_ATA_COMMAND_BLOCK Acb
;
1154 EFI_ATA_STATUS_BLOCK Asb
;
1156 if (Buffer
== NULL
) {
1157 return EFI_INVALID_PARAMETER
;
1160 ZeroMem (&Acb
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1161 ZeroMem (&Asb
, sizeof (EFI_ATA_STATUS_BLOCK
));
1163 Acb
.AtaCommand
= ATA_CMD_IDENTIFY_DRIVE
;
1164 Acb
.AtaSectorCount
= 1;
1166 Status
= AhciPioTransfer (
1175 sizeof (ATA_IDENTIFY_DATA
),
1184 Collect the number of bits set within a port bitmap.
1186 @param[in] PortBitMap A 32-bit wide bit map of ATA AHCI ports.
1188 @retval The number of bits set in the bitmap.
1192 AhciGetNumberOfPortsFromMap (
1193 IN UINT32 PortBitMap
1196 UINT8 NumberOfPorts
;
1200 while (PortBitMap
!= 0) {
1201 if ((PortBitMap
& ((UINT32
)BIT0
)) != 0) {
1204 PortBitMap
= PortBitMap
>> 1;
1207 return NumberOfPorts
;
1211 Get the specified port number from a port bitmap.
1213 @param[in] PortBitMap A 32-bit wide bit map of ATA AHCI ports.
1214 @param[in] PortIndex The specified port index.
1215 @param[out] Port The port number of the port specified by PortIndex.
1217 @retval EFI_SUCCESS The specified port is found and its port number is
1219 @retval EFI_NOT_FOUND Cannot find the specified port within the port bitmap.
1223 AhciGetPortFromMap (
1224 IN UINT32 PortBitMap
,
1229 if (PortIndex
== 0) {
1230 return EFI_NOT_FOUND
;
1235 while (PortBitMap
!= 0) {
1236 if ((PortBitMap
& ((UINT32
)BIT0
)) != 0) {
1240 // Found the port specified by PortIndex.
1242 if (PortIndex
== 0) {
1246 PortBitMap
= PortBitMap
>> 1;
1250 return EFI_NOT_FOUND
;
1254 Allocate transfer-related data struct which is used at AHCI mode.
1256 @param[in,out] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA instance.
1258 @retval EFI_SUCCESS Data structures are allocated successfully.
1259 @retval Others Data structures are not allocated successfully.
1263 AhciCreateTransferDescriptor (
1264 IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA
*Private
1269 EFI_AHCI_REGISTERS
*AhciRegisters
;
1270 EFI_PHYSICAL_ADDRESS DeviceAddress
;
1274 UINT32 PortImplementBitMap
;
1275 UINT8 MaxPortNumber
;
1276 UINT8 MaxCommandSlotNumber
;
1278 UINTN MaxCmdListSize
;
1279 UINTN MaxCmdTableSize
;
1281 AhciBar
= Private
->MmioBase
;
1282 AhciRegisters
= &Private
->AhciRegisters
;
1285 // Collect AHCI controller information
1287 Capability
= AhciReadReg (AhciBar
, AHCI_CAPABILITY_OFFSET
);
1290 // Get the number of command slots per port supported by this HBA.
1292 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1293 ASSERT (MaxCommandSlotNumber
> 0);
1294 if (MaxCommandSlotNumber
== 0) {
1295 return EFI_DEVICE_ERROR
;
1299 // Get the highest bit of implemented ports which decides how many bytes are
1300 // allocated for recived FIS.
1302 PortImplementBitMap
= AhciReadReg (AhciBar
, AHCI_PI_OFFSET
);
1303 MaxPortNumber
= (UINT8
)(UINTN
)(HighBitSet32(PortImplementBitMap
) + 1);
1304 if (MaxPortNumber
== 0) {
1305 return EFI_DEVICE_ERROR
;
1308 // Get the number of ports that actually needed to be initialized.
1310 MaxPortNumber
= MIN (MaxPortNumber
, AhciGetNumberOfPortsFromMap (Private
->PortBitMap
));
1313 // Allocate memory for received FIS.
1315 MaxRFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1316 Status
= IoMmuAllocateBuffer (
1317 EFI_SIZE_TO_PAGES (MaxRFisSize
),
1322 if (EFI_ERROR (Status
)) {
1323 return EFI_OUT_OF_RESOURCES
;
1325 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Base
));
1326 AhciRegisters
->AhciRFis
= Base
;
1327 AhciRegisters
->AhciRFisMap
= Mapping
;
1328 AhciRegisters
->MaxRFisSize
= MaxRFisSize
;
1329 ZeroMem (AhciRegisters
->AhciRFis
, EFI_PAGE_SIZE
* EFI_SIZE_TO_PAGES (MaxRFisSize
));
1332 // Allocate memory for command list.
1333 // Note that the implemenation is a single task model which only use a command
1334 // list for each port.
1336 MaxCmdListSize
= 1 * sizeof (EFI_AHCI_COMMAND_LIST
);
1337 Status
= IoMmuAllocateBuffer (
1338 EFI_SIZE_TO_PAGES (MaxCmdListSize
),
1343 if (EFI_ERROR (Status
)) {
1344 Status
= EFI_OUT_OF_RESOURCES
;
1347 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Base
));
1348 AhciRegisters
->AhciCmdList
= Base
;
1349 AhciRegisters
->AhciCmdListMap
= Mapping
;
1350 AhciRegisters
->MaxCmdListSize
= MaxCmdListSize
;
1351 ZeroMem (AhciRegisters
->AhciCmdList
, EFI_PAGE_SIZE
* EFI_SIZE_TO_PAGES (MaxCmdListSize
));
1354 // Allocate memory for command table
1355 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
1357 MaxCmdTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
1358 Status
= IoMmuAllocateBuffer (
1359 EFI_SIZE_TO_PAGES (MaxCmdTableSize
),
1364 if (EFI_ERROR (Status
)) {
1365 Status
= EFI_OUT_OF_RESOURCES
;
1368 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Base
));
1369 AhciRegisters
->AhciCmdTable
= Base
;
1370 AhciRegisters
->AhciCmdTableMap
= Mapping
;
1371 AhciRegisters
->MaxCmdTableSize
= MaxCmdTableSize
;
1372 ZeroMem (AhciRegisters
->AhciCmdTable
, EFI_PAGE_SIZE
* EFI_SIZE_TO_PAGES (MaxCmdTableSize
));
1377 if (AhciRegisters
->AhciRFisMap
!= NULL
) {
1379 EFI_SIZE_TO_PAGES (AhciRegisters
->MaxRFisSize
),
1380 AhciRegisters
->AhciRFis
,
1381 AhciRegisters
->AhciRFisMap
1383 AhciRegisters
->AhciRFis
= NULL
;
1386 if (AhciRegisters
->AhciCmdListMap
!= NULL
) {
1388 EFI_SIZE_TO_PAGES (AhciRegisters
->MaxCmdListSize
),
1389 AhciRegisters
->AhciCmdList
,
1390 AhciRegisters
->AhciCmdListMap
1392 AhciRegisters
->AhciCmdList
= NULL
;
1399 Gets ATA device Capacity according to ATA 6.
1401 This function returns the capacity of the ATA device if it follows
1402 ATA 6 to support 48 bit addressing.
1404 @param[in] IdentifyData A pointer to ATA_IDENTIFY_DATA structure.
1406 @return The capacity of the ATA device or 0 if the device does not support
1407 48-bit addressing defined in ATA 6.
1412 IN ATA_IDENTIFY_DATA
*IdentifyData
1419 if ((IdentifyData
->command_set_supported_83
& BIT10
) == 0) {
1421 // The device doesn't support 48 bit addressing
1427 // 48 bit address feature set is supported, get maximum capacity
1430 for (Index
= 0; Index
< 4; Index
++) {
1432 // Lower byte goes first: word[100] is the lowest word, word[103] is highest
1434 TmpLba
= IdentifyData
->maximum_lba_for_48bit_addressing
[Index
];
1435 Capacity
|= LShiftU64 (TmpLba
, 16 * Index
);
1442 Identifies ATA device via the Identify data.
1444 This function identifies the ATA device and initializes the media information.
1446 @attention This is boundary function that may receive untrusted input.
1447 @attention The input is from peripheral hardware device.
1449 The Identify Drive command response data from an ATA device is the peripheral
1450 hardware input, so this routine will do basic validation for the Identify Drive
1451 command response data.
1453 @param[in,out] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
1455 @retval EFI_SUCCESS The device is successfully identified and media
1456 information is correctly initialized.
1457 @retval EFI_UNSUPPORTED The device is not a valid ATA device (hard disk).
1462 IN OUT PEI_AHCI_ATA_DEVICE_DATA
*DeviceData
1465 ATA_IDENTIFY_DATA
*IdentifyData
;
1466 EFI_PEI_BLOCK_IO2_MEDIA
*Media
;
1468 UINT32 MaxSectorCount
;
1469 UINT16 PhyLogicSectorSupport
;
1471 IdentifyData
= DeviceData
->IdentifyData
;
1472 Media
= &DeviceData
->Media
;
1474 if ((IdentifyData
->config
& BIT15
) != 0) {
1476 DEBUG_ERROR
, "%a: Not a hard disk device on Port 0x%x PortMultiplierPort 0x%x\n",
1477 __FUNCTION__
, DeviceData
->Port
, DeviceData
->PortMultiplier
1479 return EFI_UNSUPPORTED
;
1483 DEBUG_INFO
, "%a: Identify Device: Port 0x%x PortMultiplierPort 0x%x\n",
1484 __FUNCTION__
, DeviceData
->Port
, DeviceData
->PortMultiplier
1488 // Skip checking whether the WORD 88 (supported UltraDMA by drive), since the
1489 // driver only support PIO data transfer for now.
1493 // Get the capacity information of the device.
1495 Capacity
= GetAtapi6Capacity (IdentifyData
);
1496 if (Capacity
> MAX_28BIT_ADDRESSING_CAPACITY
) {
1498 // Capacity exceeds 120GB. 48-bit addressing is really needed
1500 DeviceData
->Lba48Bit
= TRUE
;
1503 // This is a hard disk <= 120GB capacity, treat it as normal hard disk
1505 Capacity
= ((UINT32
)IdentifyData
->user_addressable_sectors_hi
<< 16) |
1506 IdentifyData
->user_addressable_sectors_lo
;
1507 DeviceData
->Lba48Bit
= FALSE
;
1510 if (Capacity
== 0) {
1511 DEBUG ((DEBUG_ERROR
, "%a: Invalid Capacity (0) for ATA device.\n", __FUNCTION__
));
1512 return EFI_UNSUPPORTED
;
1514 Media
->LastBlock
= (EFI_PEI_LBA
) (Capacity
- 1);
1516 Media
->BlockSize
= 0x200;
1518 // Check whether Long Physical Sector Feature is supported
1520 PhyLogicSectorSupport
= IdentifyData
->phy_logic_sector_support
;
1522 DEBUG_INFO
, "%a: PhyLogicSectorSupport = 0x%x\n",
1523 __FUNCTION__
, PhyLogicSectorSupport
1525 if ((PhyLogicSectorSupport
& (BIT14
| BIT15
)) == BIT14
) {
1527 // Check logical block size
1529 if ((PhyLogicSectorSupport
& BIT12
) != 0) {
1530 Media
->BlockSize
= (UINT32
) (((IdentifyData
->logic_sector_size_hi
<< 16) |
1531 IdentifyData
->logic_sector_size_lo
) * sizeof (UINT16
));
1536 // Check BlockSize validity
1538 MaxSectorCount
= mMaxTransferBlockNumber
[DeviceData
->Lba48Bit
];
1539 if ((Media
->BlockSize
== 0) || (Media
->BlockSize
> MAX_UINT32
/ MaxSectorCount
)) {
1540 DEBUG ((DEBUG_ERROR
, "%a: Invalid BlockSize (0x%x).\n", __FUNCTION__
, Media
->BlockSize
));
1541 return EFI_UNSUPPORTED
;
1545 DEBUG_INFO
, "%a: BlockSize = 0x%x, LastBlock = 0x%lx\n",
1546 __FUNCTION__
, Media
->BlockSize
, Media
->LastBlock
1549 if ((IdentifyData
->trusted_computing_support
& BIT0
) != 0) {
1550 DEBUG ((DEBUG_INFO
, "%a: Found Trust Computing feature support.\n", __FUNCTION__
));
1551 DeviceData
->TrustComputing
= TRUE
;
1554 Media
->InterfaceType
= MSG_SATA_DP
;
1555 Media
->RemovableMedia
= FALSE
;
1556 Media
->MediaPresent
= TRUE
;
1557 Media
->ReadOnly
= FALSE
;
1563 Allocate device information data structure to contain device information.
1564 And insert the data structure to the tail of device list for tracing.
1566 @param[in,out] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
1568 @param[in] DeviceIndex The device index.
1569 @param[in] Port The port number of the ATA device to send
1571 @param[in] PortMultiplierPort The port multiplier port number of the ATA
1572 device to send the command.
1573 If there is no port multiplier, then specify
1575 @param[in] FisIndex The index of the FIS of the ATA device to
1577 @param[in] IdentifyData The data buffer to store the output of the
1580 @retval EFI_SUCCESS Successfully insert the ATA device to the
1581 tail of device list.
1582 @retval EFI_OUT_OF_RESOURCES Not enough resource.
1587 IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA
*Private
,
1588 IN UINTN DeviceIndex
,
1590 IN UINT16 PortMultiplier
,
1592 IN ATA_IDENTIFY_DATA
*IdentifyData
1595 PEI_AHCI_ATA_DEVICE_DATA
*DeviceData
;
1598 DeviceData
= AllocateZeroPool (sizeof (PEI_AHCI_ATA_DEVICE_DATA
));
1599 if (DeviceData
== NULL
) {
1600 return EFI_OUT_OF_RESOURCES
;
1603 if (IdentifyData
!= NULL
) {
1604 DeviceData
->IdentifyData
= AllocateCopyPool (sizeof (ATA_IDENTIFY_DATA
), IdentifyData
);
1605 if (DeviceData
->IdentifyData
== NULL
) {
1606 return EFI_OUT_OF_RESOURCES
;
1610 DeviceData
->Signature
= AHCI_PEI_ATA_DEVICE_DATA_SIGNATURE
;
1611 DeviceData
->Port
= Port
;
1612 DeviceData
->PortMultiplier
= PortMultiplier
;
1613 DeviceData
->FisIndex
= FisIndex
;
1614 DeviceData
->DeviceIndex
= DeviceIndex
;
1615 DeviceData
->Private
= Private
;
1617 Status
= IdentifyAtaDevice (DeviceData
);
1618 if (EFI_ERROR (Status
)) {
1622 if (DeviceData
->TrustComputing
) {
1623 Private
->TrustComputingDevices
++;
1624 DeviceData
->TrustComputingDeviceIndex
= Private
->TrustComputingDevices
;
1626 Private
->ActiveDevices
++;
1627 InsertTailList (&Private
->DeviceList
, &DeviceData
->Link
);
1633 Initialize ATA host controller at AHCI mode.
1635 The function is designed to initialize ATA host controller.
1637 @param[in,out] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA instance.
1639 @retval EFI_SUCCESS The ATA AHCI controller is initialized successfully.
1640 @retval EFI_OUT_OF_RESOURCES Not enough resource to complete while initializing
1642 @retval Others A device error occurred while initializing the
1647 AhciModeInitialization (
1648 IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA
*Private
1655 UINT8 MaxPortNumber
;
1656 UINT32 PortImplementBitMap
;
1657 UINT32 PortInitializeBitMap
;
1658 EFI_AHCI_REGISTERS
*AhciRegisters
;
1664 UINT32 PhyDetectDelay
;
1666 ATA_IDENTIFY_DATA IdentifyData
;
1668 AhciBar
= Private
->MmioBase
;
1670 Status
= AhciReset (AhciBar
, AHCI_PEI_RESET_TIMEOUT
);
1671 if (EFI_ERROR (Status
)) {
1672 DEBUG ((DEBUG_ERROR
, "%a: AHCI HBA reset failed with %r.\n", __FUNCTION__
, Status
));
1673 return EFI_DEVICE_ERROR
;
1677 // Collect AHCI controller information
1679 Capability
= AhciReadReg (AhciBar
, AHCI_CAPABILITY_OFFSET
);
1682 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
1684 Value
= AhciReadReg (AhciBar
, AHCI_GHC_OFFSET
);
1685 if ((Value
& AHCI_GHC_ENABLE
) == 0) {
1686 AhciOrReg (AhciBar
, AHCI_GHC_OFFSET
, AHCI_GHC_ENABLE
);
1689 Status
= AhciCreateTransferDescriptor (Private
);
1690 if (EFI_ERROR (Status
)) {
1693 "%a: Transfer-related data allocation failed with %r.\n",
1694 __FUNCTION__
, Status
1696 return EFI_OUT_OF_RESOURCES
;
1700 // Get the number of command slots per port supported by this HBA.
1702 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
1705 // Get the bit map of those ports exposed by this HBA.
1706 // It indicates which ports that the HBA supports are available for software
1709 PortImplementBitMap
= AhciReadReg (AhciBar
, AHCI_PI_OFFSET
);
1712 // Get the number of ports that actually needed to be initialized.
1714 MaxPortNumber
= MIN (MaxPortNumber
, (UINT8
)(UINTN
)(HighBitSet32(PortImplementBitMap
) + 1));
1715 MaxPortNumber
= MIN (MaxPortNumber
, AhciGetNumberOfPortsFromMap (Private
->PortBitMap
));
1717 PortInitializeBitMap
= Private
->PortBitMap
;
1718 AhciRegisters
= &Private
->AhciRegisters
;
1721 // Enumerate ATA ports
1723 for (PortIndex
= 1; PortIndex
<= MaxPortNumber
; PortIndex
++) {
1724 Status
= AhciGetPortFromMap (PortInitializeBitMap
, PortIndex
, &Port
);
1725 if ((PortImplementBitMap
& (BIT0
<< Port
)) != 0) {
1727 // Initialize FIS Base Address Register and Command List Base Address
1728 // Register for use.
1730 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFis
) +
1731 sizeof (EFI_AHCI_RECEIVED_FIS
) * (PortIndex
- 1);
1732 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_FB
;
1733 AhciWriteReg (AhciBar
, Offset
, Data64
.Uint32
.Lower32
);
1734 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_FBU
;
1735 AhciWriteReg (AhciBar
, Offset
, Data64
.Uint32
.Upper32
);
1737 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdList
);
1738 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CLB
;
1739 AhciWriteReg (AhciBar
, Offset
, Data64
.Uint32
.Lower32
);
1740 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CLBU
;
1741 AhciWriteReg (AhciBar
, Offset
, Data64
.Uint32
.Upper32
);
1743 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
1744 Data
= AhciReadReg (AhciBar
, Offset
);
1745 if ((Data
& AHCI_PORT_CMD_CPD
) != 0) {
1746 AhciOrReg (AhciBar
, Offset
, AHCI_PORT_CMD_POD
);
1749 if ((Capability
& AHCI_CAP_SSS
) != 0) {
1750 AhciOrReg (AhciBar
, Offset
, AHCI_PORT_CMD_SUD
);
1754 // Disable aggressive power management.
1756 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_SCTL
;
1757 AhciOrReg (AhciBar
, Offset
, AHCI_PORT_SCTL_IPM_INIT
);
1759 // Disable the reporting of the corresponding interrupt to system software.
1761 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_IE
;
1762 AhciAndReg (AhciBar
, Offset
, 0);
1765 // Enable FIS Receive DMA engine for the first D2H FIS.
1767 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
1768 AhciOrReg (AhciBar
, Offset
, AHCI_PORT_CMD_FRE
);
1771 // Wait no longer than 15 ms to wait the Phy to detect the presence of a device.
1773 PhyDetectDelay
= AHCI_BUS_PHY_DETECT_TIMEOUT
;
1774 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_SSTS
;
1776 Data
= AhciReadReg (AhciBar
, Offset
) & AHCI_PORT_SSTS_DET_MASK
;
1777 if ((Data
== AHCI_PORT_SSTS_DET_PCE
) || (Data
== AHCI_PORT_SSTS_DET
)) {
1781 MicroSecondDelay (1000);
1783 } while (PhyDetectDelay
> 0);
1785 if (PhyDetectDelay
== 0) {
1787 // No device detected at this port.
1788 // Clear PxCMD.SUD for those ports at which there are no device present.
1790 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_CMD
;
1791 AhciAndReg (AhciBar
, Offset
, (UINT32
) ~(AHCI_PORT_CMD_SUD
));
1792 DEBUG ((DEBUG_ERROR
, "%a: No device detected at Port %d.\n", __FUNCTION__
, Port
));
1797 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
1798 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
1800 PhyDetectDelay
= 16 * 1000;
1802 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_SERR
;
1803 if (AhciReadReg(AhciBar
, Offset
) != 0) {
1804 AhciWriteReg (AhciBar
, Offset
, AhciReadReg (AhciBar
, Offset
));
1806 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_TFD
;
1808 Data
= AhciReadReg (AhciBar
, Offset
) & AHCI_PORT_TFD_MASK
;
1813 MicroSecondDelay (1000);
1815 } while (PhyDetectDelay
> 0);
1817 if (PhyDetectDelay
== 0) {
1820 "%a: Port %d device presence detected but phy not ready (TFD=0x%x).\n",
1821 __FUNCTION__
, Port
, Data
1827 // When the first D2H register FIS is received, the content of PxSIG register is updated.
1829 Offset
= AHCI_PORT_START
+ Port
* AHCI_PORT_REG_WIDTH
+ AHCI_PORT_SIG
;
1830 Status
= AhciWaitMmioSet (
1837 if (EFI_ERROR (Status
)) {
1840 "%a: Error occured when waiting for the first D2H register FIS - %r\n",
1841 __FUNCTION__
, Status
1846 Data
= AhciReadReg (AhciBar
, Offset
);
1847 if ((Data
& AHCI_ATAPI_SIG_MASK
) == AHCI_ATA_DEVICE_SIG
) {
1848 Status
= AhciIdentify (Private
, Port
, 0, PortIndex
- 1, &IdentifyData
);
1849 if (EFI_ERROR (Status
)) {
1850 DEBUG ((DEBUG_ERROR
, "%a: AhciIdentify() failed with %r\n", __FUNCTION__
, Status
));
1853 DEBUG ((DEBUG_INFO
, "%a: ATA hard disk found on Port %d.\n", __FUNCTION__
, Port
));
1859 // Found an ATA hard disk device, add it into the device list.
1877 Trust transfer data from/to ATA device.
1879 This function performs one ATA pass through transaction to do a trust transfer
1880 from/to ATA device. It chooses the appropriate ATA command and protocol to invoke
1881 PassThru interface of ATA pass through.
1883 @param[in] DeviceData Pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
1884 @param[in,out] Buffer The pointer to the current transaction buffer.
1885 @param[in] SecurityProtocolId
1886 The value of the "Security Protocol" parameter
1887 of the security protocol command to be sent.
1888 @param[in] SecurityProtocolSpecificData
1889 The value of the "Security Protocol Specific"
1890 parameter of the security protocol command to
1892 @param[in] TransferLength The block number or sector count of the transfer.
1893 @param[in] IsTrustSend Indicates whether it is a trust send operation
1895 @param[in] Timeout The timeout, in 100ns units, to use for the execution
1896 of the security protocol command. A Timeout value
1897 of 0 means that this function will wait indefinitely
1898 for the security protocol command to execute. If
1899 Timeout is greater than zero, then this function
1900 will return EFI_TIMEOUT if the time required to
1901 execute the receive data command is greater than
1903 @param[out] TransferLengthOut
1904 A pointer to a buffer to store the size in bytes
1905 of the data written to the buffer. Ignore it when
1906 IsTrustSend is TRUE.
1908 @retval EFI_SUCCESS The data transfer is complete successfully.
1909 @return others Some error occurs when transferring data.
1913 TrustTransferAtaDevice (
1914 IN PEI_AHCI_ATA_DEVICE_DATA
*DeviceData
,
1915 IN OUT VOID
*Buffer
,
1916 IN UINT8 SecurityProtocolId
,
1917 IN UINT16 SecurityProtocolSpecificData
,
1918 IN UINTN TransferLength
,
1919 IN BOOLEAN IsTrustSend
,
1921 OUT UINTN
*TransferLengthOut
1924 PEI_AHCI_CONTROLLER_PRIVATE_DATA
*Private
;
1925 EDKII_PEI_ATA_PASS_THRU_PPI
*AtaPassThru
;
1926 EFI_ATA_COMMAND_BLOCK Acb
;
1927 EFI_ATA_PASS_THRU_COMMAND_PACKET Packet
;
1931 Private
= DeviceData
->Private
;
1932 AtaPassThru
= &Private
->AtaPassThruPpi
;
1935 // Ensure IsTrustSend are valid boolean values
1937 ASSERT ((UINTN
) IsTrustSend
< 2);
1938 if ((UINTN
) IsTrustSend
>= 2) {
1939 return EFI_INVALID_PARAMETER
;
1943 // Prepare for ATA command block.
1945 ZeroMem (&Acb
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1946 if (TransferLength
== 0) {
1947 Acb
.AtaCommand
= ATA_CMD_TRUST_NON_DATA
;
1949 Acb
.AtaCommand
= mAtaTrustCommands
[IsTrustSend
];
1951 Acb
.AtaFeatures
= SecurityProtocolId
;
1952 Acb
.AtaSectorCount
= (UINT8
) (TransferLength
/ 512);
1953 Acb
.AtaSectorNumber
= (UINT8
) ((TransferLength
/ 512) >> 8);
1955 // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout.
1956 // Here use big endian for Cylinder register.
1958 Acb
.AtaCylinderHigh
= (UINT8
) SecurityProtocolSpecificData
;
1959 Acb
.AtaCylinderLow
= (UINT8
) (SecurityProtocolSpecificData
>> 8);
1960 Acb
.AtaDeviceHead
= (UINT8
) (BIT7
| BIT6
| BIT5
|
1961 (DeviceData
->PortMultiplier
== 0xFFFF ?
1962 0 : (DeviceData
->PortMultiplier
<< 4)));
1965 // Prepare for ATA pass through packet.
1967 ZeroMem (&Packet
, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET
));
1968 if (TransferLength
== 0) {
1969 Packet
.InTransferLength
= 0;
1970 Packet
.OutTransferLength
= 0;
1971 Packet
.Protocol
= EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA
;
1972 } else if (IsTrustSend
) {
1974 // Check the alignment of the incoming buffer prior to invoking underlying
1975 // ATA PassThru PPI.
1977 if ((AtaPassThru
->Mode
->IoAlign
> 1) &&
1978 !IS_ALIGNED (Buffer
, AtaPassThru
->Mode
->IoAlign
)) {
1979 NewBuffer
= AllocateAlignedPages (
1980 EFI_SIZE_TO_PAGES (TransferLength
),
1981 AtaPassThru
->Mode
->IoAlign
1983 if (NewBuffer
== NULL
) {
1984 return EFI_OUT_OF_RESOURCES
;
1987 CopyMem (NewBuffer
, Buffer
, TransferLength
);
1990 Packet
.OutDataBuffer
= Buffer
;
1991 Packet
.OutTransferLength
= (UINT32
) TransferLength
;
1992 Packet
.Protocol
= mAtaPassThruCmdProtocols
[IsTrustSend
];
1994 Packet
.InDataBuffer
= Buffer
;
1995 Packet
.InTransferLength
= (UINT32
) TransferLength
;
1996 Packet
.Protocol
= mAtaPassThruCmdProtocols
[IsTrustSend
];
2000 Packet
.Timeout
= Timeout
;
2001 Packet
.Length
= EFI_ATA_PASS_THRU_LENGTH_BYTES
;
2003 Status
= AtaPassThru
->PassThru (
2006 DeviceData
->PortMultiplier
,
2009 if (TransferLengthOut
!= NULL
) {
2011 *TransferLengthOut
= Packet
.InTransferLength
;