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 Wait until SATA device reports it is ready for operation.
614 @param[in] PciIo Pointer to AHCI controller PciIo.
615 @param[in] Port SATA port index on which to reset.
617 @retval EFI_SUCCESS Device ready for operation.
618 @retval EFI_TIMEOUT Device failed to get ready within required period.
621 AhciWaitDeviceReady (
622 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
626 UINT32 PhyDetectDelay
;
631 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
632 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
634 PhyDetectDelay
= 16 * 1000;
636 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
637 if (AhciReadReg(PciIo
, Offset
) != 0) {
638 AhciWriteReg (PciIo
, Offset
, AhciReadReg(PciIo
, Offset
));
640 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
642 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_TFD_MASK
;
647 MicroSecondDelay (1000);
649 } while (PhyDetectDelay
> 0);
651 if (PhyDetectDelay
== 0) {
652 DEBUG ((DEBUG_ERROR
, "Port %d Device not ready (TFD=0x%X)\n", Port
, Data
));
661 Reset the SATA port. Algorithm follows AHCI spec 1.3.1 section 10.4.2
663 @param[in] PciIo Pointer to AHCI controller PciIo.
664 @param[in] Port SATA port index on which to reset.
666 @retval EFI_SUCCESS Port reset.
667 @retval Others Failed to reset the port.
671 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
678 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
679 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_DET_INIT
);
681 // SW is required to keep DET set to 0x1 at least for 1 milisecond to ensure that
682 // at least one COMRESET signal is sent.
684 MicroSecondDelay(1000);
685 AhciAndReg (PciIo
, Offset
, ~(UINT32
)EFI_AHCI_PORT_SSTS_DET_MASK
);
687 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
688 Status
= AhciWaitMmioSet (PciIo
, Offset
, EFI_AHCI_PORT_SSTS_DET_MASK
, EFI_AHCI_PORT_SSTS_DET_PCE
, ATA_ATAPI_TIMEOUT
);
689 if (EFI_ERROR (Status
)) {
693 return AhciWaitDeviceReady (PciIo
, Port
);
697 Recovers the SATA port from error condition.
698 This function implements algorithm described in
699 AHCI spec 1.3.1 section 6.2.2
701 @param[in] PciIo Pointer to AHCI controller PciIo.
702 @param[in] Port SATA port index on which to check.
704 @retval EFI_SUCCESS Port recovered.
705 @retval Others Failed to recover port.
708 AhciRecoverPortError (
709 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
714 UINT32 PortInterrupt
;
718 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
719 PortInterrupt
= AhciReadReg (PciIo
, Offset
);
720 if ((PortInterrupt
& EFI_AHCI_PORT_IS_FATAL_ERROR_MASK
) == 0) {
722 // No fatal error detected. Exit with success as port should still be operational.
723 // No need to clear IS as it will be cleared when the next command starts.
728 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
729 AhciAndReg (PciIo
, Offset
, ~(UINT32
)EFI_AHCI_PORT_CMD_ST
);
731 Status
= AhciWaitMmioSet (PciIo
, Offset
, EFI_AHCI_PORT_CMD_CR
, 0, ATA_ATAPI_TIMEOUT
);
732 if (EFI_ERROR (Status
)) {
733 DEBUG ((DEBUG_ERROR
, "Ahci port %d is in hung state, aborting recovery\n", Port
));
738 // If TFD.BSY or TFD.DRQ is still set it means that drive is hung and software has
739 // to reset it before sending any additional commands.
741 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
742 PortTfd
= AhciReadReg (PciIo
, Offset
);
743 if ((PortTfd
& (EFI_AHCI_PORT_TFD_BSY
| EFI_AHCI_PORT_TFD_DRQ
)) != 0) {
744 Status
= AhciResetPort (PciIo
, Port
);
745 if (EFI_ERROR (Status
)) {
746 DEBUG ((DEBUG_ERROR
, "Failed to reset the port %d\n", Port
));
754 Checks if specified FIS has been received.
756 @param[in] PciIo Pointer to AHCI controller PciIo.
757 @param[in] Port SATA port index on which to check.
758 @param[in] FisType FIS type for which to check.
760 @retval EFI_SUCCESS FIS received.
761 @retval EFI_NOT_READY FIS not received yet.
762 @retval EFI_DEVICE_ERROR AHCI controller reported an error on port.
765 AhciCheckFisReceived (
766 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
768 IN SATA_FIS_TYPE FisType
772 UINT32 PortInterrupt
;
775 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
776 PortInterrupt
= AhciReadReg (PciIo
, Offset
);
777 if ((PortInterrupt
& EFI_AHCI_PORT_IS_ERROR_MASK
) != 0) {
778 DEBUG ((DEBUG_ERROR
, "AHCI: Error interrupt reported PxIS: %X\n", PortInterrupt
));
779 return EFI_DEVICE_ERROR
;
782 // For PIO setup FIS - According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
783 // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device
784 // after the transaction is finished successfully.
785 // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.
786 // By this way, we can know if there is a real error happened.
788 if (((FisType
== SataFisD2H
) && ((PortInterrupt
& EFI_AHCI_PORT_IS_DHRS
) != 0)) ||
789 ((FisType
== SataFisPioSetup
) && (PortInterrupt
& (EFI_AHCI_PORT_IS_PSS
| EFI_AHCI_PORT_IS_DHRS
)) != 0) ||
790 ((FisType
== SataFisDmaSetup
) && (PortInterrupt
& (EFI_AHCI_PORT_IS_DSS
| EFI_AHCI_PORT_IS_DHRS
)) != 0)) {
791 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
792 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
793 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
794 return EFI_DEVICE_ERROR
;
800 return EFI_NOT_READY
;
804 Waits until specified FIS has been received.
806 @param[in] PciIo Pointer to AHCI controller PciIo.
807 @param[in] Port SATA port index on which to check.
808 @param[in] Timeout Time after which function should stop polling.
809 @param[in] FisType FIS type for which to check.
811 @retval EFI_SUCCESS FIS received.
812 @retval EFI_TIMEOUT FIS failed to arrive within a specified time period.
813 @retval EFI_DEVICE_ERROR AHCI controller reported an error on port.
816 AhciWaitUntilFisReceived (
817 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
820 IN SATA_FIS_TYPE FisType
824 BOOLEAN InfiniteWait
;
827 Delay
= DivU64x32 (Timeout
, 1000) + 1;
831 InfiniteWait
= FALSE
;
835 Status
= AhciCheckFisReceived (PciIo
, Port
, FisType
);
836 if (Status
!= EFI_NOT_READY
) {
840 // Stall for 100 microseconds.
842 MicroSecondDelay (100);
844 } while (InfiniteWait
|| (Delay
> 0));
850 Prints contents of the ATA command block into the debug port.
852 @param[in] AtaCommandBlock AtaCommandBlock to print.
853 @param[in] DebugLevel Debug level on which to print.
856 AhciPrintCommandBlock (
857 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
861 DEBUG ((DebugLevel
, "ATA COMMAND BLOCK:\n"));
862 DEBUG ((DebugLevel
, "AtaCommand: %d\n", AtaCommandBlock
->AtaCommand
));
863 DEBUG ((DebugLevel
, "AtaFeatures: %X\n", AtaCommandBlock
->AtaFeatures
));
864 DEBUG ((DebugLevel
, "AtaSectorNumber: %d\n", AtaCommandBlock
->AtaSectorNumber
));
865 DEBUG ((DebugLevel
, "AtaCylinderLow: %X\n", AtaCommandBlock
->AtaCylinderHigh
));
866 DEBUG ((DebugLevel
, "AtaCylinderHigh: %X\n", AtaCommandBlock
->AtaCylinderHigh
));
867 DEBUG ((DebugLevel
, "AtaDeviceHead: %d\n", AtaCommandBlock
->AtaDeviceHead
));
868 DEBUG ((DebugLevel
, "AtaSectorNumberExp: %d\n", AtaCommandBlock
->AtaSectorNumberExp
));
869 DEBUG ((DebugLevel
, "AtaCylinderLowExp: %X\n", AtaCommandBlock
->AtaCylinderLowExp
));
870 DEBUG ((DebugLevel
, "AtaCylinderHighExp: %X\n", AtaCommandBlock
->AtaCylinderHighExp
));
871 DEBUG ((DebugLevel
, "AtaFeaturesExp: %X\n", AtaCommandBlock
->AtaFeaturesExp
));
872 DEBUG ((DebugLevel
, "AtaSectorCount: %d\n", AtaCommandBlock
->AtaSectorCount
));
873 DEBUG ((DebugLevel
, "AtaSectorCountExp: %d\n", AtaCommandBlock
->AtaSectorCountExp
));
877 Prints contents of the ATA status block into the debug port.
879 @param[in] AtaStatusBlock AtaStatusBlock to print.
880 @param[in] DebugLevel Debug level on which to print.
883 AhciPrintStatusBlock (
884 IN EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
891 if (AtaStatusBlock
== NULL
) {
896 // Only print status and error since we have all of the rest printed as
897 // a part of command block print.
899 DEBUG ((DebugLevel
, "ATA STATUS BLOCK:\n"));
900 DEBUG ((DebugLevel
, "AtaStatus: %d\n", AtaStatusBlock
->AtaStatus
));
901 DEBUG ((DebugLevel
, "AtaError: %d\n", AtaStatusBlock
->AtaError
));
905 Start a PIO data transfer on specific port.
907 @param[in] PciIo The PCI IO protocol instance.
908 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
909 @param[in] Port The number of port.
910 @param[in] PortMultiplier The timeout value of stop.
911 @param[in] AtapiCommand The atapi command will be used for the
913 @param[in] AtapiCommandLength The length of the atapi command.
914 @param[in] Read The transfer direction.
915 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
916 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
917 @param[in, out] MemoryAddr The pointer to the data buffer.
918 @param[in] DataCount The data count to be transferred.
919 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
920 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
921 used by non-blocking mode.
923 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
924 @retval EFI_TIMEOUT The operation is time out.
925 @retval EFI_UNSUPPORTED The device is not ready for transfer.
926 @retval EFI_SUCCESS The PIO data transfer executes successfully.
932 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
933 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
935 IN UINT8 PortMultiplier
,
936 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
937 IN UINT8 AtapiCommandLength
,
939 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
940 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
941 IN OUT VOID
*MemoryAddr
,
944 IN ATA_NONBLOCK_TASK
*Task
948 EFI_PHYSICAL_ADDRESS PhyAddr
;
951 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
952 EFI_AHCI_COMMAND_FIS CFis
;
953 EFI_AHCI_COMMAND_LIST CmdList
;
958 Flag
= EfiPciIoOperationBusMasterWrite
;
960 Flag
= EfiPciIoOperationBusMasterRead
;
964 // construct command list and command table with pci bus address
966 MapLength
= DataCount
;
967 Status
= PciIo
->Map (
976 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
977 return EFI_BAD_BUFFER_SIZE
;
981 // Package read needed
983 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
985 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
987 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
988 CmdList
.AhciCmdW
= Read
? 0 : 1;
990 for (Retry
= 0; Retry
< AHCI_COMMAND_RETRIES
; Retry
++) {
1001 (VOID
*)(UINTN
)PhyAddr
,
1005 DEBUG ((DEBUG_VERBOSE
, "Starting command for PIO transfer:\n"));
1006 AhciPrintCommandBlock (AtaCommandBlock
, DEBUG_VERBOSE
);
1007 Status
= AhciStartCommand (
1013 if (EFI_ERROR (Status
)) {
1017 if (Read
&& (AtapiCommand
== 0)) {
1018 Status
= AhciWaitUntilFisReceived (PciIo
, Port
, Timeout
, SataFisPioSetup
);
1019 if (Status
== EFI_SUCCESS
) {
1020 PrdCount
= *(volatile UINT32
*) (&(AhciRegisters
->AhciCmdList
[0].AhciCmdPrdbc
));
1021 if (PrdCount
== DataCount
) {
1022 Status
= EFI_SUCCESS
;
1024 Status
= EFI_DEVICE_ERROR
;
1028 Status
= AhciWaitUntilFisReceived (PciIo
, Port
, Timeout
, SataFisD2H
);
1031 if (Status
== EFI_DEVICE_ERROR
) {
1032 DEBUG ((DEBUG_ERROR
, "PIO command failed at retry %d\n", Retry
));
1033 Status
= AhciRecoverPortError (PciIo
, Port
);
1034 if (EFI_ERROR (Status
)) {
1048 AhciDisableFisReceive (
1059 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1061 if (Status
== EFI_DEVICE_ERROR
) {
1062 DEBUG ((DEBUG_ERROR
, "Failed to execute command for PIO transfer:\n"));
1064 // Repeat command block here to make sure it is printed on
1065 // device error debug level.
1067 AhciPrintCommandBlock (AtaCommandBlock
, DEBUG_ERROR
);
1068 AhciPrintStatusBlock (AtaStatusBlock
, DEBUG_ERROR
);
1070 AhciPrintStatusBlock (AtaStatusBlock
, DEBUG_VERBOSE
);
1077 Start a DMA data transfer on specific port
1079 @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE 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] Read The transfer direction.
1087 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
1088 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
1089 @param[in, out] MemoryAddr The pointer to the data buffer.
1090 @param[in] DataCount The data count to be transferred.
1091 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
1092 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
1093 used by non-blocking mode.
1095 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
1096 @retval EFI_TIMEOUT The operation is time out.
1097 @retval EFI_UNSUPPORTED The device is not ready for transfer.
1098 @retval EFI_SUCCESS The DMA data transfer executes successfully.
1104 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
,
1105 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1107 IN UINT8 PortMultiplier
,
1108 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
1109 IN UINT8 AtapiCommandLength
,
1111 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
1112 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
1113 IN OUT VOID
*MemoryAddr
,
1114 IN UINT32 DataCount
,
1116 IN ATA_NONBLOCK_TASK
*Task
1120 EFI_PHYSICAL_ADDRESS PhyAddr
;
1123 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
1124 EFI_AHCI_COMMAND_FIS CFis
;
1125 EFI_AHCI_COMMAND_LIST CmdList
;
1126 EFI_PCI_IO_PROTOCOL
*PciIo
;
1131 PciIo
= Instance
->PciIo
;
1133 if (PciIo
== NULL
) {
1134 return EFI_INVALID_PARAMETER
;
1138 // Set Status to suppress incorrect compiler/analyzer warnings
1140 Status
= EFI_SUCCESS
;
1143 // DMA buffer allocation. Needs to be done only once for both sync and async
1144 // DMA transfers irrespective of number of retries.
1146 if ((Task
== NULL
) || ((Task
!= NULL
) && (Task
->Map
== NULL
))) {
1148 Flag
= EfiPciIoOperationBusMasterWrite
;
1150 Flag
= EfiPciIoOperationBusMasterRead
;
1153 MapLength
= DataCount
;
1154 Status
= PciIo
->Map (
1163 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
1164 return EFI_BAD_BUFFER_SIZE
;
1171 if (Task
== NULL
|| (Task
!= NULL
&& !Task
->IsStart
)) {
1172 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
1174 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
1176 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
1177 CmdList
.AhciCmdW
= Read
? 0 : 1;
1182 // Before starting the Blocking BlockIO operation, push to finish all non-blocking
1184 // Delay 100us to simulate the blocking time out checking.
1186 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1187 while (!IsListEmpty (&Instance
->NonBlockingTaskList
)) {
1188 AsyncNonBlockingTransferRoutine (NULL
, Instance
);
1192 MicroSecondDelay (100);
1194 gBS
->RestoreTPL (OldTpl
);
1195 for (Retry
= 0; Retry
< AHCI_COMMAND_RETRIES
; Retry
++) {
1206 (VOID
*)(UINTN
)PhyAddr
,
1210 DEBUG ((DEBUG_VERBOSE
, "Starting command for sync DMA transfer:\n"));
1211 AhciPrintCommandBlock (AtaCommandBlock
, DEBUG_VERBOSE
);
1212 Status
= AhciStartCommand (
1218 if (EFI_ERROR (Status
)) {
1221 Status
= AhciWaitUntilFisReceived (PciIo
, Port
, Timeout
, SataFisD2H
);
1222 if (Status
== EFI_DEVICE_ERROR
) {
1223 DEBUG ((DEBUG_ERROR
, "DMA command failed at retry: %d\n", Retry
));
1224 Status
= AhciRecoverPortError (PciIo
, Port
);
1225 if (EFI_ERROR (Status
)) {
1233 if (!Task
->IsStart
) {
1244 (VOID
*)(UINTN
)PhyAddr
,
1248 DEBUG ((DEBUG_VERBOSE
, "Starting command for async DMA transfer:\n"));
1249 AhciPrintCommandBlock (AtaCommandBlock
, DEBUG_VERBOSE
);
1250 Status
= AhciStartCommand (
1256 if (!EFI_ERROR (Status
)) {
1257 Task
->IsStart
= TRUE
;
1260 if (Task
->IsStart
) {
1261 Status
= AhciCheckFisReceived (PciIo
, Port
, SataFisD2H
);
1262 if (Status
== EFI_DEVICE_ERROR
) {
1263 DEBUG ((DEBUG_ERROR
, "DMA command failed at retry: %d\n", Task
->RetryTimes
));
1264 Status
= AhciRecoverPortError (PciIo
, Port
);
1266 // If recovery passed mark the Task as not started and change the status
1267 // to EFI_NOT_READY. This will make the higher level call this function again
1268 // and on next call the command will be re-issued due to IsStart being FALSE.
1269 // This also makes the next condition decrement the RetryTimes.
1271 if (Status
== EFI_SUCCESS
) {
1272 Task
->IsStart
= FALSE
;
1273 Status
= EFI_NOT_READY
;
1277 if (Status
== EFI_NOT_READY
) {
1278 if (!Task
->InfiniteWait
&& Task
->RetryTimes
== 0) {
1279 Status
= EFI_TIMEOUT
;
1288 // For Blocking mode, the command should be stopped, the Fis should be disabled
1289 // and the PciIo should be unmapped.
1290 // For non-blocking mode, only when a error is happened (if the return status is
1291 // EFI_NOT_READY that means the command doesn't finished, try again.), first do the
1292 // context cleanup, then set the packet's Asb status.
1295 ((Task
!= NULL
) && (Status
!= EFI_NOT_READY
))
1303 AhciDisableFisReceive (
1311 (Task
!= NULL
) ? Task
->Map
: Map
1315 Task
->Packet
->Asb
->AtaStatus
= 0x01;
1319 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1321 if (Status
== EFI_DEVICE_ERROR
) {
1322 DEBUG ((DEBUG_ERROR
, "Failed to execute command for DMA transfer:\n"));
1324 // Repeat command block here to make sure it is printed on
1325 // device error debug level.
1327 AhciPrintCommandBlock (AtaCommandBlock
, DEBUG_ERROR
);
1328 AhciPrintStatusBlock (AtaStatusBlock
, DEBUG_ERROR
);
1330 AhciPrintStatusBlock (AtaStatusBlock
, DEBUG_VERBOSE
);
1337 Start a non data transfer on specific port.
1339 @param[in] PciIo The PCI IO protocol instance.
1340 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1341 @param[in] Port The number of port.
1342 @param[in] PortMultiplier The timeout value of stop.
1343 @param[in] AtapiCommand The atapi command will be used for the
1345 @param[in] AtapiCommandLength The length of the atapi command.
1346 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
1347 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
1348 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
1349 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
1350 used by non-blocking mode.
1352 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
1353 @retval EFI_TIMEOUT The operation is time out.
1354 @retval EFI_UNSUPPORTED The device is not ready for transfer.
1355 @retval EFI_SUCCESS The non data transfer executes successfully.
1360 AhciNonDataTransfer (
1361 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1362 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1364 IN UINT8 PortMultiplier
,
1365 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
1366 IN UINT8 AtapiCommandLength
,
1367 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
1368 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
1370 IN ATA_NONBLOCK_TASK
*Task
1374 EFI_AHCI_COMMAND_FIS CFis
;
1375 EFI_AHCI_COMMAND_LIST CmdList
;
1379 // Package read needed
1381 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
1383 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
1385 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
1387 for (Retry
= 0; Retry
< AHCI_COMMAND_RETRIES
; Retry
++) {
1402 DEBUG ((DEBUG_VERBOSE
, "Starting command for non data transfer:\n"));
1403 AhciPrintCommandBlock (AtaCommandBlock
, DEBUG_VERBOSE
);
1404 Status
= AhciStartCommand (
1410 if (EFI_ERROR (Status
)) {
1414 Status
= AhciWaitUntilFisReceived (PciIo
, Port
, Timeout
, SataFisD2H
);
1415 if (Status
== EFI_DEVICE_ERROR
) {
1416 DEBUG ((DEBUG_ERROR
, "Non data transfer failed at retry %d\n", Retry
));
1417 Status
= AhciRecoverPortError (PciIo
, Port
);
1418 if (EFI_ERROR (Status
)) {
1432 AhciDisableFisReceive (
1438 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1440 if (Status
== EFI_DEVICE_ERROR
) {
1441 DEBUG ((DEBUG_ERROR
, "Failed to execute command for non data transfer:\n"));
1443 // Repeat command block here to make sure it is printed on
1444 // device error debug level.
1446 AhciPrintCommandBlock (AtaCommandBlock
, DEBUG_ERROR
);
1447 AhciPrintStatusBlock (AtaStatusBlock
, DEBUG_ERROR
);
1449 AhciPrintStatusBlock (AtaStatusBlock
, DEBUG_VERBOSE
);
1456 Stop command running for giving port
1458 @param PciIo The PCI IO protocol instance.
1459 @param Port The number of port.
1460 @param Timeout The timeout value of stop, uses 100ns as a unit.
1462 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
1463 @retval EFI_TIMEOUT The operation is time out.
1464 @retval EFI_SUCCESS The command stop successfully.
1470 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1478 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1479 Data
= AhciReadReg (PciIo
, Offset
);
1481 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) == 0) {
1485 if ((Data
& EFI_AHCI_PORT_CMD_ST
) != 0) {
1486 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_ST
));
1489 return AhciWaitMmioSet (
1492 EFI_AHCI_PORT_CMD_CR
,
1499 Start command for give slot on specific port.
1501 @param PciIo The PCI IO protocol instance.
1502 @param Port The number of port.
1503 @param CommandSlot The number of Command Slot.
1504 @param Timeout The timeout value of start, uses 100ns as a unit.
1506 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
1507 @retval EFI_TIMEOUT The operation is time out.
1508 @retval EFI_SUCCESS The command start successfully.
1514 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1516 IN UINT8 CommandSlot
,
1529 // Collect AHCI controller information
1531 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1533 CmdSlotBit
= (UINT32
) (1 << CommandSlot
);
1535 AhciClearPortStatus (
1540 Status
= AhciEnableFisReceive (
1546 if (EFI_ERROR (Status
)) {
1550 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1551 PortStatus
= AhciReadReg (PciIo
, Offset
);
1554 if ((PortStatus
& EFI_AHCI_PORT_CMD_ALPE
) != 0) {
1555 StartCmd
= AhciReadReg (PciIo
, Offset
);
1556 StartCmd
&= ~EFI_AHCI_PORT_CMD_ICC_MASK
;
1557 StartCmd
|= EFI_AHCI_PORT_CMD_ACTIVE
;
1560 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1561 PortTfd
= AhciReadReg (PciIo
, Offset
);
1563 if ((PortTfd
& (EFI_AHCI_PORT_TFD_BSY
| EFI_AHCI_PORT_TFD_DRQ
)) != 0) {
1564 if ((Capability
& BIT24
) != 0) {
1565 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1566 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_CLO
);
1571 EFI_AHCI_PORT_CMD_CLO
,
1578 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1579 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_ST
| StartCmd
);
1582 // Setting the command
1584 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
1585 AhciAndReg (PciIo
, Offset
, 0);
1586 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1595 @param PciIo The PCI IO protocol instance.
1596 @param Timeout The timeout value of reset, uses 100ns as a unit.
1598 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
1599 @retval EFI_TIMEOUT The reset operation is time out.
1600 @retval EFI_SUCCESS AHCI controller is reset successfully.
1606 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1614 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
1616 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1618 if ((Value
& EFI_AHCI_GHC_ENABLE
) == 0) {
1619 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
1622 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_RESET
);
1624 Delay
= DivU64x32(Timeout
, 1000) + 1;
1627 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1629 if ((Value
& EFI_AHCI_GHC_RESET
) == 0) {
1634 // Stall for 100 microseconds.
1636 MicroSecondDelay(100);
1639 } while (Delay
> 0);
1649 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
1651 @param PciIo The PCI IO protocol instance.
1652 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1653 @param Port The number of port.
1654 @param PortMultiplier The port multiplier port number.
1655 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1657 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
1658 @retval Others Fail to get return status data.
1663 AhciAtaSmartReturnStatusCheck (
1664 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1665 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1667 IN UINT8 PortMultiplier
,
1668 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1672 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1678 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1680 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1681 AtaCommandBlock
.AtaFeatures
= ATA_SMART_RETURN_STATUS
;
1682 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1683 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1686 // Send S.M.A.R.T Read Return Status command to device
1688 Status
= AhciNonDataTransfer (
1692 (UINT8
)PortMultiplier
,
1701 if (EFI_ERROR (Status
)) {
1702 REPORT_STATUS_CODE (
1703 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1704 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_DISABLED
)
1706 return EFI_DEVICE_ERROR
;
1709 REPORT_STATUS_CODE (
1711 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_ENABLE
)
1714 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1716 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
1718 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
1719 LBAMid
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[5];
1720 LBAHigh
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[6];
1722 if ((LBAMid
== 0x4f) && (LBAHigh
== 0xc2)) {
1724 // The threshold exceeded condition is not detected by the device
1726 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
1727 REPORT_STATUS_CODE (
1729 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD
)
1731 } else if ((LBAMid
== 0xf4) && (LBAHigh
== 0x2c)) {
1733 // The threshold exceeded condition is detected by the device
1735 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is detected\n"));
1736 REPORT_STATUS_CODE (
1738 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD
)
1747 Enable SMART command of the disk if supported.
1749 @param PciIo The PCI IO protocol instance.
1750 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1751 @param Port The number of port.
1752 @param PortMultiplier The port multiplier port number.
1753 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
1754 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1759 AhciAtaSmartSupport (
1760 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1761 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1763 IN UINT8 PortMultiplier
,
1764 IN EFI_IDENTIFY_DATA
*IdentifyData
,
1765 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1769 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1772 // Detect if the device supports S.M.A.R.T.
1774 if ((IdentifyData
->AtaData
.command_set_supported_82
& 0x0001) != 0x0001) {
1776 // S.M.A.R.T is not supported by the device
1778 DEBUG ((EFI_D_INFO
, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
1779 Port
, PortMultiplier
));
1780 REPORT_STATUS_CODE (
1781 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1782 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED
)
1786 // Check if the feature is enabled. If not, then enable S.M.A.R.T.
1788 if ((IdentifyData
->AtaData
.command_set_feature_enb_85
& 0x0001) != 0x0001) {
1790 REPORT_STATUS_CODE (
1792 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_DISABLE
)
1795 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1797 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1798 AtaCommandBlock
.AtaFeatures
= ATA_SMART_ENABLE_OPERATION
;
1799 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1800 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1803 // Send S.M.A.R.T Enable command to device
1805 Status
= AhciNonDataTransfer (
1809 (UINT8
)PortMultiplier
,
1819 if (!EFI_ERROR (Status
)) {
1821 // Send S.M.A.R.T AutoSave command to device
1823 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1825 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1826 AtaCommandBlock
.AtaFeatures
= 0xD2;
1827 AtaCommandBlock
.AtaSectorCount
= 0xF1;
1828 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1829 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1831 Status
= AhciNonDataTransfer (
1835 (UINT8
)PortMultiplier
,
1846 AhciAtaSmartReturnStatusCheck (
1850 (UINT8
)PortMultiplier
,
1854 DEBUG ((EFI_D_INFO
, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
1855 Port
, PortMultiplier
));
1862 Send Buffer cmd to specific device.
1864 @param PciIo The PCI IO protocol instance.
1865 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1866 @param Port The number of port.
1867 @param PortMultiplier The port multiplier port number.
1868 @param Buffer The data buffer to store IDENTIFY PACKET data.
1870 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1871 @retval EFI_TIMEOUT The operation is time out.
1872 @retval EFI_UNSUPPORTED The device is not ready for executing.
1873 @retval EFI_SUCCESS The cmd executes successfully.
1879 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1880 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1882 IN UINT8 PortMultiplier
,
1883 IN OUT EFI_IDENTIFY_DATA
*Buffer
1887 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1888 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1890 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
1891 return EFI_INVALID_PARAMETER
;
1894 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1895 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1897 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DRIVE
;
1898 AtaCommandBlock
.AtaSectorCount
= 1;
1900 Status
= AhciPioTransfer (
1911 sizeof (EFI_IDENTIFY_DATA
),
1920 Send Buffer cmd to specific device.
1922 @param PciIo The PCI IO protocol instance.
1923 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1924 @param Port The number of port.
1925 @param PortMultiplier The port multiplier port number.
1926 @param Buffer The data buffer to store IDENTIFY PACKET data.
1928 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1929 @retval EFI_TIMEOUT The operation is time out.
1930 @retval EFI_UNSUPPORTED The device is not ready for executing.
1931 @retval EFI_SUCCESS The cmd executes successfully.
1936 AhciIdentifyPacket (
1937 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1938 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1940 IN UINT8 PortMultiplier
,
1941 IN OUT EFI_IDENTIFY_DATA
*Buffer
1945 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1946 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1948 if (PciIo
== NULL
|| AhciRegisters
== NULL
) {
1949 return EFI_INVALID_PARAMETER
;
1952 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1953 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1955 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DEVICE
;
1956 AtaCommandBlock
.AtaSectorCount
= 1;
1958 Status
= AhciPioTransfer (
1969 sizeof (EFI_IDENTIFY_DATA
),
1978 Send SET FEATURE cmd on specific device.
1980 @param PciIo The PCI IO protocol instance.
1981 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1982 @param Port The number of port.
1983 @param PortMultiplier The port multiplier port number.
1984 @param Feature The data to send Feature register.
1985 @param FeatureSpecificData The specific data for SET FEATURE cmd.
1986 @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.
1988 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1989 @retval EFI_TIMEOUT The operation is time out.
1990 @retval EFI_UNSUPPORTED The device is not ready for executing.
1991 @retval EFI_SUCCESS The cmd executes successfully.
1996 AhciDeviceSetFeature (
1997 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1998 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2000 IN UINT8 PortMultiplier
,
2002 IN UINT32 FeatureSpecificData
,
2007 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2008 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2010 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2011 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2013 AtaCommandBlock
.AtaCommand
= ATA_CMD_SET_FEATURES
;
2014 AtaCommandBlock
.AtaFeatures
= (UINT8
) Feature
;
2015 AtaCommandBlock
.AtaFeaturesExp
= (UINT8
) (Feature
>> 8);
2016 AtaCommandBlock
.AtaSectorCount
= (UINT8
) FeatureSpecificData
;
2017 AtaCommandBlock
.AtaSectorNumber
= (UINT8
) (FeatureSpecificData
>> 8);
2018 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (FeatureSpecificData
>> 16);
2019 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (FeatureSpecificData
>> 24);
2021 Status
= AhciNonDataTransfer (
2025 (UINT8
)PortMultiplier
,
2038 This function is used to send out ATAPI commands conforms to the Packet Command
2041 @param PciIo The PCI IO protocol instance.
2042 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2043 @param Port The number of port.
2044 @param PortMultiplier The number of port multiplier.
2045 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
2047 @retval EFI_SUCCESS send out the ATAPI packet command successfully
2048 and device sends data successfully.
2049 @retval EFI_DEVICE_ERROR the device failed to send data.
2054 AhciPacketCommandExecute (
2055 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2056 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2058 IN UINT8 PortMultiplier
,
2059 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
2065 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2066 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2069 if (Packet
== NULL
|| Packet
->Cdb
== NULL
) {
2070 return EFI_INVALID_PARAMETER
;
2073 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2074 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2075 AtaCommandBlock
.AtaCommand
= ATA_CMD_PACKET
;
2079 AtaCommandBlock
.AtaFeatures
= 0x00;
2081 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
2082 // determine how many data should be transferred.
2084 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
& 0x00ff);
2085 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
>> 8);
2087 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2088 Buffer
= Packet
->InDataBuffer
;
2089 Length
= Packet
->InTransferLength
;
2092 Buffer
= Packet
->OutDataBuffer
;
2093 Length
= Packet
->OutTransferLength
;
2098 Status
= AhciNonDataTransfer (
2111 Status
= AhciPioTransfer (
2131 Allocate transfer-related data struct which is used at AHCI mode.
2133 @param PciIo The PCI IO protocol instance.
2134 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2139 AhciCreateTransferDescriptor (
2140 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2141 IN OUT EFI_AHCI_REGISTERS
*AhciRegisters
2149 UINT32 PortImplementBitMap
;
2150 UINT8 MaxPortNumber
;
2151 UINT8 MaxCommandSlotNumber
;
2152 BOOLEAN Support64Bit
;
2153 UINT64 MaxReceiveFisSize
;
2154 UINT64 MaxCommandListSize
;
2155 UINT64 MaxCommandTableSize
;
2156 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr
;
2157 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr
;
2158 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr
;
2162 // Collect AHCI controller information
2164 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
2166 // Get the number of command slots per port supported by this HBA.
2168 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
2169 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
2171 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
2173 // Get the highest bit of implemented ports which decides how many bytes are allocated for received FIS.
2175 MaxPortNumber
= (UINT8
)(UINTN
)(HighBitSet32(PortImplementBitMap
) + 1);
2176 if (MaxPortNumber
== 0) {
2177 return EFI_DEVICE_ERROR
;
2180 MaxReceiveFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
2181 Status
= PciIo
->AllocateBuffer (
2184 EfiBootServicesData
,
2185 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
2190 if (EFI_ERROR (Status
)) {
2191 return EFI_OUT_OF_RESOURCES
;
2194 ZeroMem (Buffer
, (UINTN
)MaxReceiveFisSize
);
2196 AhciRegisters
->AhciRFis
= Buffer
;
2197 AhciRegisters
->MaxReceiveFisSize
= MaxReceiveFisSize
;
2198 Bytes
= (UINTN
)MaxReceiveFisSize
;
2200 Status
= PciIo
->Map (
2202 EfiPciIoOperationBusMasterCommonBuffer
,
2206 &AhciRegisters
->MapRFis
2209 if (EFI_ERROR (Status
) || (Bytes
!= MaxReceiveFisSize
)) {
2211 // Map error or unable to map the whole RFis buffer into a contiguous region.
2213 Status
= EFI_OUT_OF_RESOURCES
;
2217 if ((!Support64Bit
) && (AhciRFisPciAddr
> 0x100000000ULL
)) {
2219 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
2221 Status
= EFI_DEVICE_ERROR
;
2224 AhciRegisters
->AhciRFisPciAddr
= (EFI_AHCI_RECEIVED_FIS
*)(UINTN
)AhciRFisPciAddr
;
2227 // Allocate memory for command list
2228 // Note that the implementation is a single task model which only use a command list for all ports.
2231 MaxCommandListSize
= MaxCommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
);
2232 Status
= PciIo
->AllocateBuffer (
2235 EfiBootServicesData
,
2236 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
2241 if (EFI_ERROR (Status
)) {
2243 // Free mapped resource.
2245 Status
= EFI_OUT_OF_RESOURCES
;
2249 ZeroMem (Buffer
, (UINTN
)MaxCommandListSize
);
2251 AhciRegisters
->AhciCmdList
= Buffer
;
2252 AhciRegisters
->MaxCommandListSize
= MaxCommandListSize
;
2253 Bytes
= (UINTN
)MaxCommandListSize
;
2255 Status
= PciIo
->Map (
2257 EfiPciIoOperationBusMasterCommonBuffer
,
2260 &AhciCmdListPciAddr
,
2261 &AhciRegisters
->MapCmdList
2264 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandListSize
)) {
2266 // Map error or unable to map the whole cmd list buffer into a contiguous region.
2268 Status
= EFI_OUT_OF_RESOURCES
;
2272 if ((!Support64Bit
) && (AhciCmdListPciAddr
> 0x100000000ULL
)) {
2274 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
2276 Status
= EFI_DEVICE_ERROR
;
2279 AhciRegisters
->AhciCmdListPciAddr
= (EFI_AHCI_COMMAND_LIST
*)(UINTN
)AhciCmdListPciAddr
;
2282 // Allocate memory for command table
2283 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
2286 MaxCommandTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
2288 Status
= PciIo
->AllocateBuffer (
2291 EfiBootServicesData
,
2292 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
2297 if (EFI_ERROR (Status
)) {
2299 // Free mapped resource.
2301 Status
= EFI_OUT_OF_RESOURCES
;
2305 ZeroMem (Buffer
, (UINTN
)MaxCommandTableSize
);
2307 AhciRegisters
->AhciCommandTable
= Buffer
;
2308 AhciRegisters
->MaxCommandTableSize
= MaxCommandTableSize
;
2309 Bytes
= (UINTN
)MaxCommandTableSize
;
2311 Status
= PciIo
->Map (
2313 EfiPciIoOperationBusMasterCommonBuffer
,
2316 &AhciCommandTablePciAddr
,
2317 &AhciRegisters
->MapCommandTable
2320 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandTableSize
)) {
2322 // Map error or unable to map the whole cmd list buffer into a contiguous region.
2324 Status
= EFI_OUT_OF_RESOURCES
;
2328 if ((!Support64Bit
) && (AhciCommandTablePciAddr
> 0x100000000ULL
)) {
2330 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
2332 Status
= EFI_DEVICE_ERROR
;
2335 AhciRegisters
->AhciCommandTablePciAddr
= (EFI_AHCI_COMMAND_TABLE
*)(UINTN
)AhciCommandTablePciAddr
;
2339 // Map error or unable to map the whole CmdList buffer into a contiguous region.
2344 AhciRegisters
->MapCommandTable
2349 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
2350 AhciRegisters
->AhciCommandTable
2355 AhciRegisters
->MapCmdList
2360 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
2361 AhciRegisters
->AhciCmdList
2366 AhciRegisters
->MapRFis
2371 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
2372 AhciRegisters
->AhciRFis
2379 Read logs from SATA device.
2381 @param PciIo The PCI IO protocol instance.
2382 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2383 @param Port The number of port.
2384 @param PortMultiplier The multiplier of port.
2385 @param Buffer The data buffer to store SATA logs.
2386 @param LogNumber The address of the log.
2387 @param PageNumber The page number of the log.
2389 @retval EFI_INVALID_PARAMETER PciIo, AhciRegisters or Buffer is NULL.
2390 @retval others Return status of AhciPioTransfer().
2394 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2395 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2397 IN UINT8 PortMultiplier
,
2398 IN OUT UINT8
*Buffer
,
2403 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2404 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2406 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
2407 return EFI_INVALID_PARAMETER
;
2411 /// Read log from device
2413 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2414 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2415 ZeroMem (Buffer
, 512);
2417 AtaCommandBlock
.AtaCommand
= ATA_CMD_READ_LOG_EXT
;
2418 AtaCommandBlock
.AtaSectorCount
= 1;
2419 AtaCommandBlock
.AtaSectorNumber
= LogNumber
;
2420 AtaCommandBlock
.AtaCylinderLow
= PageNumber
;
2422 return AhciPioTransfer (
2440 Enable DEVSLP of the disk if supported.
2442 @param PciIo The PCI IO protocol instance.
2443 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2444 @param Port The number of port.
2445 @param PortMultiplier The multiplier of port.
2446 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
2448 @retval EFI_SUCCESS The DEVSLP is enabled per policy successfully.
2449 @retval EFI_UNSUPPORTED The DEVSLP isn't supported by the controller/device and policy requires to enable it.
2453 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2454 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2456 IN UINT8 PortMultiplier
,
2457 IN EFI_IDENTIFY_DATA
*IdentifyData
2464 DEVSLP_TIMING_VARIABLES DevSlpTiming
;
2468 if (mAtaAtapiPolicy
->DeviceSleepEnable
!= 1) {
2473 // Do not enable DevSlp if DevSlp is not supported.
2475 Capability2
= AhciReadReg (PciIo
, AHCI_CAPABILITY2_OFFSET
);
2476 DEBUG ((DEBUG_INFO
, "AHCI CAPABILITY2 = %08x\n", Capability2
));
2477 if ((Capability2
& AHCI_CAP2_SDS
) == 0) {
2478 return EFI_UNSUPPORTED
;
2482 // Do not enable DevSlp if DevSlp is not present
2483 // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported
2485 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
;
2486 PortCmd
= AhciReadReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
);
2487 PortDevSlp
= AhciReadReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
);
2488 DEBUG ((DEBUG_INFO
, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd
, PortDevSlp
));
2489 if (((PortDevSlp
& AHCI_PORT_DEVSLP_DSP
) == 0) ||
2490 ((PortCmd
& (EFI_AHCI_PORT_CMD_HPCP
| EFI_AHCI_PORT_CMD_MPSP
)) != 0)
2492 return EFI_UNSUPPORTED
;
2496 // Do not enable DevSlp if the device doesn't support DevSlp
2498 DEBUG ((DEBUG_INFO
, "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",
2499 IdentifyData
->AtaData
.reserved_77
,
2500 IdentifyData
->AtaData
.serial_ata_features_supported
, IdentifyData
->AtaData
.serial_ata_features_enabled
));
2501 if ((IdentifyData
->AtaData
.serial_ata_features_supported
& BIT8
) == 0) {
2502 DEBUG ((DEBUG_INFO
, "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",
2503 Port
, PortMultiplier
));
2504 return EFI_UNSUPPORTED
;
2508 // Enable DevSlp when it is not enabled.
2510 if ((IdentifyData
->AtaData
.serial_ata_features_enabled
& BIT8
) != 0) {
2511 Status
= AhciDeviceSetFeature (
2512 PciIo
, AhciRegisters
, Port
, 0, ATA_SUB_CMD_ENABLE_SATA_FEATURE
, 0x09, ATA_ATAPI_TIMEOUT
2514 DEBUG ((DEBUG_INFO
, "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",
2515 Port
, PortMultiplier
, Status
));
2516 if (EFI_ERROR (Status
)) {
2521 Status
= AhciReadLogExt(PciIo
, AhciRegisters
, Port
, PortMultiplier
, LogData
, 0x30, 0x08);
2524 // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.
2526 AhciWriteReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
, PortCmd
& ~EFI_AHCI_PORT_CMD_ST
);
2527 PortDevSlp
&= ~AHCI_PORT_DEVSLP_ADSE
;
2528 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2531 // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.
2533 PortDevSlp
&= ~AHCI_PORT_DEVSLP_DETO_MASK
;
2534 PortDevSlp
&= ~AHCI_PORT_DEVSLP_MDAT_MASK
;
2535 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2536 DEBUG ((DEBUG_INFO
, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port
, PortMultiplier
, Status
));
2537 if (EFI_ERROR (Status
)) {
2539 // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails
2541 ZeroMem (&DevSlpTiming
, sizeof (DevSlpTiming
));
2543 CopyMem (&DevSlpTiming
, &LogData
[48], sizeof (DevSlpTiming
));
2544 DEBUG ((DEBUG_INFO
, "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",
2545 DevSlpTiming
.Supported
, DevSlpTiming
.Deto
, DevSlpTiming
.Madt
));
2549 // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.
2551 if ((DevSlpTiming
.Supported
== 0) || (DevSlpTiming
.Deto
== 0)) {
2552 DevSlpTiming
.Deto
= 20;
2556 // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.
2558 if ((DevSlpTiming
.Supported
== 0) || (DevSlpTiming
.Madt
== 0)) {
2559 DevSlpTiming
.Madt
= 10;
2562 PortDevSlp
|= DevSlpTiming
.Deto
<< 2;
2563 PortDevSlp
|= DevSlpTiming
.Madt
<< 10;
2564 AhciOrReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2566 if (mAtaAtapiPolicy
->AggressiveDeviceSleepEnable
== 1) {
2567 if ((Capability2
& AHCI_CAP2_SADM
) != 0) {
2568 PortDevSlp
&= ~AHCI_PORT_DEVSLP_DITO_MASK
;
2569 PortDevSlp
|= (625 << 15);
2570 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2572 PortDevSlp
|= AHCI_PORT_DEVSLP_ADSE
;
2573 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2578 AhciWriteReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
, PortCmd
);
2580 DEBUG ((DEBUG_INFO
, "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",
2581 Port
, PortMultiplier
, PortCmd
, PortDevSlp
));
2587 Spin-up disk if IDD was incomplete or PUIS feature is enabled
2589 @param PciIo The PCI IO protocol instance.
2590 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2591 @param Port The number of port.
2592 @param PortMultiplier The multiplier of port.
2593 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
2598 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2599 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2601 IN UINT8 PortMultiplier
,
2602 IN OUT EFI_IDENTIFY_DATA
*IdentifyData
2606 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2607 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2610 if (IdentifyData
->AtaData
.specific_config
== ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE
) {
2612 // Use SET_FEATURE subcommand to spin up the device.
2614 Status
= AhciDeviceSetFeature (
2615 PciIo
, AhciRegisters
, Port
, PortMultiplier
,
2616 ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP
, 0x00, ATA_SPINUP_TIMEOUT
2618 DEBUG ((DEBUG_INFO
, "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",
2619 Port
, PortMultiplier
, Status
));
2620 if (EFI_ERROR (Status
)) {
2624 ASSERT (IdentifyData
->AtaData
.specific_config
== ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE
);
2627 // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported
2629 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2630 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2632 // Perform READ SECTORS PIO Data-In command to Read LBA 0
2634 AtaCommandBlock
.AtaCommand
= ATA_CMD_READ_SECTORS
;
2635 AtaCommandBlock
.AtaSectorCount
= 0x1;
2637 Status
= AhciPioTransfer (
2652 DEBUG ((DEBUG_INFO
, "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",
2653 Port
, PortMultiplier
, Status
));
2654 if (EFI_ERROR (Status
)) {
2660 // Read the complete IDENTIFY DEVICE data.
2662 ZeroMem (IdentifyData
, sizeof (*IdentifyData
));
2663 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, PortMultiplier
, IdentifyData
);
2664 if (EFI_ERROR (Status
)) {
2665 DEBUG ((DEBUG_ERROR
, "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",
2666 Port
, PortMultiplier
, Status
));
2670 DEBUG ((DEBUG_INFO
, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
2671 IdentifyData
->AtaData
.config
, IdentifyData
->AtaData
.specific_config
,
2672 IdentifyData
->AtaData
.command_set_supported_83
, IdentifyData
->AtaData
.command_set_feature_enb_86
));
2674 // Check if IDD is incomplete
2676 if ((IdentifyData
->AtaData
.config
& BIT2
) != 0) {
2677 return EFI_DEVICE_ERROR
;
2684 Enable/disable/skip PUIS of the disk according to policy.
2686 @param PciIo The PCI IO protocol instance.
2687 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2688 @param Port The number of port.
2689 @param PortMultiplier The multiplier of port.
2694 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2695 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2697 IN UINT8 PortMultiplier
2702 Status
= EFI_SUCCESS
;
2703 if (mAtaAtapiPolicy
->PuisEnable
== 0) {
2704 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, PortMultiplier
, ATA_SUB_CMD_DISABLE_PUIS
, 0x00, ATA_ATAPI_TIMEOUT
);
2705 } else if (mAtaAtapiPolicy
->PuisEnable
== 1) {
2706 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, PortMultiplier
, ATA_SUB_CMD_ENABLE_PUIS
, 0x00, ATA_ATAPI_TIMEOUT
);
2708 DEBUG ((DEBUG_INFO
, "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",
2709 (mAtaAtapiPolicy
->PuisEnable
== 0) ? "Disable" : (
2710 (mAtaAtapiPolicy
->PuisEnable
== 1) ? "Enable" : "Skip"
2711 ), Port
, PortMultiplier
, Status
));
2716 Initialize ATA host controller at AHCI mode.
2718 The function is designed to initialize ATA host controller.
2720 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
2725 AhciModeInitialization (
2726 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
2730 EFI_PCI_IO_PROTOCOL
*PciIo
;
2731 EFI_IDE_CONTROLLER_INIT_PROTOCOL
*IdeInit
;
2733 UINT8 MaxPortNumber
;
2734 UINT32 PortImplementBitMap
;
2736 EFI_AHCI_REGISTERS
*AhciRegisters
;
2742 EFI_IDENTIFY_DATA Buffer
;
2743 EFI_ATA_DEVICE_TYPE DeviceType
;
2744 EFI_ATA_COLLECTIVE_MODE
*SupportedModes
;
2745 EFI_ATA_TRANSFER_MODE TransferMode
;
2746 UINT32 PhyDetectDelay
;
2749 if (Instance
== NULL
) {
2750 return EFI_INVALID_PARAMETER
;
2753 PciIo
= Instance
->PciIo
;
2754 IdeInit
= Instance
->IdeControllerInit
;
2756 Status
= AhciReset (PciIo
, EFI_AHCI_BUS_RESET_TIMEOUT
);
2758 if (EFI_ERROR (Status
)) {
2759 return EFI_DEVICE_ERROR
;
2763 // Collect AHCI controller information
2765 Capability
= AhciReadReg (PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
2768 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
2770 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
2772 if ((Value
& EFI_AHCI_GHC_ENABLE
) == 0) {
2773 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
2777 // Enable 64-bit DMA support in the PCI layer if this controller
2780 if ((Capability
& EFI_AHCI_CAP_S64A
) != 0) {
2781 Status
= PciIo
->Attributes (
2783 EfiPciIoAttributeOperationEnable
,
2784 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
2787 if (EFI_ERROR (Status
)) {
2789 "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",
2795 // Get the number of command slots per port supported by this HBA.
2797 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
2800 // Get the bit map of those ports exposed by this HBA.
2801 // It indicates which ports that the HBA supports are available for software to use.
2803 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
2805 AhciRegisters
= &Instance
->AhciRegisters
;
2806 Status
= AhciCreateTransferDescriptor (PciIo
, AhciRegisters
);
2808 if (EFI_ERROR (Status
)) {
2809 return EFI_OUT_OF_RESOURCES
;
2812 for (Port
= 0; Port
< EFI_AHCI_MAX_PORTS
; Port
++) {
2813 if ((PortImplementBitMap
& (((UINT32
)BIT0
) << Port
)) != 0) {
2815 // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.
2817 if ((MaxPortNumber
--) == 0) {
2819 // Should never be here.
2825 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBeforeChannelEnumeration
, Port
);
2828 // Initialize FIS Base Address Register and Command List Base Address Register for use.
2830 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFisPciAddr
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
2831 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FB
;
2832 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2833 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FBU
;
2834 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2836 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdListPciAddr
);
2837 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLB
;
2838 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2839 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLBU
;
2840 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2842 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2843 Data
= AhciReadReg (PciIo
, Offset
);
2844 if ((Data
& EFI_AHCI_PORT_CMD_CPD
) != 0) {
2845 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_POD
);
2848 if ((Capability
& EFI_AHCI_CAP_SSS
) != 0) {
2849 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_SUD
);
2853 // Disable aggressive power management.
2855 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
2856 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_INIT
);
2858 // Disable the reporting of the corresponding interrupt to system software.
2860 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IE
;
2861 AhciAndReg (PciIo
, Offset
, 0);
2864 // Now inform the IDE Controller Init Module.
2866 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBusBeforeDevicePresenceDetection
, Port
);
2869 // Enable FIS Receive DMA engine for the first D2H FIS.
2871 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2872 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
2875 // Wait for the Phy to detect the presence of a device.
2877 PhyDetectDelay
= EFI_AHCI_BUS_PHY_DETECT_TIMEOUT
;
2878 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
2880 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
2881 if ((Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) || (Data
== EFI_AHCI_PORT_SSTS_DET
)) {
2885 MicroSecondDelay (1000);
2887 } while (PhyDetectDelay
> 0);
2889 if (PhyDetectDelay
== 0) {
2891 // No device detected at this port.
2892 // Clear PxCMD.SUD for those ports at which there are no device present.
2894 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2895 AhciAndReg (PciIo
, Offset
, (UINT32
) ~(EFI_AHCI_PORT_CMD_SUD
));
2899 Status
= AhciWaitDeviceReady (PciIo
, Port
);
2900 if (EFI_ERROR (Status
)) {
2905 // When the first D2H register FIS is received, the content of PxSIG register is updated.
2907 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SIG
;
2908 Status
= AhciWaitMmioSet (
2913 EFI_TIMER_PERIOD_SECONDS(16)
2915 if (EFI_ERROR (Status
)) {
2919 Data
= AhciReadReg (PciIo
, Offset
);
2920 if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATAPI_DEVICE_SIG
) {
2921 Status
= AhciIdentifyPacket (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2923 if (EFI_ERROR (Status
)) {
2927 DeviceType
= EfiIdeCdrom
;
2928 } else if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATA_DEVICE_SIG
) {
2929 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2931 if (EFI_ERROR (Status
)) {
2932 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_PERIPHERAL_FIXED_MEDIA
| EFI_P_EC_NOT_DETECTED
));
2937 DEBUG_INFO
, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
2938 Buffer
.AtaData
.config
, Buffer
.AtaData
.specific_config
,
2939 Buffer
.AtaData
.command_set_supported_83
, Buffer
.AtaData
.command_set_feature_enb_86
2941 if ((Buffer
.AtaData
.config
& BIT2
) != 0) {
2943 // SpinUp disk if device reported incomplete IDENTIFY DEVICE.
2945 Status
= AhciSpinUpDisk (
2952 if (EFI_ERROR (Status
)) {
2953 DEBUG ((DEBUG_ERROR
, "Spin up standby device failed - %r\n", Status
));
2958 DeviceType
= EfiIdeHarddisk
;
2962 DEBUG ((DEBUG_INFO
, "port [%d] port multitplier [%d] has a [%a]\n",
2963 Port
, 0, DeviceType
== EfiIdeCdrom
? "cdrom" : "harddisk"));
2966 // If the device is a hard disk, then try to enable S.M.A.R.T feature
2968 if ((DeviceType
== EfiIdeHarddisk
) && PcdGetBool (PcdAtaSmartEnable
)) {
2969 AhciAtaSmartSupport (
2980 // Submit identify data to IDE controller init driver
2982 IdeInit
->SubmitData (IdeInit
, Port
, 0, &Buffer
);
2985 // Now start to config ide device parameter and transfer mode.
2987 Status
= IdeInit
->CalculateMode (
2993 if (EFI_ERROR (Status
)) {
2994 DEBUG ((EFI_D_ERROR
, "Calculate Mode Fail, Status = %r\n", Status
));
2999 // Set best supported PIO mode on this IDE device
3001 if (SupportedModes
->PioMode
.Mode
<= EfiAtaPioMode2
) {
3002 TransferMode
.ModeCategory
= EFI_ATA_MODE_DEFAULT_PIO
;
3004 TransferMode
.ModeCategory
= EFI_ATA_MODE_FLOW_PIO
;
3007 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->PioMode
.Mode
);
3010 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA can't
3011 // be set together. Only one DMA mode can be set to a device. If setting
3012 // DMA mode operation fails, we can continue moving on because we only use
3013 // PIO mode at boot time. DMA modes are used by certain kind of OS booting
3015 if (SupportedModes
->UdmaMode
.Valid
) {
3016 TransferMode
.ModeCategory
= EFI_ATA_MODE_UDMA
;
3017 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->UdmaMode
.Mode
);
3018 } else if (SupportedModes
->MultiWordDmaMode
.Valid
) {
3019 TransferMode
.ModeCategory
= EFI_ATA_MODE_MDMA
;
3020 TransferMode
.ModeNumber
= (UINT8
) SupportedModes
->MultiWordDmaMode
.Mode
;
3023 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, 0, 0x03, (UINT32
)(*(UINT8
*)&TransferMode
), ATA_ATAPI_TIMEOUT
);
3024 if (EFI_ERROR (Status
)) {
3025 DEBUG ((EFI_D_ERROR
, "Set transfer Mode Fail, Status = %r\n", Status
));
3030 // Found a ATA or ATAPI device, add it into the device list.
3032 CreateNewDeviceInfo (Instance
, Port
, 0xFFFF, DeviceType
, &Buffer
);
3033 if (DeviceType
== EfiIdeHarddisk
) {
3034 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_PERIPHERAL_FIXED_MEDIA
| EFI_P_PC_ENABLE
));
3045 // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).
3047 if ((Buffer
.AtaData
.command_set_supported_83
& BIT5
) != 0) {
3048 Status
= AhciPuisEnable (
3054 if (EFI_ERROR (Status
)) {
3055 DEBUG ((DEBUG_ERROR
, "PUIS enable/disable failed, Status = %r\n", Status
));