2 The file for AHCI mode of ATA host controller.
4 Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "AtaAtapiPassThru.h"
13 Read AHCI Operation register.
15 @param PciIo The PCI IO protocol instance.
16 @param Offset The operation register offset.
18 @return The register content read.
24 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
30 ASSERT (PciIo
!= NULL
);
47 Write AHCI Operation register.
49 @param PciIo The PCI IO protocol instance.
50 @param Offset The operation register offset.
51 @param Data The data used to write down.
57 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
62 ASSERT (PciIo
!= NULL
);
77 Do AND operation with the value of AHCI Operation register.
79 @param PciIo The PCI IO protocol instance.
80 @param Offset The operation register offset.
81 @param AndData The data used to do AND operation.
87 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
94 ASSERT (PciIo
!= NULL
);
96 Data
= AhciReadReg (PciIo
, Offset
);
100 AhciWriteReg (PciIo
, Offset
, Data
);
104 Do OR operation with the value of AHCI Operation register.
106 @param PciIo The PCI IO protocol instance.
107 @param Offset The operation register offset.
108 @param OrData The data used to do OR operation.
114 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
121 ASSERT (PciIo
!= NULL
);
123 Data
= AhciReadReg (PciIo
, Offset
);
127 AhciWriteReg (PciIo
, Offset
, Data
);
131 Wait for the value of the specified MMIO register set to the test value.
133 @param PciIo The PCI IO protocol instance.
134 @param Offset The MMIO address to test.
135 @param MaskValue The mask value of memory.
136 @param TestValue The test value of memory.
137 @param Timeout The time out value for wait memory set, uses 100ns as a unit.
139 @retval EFI_TIMEOUT The MMIO setting is time out.
140 @retval EFI_SUCCESS The MMIO is correct set.
146 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
155 BOOLEAN InfiniteWait
;
160 InfiniteWait
= FALSE
;
163 Delay
= DivU64x32 (Timeout
, 1000) + 1;
167 // Access PCI MMIO space to see if the value is the tested one.
169 Value
= AhciReadReg (PciIo
, (UINT32
) Offset
) & MaskValue
;
171 if (Value
== TestValue
) {
176 // Stall for 100 microseconds.
178 MicroSecondDelay (100);
182 } while (InfiniteWait
|| (Delay
> 0));
188 Wait for the value of the specified system memory set to the test value.
190 @param Address The system memory address to test.
191 @param MaskValue The mask value of memory.
192 @param TestValue The test value of memory.
193 @param Timeout The time out value for wait memory set, uses 100ns as a unit.
195 @retval EFI_TIMEOUT The system memory setting is time out.
196 @retval EFI_SUCCESS The system memory is correct set.
202 IN EFI_PHYSICAL_ADDRESS Address
,
210 BOOLEAN InfiniteWait
;
215 InfiniteWait
= FALSE
;
218 Delay
= DivU64x32 (Timeout
, 1000) + 1;
222 // Access system memory to see if the value is the tested one.
224 // The system memory pointed by Address will be updated by the
225 // SATA Host Controller, "volatile" is introduced to prevent
226 // compiler from optimizing the access to the memory address
227 // to only read once.
229 Value
= *(volatile UINT32
*) (UINTN
) Address
;
232 if (Value
== TestValue
) {
237 // Stall for 100 microseconds.
239 MicroSecondDelay (100);
243 } while (InfiniteWait
|| (Delay
> 0));
249 Check the memory status to the test value.
251 @param[in] Address The memory address to test.
252 @param[in] MaskValue The mask value of memory.
253 @param[in] TestValue The test value of memory.
255 @retval EFI_NOT_READY The memory is not set.
256 @retval EFI_SUCCESS The memory is correct set.
268 Value
= *(volatile UINT32
*) Address
;
271 if (Value
== TestValue
) {
275 return EFI_NOT_READY
;
281 Clear the port interrupt and error status. It will also clear
282 HBA interrupt status.
284 @param PciIo The PCI IO protocol instance.
285 @param Port The number of port.
290 AhciClearPortStatus (
291 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
298 // Clear any error status
300 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
301 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
304 // Clear any port interrupt status
306 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
307 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
310 // Clear any HBA interrupt status
312 AhciWriteReg (PciIo
, EFI_AHCI_IS_OFFSET
, AhciReadReg (PciIo
, EFI_AHCI_IS_OFFSET
));
316 This function is used to dump the Status Registers and if there is ERR bit set
317 in the Status Register, the Error Register's value is also be dumped.
319 @param PciIo The PCI IO protocol instance.
320 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
321 @param Port The number of port.
322 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
328 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
329 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
331 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
339 ASSERT (PciIo
!= NULL
);
341 if (AtaStatusBlock
!= NULL
) {
342 ZeroMem (AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
344 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
345 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
347 Status
= AhciCheckMemSet (Offset
, EFI_AHCI_FIS_TYPE_MASK
, EFI_AHCI_FIS_REGISTER_D2H
);
348 if (!EFI_ERROR (Status
)) {
350 // If D2H FIS is received, update StatusBlock with its content.
352 CopyMem (AtaStatusBlock
, (UINT8
*)Offset
, sizeof (EFI_ATA_STATUS_BLOCK
));
355 // If D2H FIS is not received, only update Status & Error field through PxTFD
356 // as there is no other way to get the content of the Shadow Register Block.
358 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
359 Data
= AhciReadReg (PciIo
, (UINT32
)Offset
);
361 AtaStatusBlock
->AtaStatus
= (UINT8
)Data
;
362 if ((AtaStatusBlock
->AtaStatus
& BIT0
) != 0) {
363 AtaStatusBlock
->AtaError
= (UINT8
)(Data
>> 8);
371 Enable the FIS running for giving port.
373 @param PciIo The PCI IO protocol instance.
374 @param Port The number of port.
375 @param Timeout The timeout value of enabling FIS, uses 100ns as a unit.
377 @retval EFI_DEVICE_ERROR The FIS enable setting fails.
378 @retval EFI_TIMEOUT The FIS enable setting is time out.
379 @retval EFI_SUCCESS The FIS enable successfully.
384 AhciEnableFisReceive (
385 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
392 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
393 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
399 Disable the FIS running for giving port.
401 @param PciIo The PCI IO protocol instance.
402 @param Port The number of port.
403 @param Timeout The timeout value of disabling FIS, uses 100ns as a unit.
405 @retval EFI_DEVICE_ERROR The FIS disable setting fails.
406 @retval EFI_TIMEOUT The FIS disable setting is time out.
407 @retval EFI_UNSUPPORTED The port is in running state.
408 @retval EFI_SUCCESS The FIS disable successfully.
413 AhciDisableFisReceive (
414 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
422 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
423 Data
= AhciReadReg (PciIo
, Offset
);
426 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
428 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) != 0) {
429 return EFI_UNSUPPORTED
;
433 // Check if the Fis receive DMA engine for the port is running.
435 if ((Data
& EFI_AHCI_PORT_CMD_FR
) != EFI_AHCI_PORT_CMD_FR
) {
439 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
));
441 return AhciWaitMmioSet (
444 EFI_AHCI_PORT_CMD_FR
,
453 Build the command list, command table and prepare the fis receiver.
455 @param PciIo The PCI IO protocol instance.
456 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
457 @param Port The number of port.
458 @param PortMultiplier The timeout value of stop.
459 @param CommandFis The control fis will be used for the transfer.
460 @param CommandList The command list will be used for the transfer.
461 @param AtapiCommand The atapi command will be used for the transfer.
462 @param AtapiCommandLength The length of the atapi command.
463 @param CommandSlotNumber The command slot will be used for the transfer.
464 @param DataPhysicalAddr The pointer to the data buffer pci bus master address.
465 @param DataLength The data count to be transferred.
471 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
472 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
474 IN UINT8 PortMultiplier
,
475 IN EFI_AHCI_COMMAND_FIS
*CommandFis
,
476 IN EFI_AHCI_COMMAND_LIST
*CommandList
,
477 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
478 IN UINT8 AtapiCommandLength
,
479 IN UINT8 CommandSlotNumber
,
480 IN OUT VOID
*DataPhysicalAddr
,
495 PrdtNumber
= (UINT32
)DivU64x32 (((UINT64
)DataLength
+ EFI_AHCI_MAX_DATA_PER_PRDT
- 1), EFI_AHCI_MAX_DATA_PER_PRDT
);
498 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
499 // It also limits that the maximum amount of the PRDT entry in the command table
502 ASSERT (PrdtNumber
<= 65535);
504 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFis
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
506 BaseAddr
= Data64
.Uint64
;
508 ZeroMem ((VOID
*)((UINTN
) BaseAddr
), sizeof (EFI_AHCI_RECEIVED_FIS
));
510 ZeroMem (AhciRegisters
->AhciCommandTable
, sizeof (EFI_AHCI_COMMAND_TABLE
));
512 CommandFis
->AhciCFisPmNum
= PortMultiplier
;
514 CopyMem (&AhciRegisters
->AhciCommandTable
->CommandFis
, CommandFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
516 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
517 if (AtapiCommand
!= NULL
) {
519 &AhciRegisters
->AhciCommandTable
->AtapiCmd
,
524 CommandList
->AhciCmdA
= 1;
525 CommandList
->AhciCmdP
= 1;
527 AhciOrReg (PciIo
, Offset
, (EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
529 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
532 RemainedData
= (UINTN
) DataLength
;
533 MemAddr
= (UINTN
) DataPhysicalAddr
;
534 CommandList
->AhciCmdPrdtl
= PrdtNumber
;
536 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
537 if (RemainedData
< EFI_AHCI_MAX_DATA_PER_PRDT
) {
538 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= (UINT32
)RemainedData
- 1;
540 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= EFI_AHCI_MAX_DATA_PER_PRDT
- 1;
543 Data64
.Uint64
= (UINT64
)MemAddr
;
544 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDba
= Data64
.Uint32
.Lower32
;
545 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbau
= Data64
.Uint32
.Upper32
;
546 RemainedData
-= EFI_AHCI_MAX_DATA_PER_PRDT
;
547 MemAddr
+= EFI_AHCI_MAX_DATA_PER_PRDT
;
551 // Set the last PRDT to Interrupt On Complete
553 if (PrdtNumber
> 0) {
554 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtNumber
- 1].AhciPrdtIoc
= 1;
558 (VOID
*) ((UINTN
) AhciRegisters
->AhciCmdList
+ (UINTN
) CommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
)),
560 sizeof (EFI_AHCI_COMMAND_LIST
)
563 Data64
.Uint64
= (UINT64
)(UINTN
) AhciRegisters
->AhciCommandTablePciAddr
;
564 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtba
= Data64
.Uint32
.Lower32
;
565 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtbau
= Data64
.Uint32
.Upper32
;
566 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdPmp
= PortMultiplier
;
573 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.
574 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.
579 AhciBuildCommandFis (
580 IN OUT EFI_AHCI_COMMAND_FIS
*CmdFis
,
581 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
584 ZeroMem (CmdFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
586 CmdFis
->AhciCFisType
= EFI_AHCI_FIS_REGISTER_H2D
;
588 // Indicator it's a command
590 CmdFis
->AhciCFisCmdInd
= 0x1;
591 CmdFis
->AhciCFisCmd
= AtaCommandBlock
->AtaCommand
;
593 CmdFis
->AhciCFisFeature
= AtaCommandBlock
->AtaFeatures
;
594 CmdFis
->AhciCFisFeatureExp
= AtaCommandBlock
->AtaFeaturesExp
;
596 CmdFis
->AhciCFisSecNum
= AtaCommandBlock
->AtaSectorNumber
;
597 CmdFis
->AhciCFisSecNumExp
= AtaCommandBlock
->AtaSectorNumberExp
;
599 CmdFis
->AhciCFisClyLow
= AtaCommandBlock
->AtaCylinderLow
;
600 CmdFis
->AhciCFisClyLowExp
= AtaCommandBlock
->AtaCylinderLowExp
;
602 CmdFis
->AhciCFisClyHigh
= AtaCommandBlock
->AtaCylinderHigh
;
603 CmdFis
->AhciCFisClyHighExp
= AtaCommandBlock
->AtaCylinderHighExp
;
605 CmdFis
->AhciCFisSecCount
= AtaCommandBlock
->AtaSectorCount
;
606 CmdFis
->AhciCFisSecCountExp
= AtaCommandBlock
->AtaSectorCountExp
;
608 CmdFis
->AhciCFisDevHead
= (UINT8
) (AtaCommandBlock
->AtaDeviceHead
| 0xE0);
612 Checks if specified FIS has been received.
614 @param[in] PciIo Pointer to AHCI controller PciIo.
615 @param[in] Port SATA port index on which to check.
616 @param[in] FisType FIS type for which to check.
618 @retval EFI_SUCCESS FIS received.
619 @retval EFI_NOT_READY FIS not received yet.
620 @retval EFI_DEVICE_ERROR AHCI controller reported an error on port.
623 AhciCheckFisReceived (
624 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
626 IN SATA_FIS_TYPE FisType
630 UINT32 PortInterrupt
;
633 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
634 PortInterrupt
= AhciReadReg (PciIo
, Offset
);
635 if ((PortInterrupt
& EFI_AHCI_PORT_IS_ERROR_MASK
) != 0) {
636 DEBUG ((DEBUG_ERROR
, "AHCI: Error interrupt reported PxIS: %X\n", PortInterrupt
));
637 return EFI_DEVICE_ERROR
;
640 // For PIO setup FIS - According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
641 // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device
642 // after the transaction is finished successfully.
643 // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.
644 // By this way, we can know if there is a real error happened.
646 if (((FisType
== SataFisD2H
) && ((PortInterrupt
& EFI_AHCI_PORT_IS_DHRS
) != 0)) ||
647 ((FisType
== SataFisPioSetup
) && (PortInterrupt
& (EFI_AHCI_PORT_IS_PSS
| EFI_AHCI_PORT_IS_DHRS
)) != 0) ||
648 ((FisType
== SataFisDmaSetup
) && (PortInterrupt
& (EFI_AHCI_PORT_IS_DSS
| EFI_AHCI_PORT_IS_DHRS
)) != 0)) {
649 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
650 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
651 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
652 return EFI_DEVICE_ERROR
;
658 return EFI_NOT_READY
;
662 Waits until specified FIS has been received.
664 @param[in] PciIo Pointer to AHCI controller PciIo.
665 @param[in] Port SATA port index on which to check.
666 @param[in] Timeout Time after which function should stop polling.
667 @param[in] FisType FIS type for which to check.
669 @retval EFI_SUCCESS FIS received.
670 @retval EFI_TIMEOUT FIS failed to arrive within a specified time period.
671 @retval EFI_DEVICE_ERROR AHCI controller reported an error on port.
674 AhciWaitUntilFisReceived (
675 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
678 IN SATA_FIS_TYPE FisType
682 BOOLEAN InfiniteWait
;
685 Delay
= DivU64x32 (Timeout
, 1000) + 1;
689 InfiniteWait
= FALSE
;
693 Status
= AhciCheckFisReceived (PciIo
, Port
, FisType
);
694 if (Status
!= EFI_NOT_READY
) {
698 // Stall for 100 microseconds.
700 MicroSecondDelay (100);
702 } while (InfiniteWait
|| (Delay
> 0));
708 Start a PIO data transfer on specific port.
710 @param[in] PciIo The PCI IO protocol instance.
711 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
712 @param[in] Port The number of port.
713 @param[in] PortMultiplier The timeout value of stop.
714 @param[in] AtapiCommand The atapi command will be used for the
716 @param[in] AtapiCommandLength The length of the atapi command.
717 @param[in] Read The transfer direction.
718 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
719 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
720 @param[in, out] MemoryAddr The pointer to the data buffer.
721 @param[in] DataCount The data count to be transferred.
722 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
723 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
724 used by non-blocking mode.
726 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
727 @retval EFI_TIMEOUT The operation is time out.
728 @retval EFI_UNSUPPORTED The device is not ready for transfer.
729 @retval EFI_SUCCESS The PIO data transfer executes successfully.
735 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
736 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
738 IN UINT8 PortMultiplier
,
739 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
740 IN UINT8 AtapiCommandLength
,
742 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
743 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
744 IN OUT VOID
*MemoryAddr
,
747 IN ATA_NONBLOCK_TASK
*Task
751 EFI_PHYSICAL_ADDRESS PhyAddr
;
754 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
755 EFI_AHCI_COMMAND_FIS CFis
;
756 EFI_AHCI_COMMAND_LIST CmdList
;
760 Flag
= EfiPciIoOperationBusMasterWrite
;
762 Flag
= EfiPciIoOperationBusMasterRead
;
766 // construct command list and command table with pci bus address
768 MapLength
= DataCount
;
769 Status
= PciIo
->Map (
778 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
779 return EFI_BAD_BUFFER_SIZE
;
783 // Package read needed
785 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
787 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
789 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
790 CmdList
.AhciCmdW
= Read
? 0 : 1;
802 (VOID
*)(UINTN
)PhyAddr
,
806 Status
= AhciStartCommand (
812 if (EFI_ERROR (Status
)) {
816 if (Read
&& (AtapiCommand
== 0)) {
817 Status
= AhciWaitUntilFisReceived (PciIo
, Port
, Timeout
, SataFisPioSetup
);
818 if (Status
== EFI_SUCCESS
) {
819 PrdCount
= *(volatile UINT32
*) (&(AhciRegisters
->AhciCmdList
[0].AhciCmdPrdbc
));
820 if (PrdCount
== DataCount
) {
821 Status
= EFI_SUCCESS
;
823 Status
= EFI_DEVICE_ERROR
;
827 Status
= AhciWaitUntilFisReceived (PciIo
, Port
, Timeout
, SataFisD2H
);
837 AhciDisableFisReceive (
848 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
854 Start a DMA data transfer on specific port
856 @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.
857 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
858 @param[in] Port The number of port.
859 @param[in] PortMultiplier The timeout value of stop.
860 @param[in] AtapiCommand The atapi command will be used for the
862 @param[in] AtapiCommandLength The length of the atapi command.
863 @param[in] Read The transfer direction.
864 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
865 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
866 @param[in, out] MemoryAddr The pointer to the data buffer.
867 @param[in] DataCount The data count to be transferred.
868 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
869 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
870 used by non-blocking mode.
872 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
873 @retval EFI_TIMEOUT The operation is time out.
874 @retval EFI_UNSUPPORTED The device is not ready for transfer.
875 @retval EFI_SUCCESS The DMA data transfer executes successfully.
881 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
,
882 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
884 IN UINT8 PortMultiplier
,
885 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
886 IN UINT8 AtapiCommandLength
,
888 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
889 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
890 IN OUT VOID
*MemoryAddr
,
893 IN ATA_NONBLOCK_TASK
*Task
897 EFI_PHYSICAL_ADDRESS PhyAddr
;
900 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
901 EFI_AHCI_COMMAND_FIS CFis
;
902 EFI_AHCI_COMMAND_LIST CmdList
;
904 EFI_PCI_IO_PROTOCOL
*PciIo
;
908 PciIo
= Instance
->PciIo
;
911 return EFI_INVALID_PARAMETER
;
915 // Before starting the Blocking BlockIO operation, push to finish all non-blocking
917 // Delay 100us to simulate the blocking time out checking.
919 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
920 while ((Task
== NULL
) && (!IsListEmpty (&Instance
->NonBlockingTaskList
))) {
921 AsyncNonBlockingTransferRoutine (NULL
, Instance
);
925 MicroSecondDelay (100);
927 gBS
->RestoreTPL (OldTpl
);
929 if ((Task
== NULL
) || ((Task
!= NULL
) && (!Task
->IsStart
))) {
931 // Mark the Task to indicate that it has been started.
934 Task
->IsStart
= TRUE
;
937 Flag
= EfiPciIoOperationBusMasterWrite
;
939 Flag
= EfiPciIoOperationBusMasterRead
;
943 // Construct command list and command table with pci bus address.
945 MapLength
= DataCount
;
946 Status
= PciIo
->Map (
955 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
956 return EFI_BAD_BUFFER_SIZE
;
963 // Package read needed
965 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
967 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
969 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
970 CmdList
.AhciCmdW
= Read
? 0 : 1;
982 (VOID
*)(UINTN
)PhyAddr
,
986 Status
= AhciStartCommand (
992 if (EFI_ERROR (Status
)) {
998 Status
= AhciCheckFisReceived (PciIo
, Port
, SataFisD2H
);
999 if (Status
== EFI_NOT_READY
) {
1000 if (!Task
->InfiniteWait
&& Task
->RetryTimes
== 0) {
1001 Status
= EFI_TIMEOUT
;
1007 Status
= AhciWaitUntilFisReceived (PciIo
, Port
, Timeout
, SataFisD2H
);
1012 // For Blocking mode, the command should be stopped, the Fis should be disabled
1013 // and the PciIo should be unmapped.
1014 // For non-blocking mode, only when a error is happened (if the return status is
1015 // EFI_NOT_READY that means the command doesn't finished, try again.), first do the
1016 // context cleanup, then set the packet's Asb status.
1019 ((Task
!= NULL
) && (Status
!= EFI_NOT_READY
))
1027 AhciDisableFisReceive (
1035 (Task
!= NULL
) ? Task
->Map
: Map
1039 Task
->Packet
->Asb
->AtaStatus
= 0x01;
1043 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1048 Start a non data transfer on specific port.
1050 @param[in] PciIo The PCI IO protocol instance.
1051 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1052 @param[in] Port The number of port.
1053 @param[in] PortMultiplier The timeout value of stop.
1054 @param[in] AtapiCommand The atapi command will be used for the
1056 @param[in] AtapiCommandLength The length of the atapi command.
1057 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
1058 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
1059 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
1060 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
1061 used by non-blocking mode.
1063 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
1064 @retval EFI_TIMEOUT The operation is time out.
1065 @retval EFI_UNSUPPORTED The device is not ready for transfer.
1066 @retval EFI_SUCCESS The non data transfer executes successfully.
1071 AhciNonDataTransfer (
1072 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1073 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1075 IN UINT8 PortMultiplier
,
1076 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
1077 IN UINT8 AtapiCommandLength
,
1078 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
1079 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
1081 IN ATA_NONBLOCK_TASK
*Task
1085 EFI_AHCI_COMMAND_FIS CFis
;
1086 EFI_AHCI_COMMAND_LIST CmdList
;
1089 // Package read needed
1091 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
1093 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
1095 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
1111 Status
= AhciStartCommand (
1117 if (EFI_ERROR (Status
)) {
1121 Status
= AhciWaitUntilFisReceived (PciIo
, Port
, Timeout
, SataFisD2H
);
1130 AhciDisableFisReceive (
1136 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1142 Stop command running for giving port
1144 @param PciIo The PCI IO protocol instance.
1145 @param Port The number of port.
1146 @param Timeout The timeout value of stop, uses 100ns as a unit.
1148 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
1149 @retval EFI_TIMEOUT The operation is time out.
1150 @retval EFI_SUCCESS The command stop successfully.
1156 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1164 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1165 Data
= AhciReadReg (PciIo
, Offset
);
1167 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) == 0) {
1171 if ((Data
& EFI_AHCI_PORT_CMD_ST
) != 0) {
1172 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_ST
));
1175 return AhciWaitMmioSet (
1178 EFI_AHCI_PORT_CMD_CR
,
1185 Start command for give slot on specific port.
1187 @param PciIo The PCI IO protocol instance.
1188 @param Port The number of port.
1189 @param CommandSlot The number of Command Slot.
1190 @param Timeout The timeout value of start, uses 100ns as a unit.
1192 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
1193 @retval EFI_TIMEOUT The operation is time out.
1194 @retval EFI_SUCCESS The command start successfully.
1200 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1202 IN UINT8 CommandSlot
,
1215 // Collect AHCI controller information
1217 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1219 CmdSlotBit
= (UINT32
) (1 << CommandSlot
);
1221 AhciClearPortStatus (
1226 Status
= AhciEnableFisReceive (
1232 if (EFI_ERROR (Status
)) {
1236 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1237 PortStatus
= AhciReadReg (PciIo
, Offset
);
1240 if ((PortStatus
& EFI_AHCI_PORT_CMD_ALPE
) != 0) {
1241 StartCmd
= AhciReadReg (PciIo
, Offset
);
1242 StartCmd
&= ~EFI_AHCI_PORT_CMD_ICC_MASK
;
1243 StartCmd
|= EFI_AHCI_PORT_CMD_ACTIVE
;
1246 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1247 PortTfd
= AhciReadReg (PciIo
, Offset
);
1249 if ((PortTfd
& (EFI_AHCI_PORT_TFD_BSY
| EFI_AHCI_PORT_TFD_DRQ
)) != 0) {
1250 if ((Capability
& BIT24
) != 0) {
1251 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1252 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_CLO
);
1257 EFI_AHCI_PORT_CMD_CLO
,
1264 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1265 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_ST
| StartCmd
);
1268 // Setting the command
1270 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
1271 AhciAndReg (PciIo
, Offset
, 0);
1272 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1281 @param PciIo The PCI IO protocol instance.
1282 @param Timeout The timeout value of reset, uses 100ns as a unit.
1284 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
1285 @retval EFI_TIMEOUT The reset operation is time out.
1286 @retval EFI_SUCCESS AHCI controller is reset successfully.
1292 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1300 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
1302 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1304 if ((Value
& EFI_AHCI_GHC_ENABLE
) == 0) {
1305 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
1308 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_RESET
);
1310 Delay
= DivU64x32(Timeout
, 1000) + 1;
1313 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1315 if ((Value
& EFI_AHCI_GHC_RESET
) == 0) {
1320 // Stall for 100 microseconds.
1322 MicroSecondDelay(100);
1325 } while (Delay
> 0);
1335 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
1337 @param PciIo The PCI IO protocol instance.
1338 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1339 @param Port The number of port.
1340 @param PortMultiplier The port multiplier port number.
1341 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1343 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
1344 @retval Others Fail to get return status data.
1349 AhciAtaSmartReturnStatusCheck (
1350 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1351 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1353 IN UINT8 PortMultiplier
,
1354 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1358 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1364 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1366 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1367 AtaCommandBlock
.AtaFeatures
= ATA_SMART_RETURN_STATUS
;
1368 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1369 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1372 // Send S.M.A.R.T Read Return Status command to device
1374 Status
= AhciNonDataTransfer (
1378 (UINT8
)PortMultiplier
,
1387 if (EFI_ERROR (Status
)) {
1388 REPORT_STATUS_CODE (
1389 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1390 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_DISABLED
)
1392 return EFI_DEVICE_ERROR
;
1395 REPORT_STATUS_CODE (
1397 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_ENABLE
)
1400 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1402 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
1404 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
1405 LBAMid
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[5];
1406 LBAHigh
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[6];
1408 if ((LBAMid
== 0x4f) && (LBAHigh
== 0xc2)) {
1410 // The threshold exceeded condition is not detected by the device
1412 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
1413 REPORT_STATUS_CODE (
1415 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD
)
1417 } else if ((LBAMid
== 0xf4) && (LBAHigh
== 0x2c)) {
1419 // The threshold exceeded condition is detected by the device
1421 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is detected\n"));
1422 REPORT_STATUS_CODE (
1424 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD
)
1433 Enable SMART command of the disk if supported.
1435 @param PciIo The PCI IO protocol instance.
1436 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1437 @param Port The number of port.
1438 @param PortMultiplier The port multiplier port number.
1439 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
1440 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1445 AhciAtaSmartSupport (
1446 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1447 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1449 IN UINT8 PortMultiplier
,
1450 IN EFI_IDENTIFY_DATA
*IdentifyData
,
1451 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1455 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1458 // Detect if the device supports S.M.A.R.T.
1460 if ((IdentifyData
->AtaData
.command_set_supported_82
& 0x0001) != 0x0001) {
1462 // S.M.A.R.T is not supported by the device
1464 DEBUG ((EFI_D_INFO
, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
1465 Port
, PortMultiplier
));
1466 REPORT_STATUS_CODE (
1467 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1468 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED
)
1472 // Check if the feature is enabled. If not, then enable S.M.A.R.T.
1474 if ((IdentifyData
->AtaData
.command_set_feature_enb_85
& 0x0001) != 0x0001) {
1476 REPORT_STATUS_CODE (
1478 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_DISABLE
)
1481 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1483 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1484 AtaCommandBlock
.AtaFeatures
= ATA_SMART_ENABLE_OPERATION
;
1485 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1486 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1489 // Send S.M.A.R.T Enable command to device
1491 Status
= AhciNonDataTransfer (
1495 (UINT8
)PortMultiplier
,
1505 if (!EFI_ERROR (Status
)) {
1507 // Send S.M.A.R.T AutoSave command to device
1509 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1511 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1512 AtaCommandBlock
.AtaFeatures
= 0xD2;
1513 AtaCommandBlock
.AtaSectorCount
= 0xF1;
1514 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1515 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1517 Status
= AhciNonDataTransfer (
1521 (UINT8
)PortMultiplier
,
1530 if (!EFI_ERROR (Status
)) {
1531 Status
= AhciAtaSmartReturnStatusCheck (
1535 (UINT8
)PortMultiplier
,
1541 DEBUG ((EFI_D_INFO
, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
1542 Port
, PortMultiplier
));
1549 Send Buffer cmd to specific device.
1551 @param PciIo The PCI IO protocol instance.
1552 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1553 @param Port The number of port.
1554 @param PortMultiplier The port multiplier port number.
1555 @param Buffer The data buffer to store IDENTIFY PACKET data.
1557 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1558 @retval EFI_TIMEOUT The operation is time out.
1559 @retval EFI_UNSUPPORTED The device is not ready for executing.
1560 @retval EFI_SUCCESS The cmd executes successfully.
1566 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1567 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1569 IN UINT8 PortMultiplier
,
1570 IN OUT EFI_IDENTIFY_DATA
*Buffer
1574 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1575 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1577 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
1578 return EFI_INVALID_PARAMETER
;
1581 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1582 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1584 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DRIVE
;
1585 AtaCommandBlock
.AtaSectorCount
= 1;
1587 Status
= AhciPioTransfer (
1598 sizeof (EFI_IDENTIFY_DATA
),
1607 Send Buffer cmd to specific device.
1609 @param PciIo The PCI IO protocol instance.
1610 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1611 @param Port The number of port.
1612 @param PortMultiplier The port multiplier port number.
1613 @param Buffer The data buffer to store IDENTIFY PACKET data.
1615 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1616 @retval EFI_TIMEOUT The operation is time out.
1617 @retval EFI_UNSUPPORTED The device is not ready for executing.
1618 @retval EFI_SUCCESS The cmd executes successfully.
1623 AhciIdentifyPacket (
1624 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1625 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1627 IN UINT8 PortMultiplier
,
1628 IN OUT EFI_IDENTIFY_DATA
*Buffer
1632 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1633 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1635 if (PciIo
== NULL
|| AhciRegisters
== NULL
) {
1636 return EFI_INVALID_PARAMETER
;
1639 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1640 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1642 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DEVICE
;
1643 AtaCommandBlock
.AtaSectorCount
= 1;
1645 Status
= AhciPioTransfer (
1656 sizeof (EFI_IDENTIFY_DATA
),
1665 Send SET FEATURE cmd on specific device.
1667 @param PciIo The PCI IO protocol instance.
1668 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1669 @param Port The number of port.
1670 @param PortMultiplier The port multiplier port number.
1671 @param Feature The data to send Feature register.
1672 @param FeatureSpecificData The specific data for SET FEATURE cmd.
1673 @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.
1675 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1676 @retval EFI_TIMEOUT The operation is time out.
1677 @retval EFI_UNSUPPORTED The device is not ready for executing.
1678 @retval EFI_SUCCESS The cmd executes successfully.
1683 AhciDeviceSetFeature (
1684 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1685 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1687 IN UINT8 PortMultiplier
,
1689 IN UINT32 FeatureSpecificData
,
1694 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1695 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1697 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1698 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1700 AtaCommandBlock
.AtaCommand
= ATA_CMD_SET_FEATURES
;
1701 AtaCommandBlock
.AtaFeatures
= (UINT8
) Feature
;
1702 AtaCommandBlock
.AtaFeaturesExp
= (UINT8
) (Feature
>> 8);
1703 AtaCommandBlock
.AtaSectorCount
= (UINT8
) FeatureSpecificData
;
1704 AtaCommandBlock
.AtaSectorNumber
= (UINT8
) (FeatureSpecificData
>> 8);
1705 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (FeatureSpecificData
>> 16);
1706 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (FeatureSpecificData
>> 24);
1708 Status
= AhciNonDataTransfer (
1712 (UINT8
)PortMultiplier
,
1725 This function is used to send out ATAPI commands conforms to the Packet Command
1728 @param PciIo The PCI IO protocol instance.
1729 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1730 @param Port The number of port.
1731 @param PortMultiplier The number of port multiplier.
1732 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
1734 @retval EFI_SUCCESS send out the ATAPI packet command successfully
1735 and device sends data successfully.
1736 @retval EFI_DEVICE_ERROR the device failed to send data.
1741 AhciPacketCommandExecute (
1742 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1743 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1745 IN UINT8 PortMultiplier
,
1746 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1752 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1753 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1756 if (Packet
== NULL
|| Packet
->Cdb
== NULL
) {
1757 return EFI_INVALID_PARAMETER
;
1760 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1761 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1762 AtaCommandBlock
.AtaCommand
= ATA_CMD_PACKET
;
1766 AtaCommandBlock
.AtaFeatures
= 0x00;
1768 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
1769 // determine how many data should be transferred.
1771 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
& 0x00ff);
1772 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
>> 8);
1774 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1775 Buffer
= Packet
->InDataBuffer
;
1776 Length
= Packet
->InTransferLength
;
1779 Buffer
= Packet
->OutDataBuffer
;
1780 Length
= Packet
->OutTransferLength
;
1785 Status
= AhciNonDataTransfer (
1798 Status
= AhciPioTransfer (
1818 Allocate transfer-related data struct which is used at AHCI mode.
1820 @param PciIo The PCI IO protocol instance.
1821 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1826 AhciCreateTransferDescriptor (
1827 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1828 IN OUT EFI_AHCI_REGISTERS
*AhciRegisters
1836 UINT32 PortImplementBitMap
;
1837 UINT8 MaxPortNumber
;
1838 UINT8 MaxCommandSlotNumber
;
1839 BOOLEAN Support64Bit
;
1840 UINT64 MaxReceiveFisSize
;
1841 UINT64 MaxCommandListSize
;
1842 UINT64 MaxCommandTableSize
;
1843 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr
;
1844 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr
;
1845 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr
;
1849 // Collect AHCI controller information
1851 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1853 // Get the number of command slots per port supported by this HBA.
1855 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1856 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
1858 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
1860 // Get the highest bit of implemented ports which decides how many bytes are allocated for received FIS.
1862 MaxPortNumber
= (UINT8
)(UINTN
)(HighBitSet32(PortImplementBitMap
) + 1);
1863 if (MaxPortNumber
== 0) {
1864 return EFI_DEVICE_ERROR
;
1867 MaxReceiveFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1868 Status
= PciIo
->AllocateBuffer (
1871 EfiBootServicesData
,
1872 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
1877 if (EFI_ERROR (Status
)) {
1878 return EFI_OUT_OF_RESOURCES
;
1881 ZeroMem (Buffer
, (UINTN
)MaxReceiveFisSize
);
1883 AhciRegisters
->AhciRFis
= Buffer
;
1884 AhciRegisters
->MaxReceiveFisSize
= MaxReceiveFisSize
;
1885 Bytes
= (UINTN
)MaxReceiveFisSize
;
1887 Status
= PciIo
->Map (
1889 EfiPciIoOperationBusMasterCommonBuffer
,
1893 &AhciRegisters
->MapRFis
1896 if (EFI_ERROR (Status
) || (Bytes
!= MaxReceiveFisSize
)) {
1898 // Map error or unable to map the whole RFis buffer into a contiguous region.
1900 Status
= EFI_OUT_OF_RESOURCES
;
1904 if ((!Support64Bit
) && (AhciRFisPciAddr
> 0x100000000ULL
)) {
1906 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1908 Status
= EFI_DEVICE_ERROR
;
1911 AhciRegisters
->AhciRFisPciAddr
= (EFI_AHCI_RECEIVED_FIS
*)(UINTN
)AhciRFisPciAddr
;
1914 // Allocate memory for command list
1915 // Note that the implementation is a single task model which only use a command list for all ports.
1918 MaxCommandListSize
= MaxCommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
);
1919 Status
= PciIo
->AllocateBuffer (
1922 EfiBootServicesData
,
1923 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
1928 if (EFI_ERROR (Status
)) {
1930 // Free mapped resource.
1932 Status
= EFI_OUT_OF_RESOURCES
;
1936 ZeroMem (Buffer
, (UINTN
)MaxCommandListSize
);
1938 AhciRegisters
->AhciCmdList
= Buffer
;
1939 AhciRegisters
->MaxCommandListSize
= MaxCommandListSize
;
1940 Bytes
= (UINTN
)MaxCommandListSize
;
1942 Status
= PciIo
->Map (
1944 EfiPciIoOperationBusMasterCommonBuffer
,
1947 &AhciCmdListPciAddr
,
1948 &AhciRegisters
->MapCmdList
1951 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandListSize
)) {
1953 // Map error or unable to map the whole cmd list buffer into a contiguous region.
1955 Status
= EFI_OUT_OF_RESOURCES
;
1959 if ((!Support64Bit
) && (AhciCmdListPciAddr
> 0x100000000ULL
)) {
1961 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1963 Status
= EFI_DEVICE_ERROR
;
1966 AhciRegisters
->AhciCmdListPciAddr
= (EFI_AHCI_COMMAND_LIST
*)(UINTN
)AhciCmdListPciAddr
;
1969 // Allocate memory for command table
1970 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
1973 MaxCommandTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
1975 Status
= PciIo
->AllocateBuffer (
1978 EfiBootServicesData
,
1979 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
1984 if (EFI_ERROR (Status
)) {
1986 // Free mapped resource.
1988 Status
= EFI_OUT_OF_RESOURCES
;
1992 ZeroMem (Buffer
, (UINTN
)MaxCommandTableSize
);
1994 AhciRegisters
->AhciCommandTable
= Buffer
;
1995 AhciRegisters
->MaxCommandTableSize
= MaxCommandTableSize
;
1996 Bytes
= (UINTN
)MaxCommandTableSize
;
1998 Status
= PciIo
->Map (
2000 EfiPciIoOperationBusMasterCommonBuffer
,
2003 &AhciCommandTablePciAddr
,
2004 &AhciRegisters
->MapCommandTable
2007 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandTableSize
)) {
2009 // Map error or unable to map the whole cmd list buffer into a contiguous region.
2011 Status
= EFI_OUT_OF_RESOURCES
;
2015 if ((!Support64Bit
) && (AhciCommandTablePciAddr
> 0x100000000ULL
)) {
2017 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
2019 Status
= EFI_DEVICE_ERROR
;
2022 AhciRegisters
->AhciCommandTablePciAddr
= (EFI_AHCI_COMMAND_TABLE
*)(UINTN
)AhciCommandTablePciAddr
;
2026 // Map error or unable to map the whole CmdList buffer into a contiguous region.
2031 AhciRegisters
->MapCommandTable
2036 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
2037 AhciRegisters
->AhciCommandTable
2042 AhciRegisters
->MapCmdList
2047 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
2048 AhciRegisters
->AhciCmdList
2053 AhciRegisters
->MapRFis
2058 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
2059 AhciRegisters
->AhciRFis
2066 Read logs from SATA device.
2068 @param PciIo The PCI IO protocol instance.
2069 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2070 @param Port The number of port.
2071 @param PortMultiplier The multiplier of port.
2072 @param Buffer The data buffer to store SATA logs.
2073 @param LogNumber The address of the log.
2074 @param PageNumber The page number of the log.
2076 @retval EFI_INVALID_PARAMETER PciIo, AhciRegisters or Buffer is NULL.
2077 @retval others Return status of AhciPioTransfer().
2081 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2082 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2084 IN UINT8 PortMultiplier
,
2085 IN OUT UINT8
*Buffer
,
2090 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2091 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2093 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
2094 return EFI_INVALID_PARAMETER
;
2098 /// Read log from device
2100 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2101 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2102 ZeroMem (Buffer
, 512);
2104 AtaCommandBlock
.AtaCommand
= ATA_CMD_READ_LOG_EXT
;
2105 AtaCommandBlock
.AtaSectorCount
= 1;
2106 AtaCommandBlock
.AtaSectorNumber
= LogNumber
;
2107 AtaCommandBlock
.AtaCylinderLow
= PageNumber
;
2109 return AhciPioTransfer (
2127 Enable DEVSLP of the disk if supported.
2129 @param PciIo The PCI IO protocol instance.
2130 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2131 @param Port The number of port.
2132 @param PortMultiplier The multiplier of port.
2133 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
2135 @retval EFI_SUCCESS The DEVSLP is enabled per policy successfully.
2136 @retval EFI_UNSUPPORTED The DEVSLP isn't supported by the controller/device and policy requires to enable it.
2140 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2141 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2143 IN UINT8 PortMultiplier
,
2144 IN EFI_IDENTIFY_DATA
*IdentifyData
2151 DEVSLP_TIMING_VARIABLES DevSlpTiming
;
2155 if (mAtaAtapiPolicy
->DeviceSleepEnable
!= 1) {
2160 // Do not enable DevSlp if DevSlp is not supported.
2162 Capability2
= AhciReadReg (PciIo
, AHCI_CAPABILITY2_OFFSET
);
2163 DEBUG ((DEBUG_INFO
, "AHCI CAPABILITY2 = %08x\n", Capability2
));
2164 if ((Capability2
& AHCI_CAP2_SDS
) == 0) {
2165 return EFI_UNSUPPORTED
;
2169 // Do not enable DevSlp if DevSlp is not present
2170 // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported
2172 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
;
2173 PortCmd
= AhciReadReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
);
2174 PortDevSlp
= AhciReadReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
);
2175 DEBUG ((DEBUG_INFO
, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd
, PortDevSlp
));
2176 if (((PortDevSlp
& AHCI_PORT_DEVSLP_DSP
) == 0) ||
2177 ((PortCmd
& (EFI_AHCI_PORT_CMD_HPCP
| EFI_AHCI_PORT_CMD_MPSP
)) != 0)
2179 return EFI_UNSUPPORTED
;
2183 // Do not enable DevSlp if the device doesn't support DevSlp
2185 DEBUG ((DEBUG_INFO
, "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",
2186 IdentifyData
->AtaData
.reserved_77
,
2187 IdentifyData
->AtaData
.serial_ata_features_supported
, IdentifyData
->AtaData
.serial_ata_features_enabled
));
2188 if ((IdentifyData
->AtaData
.serial_ata_features_supported
& BIT8
) == 0) {
2189 DEBUG ((DEBUG_INFO
, "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",
2190 Port
, PortMultiplier
));
2191 return EFI_UNSUPPORTED
;
2195 // Enable DevSlp when it is not enabled.
2197 if ((IdentifyData
->AtaData
.serial_ata_features_enabled
& BIT8
) != 0) {
2198 Status
= AhciDeviceSetFeature (
2199 PciIo
, AhciRegisters
, Port
, 0, ATA_SUB_CMD_ENABLE_SATA_FEATURE
, 0x09, ATA_ATAPI_TIMEOUT
2201 DEBUG ((DEBUG_INFO
, "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",
2202 Port
, PortMultiplier
, Status
));
2203 if (EFI_ERROR (Status
)) {
2208 Status
= AhciReadLogExt(PciIo
, AhciRegisters
, Port
, PortMultiplier
, LogData
, 0x30, 0x08);
2211 // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.
2213 AhciWriteReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
, PortCmd
& ~EFI_AHCI_PORT_CMD_ST
);
2214 PortDevSlp
&= ~AHCI_PORT_DEVSLP_ADSE
;
2215 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2218 // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.
2220 PortDevSlp
&= ~AHCI_PORT_DEVSLP_DETO_MASK
;
2221 PortDevSlp
&= ~AHCI_PORT_DEVSLP_MDAT_MASK
;
2222 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2223 DEBUG ((DEBUG_INFO
, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port
, PortMultiplier
, Status
));
2224 if (EFI_ERROR (Status
)) {
2226 // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails
2228 ZeroMem (&DevSlpTiming
, sizeof (DevSlpTiming
));
2230 CopyMem (&DevSlpTiming
, &LogData
[48], sizeof (DevSlpTiming
));
2231 DEBUG ((DEBUG_INFO
, "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",
2232 DevSlpTiming
.Supported
, DevSlpTiming
.Deto
, DevSlpTiming
.Madt
));
2236 // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.
2238 if ((DevSlpTiming
.Supported
== 0) || (DevSlpTiming
.Deto
== 0)) {
2239 DevSlpTiming
.Deto
= 20;
2243 // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.
2245 if ((DevSlpTiming
.Supported
== 0) || (DevSlpTiming
.Madt
== 0)) {
2246 DevSlpTiming
.Madt
= 10;
2249 PortDevSlp
|= DevSlpTiming
.Deto
<< 2;
2250 PortDevSlp
|= DevSlpTiming
.Madt
<< 10;
2251 AhciOrReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2253 if (mAtaAtapiPolicy
->AggressiveDeviceSleepEnable
== 1) {
2254 if ((Capability2
& AHCI_CAP2_SADM
) != 0) {
2255 PortDevSlp
&= ~AHCI_PORT_DEVSLP_DITO_MASK
;
2256 PortDevSlp
|= (625 << 15);
2257 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2259 PortDevSlp
|= AHCI_PORT_DEVSLP_ADSE
;
2260 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2265 AhciWriteReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
, PortCmd
);
2267 DEBUG ((DEBUG_INFO
, "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",
2268 Port
, PortMultiplier
, PortCmd
, PortDevSlp
));
2274 Spin-up disk if IDD was incomplete or PUIS feature is enabled
2276 @param PciIo The PCI IO protocol instance.
2277 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2278 @param Port The number of port.
2279 @param PortMultiplier The multiplier of port.
2280 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
2285 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2286 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2288 IN UINT8 PortMultiplier
,
2289 IN OUT EFI_IDENTIFY_DATA
*IdentifyData
2293 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2294 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2297 if (IdentifyData
->AtaData
.specific_config
== ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE
) {
2299 // Use SET_FEATURE subcommand to spin up the device.
2301 Status
= AhciDeviceSetFeature (
2302 PciIo
, AhciRegisters
, Port
, PortMultiplier
,
2303 ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP
, 0x00, ATA_SPINUP_TIMEOUT
2305 DEBUG ((DEBUG_INFO
, "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",
2306 Port
, PortMultiplier
, Status
));
2307 if (EFI_ERROR (Status
)) {
2311 ASSERT (IdentifyData
->AtaData
.specific_config
== ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE
);
2314 // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported
2316 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2317 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2319 // Perform READ SECTORS PIO Data-In command to Read LBA 0
2321 AtaCommandBlock
.AtaCommand
= ATA_CMD_READ_SECTORS
;
2322 AtaCommandBlock
.AtaSectorCount
= 0x1;
2324 Status
= AhciPioTransfer (
2339 DEBUG ((DEBUG_INFO
, "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",
2340 Port
, PortMultiplier
, Status
));
2341 if (EFI_ERROR (Status
)) {
2347 // Read the complete IDENTIFY DEVICE data.
2349 ZeroMem (IdentifyData
, sizeof (*IdentifyData
));
2350 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, PortMultiplier
, IdentifyData
);
2351 if (EFI_ERROR (Status
)) {
2352 DEBUG ((DEBUG_ERROR
, "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",
2353 Port
, PortMultiplier
, Status
));
2357 DEBUG ((DEBUG_INFO
, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
2358 IdentifyData
->AtaData
.config
, IdentifyData
->AtaData
.specific_config
,
2359 IdentifyData
->AtaData
.command_set_supported_83
, IdentifyData
->AtaData
.command_set_feature_enb_86
));
2361 // Check if IDD is incomplete
2363 if ((IdentifyData
->AtaData
.config
& BIT2
) != 0) {
2364 return EFI_DEVICE_ERROR
;
2371 Enable/disable/skip PUIS of the disk according to policy.
2373 @param PciIo The PCI IO protocol instance.
2374 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2375 @param Port The number of port.
2376 @param PortMultiplier The multiplier of port.
2381 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2382 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2384 IN UINT8 PortMultiplier
2389 Status
= EFI_SUCCESS
;
2390 if (mAtaAtapiPolicy
->PuisEnable
== 0) {
2391 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, PortMultiplier
, ATA_SUB_CMD_DISABLE_PUIS
, 0x00, ATA_ATAPI_TIMEOUT
);
2392 } else if (mAtaAtapiPolicy
->PuisEnable
== 1) {
2393 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, PortMultiplier
, ATA_SUB_CMD_ENABLE_PUIS
, 0x00, ATA_ATAPI_TIMEOUT
);
2395 DEBUG ((DEBUG_INFO
, "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",
2396 (mAtaAtapiPolicy
->PuisEnable
== 0) ? "Disable" : (
2397 (mAtaAtapiPolicy
->PuisEnable
== 1) ? "Enable" : "Skip"
2398 ), Port
, PortMultiplier
, Status
));
2403 Initialize ATA host controller at AHCI mode.
2405 The function is designed to initialize ATA host controller.
2407 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
2412 AhciModeInitialization (
2413 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
2417 EFI_PCI_IO_PROTOCOL
*PciIo
;
2418 EFI_IDE_CONTROLLER_INIT_PROTOCOL
*IdeInit
;
2420 UINT8 MaxPortNumber
;
2421 UINT32 PortImplementBitMap
;
2423 EFI_AHCI_REGISTERS
*AhciRegisters
;
2429 EFI_IDENTIFY_DATA Buffer
;
2430 EFI_ATA_DEVICE_TYPE DeviceType
;
2431 EFI_ATA_COLLECTIVE_MODE
*SupportedModes
;
2432 EFI_ATA_TRANSFER_MODE TransferMode
;
2433 UINT32 PhyDetectDelay
;
2436 if (Instance
== NULL
) {
2437 return EFI_INVALID_PARAMETER
;
2440 PciIo
= Instance
->PciIo
;
2441 IdeInit
= Instance
->IdeControllerInit
;
2443 Status
= AhciReset (PciIo
, EFI_AHCI_BUS_RESET_TIMEOUT
);
2445 if (EFI_ERROR (Status
)) {
2446 return EFI_DEVICE_ERROR
;
2450 // Collect AHCI controller information
2452 Capability
= AhciReadReg (PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
2455 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
2457 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
2459 if ((Value
& EFI_AHCI_GHC_ENABLE
) == 0) {
2460 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
2464 // Enable 64-bit DMA support in the PCI layer if this controller
2467 if ((Capability
& EFI_AHCI_CAP_S64A
) != 0) {
2468 Status
= PciIo
->Attributes (
2470 EfiPciIoAttributeOperationEnable
,
2471 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
2474 if (EFI_ERROR (Status
)) {
2476 "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",
2482 // Get the number of command slots per port supported by this HBA.
2484 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
2487 // Get the bit map of those ports exposed by this HBA.
2488 // It indicates which ports that the HBA supports are available for software to use.
2490 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
2492 AhciRegisters
= &Instance
->AhciRegisters
;
2493 Status
= AhciCreateTransferDescriptor (PciIo
, AhciRegisters
);
2495 if (EFI_ERROR (Status
)) {
2496 return EFI_OUT_OF_RESOURCES
;
2499 for (Port
= 0; Port
< EFI_AHCI_MAX_PORTS
; Port
++) {
2500 if ((PortImplementBitMap
& (((UINT32
)BIT0
) << Port
)) != 0) {
2502 // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.
2504 if ((MaxPortNumber
--) == 0) {
2506 // Should never be here.
2512 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBeforeChannelEnumeration
, Port
);
2515 // Initialize FIS Base Address Register and Command List Base Address Register for use.
2517 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFisPciAddr
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
2518 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FB
;
2519 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2520 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FBU
;
2521 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2523 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdListPciAddr
);
2524 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLB
;
2525 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2526 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLBU
;
2527 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2529 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2530 Data
= AhciReadReg (PciIo
, Offset
);
2531 if ((Data
& EFI_AHCI_PORT_CMD_CPD
) != 0) {
2532 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_POD
);
2535 if ((Capability
& EFI_AHCI_CAP_SSS
) != 0) {
2536 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_SUD
);
2540 // Disable aggressive power management.
2542 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
2543 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_INIT
);
2545 // Disable the reporting of the corresponding interrupt to system software.
2547 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IE
;
2548 AhciAndReg (PciIo
, Offset
, 0);
2551 // Now inform the IDE Controller Init Module.
2553 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBusBeforeDevicePresenceDetection
, Port
);
2556 // Enable FIS Receive DMA engine for the first D2H FIS.
2558 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2559 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
2562 // Wait for the Phy to detect the presence of a device.
2564 PhyDetectDelay
= EFI_AHCI_BUS_PHY_DETECT_TIMEOUT
;
2565 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
2567 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
2568 if ((Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) || (Data
== EFI_AHCI_PORT_SSTS_DET
)) {
2572 MicroSecondDelay (1000);
2574 } while (PhyDetectDelay
> 0);
2576 if (PhyDetectDelay
== 0) {
2578 // No device detected at this port.
2579 // Clear PxCMD.SUD for those ports at which there are no device present.
2581 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2582 AhciAndReg (PciIo
, Offset
, (UINT32
) ~(EFI_AHCI_PORT_CMD_SUD
));
2587 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
2588 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
2590 PhyDetectDelay
= 16 * 1000;
2592 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
2593 if (AhciReadReg(PciIo
, Offset
) != 0) {
2594 AhciWriteReg (PciIo
, Offset
, AhciReadReg(PciIo
, Offset
));
2596 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
2598 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_TFD_MASK
;
2603 MicroSecondDelay (1000);
2605 } while (PhyDetectDelay
> 0);
2607 if (PhyDetectDelay
== 0) {
2608 DEBUG ((EFI_D_ERROR
, "Port %d Device presence detected but phy not ready (TFD=0x%X)\n", Port
, Data
));
2613 // When the first D2H register FIS is received, the content of PxSIG register is updated.
2615 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SIG
;
2616 Status
= AhciWaitMmioSet (
2621 EFI_TIMER_PERIOD_SECONDS(16)
2623 if (EFI_ERROR (Status
)) {
2627 Data
= AhciReadReg (PciIo
, Offset
);
2628 if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATAPI_DEVICE_SIG
) {
2629 Status
= AhciIdentifyPacket (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2631 if (EFI_ERROR (Status
)) {
2635 DeviceType
= EfiIdeCdrom
;
2636 } else if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATA_DEVICE_SIG
) {
2637 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2639 if (EFI_ERROR (Status
)) {
2640 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_PERIPHERAL_FIXED_MEDIA
| EFI_P_EC_NOT_DETECTED
));
2645 DEBUG_INFO
, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
2646 Buffer
.AtaData
.config
, Buffer
.AtaData
.specific_config
,
2647 Buffer
.AtaData
.command_set_supported_83
, Buffer
.AtaData
.command_set_feature_enb_86
2649 if ((Buffer
.AtaData
.config
& BIT2
) != 0) {
2651 // SpinUp disk if device reported incomplete IDENTIFY DEVICE.
2653 Status
= AhciSpinUpDisk (
2660 if (EFI_ERROR (Status
)) {
2661 DEBUG ((DEBUG_ERROR
, "Spin up standby device failed - %r\n", Status
));
2666 DeviceType
= EfiIdeHarddisk
;
2670 DEBUG ((DEBUG_INFO
, "port [%d] port multitplier [%d] has a [%a]\n",
2671 Port
, 0, DeviceType
== EfiIdeCdrom
? "cdrom" : "harddisk"));
2674 // If the device is a hard disk, then try to enable S.M.A.R.T feature
2676 if ((DeviceType
== EfiIdeHarddisk
) && PcdGetBool (PcdAtaSmartEnable
)) {
2677 AhciAtaSmartSupport (
2688 // Submit identify data to IDE controller init driver
2690 IdeInit
->SubmitData (IdeInit
, Port
, 0, &Buffer
);
2693 // Now start to config ide device parameter and transfer mode.
2695 Status
= IdeInit
->CalculateMode (
2701 if (EFI_ERROR (Status
)) {
2702 DEBUG ((EFI_D_ERROR
, "Calculate Mode Fail, Status = %r\n", Status
));
2707 // Set best supported PIO mode on this IDE device
2709 if (SupportedModes
->PioMode
.Mode
<= EfiAtaPioMode2
) {
2710 TransferMode
.ModeCategory
= EFI_ATA_MODE_DEFAULT_PIO
;
2712 TransferMode
.ModeCategory
= EFI_ATA_MODE_FLOW_PIO
;
2715 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->PioMode
.Mode
);
2718 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA can't
2719 // be set together. Only one DMA mode can be set to a device. If setting
2720 // DMA mode operation fails, we can continue moving on because we only use
2721 // PIO mode at boot time. DMA modes are used by certain kind of OS booting
2723 if (SupportedModes
->UdmaMode
.Valid
) {
2724 TransferMode
.ModeCategory
= EFI_ATA_MODE_UDMA
;
2725 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->UdmaMode
.Mode
);
2726 } else if (SupportedModes
->MultiWordDmaMode
.Valid
) {
2727 TransferMode
.ModeCategory
= EFI_ATA_MODE_MDMA
;
2728 TransferMode
.ModeNumber
= (UINT8
) SupportedModes
->MultiWordDmaMode
.Mode
;
2731 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, 0, 0x03, (UINT32
)(*(UINT8
*)&TransferMode
), ATA_ATAPI_TIMEOUT
);
2732 if (EFI_ERROR (Status
)) {
2733 DEBUG ((EFI_D_ERROR
, "Set transfer Mode Fail, Status = %r\n", Status
));
2738 // Found a ATA or ATAPI device, add it into the device list.
2740 CreateNewDeviceInfo (Instance
, Port
, 0xFFFF, DeviceType
, &Buffer
);
2741 if (DeviceType
== EfiIdeHarddisk
) {
2742 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_PERIPHERAL_FIXED_MEDIA
| EFI_P_PC_ENABLE
));
2753 // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).
2755 if ((Buffer
.AtaData
.command_set_supported_83
& BIT5
) != 0) {
2756 Status
= AhciPuisEnable (
2762 if (EFI_ERROR (Status
)) {
2763 DEBUG ((DEBUG_ERROR
, "PUIS enable/disable failed, Status = %r\n", Status
));