2 The file for AHCI mode of ATA host controller.
4 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "AtaAtapiPassThru.h"
19 Read AHCI Operation register.
21 @param PciIo The PCI IO protocol instance.
22 @param Offset The operation register offset.
24 @return The register content read.
30 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
36 ASSERT (PciIo
!= NULL
);
53 Write AHCI Operation register.
55 @param PciIo The PCI IO protocol instance.
56 @param Offset The operation register offset.
57 @param Data The data used to write down.
63 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
68 ASSERT (PciIo
!= NULL
);
83 Do AND operation with the value of AHCI Operation register.
85 @param PciIo The PCI IO protocol instance.
86 @param Offset The operation register offset.
87 @param AndData The data used to do AND operation.
93 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
100 ASSERT (PciIo
!= NULL
);
102 Data
= AhciReadReg (PciIo
, Offset
);
106 AhciWriteReg (PciIo
, Offset
, Data
);
110 Do OR operation with the value of AHCI Operation register.
112 @param PciIo The PCI IO protocol instance.
113 @param Offset The operation register offset.
114 @param OrData The data used to do OR operation.
120 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
127 ASSERT (PciIo
!= NULL
);
129 Data
= AhciReadReg (PciIo
, Offset
);
133 AhciWriteReg (PciIo
, Offset
, Data
);
137 Wait for the value of the specified MMIO register set to the test value.
139 @param PciIo The PCI IO protocol instance.
140 @param Offset The MMIO address to test.
141 @param MaskValue The mask value of memory.
142 @param TestValue The test value of memory.
143 @param Timeout The time out value for wait memory set, uses 100ns as a unit.
145 @retval EFI_TIMEOUT The MMIO setting is time out.
146 @retval EFI_SUCCESS The MMIO is correct set.
152 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
161 BOOLEAN InfiniteWait
;
166 InfiniteWait
= FALSE
;
169 Delay
= DivU64x32 (Timeout
, 1000) + 1;
173 // Access PCI MMIO space to see if the value is the tested one.
175 Value
= AhciReadReg (PciIo
, (UINT32
) Offset
) & MaskValue
;
177 if (Value
== TestValue
) {
182 // Stall for 100 microseconds.
184 MicroSecondDelay (100);
188 } while (InfiniteWait
|| (Delay
> 0));
194 Wait for the value of the specified system memory set to the test value.
196 @param Address The system memory address to test.
197 @param MaskValue The mask value of memory.
198 @param TestValue The test value of memory.
199 @param Timeout The time out value for wait memory set, uses 100ns as a unit.
201 @retval EFI_TIMEOUT The system memory setting is time out.
202 @retval EFI_SUCCESS The system memory is correct set.
208 IN EFI_PHYSICAL_ADDRESS Address
,
216 BOOLEAN InfiniteWait
;
221 InfiniteWait
= FALSE
;
224 Delay
= DivU64x32 (Timeout
, 1000) + 1;
228 // Access sytem memory to see if the value is the tested one.
230 // The system memory pointed by Address will be updated by the
231 // SATA Host Controller, "volatile" is introduced to prevent
232 // compiler from optimizing the access to the memory address
233 // to only read once.
235 Value
= *(volatile UINT32
*) (UINTN
) Address
;
238 if (Value
== TestValue
) {
243 // Stall for 100 microseconds.
245 MicroSecondDelay (100);
249 } while (InfiniteWait
|| (Delay
> 0));
255 Check the memory status to the test value.
257 @param[in] Address The memory address to test.
258 @param[in] MaskValue The mask value of memory.
259 @param[in] TestValue The test value of memory.
260 @param[in, out] Task Optional. Pointer to the ATA_NONBLOCK_TASK used by
261 non-blocking mode. If NULL, then just try once.
263 @retval EFI_NOTREADY The memory is not set.
264 @retval EFI_TIMEOUT The memory setting retry times out.
265 @retval EFI_SUCCESS The memory is correct set.
274 IN OUT ATA_NONBLOCK_TASK
*Task
283 Value
= *(volatile UINT32
*) Address
;
286 if (Value
== TestValue
) {
290 if ((Task
!= NULL
) && !Task
->InfiniteWait
&& (Task
->RetryTimes
== 0)) {
293 return EFI_NOT_READY
;
300 Clear the port interrupt and error status. It will also clear
301 HBA interrupt status.
303 @param PciIo The PCI IO protocol instance.
304 @param Port The number of port.
309 AhciClearPortStatus (
310 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
317 // Clear any error status
319 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
320 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
323 // Clear any port interrupt status
325 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
326 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
329 // Clear any HBA interrupt status
331 AhciWriteReg (PciIo
, EFI_AHCI_IS_OFFSET
, AhciReadReg (PciIo
, EFI_AHCI_IS_OFFSET
));
335 This function is used to dump the Status Registers and if there is ERR bit set
336 in the Status Register, the Error Register's value is also be dumped.
338 @param PciIo The PCI IO protocol instance.
339 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
340 @param Port The number of port.
341 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
347 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
348 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
350 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
358 ASSERT (PciIo
!= NULL
);
360 if (AtaStatusBlock
!= NULL
) {
361 ZeroMem (AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
363 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
364 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
366 Status
= AhciCheckMemSet (Offset
, EFI_AHCI_FIS_TYPE_MASK
, EFI_AHCI_FIS_REGISTER_D2H
, NULL
);
367 if (!EFI_ERROR (Status
)) {
369 // If D2H FIS is received, update StatusBlock with its content.
371 CopyMem (AtaStatusBlock
, (UINT8
*)Offset
, sizeof (EFI_ATA_STATUS_BLOCK
));
374 // If D2H FIS is not received, only update Status & Error field through PxTFD
375 // as there is no other way to get the content of the Shadow Register Block.
377 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
378 Data
= AhciReadReg (PciIo
, (UINT32
)Offset
);
380 AtaStatusBlock
->AtaStatus
= (UINT8
)Data
;
381 if ((AtaStatusBlock
->AtaStatus
& BIT0
) != 0) {
382 AtaStatusBlock
->AtaError
= (UINT8
)(Data
>> 8);
390 Enable the FIS running for giving port.
392 @param PciIo The PCI IO protocol instance.
393 @param Port The number of port.
394 @param Timeout The timeout value of enabling FIS, uses 100ns as a unit.
396 @retval EFI_DEVICE_ERROR The FIS enable setting fails.
397 @retval EFI_TIMEOUT The FIS enable setting is time out.
398 @retval EFI_SUCCESS The FIS enable successfully.
403 AhciEnableFisReceive (
404 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
411 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
412 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
418 Disable the FIS running for giving port.
420 @param PciIo The PCI IO protocol instance.
421 @param Port The number of port.
422 @param Timeout The timeout value of disabling FIS, uses 100ns as a unit.
424 @retval EFI_DEVICE_ERROR The FIS disable setting fails.
425 @retval EFI_TIMEOUT The FIS disable setting is time out.
426 @retval EFI_UNSUPPORTED The port is in running state.
427 @retval EFI_SUCCESS The FIS disable successfully.
432 AhciDisableFisReceive (
433 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
441 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
442 Data
= AhciReadReg (PciIo
, Offset
);
445 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
447 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) != 0) {
448 return EFI_UNSUPPORTED
;
452 // Check if the Fis receive DMA engine for the port is running.
454 if ((Data
& EFI_AHCI_PORT_CMD_FR
) != EFI_AHCI_PORT_CMD_FR
) {
458 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
));
460 return AhciWaitMmioSet (
463 EFI_AHCI_PORT_CMD_FR
,
472 Build the command list, command table and prepare the fis receiver.
474 @param PciIo The PCI IO protocol instance.
475 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
476 @param Port The number of port.
477 @param PortMultiplier The timeout value of stop.
478 @param CommandFis The control fis will be used for the transfer.
479 @param CommandList The command list will be used for the transfer.
480 @param AtapiCommand The atapi command will be used for the transfer.
481 @param AtapiCommandLength The length of the atapi command.
482 @param CommandSlotNumber The command slot will be used for the transfer.
483 @param DataPhysicalAddr The pointer to the data buffer pci bus master address.
484 @param DataLength The data count to be transferred.
490 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
491 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
493 IN UINT8 PortMultiplier
,
494 IN EFI_AHCI_COMMAND_FIS
*CommandFis
,
495 IN EFI_AHCI_COMMAND_LIST
*CommandList
,
496 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
497 IN UINT8 AtapiCommandLength
,
498 IN UINT8 CommandSlotNumber
,
499 IN OUT VOID
*DataPhysicalAddr
,
514 PrdtNumber
= (UINT32
)DivU64x32 (((UINT64
)DataLength
+ EFI_AHCI_MAX_DATA_PER_PRDT
- 1), EFI_AHCI_MAX_DATA_PER_PRDT
);
517 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
518 // It also limits that the maximum amount of the PRDT entry in the command table
521 ASSERT (PrdtNumber
<= 65535);
523 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFis
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
525 BaseAddr
= Data64
.Uint64
;
527 ZeroMem ((VOID
*)((UINTN
) BaseAddr
), sizeof (EFI_AHCI_RECEIVED_FIS
));
529 ZeroMem (AhciRegisters
->AhciCommandTable
, sizeof (EFI_AHCI_COMMAND_TABLE
));
531 CommandFis
->AhciCFisPmNum
= PortMultiplier
;
533 CopyMem (&AhciRegisters
->AhciCommandTable
->CommandFis
, CommandFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
535 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
536 if (AtapiCommand
!= NULL
) {
538 &AhciRegisters
->AhciCommandTable
->AtapiCmd
,
543 CommandList
->AhciCmdA
= 1;
544 CommandList
->AhciCmdP
= 1;
546 AhciOrReg (PciIo
, Offset
, (EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
548 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
551 RemainedData
= (UINTN
) DataLength
;
552 MemAddr
= (UINTN
) DataPhysicalAddr
;
553 CommandList
->AhciCmdPrdtl
= PrdtNumber
;
555 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
556 if (RemainedData
< EFI_AHCI_MAX_DATA_PER_PRDT
) {
557 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= (UINT32
)RemainedData
- 1;
559 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= EFI_AHCI_MAX_DATA_PER_PRDT
- 1;
562 Data64
.Uint64
= (UINT64
)MemAddr
;
563 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDba
= Data64
.Uint32
.Lower32
;
564 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbau
= Data64
.Uint32
.Upper32
;
565 RemainedData
-= EFI_AHCI_MAX_DATA_PER_PRDT
;
566 MemAddr
+= EFI_AHCI_MAX_DATA_PER_PRDT
;
570 // Set the last PRDT to Interrupt On Complete
572 if (PrdtNumber
> 0) {
573 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtNumber
- 1].AhciPrdtIoc
= 1;
577 (VOID
*) ((UINTN
) AhciRegisters
->AhciCmdList
+ (UINTN
) CommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
)),
579 sizeof (EFI_AHCI_COMMAND_LIST
)
582 Data64
.Uint64
= (UINT64
)(UINTN
) AhciRegisters
->AhciCommandTablePciAddr
;
583 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtba
= Data64
.Uint32
.Lower32
;
584 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtbau
= Data64
.Uint32
.Upper32
;
585 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdPmp
= PortMultiplier
;
592 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.
593 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.
598 AhciBuildCommandFis (
599 IN OUT EFI_AHCI_COMMAND_FIS
*CmdFis
,
600 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
603 ZeroMem (CmdFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
605 CmdFis
->AhciCFisType
= EFI_AHCI_FIS_REGISTER_H2D
;
607 // Indicator it's a command
609 CmdFis
->AhciCFisCmdInd
= 0x1;
610 CmdFis
->AhciCFisCmd
= AtaCommandBlock
->AtaCommand
;
612 CmdFis
->AhciCFisFeature
= AtaCommandBlock
->AtaFeatures
;
613 CmdFis
->AhciCFisFeatureExp
= AtaCommandBlock
->AtaFeaturesExp
;
615 CmdFis
->AhciCFisSecNum
= AtaCommandBlock
->AtaSectorNumber
;
616 CmdFis
->AhciCFisSecNumExp
= AtaCommandBlock
->AtaSectorNumberExp
;
618 CmdFis
->AhciCFisClyLow
= AtaCommandBlock
->AtaCylinderLow
;
619 CmdFis
->AhciCFisClyLowExp
= AtaCommandBlock
->AtaCylinderLowExp
;
621 CmdFis
->AhciCFisClyHigh
= AtaCommandBlock
->AtaCylinderHigh
;
622 CmdFis
->AhciCFisClyHighExp
= AtaCommandBlock
->AtaCylinderHighExp
;
624 CmdFis
->AhciCFisSecCount
= AtaCommandBlock
->AtaSectorCount
;
625 CmdFis
->AhciCFisSecCountExp
= AtaCommandBlock
->AtaSectorCountExp
;
627 CmdFis
->AhciCFisDevHead
= (UINT8
) (AtaCommandBlock
->AtaDeviceHead
| 0xE0);
631 Start a PIO data transfer on specific port.
633 @param[in] PciIo The PCI IO protocol instance.
634 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
635 @param[in] Port The number of port.
636 @param[in] PortMultiplier The timeout value of stop.
637 @param[in] AtapiCommand The atapi command will be used for the
639 @param[in] AtapiCommandLength The length of the atapi command.
640 @param[in] Read The transfer direction.
641 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
642 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
643 @param[in, out] MemoryAddr The pointer to the data buffer.
644 @param[in] DataCount The data count to be transferred.
645 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
646 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
647 used by non-blocking mode.
649 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
650 @retval EFI_TIMEOUT The operation is time out.
651 @retval EFI_UNSUPPORTED The device is not ready for transfer.
652 @retval EFI_SUCCESS The PIO data transfer executes successfully.
658 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
659 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
661 IN UINT8 PortMultiplier
,
662 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
663 IN UINT8 AtapiCommandLength
,
665 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
666 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
667 IN OUT VOID
*MemoryAddr
,
670 IN ATA_NONBLOCK_TASK
*Task
676 EFI_PHYSICAL_ADDRESS PhyAddr
;
679 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
681 EFI_AHCI_COMMAND_FIS CFis
;
682 EFI_AHCI_COMMAND_LIST CmdList
;
685 BOOLEAN InfiniteWait
;
686 BOOLEAN PioFisReceived
;
687 BOOLEAN D2hFisReceived
;
692 InfiniteWait
= FALSE
;
696 Flag
= EfiPciIoOperationBusMasterWrite
;
698 Flag
= EfiPciIoOperationBusMasterRead
;
702 // construct command list and command table with pci bus address
704 MapLength
= DataCount
;
705 Status
= PciIo
->Map (
714 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
715 return EFI_BAD_BUFFER_SIZE
;
719 // Package read needed
721 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
723 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
725 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
726 CmdList
.AhciCmdW
= Read
? 0 : 1;
738 (VOID
*)(UINTN
)PhyAddr
,
742 Status
= AhciStartCommand (
748 if (EFI_ERROR (Status
)) {
753 // Check the status and wait the driver sending data
755 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
757 if (Read
&& (AtapiCommand
== 0)) {
759 // Wait device sends the PIO setup fis before data transfer
761 Status
= EFI_TIMEOUT
;
762 Delay
= DivU64x32 (Timeout
, 1000) + 1;
764 PioFisReceived
= FALSE
;
765 D2hFisReceived
= FALSE
;
766 Offset
= FisBaseAddr
+ EFI_AHCI_PIO_FIS_OFFSET
;
767 Status
= AhciCheckMemSet (Offset
, EFI_AHCI_FIS_TYPE_MASK
, EFI_AHCI_FIS_PIO_SETUP
, NULL
);
768 if (!EFI_ERROR (Status
)) {
769 PioFisReceived
= TRUE
;
772 // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
773 // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device
774 // after the transaction is finished successfully.
775 // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.
776 // By this way, we can know if there is a real error happened.
778 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
779 Status
= AhciCheckMemSet (Offset
, EFI_AHCI_FIS_TYPE_MASK
, EFI_AHCI_FIS_REGISTER_D2H
, NULL
);
780 if (!EFI_ERROR (Status
)) {
781 D2hFisReceived
= TRUE
;
784 if (PioFisReceived
|| D2hFisReceived
) {
785 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
786 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
788 // PxTFD will be updated if there is a D2H or SetupFIS received.
790 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
791 Status
= EFI_DEVICE_ERROR
;
795 PrdCount
= *(volatile UINT32
*) (&(AhciRegisters
->AhciCmdList
[0].AhciCmdPrdbc
));
796 if (PrdCount
== DataCount
) {
797 Status
= EFI_SUCCESS
;
803 // Stall for 100 microseconds.
805 MicroSecondDelay(100);
809 Status
= EFI_TIMEOUT
;
811 } while (InfiniteWait
|| (Delay
> 0));
814 // Wait for D2H Fis is received
816 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
817 Status
= AhciWaitMemSet (
819 EFI_AHCI_FIS_TYPE_MASK
,
820 EFI_AHCI_FIS_REGISTER_D2H
,
824 if (EFI_ERROR (Status
)) {
828 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
829 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
830 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
831 Status
= EFI_DEVICE_ERROR
;
842 AhciDisableFisReceive (
853 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
859 Start a DMA data transfer on specific port
861 @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.
862 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
863 @param[in] Port The number of port.
864 @param[in] PortMultiplier The timeout value of stop.
865 @param[in] AtapiCommand The atapi command will be used for the
867 @param[in] AtapiCommandLength The length of the atapi command.
868 @param[in] Read The transfer direction.
869 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
870 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
871 @param[in, out] MemoryAddr The pointer to the data buffer.
872 @param[in] DataCount The data count to be transferred.
873 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
874 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
875 used by non-blocking mode.
877 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
878 @retval EFI_TIMEOUT The operation is time out.
879 @retval EFI_UNSUPPORTED The device is not ready for transfer.
880 @retval EFI_SUCCESS The DMA data transfer executes successfully.
886 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
,
887 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
889 IN UINT8 PortMultiplier
,
890 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
891 IN UINT8 AtapiCommandLength
,
893 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
894 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
895 IN OUT VOID
*MemoryAddr
,
898 IN ATA_NONBLOCK_TASK
*Task
903 EFI_PHYSICAL_ADDRESS PhyAddr
;
906 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
907 EFI_AHCI_COMMAND_FIS CFis
;
908 EFI_AHCI_COMMAND_LIST CmdList
;
912 EFI_PCI_IO_PROTOCOL
*PciIo
;
916 PciIo
= Instance
->PciIo
;
919 return EFI_INVALID_PARAMETER
;
923 // Before starting the Blocking BlockIO operation, push to finish all non-blocking
925 // Delay 100us to simulate the blocking time out checking.
927 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
928 while ((Task
== NULL
) && (!IsListEmpty (&Instance
->NonBlockingTaskList
))) {
929 AsyncNonBlockingTransferRoutine (NULL
, Instance
);
933 MicroSecondDelay (100);
935 gBS
->RestoreTPL (OldTpl
);
937 if ((Task
== NULL
) || ((Task
!= NULL
) && (!Task
->IsStart
))) {
939 // Mark the Task to indicate that it has been started.
942 Task
->IsStart
= TRUE
;
945 Flag
= EfiPciIoOperationBusMasterWrite
;
947 Flag
= EfiPciIoOperationBusMasterRead
;
951 // Construct command list and command table with pci bus address.
953 MapLength
= DataCount
;
954 Status
= PciIo
->Map (
963 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
964 return EFI_BAD_BUFFER_SIZE
;
971 // Package read needed
973 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
975 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
977 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
978 CmdList
.AhciCmdW
= Read
? 0 : 1;
990 (VOID
*)(UINTN
)PhyAddr
,
994 Status
= AhciStartCommand (
1000 if (EFI_ERROR (Status
)) {
1006 // Wait for command compelte
1008 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1009 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
1014 Status
= AhciCheckMemSet (
1016 EFI_AHCI_FIS_TYPE_MASK
,
1017 EFI_AHCI_FIS_REGISTER_D2H
,
1021 Status
= AhciWaitMemSet (
1023 EFI_AHCI_FIS_TYPE_MASK
,
1024 EFI_AHCI_FIS_REGISTER_D2H
,
1029 if (EFI_ERROR (Status
)) {
1033 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1034 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
1035 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
1036 Status
= EFI_DEVICE_ERROR
;
1041 // For Blocking mode, the command should be stopped, the Fis should be disabled
1042 // and the PciIo should be unmapped.
1043 // For non-blocking mode, only when a error is happened (if the return status is
1044 // EFI_NOT_READY that means the command doesn't finished, try again.), first do the
1045 // context cleanup, then set the packet's Asb status.
1048 ((Task
!= NULL
) && (Status
!= EFI_NOT_READY
))
1056 AhciDisableFisReceive (
1064 (Task
!= NULL
) ? Task
->Map
: Map
1068 Task
->Packet
->Asb
->AtaStatus
= 0x01;
1072 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1077 Start a non data transfer on specific port.
1079 @param[in] PciIo The PCI IO protocol instance.
1080 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1081 @param[in] Port The number of port.
1082 @param[in] PortMultiplier The timeout value of stop.
1083 @param[in] AtapiCommand The atapi command will be used for the
1085 @param[in] AtapiCommandLength The length of the atapi command.
1086 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
1087 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
1088 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
1089 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
1090 used by non-blocking mode.
1092 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
1093 @retval EFI_TIMEOUT The operation is time out.
1094 @retval EFI_UNSUPPORTED The device is not ready for transfer.
1095 @retval EFI_SUCCESS The non data transfer executes successfully.
1100 AhciNonDataTransfer (
1101 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1102 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1104 IN UINT8 PortMultiplier
,
1105 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
1106 IN UINT8 AtapiCommandLength
,
1107 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
1108 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
1110 IN ATA_NONBLOCK_TASK
*Task
1117 EFI_AHCI_COMMAND_FIS CFis
;
1118 EFI_AHCI_COMMAND_LIST CmdList
;
1121 // Package read needed
1123 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
1125 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
1127 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
1143 Status
= AhciStartCommand (
1149 if (EFI_ERROR (Status
)) {
1154 // Wait device sends the Response Fis
1156 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1157 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
1158 Status
= AhciWaitMemSet (
1160 EFI_AHCI_FIS_TYPE_MASK
,
1161 EFI_AHCI_FIS_REGISTER_D2H
,
1165 if (EFI_ERROR (Status
)) {
1169 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1170 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
1171 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
1172 Status
= EFI_DEVICE_ERROR
;
1182 AhciDisableFisReceive (
1188 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1194 Stop command running for giving port
1196 @param PciIo The PCI IO protocol instance.
1197 @param Port The number of port.
1198 @param Timeout The timeout value of stop, uses 100ns as a unit.
1200 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
1201 @retval EFI_TIMEOUT The operation is time out.
1202 @retval EFI_SUCCESS The command stop successfully.
1208 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1216 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1217 Data
= AhciReadReg (PciIo
, Offset
);
1219 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) == 0) {
1223 if ((Data
& EFI_AHCI_PORT_CMD_ST
) != 0) {
1224 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_ST
));
1227 return AhciWaitMmioSet (
1230 EFI_AHCI_PORT_CMD_CR
,
1237 Start command for give slot on specific port.
1239 @param PciIo The PCI IO protocol instance.
1240 @param Port The number of port.
1241 @param CommandSlot The number of Command Slot.
1242 @param Timeout The timeout value of start, uses 100ns as a unit.
1244 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
1245 @retval EFI_TIMEOUT The operation is time out.
1246 @retval EFI_SUCCESS The command start successfully.
1252 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1254 IN UINT8 CommandSlot
,
1267 // Collect AHCI controller information
1269 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1271 CmdSlotBit
= (UINT32
) (1 << CommandSlot
);
1273 AhciClearPortStatus (
1278 Status
= AhciEnableFisReceive (
1284 if (EFI_ERROR (Status
)) {
1288 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1289 PortStatus
= AhciReadReg (PciIo
, Offset
);
1292 if ((PortStatus
& EFI_AHCI_PORT_CMD_ALPE
) != 0) {
1293 StartCmd
= AhciReadReg (PciIo
, Offset
);
1294 StartCmd
&= ~EFI_AHCI_PORT_CMD_ICC_MASK
;
1295 StartCmd
|= EFI_AHCI_PORT_CMD_ACTIVE
;
1298 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1299 PortTfd
= AhciReadReg (PciIo
, Offset
);
1301 if ((PortTfd
& (EFI_AHCI_PORT_TFD_BSY
| EFI_AHCI_PORT_TFD_DRQ
)) != 0) {
1302 if ((Capability
& BIT24
) != 0) {
1303 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1304 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_CLO
);
1309 EFI_AHCI_PORT_CMD_CLO
,
1316 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1317 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_ST
| StartCmd
);
1320 // Setting the command
1322 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
1323 AhciAndReg (PciIo
, Offset
, 0);
1324 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1333 @param PciIo The PCI IO protocol instance.
1334 @param Timeout The timeout value of reset, uses 100ns as a unit.
1336 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
1337 @retval EFI_TIMEOUT The reset operation is time out.
1338 @retval EFI_SUCCESS AHCI controller is reset successfully.
1344 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1352 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
1354 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1356 if ((Value
& EFI_AHCI_GHC_ENABLE
) == 0) {
1357 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
1360 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_RESET
);
1362 Delay
= DivU64x32(Timeout
, 1000) + 1;
1365 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1367 if ((Value
& EFI_AHCI_GHC_RESET
) == 0) {
1372 // Stall for 100 microseconds.
1374 MicroSecondDelay(100);
1377 } while (Delay
> 0);
1387 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
1389 @param PciIo The PCI IO protocol instance.
1390 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1391 @param Port The number of port.
1392 @param PortMultiplier The port multiplier port number.
1393 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1395 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
1396 @retval Others Fail to get return status data.
1401 AhciAtaSmartReturnStatusCheck (
1402 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1403 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1405 IN UINT8 PortMultiplier
,
1406 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1410 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1416 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1418 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1419 AtaCommandBlock
.AtaFeatures
= ATA_SMART_RETURN_STATUS
;
1420 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1421 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1424 // Send S.M.A.R.T Read Return Status command to device
1426 Status
= AhciNonDataTransfer (
1430 (UINT8
)PortMultiplier
,
1439 if (EFI_ERROR (Status
)) {
1440 REPORT_STATUS_CODE (
1441 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1442 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_DISABLED
)
1444 return EFI_DEVICE_ERROR
;
1447 REPORT_STATUS_CODE (
1449 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_ENABLE
)
1452 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1454 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
1456 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
1457 LBAMid
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[5];
1458 LBAHigh
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[6];
1460 if ((LBAMid
== 0x4f) && (LBAHigh
== 0xc2)) {
1462 // The threshold exceeded condition is not detected by the device
1464 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
1465 REPORT_STATUS_CODE (
1467 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD
)
1469 } else if ((LBAMid
== 0xf4) && (LBAHigh
== 0x2c)) {
1471 // The threshold exceeded condition is detected by the device
1473 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is detected\n"));
1474 REPORT_STATUS_CODE (
1476 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD
)
1485 Enable SMART command of the disk if supported.
1487 @param PciIo The PCI IO protocol instance.
1488 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1489 @param Port The number of port.
1490 @param PortMultiplier The port multiplier port number.
1491 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
1492 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1497 AhciAtaSmartSupport (
1498 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1499 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1501 IN UINT8 PortMultiplier
,
1502 IN EFI_IDENTIFY_DATA
*IdentifyData
,
1503 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1507 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1510 // Detect if the device supports S.M.A.R.T.
1512 if ((IdentifyData
->AtaData
.command_set_supported_82
& 0x0001) != 0x0001) {
1514 // S.M.A.R.T is not supported by the device
1516 DEBUG ((EFI_D_INFO
, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
1517 Port
, PortMultiplier
));
1518 REPORT_STATUS_CODE (
1519 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1520 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED
)
1524 // Check if the feature is enabled. If not, then enable S.M.A.R.T.
1526 if ((IdentifyData
->AtaData
.command_set_feature_enb_85
& 0x0001) != 0x0001) {
1528 REPORT_STATUS_CODE (
1530 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_DISABLE
)
1533 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1535 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1536 AtaCommandBlock
.AtaFeatures
= ATA_SMART_ENABLE_OPERATION
;
1537 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1538 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1541 // Send S.M.A.R.T Enable command to device
1543 Status
= AhciNonDataTransfer (
1547 (UINT8
)PortMultiplier
,
1557 if (!EFI_ERROR (Status
)) {
1559 // Send S.M.A.R.T AutoSave command to device
1561 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1563 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1564 AtaCommandBlock
.AtaFeatures
= 0xD2;
1565 AtaCommandBlock
.AtaSectorCount
= 0xF1;
1566 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1567 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1569 Status
= AhciNonDataTransfer (
1573 (UINT8
)PortMultiplier
,
1582 if (!EFI_ERROR (Status
)) {
1583 Status
= AhciAtaSmartReturnStatusCheck (
1587 (UINT8
)PortMultiplier
,
1593 DEBUG ((EFI_D_INFO
, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
1594 Port
, PortMultiplier
));
1601 Send Buffer cmd to specific device.
1603 @param PciIo The PCI IO protocol instance.
1604 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1605 @param Port The number of port.
1606 @param PortMultiplier The port multiplier port number.
1607 @param Buffer The data buffer to store IDENTIFY PACKET data.
1609 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1610 @retval EFI_TIMEOUT The operation is time out.
1611 @retval EFI_UNSUPPORTED The device is not ready for executing.
1612 @retval EFI_SUCCESS The cmd executes successfully.
1618 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1619 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1621 IN UINT8 PortMultiplier
,
1622 IN OUT EFI_IDENTIFY_DATA
*Buffer
1626 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1627 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1629 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
1630 return EFI_INVALID_PARAMETER
;
1633 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1634 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1636 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DRIVE
;
1637 AtaCommandBlock
.AtaSectorCount
= 1;
1639 Status
= AhciPioTransfer (
1650 sizeof (EFI_IDENTIFY_DATA
),
1659 Send Buffer cmd to specific device.
1661 @param PciIo The PCI IO protocol instance.
1662 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1663 @param Port The number of port.
1664 @param PortMultiplier The port multiplier port number.
1665 @param Buffer The data buffer to store IDENTIFY PACKET data.
1667 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1668 @retval EFI_TIMEOUT The operation is time out.
1669 @retval EFI_UNSUPPORTED The device is not ready for executing.
1670 @retval EFI_SUCCESS The cmd executes successfully.
1675 AhciIdentifyPacket (
1676 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1677 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1679 IN UINT8 PortMultiplier
,
1680 IN OUT EFI_IDENTIFY_DATA
*Buffer
1684 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1685 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1687 if (PciIo
== NULL
|| AhciRegisters
== NULL
) {
1688 return EFI_INVALID_PARAMETER
;
1691 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1692 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1694 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DEVICE
;
1695 AtaCommandBlock
.AtaSectorCount
= 1;
1697 Status
= AhciPioTransfer (
1708 sizeof (EFI_IDENTIFY_DATA
),
1717 Send SET FEATURE cmd on specific device.
1719 @param PciIo The PCI IO protocol instance.
1720 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1721 @param Port The number of port.
1722 @param PortMultiplier The port multiplier port number.
1723 @param Feature The data to send Feature register.
1724 @param FeatureSpecificData The specific data for SET FEATURE cmd.
1725 @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.
1727 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1728 @retval EFI_TIMEOUT The operation is time out.
1729 @retval EFI_UNSUPPORTED The device is not ready for executing.
1730 @retval EFI_SUCCESS The cmd executes successfully.
1735 AhciDeviceSetFeature (
1736 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1737 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1739 IN UINT8 PortMultiplier
,
1741 IN UINT32 FeatureSpecificData
,
1746 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1747 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1749 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1750 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1752 AtaCommandBlock
.AtaCommand
= ATA_CMD_SET_FEATURES
;
1753 AtaCommandBlock
.AtaFeatures
= (UINT8
) Feature
;
1754 AtaCommandBlock
.AtaFeaturesExp
= (UINT8
) (Feature
>> 8);
1755 AtaCommandBlock
.AtaSectorCount
= (UINT8
) FeatureSpecificData
;
1756 AtaCommandBlock
.AtaSectorNumber
= (UINT8
) (FeatureSpecificData
>> 8);
1757 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (FeatureSpecificData
>> 16);
1758 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (FeatureSpecificData
>> 24);
1760 Status
= AhciNonDataTransfer (
1764 (UINT8
)PortMultiplier
,
1777 This function is used to send out ATAPI commands conforms to the Packet Command
1780 @param PciIo The PCI IO protocol instance.
1781 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1782 @param Port The number of port.
1783 @param PortMultiplier The number of port multiplier.
1784 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
1786 @retval EFI_SUCCESS send out the ATAPI packet command successfully
1787 and device sends data successfully.
1788 @retval EFI_DEVICE_ERROR the device failed to send data.
1793 AhciPacketCommandExecute (
1794 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1795 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1797 IN UINT8 PortMultiplier
,
1798 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1804 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1805 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1808 if (Packet
== NULL
|| Packet
->Cdb
== NULL
) {
1809 return EFI_INVALID_PARAMETER
;
1812 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1813 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1814 AtaCommandBlock
.AtaCommand
= ATA_CMD_PACKET
;
1818 AtaCommandBlock
.AtaFeatures
= 0x00;
1820 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
1821 // determine how many data should be transferred.
1823 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
& 0x00ff);
1824 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
>> 8);
1826 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1827 Buffer
= Packet
->InDataBuffer
;
1828 Length
= Packet
->InTransferLength
;
1831 Buffer
= Packet
->OutDataBuffer
;
1832 Length
= Packet
->OutTransferLength
;
1837 Status
= AhciNonDataTransfer (
1850 Status
= AhciPioTransfer (
1870 Allocate transfer-related data struct which is used at AHCI mode.
1872 @param PciIo The PCI IO protocol instance.
1873 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1878 AhciCreateTransferDescriptor (
1879 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1880 IN OUT EFI_AHCI_REGISTERS
*AhciRegisters
1888 UINT32 PortImplementBitMap
;
1889 UINT8 MaxPortNumber
;
1890 UINT8 MaxCommandSlotNumber
;
1891 BOOLEAN Support64Bit
;
1892 UINT64 MaxReceiveFisSize
;
1893 UINT64 MaxCommandListSize
;
1894 UINT64 MaxCommandTableSize
;
1895 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr
;
1896 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr
;
1897 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr
;
1901 // Collect AHCI controller information
1903 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1905 // Get the number of command slots per port supported by this HBA.
1907 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1908 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
1910 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
1912 // Get the highest bit of implemented ports which decides how many bytes are allocated for recived FIS.
1914 MaxPortNumber
= (UINT8
)(UINTN
)(HighBitSet32(PortImplementBitMap
) + 1);
1915 if (MaxPortNumber
== 0) {
1916 return EFI_DEVICE_ERROR
;
1919 MaxReceiveFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1920 Status
= PciIo
->AllocateBuffer (
1923 EfiBootServicesData
,
1924 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
1929 if (EFI_ERROR (Status
)) {
1930 return EFI_OUT_OF_RESOURCES
;
1933 ZeroMem (Buffer
, (UINTN
)MaxReceiveFisSize
);
1935 AhciRegisters
->AhciRFis
= Buffer
;
1936 AhciRegisters
->MaxReceiveFisSize
= MaxReceiveFisSize
;
1937 Bytes
= (UINTN
)MaxReceiveFisSize
;
1939 Status
= PciIo
->Map (
1941 EfiPciIoOperationBusMasterCommonBuffer
,
1945 &AhciRegisters
->MapRFis
1948 if (EFI_ERROR (Status
) || (Bytes
!= MaxReceiveFisSize
)) {
1950 // Map error or unable to map the whole RFis buffer into a contiguous region.
1952 Status
= EFI_OUT_OF_RESOURCES
;
1956 if ((!Support64Bit
) && (AhciRFisPciAddr
> 0x100000000ULL
)) {
1958 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1960 Status
= EFI_DEVICE_ERROR
;
1963 AhciRegisters
->AhciRFisPciAddr
= (EFI_AHCI_RECEIVED_FIS
*)(UINTN
)AhciRFisPciAddr
;
1966 // Allocate memory for command list
1967 // Note that the implemenation is a single task model which only use a command list for all ports.
1970 MaxCommandListSize
= MaxCommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
);
1971 Status
= PciIo
->AllocateBuffer (
1974 EfiBootServicesData
,
1975 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
1980 if (EFI_ERROR (Status
)) {
1982 // Free mapped resource.
1984 Status
= EFI_OUT_OF_RESOURCES
;
1988 ZeroMem (Buffer
, (UINTN
)MaxCommandListSize
);
1990 AhciRegisters
->AhciCmdList
= Buffer
;
1991 AhciRegisters
->MaxCommandListSize
= MaxCommandListSize
;
1992 Bytes
= (UINTN
)MaxCommandListSize
;
1994 Status
= PciIo
->Map (
1996 EfiPciIoOperationBusMasterCommonBuffer
,
1999 &AhciCmdListPciAddr
,
2000 &AhciRegisters
->MapCmdList
2003 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandListSize
)) {
2005 // Map error or unable to map the whole cmd list buffer into a contiguous region.
2007 Status
= EFI_OUT_OF_RESOURCES
;
2011 if ((!Support64Bit
) && (AhciCmdListPciAddr
> 0x100000000ULL
)) {
2013 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
2015 Status
= EFI_DEVICE_ERROR
;
2018 AhciRegisters
->AhciCmdListPciAddr
= (EFI_AHCI_COMMAND_LIST
*)(UINTN
)AhciCmdListPciAddr
;
2021 // Allocate memory for command table
2022 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
2025 MaxCommandTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
2027 Status
= PciIo
->AllocateBuffer (
2030 EfiBootServicesData
,
2031 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
2036 if (EFI_ERROR (Status
)) {
2038 // Free mapped resource.
2040 Status
= EFI_OUT_OF_RESOURCES
;
2044 ZeroMem (Buffer
, (UINTN
)MaxCommandTableSize
);
2046 AhciRegisters
->AhciCommandTable
= Buffer
;
2047 AhciRegisters
->MaxCommandTableSize
= MaxCommandTableSize
;
2048 Bytes
= (UINTN
)MaxCommandTableSize
;
2050 Status
= PciIo
->Map (
2052 EfiPciIoOperationBusMasterCommonBuffer
,
2055 &AhciCommandTablePciAddr
,
2056 &AhciRegisters
->MapCommandTable
2059 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandTableSize
)) {
2061 // Map error or unable to map the whole cmd list buffer into a contiguous region.
2063 Status
= EFI_OUT_OF_RESOURCES
;
2067 if ((!Support64Bit
) && (AhciCommandTablePciAddr
> 0x100000000ULL
)) {
2069 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
2071 Status
= EFI_DEVICE_ERROR
;
2074 AhciRegisters
->AhciCommandTablePciAddr
= (EFI_AHCI_COMMAND_TABLE
*)(UINTN
)AhciCommandTablePciAddr
;
2078 // Map error or unable to map the whole CmdList buffer into a contiguous region.
2083 AhciRegisters
->MapCommandTable
2088 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
2089 AhciRegisters
->AhciCommandTable
2094 AhciRegisters
->MapCmdList
2099 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
2100 AhciRegisters
->AhciCmdList
2105 AhciRegisters
->MapRFis
2110 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
2111 AhciRegisters
->AhciRFis
2118 Read logs from SATA device.
2120 @param PciIo The PCI IO protocol instance.
2121 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2122 @param Port The number of port.
2123 @param PortMultiplier The multiplier of port.
2124 @param Buffer The data buffer to store SATA logs.
2125 @param LogNumber The address of the log.
2126 @param PageNumber The page number of the log.
2128 @retval EFI_INVALID_PARAMETER PciIo, AhciRegisters or Buffer is NULL.
2129 @retval others Return status of AhciPioTransfer().
2133 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2134 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2136 IN UINT8 PortMultiplier
,
2137 IN OUT UINT8
*Buffer
,
2142 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2143 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2145 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
2146 return EFI_INVALID_PARAMETER
;
2150 /// Read log from device
2152 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2153 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2154 ZeroMem (Buffer
, 512);
2156 AtaCommandBlock
.AtaCommand
= ATA_CMD_READ_LOG_EXT
;
2157 AtaCommandBlock
.AtaSectorCount
= 1;
2158 AtaCommandBlock
.AtaSectorNumber
= LogNumber
;
2159 AtaCommandBlock
.AtaCylinderLow
= PageNumber
;
2161 return AhciPioTransfer (
2179 Enable DEVSLP of the disk if supported.
2181 @param PciIo The PCI IO protocol instance.
2182 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2183 @param Port The number of port.
2184 @param PortMultiplier The multiplier of port.
2185 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
2187 @retval EFI_SUCCESS The DEVSLP is enabled per policy successfully.
2188 @retval EFI_UNSUPPORTED The DEVSLP isn't supported by the controller/device and policy requires to enable it.
2192 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2193 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2195 IN UINT8 PortMultiplier
,
2196 IN EFI_IDENTIFY_DATA
*IdentifyData
2203 DEVSLP_TIMING_VARIABLES DevSlpTiming
;
2207 if (mAtaAtapiPolicy
->DeviceSleepEnable
!= 1) {
2212 // Do not enable DevSlp if DevSlp is not supported.
2214 Capability2
= AhciReadReg (PciIo
, AHCI_CAPABILITY2_OFFSET
);
2215 DEBUG ((DEBUG_INFO
, "AHCI CAPABILITY2 = %08x\n", Capability2
));
2216 if ((Capability2
& AHCI_CAP2_SDS
) == 0) {
2217 return EFI_UNSUPPORTED
;
2221 // Do not enable DevSlp if DevSlp is not present
2222 // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported
2224 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
;
2225 PortCmd
= AhciReadReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
);
2226 PortDevSlp
= AhciReadReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
);
2227 DEBUG ((DEBUG_INFO
, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd
, PortDevSlp
));
2228 if (((PortDevSlp
& AHCI_PORT_DEVSLP_DSP
) == 0) ||
2229 ((PortCmd
& (EFI_AHCI_PORT_CMD_HPCP
| EFI_AHCI_PORT_CMD_MPSP
)) != 0)
2231 return EFI_UNSUPPORTED
;
2235 // Do not enable DevSlp if the device doesn't support DevSlp
2237 DEBUG ((DEBUG_INFO
, "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",
2238 IdentifyData
->AtaData
.reserved_77
,
2239 IdentifyData
->AtaData
.serial_ata_features_supported
, IdentifyData
->AtaData
.serial_ata_features_enabled
));
2240 if ((IdentifyData
->AtaData
.serial_ata_features_supported
& BIT8
) == 0) {
2241 DEBUG ((DEBUG_INFO
, "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",
2242 Port
, PortMultiplier
));
2243 return EFI_UNSUPPORTED
;
2247 // Enable DevSlp when it is not enabled.
2249 if ((IdentifyData
->AtaData
.serial_ata_features_enabled
& BIT8
) != 0) {
2250 Status
= AhciDeviceSetFeature (
2251 PciIo
, AhciRegisters
, Port
, 0, ATA_SUB_CMD_ENABLE_SATA_FEATURE
, 0x09, ATA_ATAPI_TIMEOUT
2253 DEBUG ((DEBUG_INFO
, "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",
2254 Port
, PortMultiplier
, Status
));
2255 if (EFI_ERROR (Status
)) {
2260 Status
= AhciReadLogExt(PciIo
, AhciRegisters
, Port
, PortMultiplier
, LogData
, 0x30, 0x08);
2263 // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.
2265 AhciWriteReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
, PortCmd
& ~EFI_AHCI_PORT_CMD_ST
);
2266 PortDevSlp
&= ~AHCI_PORT_DEVSLP_ADSE
;
2267 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2270 // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.
2272 PortDevSlp
&= ~AHCI_PORT_DEVSLP_DETO_MASK
;
2273 PortDevSlp
&= ~AHCI_PORT_DEVSLP_MDAT_MASK
;
2274 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2275 DEBUG ((DEBUG_INFO
, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port
, PortMultiplier
, Status
));
2276 if (EFI_ERROR (Status
)) {
2278 // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails
2280 ZeroMem (&DevSlpTiming
, sizeof (DevSlpTiming
));
2282 CopyMem (&DevSlpTiming
, &LogData
[48], sizeof (DevSlpTiming
));
2283 DEBUG ((DEBUG_INFO
, "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",
2284 DevSlpTiming
.Supported
, DevSlpTiming
.Deto
, DevSlpTiming
.Madt
));
2288 // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.
2290 if ((DevSlpTiming
.Supported
== 0) || (DevSlpTiming
.Deto
== 0)) {
2291 DevSlpTiming
.Deto
= 20;
2295 // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.
2297 if ((DevSlpTiming
.Supported
== 0) || (DevSlpTiming
.Madt
== 0)) {
2298 DevSlpTiming
.Madt
= 10;
2301 PortDevSlp
|= DevSlpTiming
.Deto
<< 2;
2302 PortDevSlp
|= DevSlpTiming
.Madt
<< 10;
2303 AhciOrReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2305 if (mAtaAtapiPolicy
->AggressiveDeviceSleepEnable
== 1) {
2306 if ((Capability2
& AHCI_CAP2_SADM
) != 0) {
2307 PortDevSlp
&= ~AHCI_PORT_DEVSLP_DITO_MASK
;
2308 PortDevSlp
|= (625 << 15);
2309 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2311 PortDevSlp
|= AHCI_PORT_DEVSLP_ADSE
;
2312 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2317 AhciWriteReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
, PortCmd
);
2319 DEBUG ((DEBUG_INFO
, "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",
2320 Port
, PortMultiplier
, PortCmd
, PortDevSlp
));
2326 Spin-up disk if IDD was incomplete or PUIS feature is enabled
2328 @param PciIo The PCI IO protocol instance.
2329 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2330 @param Port The number of port.
2331 @param PortMultiplier The multiplier of port.
2332 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
2337 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2338 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2340 IN UINT8 PortMultiplier
,
2341 IN OUT EFI_IDENTIFY_DATA
*IdentifyData
2345 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2346 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2349 if (IdentifyData
->AtaData
.specific_config
== ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE
) {
2351 // Use SET_FEATURE subcommand to spin up the device.
2353 Status
= AhciDeviceSetFeature (
2354 PciIo
, AhciRegisters
, Port
, PortMultiplier
,
2355 ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP
, 0x00, ATA_SPINUP_TIMEOUT
2357 DEBUG ((DEBUG_INFO
, "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",
2358 Port
, PortMultiplier
, Status
));
2359 if (EFI_ERROR (Status
)) {
2363 ASSERT (IdentifyData
->AtaData
.specific_config
== ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE
);
2366 // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported
2368 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2369 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2371 // Perform READ SECTORS PIO Data-In command to Read LBA 0
2373 AtaCommandBlock
.AtaCommand
= ATA_CMD_READ_SECTORS
;
2374 AtaCommandBlock
.AtaSectorCount
= 0x1;
2376 Status
= AhciPioTransfer (
2391 DEBUG ((DEBUG_INFO
, "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",
2392 Port
, PortMultiplier
, Status
));
2393 if (EFI_ERROR (Status
)) {
2399 // Read the complete IDENTIFY DEVICE data.
2401 ZeroMem (IdentifyData
, sizeof (*IdentifyData
));
2402 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, PortMultiplier
, IdentifyData
);
2403 if (EFI_ERROR (Status
)) {
2404 DEBUG ((DEBUG_ERROR
, "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",
2405 Port
, PortMultiplier
, Status
));
2409 DEBUG ((DEBUG_INFO
, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
2410 IdentifyData
->AtaData
.config
, IdentifyData
->AtaData
.specific_config
,
2411 IdentifyData
->AtaData
.command_set_supported_83
, IdentifyData
->AtaData
.command_set_feature_enb_86
));
2413 // Check if IDD is incomplete
2415 if ((IdentifyData
->AtaData
.config
& BIT2
) != 0) {
2416 return EFI_DEVICE_ERROR
;
2423 Enable/disable/skip PUIS of the disk according to policy.
2425 @param PciIo The PCI IO protocol instance.
2426 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2427 @param Port The number of port.
2428 @param PortMultiplier The multiplier of port.
2433 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2434 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2436 IN UINT8 PortMultiplier
2441 Status
= EFI_SUCCESS
;
2442 if (mAtaAtapiPolicy
->PuisEnable
== 0) {
2443 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, PortMultiplier
, ATA_SUB_CMD_DISABLE_PUIS
, 0x00, ATA_ATAPI_TIMEOUT
);
2444 } else if (mAtaAtapiPolicy
->PuisEnable
== 1) {
2445 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, PortMultiplier
, ATA_SUB_CMD_ENABLE_PUIS
, 0x00, ATA_ATAPI_TIMEOUT
);
2447 DEBUG ((DEBUG_INFO
, "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",
2448 (mAtaAtapiPolicy
->PuisEnable
== 0) ? "Disable" : (
2449 (mAtaAtapiPolicy
->PuisEnable
== 1) ? "Enable" : "Skip"
2450 ), Port
, PortMultiplier
, Status
));
2455 Initialize ATA host controller at AHCI mode.
2457 The function is designed to initialize ATA host controller.
2459 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
2464 AhciModeInitialization (
2465 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
2469 EFI_PCI_IO_PROTOCOL
*PciIo
;
2470 EFI_IDE_CONTROLLER_INIT_PROTOCOL
*IdeInit
;
2472 UINT8 MaxPortNumber
;
2473 UINT32 PortImplementBitMap
;
2475 EFI_AHCI_REGISTERS
*AhciRegisters
;
2481 EFI_IDENTIFY_DATA Buffer
;
2482 EFI_ATA_DEVICE_TYPE DeviceType
;
2483 EFI_ATA_COLLECTIVE_MODE
*SupportedModes
;
2484 EFI_ATA_TRANSFER_MODE TransferMode
;
2485 UINT32 PhyDetectDelay
;
2488 if (Instance
== NULL
) {
2489 return EFI_INVALID_PARAMETER
;
2492 PciIo
= Instance
->PciIo
;
2493 IdeInit
= Instance
->IdeControllerInit
;
2495 Status
= AhciReset (PciIo
, EFI_AHCI_BUS_RESET_TIMEOUT
);
2497 if (EFI_ERROR (Status
)) {
2498 return EFI_DEVICE_ERROR
;
2502 // Collect AHCI controller information
2504 Capability
= AhciReadReg (PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
2507 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
2509 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
2511 if ((Value
& EFI_AHCI_GHC_ENABLE
) == 0) {
2512 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
2516 // Enable 64-bit DMA support in the PCI layer if this controller
2519 if ((Capability
& EFI_AHCI_CAP_S64A
) != 0) {
2520 Status
= PciIo
->Attributes (
2522 EfiPciIoAttributeOperationEnable
,
2523 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
2526 if (EFI_ERROR (Status
)) {
2528 "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",
2534 // Get the number of command slots per port supported by this HBA.
2536 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
2539 // Get the bit map of those ports exposed by this HBA.
2540 // It indicates which ports that the HBA supports are available for software to use.
2542 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
2544 AhciRegisters
= &Instance
->AhciRegisters
;
2545 Status
= AhciCreateTransferDescriptor (PciIo
, AhciRegisters
);
2547 if (EFI_ERROR (Status
)) {
2548 return EFI_OUT_OF_RESOURCES
;
2551 for (Port
= 0; Port
< EFI_AHCI_MAX_PORTS
; Port
++) {
2552 if ((PortImplementBitMap
& (((UINT32
)BIT0
) << Port
)) != 0) {
2554 // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.
2556 if ((MaxPortNumber
--) == 0) {
2558 // Should never be here.
2564 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBeforeChannelEnumeration
, Port
);
2567 // Initialize FIS Base Address Register and Command List Base Address Register for use.
2569 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFisPciAddr
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
2570 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FB
;
2571 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2572 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FBU
;
2573 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2575 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdListPciAddr
);
2576 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLB
;
2577 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2578 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLBU
;
2579 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2581 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2582 Data
= AhciReadReg (PciIo
, Offset
);
2583 if ((Data
& EFI_AHCI_PORT_CMD_CPD
) != 0) {
2584 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_POD
);
2587 if ((Capability
& EFI_AHCI_CAP_SSS
) != 0) {
2588 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_SUD
);
2592 // Disable aggressive power management.
2594 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
2595 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_INIT
);
2597 // Disable the reporting of the corresponding interrupt to system software.
2599 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IE
;
2600 AhciAndReg (PciIo
, Offset
, 0);
2603 // Now inform the IDE Controller Init Module.
2605 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBusBeforeDevicePresenceDetection
, Port
);
2608 // Enable FIS Receive DMA engine for the first D2H FIS.
2610 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2611 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
2614 // Wait for the Phy to detect the presence of a device.
2616 PhyDetectDelay
= EFI_AHCI_BUS_PHY_DETECT_TIMEOUT
;
2617 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
2619 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
2620 if ((Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) || (Data
== EFI_AHCI_PORT_SSTS_DET
)) {
2624 MicroSecondDelay (1000);
2626 } while (PhyDetectDelay
> 0);
2628 if (PhyDetectDelay
== 0) {
2630 // No device detected at this port.
2631 // Clear PxCMD.SUD for those ports at which there are no device present.
2633 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2634 AhciAndReg (PciIo
, Offset
, (UINT32
) ~(EFI_AHCI_PORT_CMD_SUD
));
2639 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
2640 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
2642 PhyDetectDelay
= 16 * 1000;
2644 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
2645 if (AhciReadReg(PciIo
, Offset
) != 0) {
2646 AhciWriteReg (PciIo
, Offset
, AhciReadReg(PciIo
, Offset
));
2648 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
2650 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_TFD_MASK
;
2655 MicroSecondDelay (1000);
2657 } while (PhyDetectDelay
> 0);
2659 if (PhyDetectDelay
== 0) {
2660 DEBUG ((EFI_D_ERROR
, "Port %d Device presence detected but phy not ready (TFD=0x%X)\n", Port
, Data
));
2665 // When the first D2H register FIS is received, the content of PxSIG register is updated.
2667 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SIG
;
2668 Status
= AhciWaitMmioSet (
2673 EFI_TIMER_PERIOD_SECONDS(16)
2675 if (EFI_ERROR (Status
)) {
2679 Data
= AhciReadReg (PciIo
, Offset
);
2680 if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATAPI_DEVICE_SIG
) {
2681 Status
= AhciIdentifyPacket (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2683 if (EFI_ERROR (Status
)) {
2687 DeviceType
= EfiIdeCdrom
;
2688 } else if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATA_DEVICE_SIG
) {
2689 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2691 if (EFI_ERROR (Status
)) {
2692 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_PERIPHERAL_FIXED_MEDIA
| EFI_P_EC_NOT_DETECTED
));
2697 DEBUG_INFO
, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
2698 Buffer
.AtaData
.config
, Buffer
.AtaData
.specific_config
,
2699 Buffer
.AtaData
.command_set_supported_83
, Buffer
.AtaData
.command_set_feature_enb_86
2701 if ((Buffer
.AtaData
.config
& BIT2
) != 0) {
2703 // SpinUp disk if device reported incomplete IDENTIFY DEVICE.
2705 Status
= AhciSpinUpDisk (
2712 if (EFI_ERROR (Status
)) {
2713 DEBUG ((DEBUG_ERROR
, "Spin up standby device failed - %r\n", Status
));
2718 DeviceType
= EfiIdeHarddisk
;
2722 DEBUG ((EFI_D_INFO
, "port [%d] port mulitplier [%d] has a [%a]\n",
2723 Port
, 0, DeviceType
== EfiIdeCdrom
? "cdrom" : "harddisk"));
2726 // If the device is a hard disk, then try to enable S.M.A.R.T feature
2728 if ((DeviceType
== EfiIdeHarddisk
) && PcdGetBool (PcdAtaSmartEnable
)) {
2729 AhciAtaSmartSupport (
2740 // Submit identify data to IDE controller init driver
2742 IdeInit
->SubmitData (IdeInit
, Port
, 0, &Buffer
);
2745 // Now start to config ide device parameter and transfer mode.
2747 Status
= IdeInit
->CalculateMode (
2753 if (EFI_ERROR (Status
)) {
2754 DEBUG ((EFI_D_ERROR
, "Calculate Mode Fail, Status = %r\n", Status
));
2759 // Set best supported PIO mode on this IDE device
2761 if (SupportedModes
->PioMode
.Mode
<= EfiAtaPioMode2
) {
2762 TransferMode
.ModeCategory
= EFI_ATA_MODE_DEFAULT_PIO
;
2764 TransferMode
.ModeCategory
= EFI_ATA_MODE_FLOW_PIO
;
2767 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->PioMode
.Mode
);
2770 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
2771 // be set together. Only one DMA mode can be set to a device. If setting
2772 // DMA mode operation fails, we can continue moving on because we only use
2773 // PIO mode at boot time. DMA modes are used by certain kind of OS booting
2775 if (SupportedModes
->UdmaMode
.Valid
) {
2776 TransferMode
.ModeCategory
= EFI_ATA_MODE_UDMA
;
2777 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->UdmaMode
.Mode
);
2778 } else if (SupportedModes
->MultiWordDmaMode
.Valid
) {
2779 TransferMode
.ModeCategory
= EFI_ATA_MODE_MDMA
;
2780 TransferMode
.ModeNumber
= (UINT8
) SupportedModes
->MultiWordDmaMode
.Mode
;
2783 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, 0, 0x03, (UINT32
)(*(UINT8
*)&TransferMode
), ATA_ATAPI_TIMEOUT
);
2784 if (EFI_ERROR (Status
)) {
2785 DEBUG ((EFI_D_ERROR
, "Set transfer Mode Fail, Status = %r\n", Status
));
2790 // Found a ATA or ATAPI device, add it into the device list.
2792 CreateNewDeviceInfo (Instance
, Port
, 0xFFFF, DeviceType
, &Buffer
);
2793 if (DeviceType
== EfiIdeHarddisk
) {
2794 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_PERIPHERAL_FIXED_MEDIA
| EFI_P_PC_ENABLE
));
2805 // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).
2807 if ((Buffer
.AtaData
.command_set_supported_83
& BIT5
) != 0) {
2808 Status
= AhciPuisEnable (
2814 if (EFI_ERROR (Status
)) {
2815 DEBUG ((DEBUG_ERROR
, "PUIS enable/disable failed, Status = %r\n", Status
));