2 The file for AHCI mode of ATA host controller.
4 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 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 sytem 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.
254 @param[in, out] Task Optional. Pointer to the ATA_NONBLOCK_TASK used by
255 non-blocking mode. If NULL, then just try once.
257 @retval EFI_NOTREADY The memory is not set.
258 @retval EFI_TIMEOUT The memory setting retry times out.
259 @retval EFI_SUCCESS The memory is correct set.
268 IN OUT ATA_NONBLOCK_TASK
*Task
277 Value
= *(volatile UINT32
*) Address
;
280 if (Value
== TestValue
) {
284 if ((Task
!= NULL
) && !Task
->InfiniteWait
&& (Task
->RetryTimes
== 0)) {
287 return EFI_NOT_READY
;
294 Clear the port interrupt and error status. It will also clear
295 HBA interrupt status.
297 @param PciIo The PCI IO protocol instance.
298 @param Port The number of port.
303 AhciClearPortStatus (
304 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
311 // Clear any error status
313 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
314 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
317 // Clear any port interrupt status
319 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IS
;
320 AhciWriteReg (PciIo
, Offset
, AhciReadReg (PciIo
, Offset
));
323 // Clear any HBA interrupt status
325 AhciWriteReg (PciIo
, EFI_AHCI_IS_OFFSET
, AhciReadReg (PciIo
, EFI_AHCI_IS_OFFSET
));
329 This function is used to dump the Status Registers and if there is ERR bit set
330 in the Status Register, the Error Register's value is also be dumped.
332 @param PciIo The PCI IO protocol instance.
333 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
334 @param Port The number of port.
335 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
341 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
342 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
344 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
352 ASSERT (PciIo
!= NULL
);
354 if (AtaStatusBlock
!= NULL
) {
355 ZeroMem (AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
357 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
358 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
360 Status
= AhciCheckMemSet (Offset
, EFI_AHCI_FIS_TYPE_MASK
, EFI_AHCI_FIS_REGISTER_D2H
, NULL
);
361 if (!EFI_ERROR (Status
)) {
363 // If D2H FIS is received, update StatusBlock with its content.
365 CopyMem (AtaStatusBlock
, (UINT8
*)Offset
, sizeof (EFI_ATA_STATUS_BLOCK
));
368 // If D2H FIS is not received, only update Status & Error field through PxTFD
369 // as there is no other way to get the content of the Shadow Register Block.
371 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
372 Data
= AhciReadReg (PciIo
, (UINT32
)Offset
);
374 AtaStatusBlock
->AtaStatus
= (UINT8
)Data
;
375 if ((AtaStatusBlock
->AtaStatus
& BIT0
) != 0) {
376 AtaStatusBlock
->AtaError
= (UINT8
)(Data
>> 8);
384 Enable the FIS running for giving port.
386 @param PciIo The PCI IO protocol instance.
387 @param Port The number of port.
388 @param Timeout The timeout value of enabling FIS, uses 100ns as a unit.
390 @retval EFI_DEVICE_ERROR The FIS enable setting fails.
391 @retval EFI_TIMEOUT The FIS enable setting is time out.
392 @retval EFI_SUCCESS The FIS enable successfully.
397 AhciEnableFisReceive (
398 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
405 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
406 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
412 Disable the FIS running for giving port.
414 @param PciIo The PCI IO protocol instance.
415 @param Port The number of port.
416 @param Timeout The timeout value of disabling FIS, uses 100ns as a unit.
418 @retval EFI_DEVICE_ERROR The FIS disable setting fails.
419 @retval EFI_TIMEOUT The FIS disable setting is time out.
420 @retval EFI_UNSUPPORTED The port is in running state.
421 @retval EFI_SUCCESS The FIS disable successfully.
426 AhciDisableFisReceive (
427 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
435 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
436 Data
= AhciReadReg (PciIo
, Offset
);
439 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
441 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) != 0) {
442 return EFI_UNSUPPORTED
;
446 // Check if the Fis receive DMA engine for the port is running.
448 if ((Data
& EFI_AHCI_PORT_CMD_FR
) != EFI_AHCI_PORT_CMD_FR
) {
452 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_FRE
));
454 return AhciWaitMmioSet (
457 EFI_AHCI_PORT_CMD_FR
,
466 Build the command list, command table and prepare the fis receiver.
468 @param PciIo The PCI IO protocol instance.
469 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
470 @param Port The number of port.
471 @param PortMultiplier The timeout value of stop.
472 @param CommandFis The control fis will be used for the transfer.
473 @param CommandList The command list will be used for the transfer.
474 @param AtapiCommand The atapi command will be used for the transfer.
475 @param AtapiCommandLength The length of the atapi command.
476 @param CommandSlotNumber The command slot will be used for the transfer.
477 @param DataPhysicalAddr The pointer to the data buffer pci bus master address.
478 @param DataLength The data count to be transferred.
484 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
485 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
487 IN UINT8 PortMultiplier
,
488 IN EFI_AHCI_COMMAND_FIS
*CommandFis
,
489 IN EFI_AHCI_COMMAND_LIST
*CommandList
,
490 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
491 IN UINT8 AtapiCommandLength
,
492 IN UINT8 CommandSlotNumber
,
493 IN OUT VOID
*DataPhysicalAddr
,
508 PrdtNumber
= (UINT32
)DivU64x32 (((UINT64
)DataLength
+ EFI_AHCI_MAX_DATA_PER_PRDT
- 1), EFI_AHCI_MAX_DATA_PER_PRDT
);
511 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
512 // It also limits that the maximum amount of the PRDT entry in the command table
515 ASSERT (PrdtNumber
<= 65535);
517 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFis
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
519 BaseAddr
= Data64
.Uint64
;
521 ZeroMem ((VOID
*)((UINTN
) BaseAddr
), sizeof (EFI_AHCI_RECEIVED_FIS
));
523 ZeroMem (AhciRegisters
->AhciCommandTable
, sizeof (EFI_AHCI_COMMAND_TABLE
));
525 CommandFis
->AhciCFisPmNum
= PortMultiplier
;
527 CopyMem (&AhciRegisters
->AhciCommandTable
->CommandFis
, CommandFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
529 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
530 if (AtapiCommand
!= NULL
) {
532 &AhciRegisters
->AhciCommandTable
->AtapiCmd
,
537 CommandList
->AhciCmdA
= 1;
538 CommandList
->AhciCmdP
= 1;
540 AhciOrReg (PciIo
, Offset
, (EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
542 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_DLAE
| EFI_AHCI_PORT_CMD_ATAPI
));
545 RemainedData
= (UINTN
) DataLength
;
546 MemAddr
= (UINTN
) DataPhysicalAddr
;
547 CommandList
->AhciCmdPrdtl
= PrdtNumber
;
549 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
550 if (RemainedData
< EFI_AHCI_MAX_DATA_PER_PRDT
) {
551 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= (UINT32
)RemainedData
- 1;
553 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbc
= EFI_AHCI_MAX_DATA_PER_PRDT
- 1;
556 Data64
.Uint64
= (UINT64
)MemAddr
;
557 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDba
= Data64
.Uint32
.Lower32
;
558 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtIndex
].AhciPrdtDbau
= Data64
.Uint32
.Upper32
;
559 RemainedData
-= EFI_AHCI_MAX_DATA_PER_PRDT
;
560 MemAddr
+= EFI_AHCI_MAX_DATA_PER_PRDT
;
564 // Set the last PRDT to Interrupt On Complete
566 if (PrdtNumber
> 0) {
567 AhciRegisters
->AhciCommandTable
->PrdtTable
[PrdtNumber
- 1].AhciPrdtIoc
= 1;
571 (VOID
*) ((UINTN
) AhciRegisters
->AhciCmdList
+ (UINTN
) CommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
)),
573 sizeof (EFI_AHCI_COMMAND_LIST
)
576 Data64
.Uint64
= (UINT64
)(UINTN
) AhciRegisters
->AhciCommandTablePciAddr
;
577 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtba
= Data64
.Uint32
.Lower32
;
578 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdCtbau
= Data64
.Uint32
.Upper32
;
579 AhciRegisters
->AhciCmdList
[CommandSlotNumber
].AhciCmdPmp
= PortMultiplier
;
586 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.
587 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.
592 AhciBuildCommandFis (
593 IN OUT EFI_AHCI_COMMAND_FIS
*CmdFis
,
594 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
597 ZeroMem (CmdFis
, sizeof (EFI_AHCI_COMMAND_FIS
));
599 CmdFis
->AhciCFisType
= EFI_AHCI_FIS_REGISTER_H2D
;
601 // Indicator it's a command
603 CmdFis
->AhciCFisCmdInd
= 0x1;
604 CmdFis
->AhciCFisCmd
= AtaCommandBlock
->AtaCommand
;
606 CmdFis
->AhciCFisFeature
= AtaCommandBlock
->AtaFeatures
;
607 CmdFis
->AhciCFisFeatureExp
= AtaCommandBlock
->AtaFeaturesExp
;
609 CmdFis
->AhciCFisSecNum
= AtaCommandBlock
->AtaSectorNumber
;
610 CmdFis
->AhciCFisSecNumExp
= AtaCommandBlock
->AtaSectorNumberExp
;
612 CmdFis
->AhciCFisClyLow
= AtaCommandBlock
->AtaCylinderLow
;
613 CmdFis
->AhciCFisClyLowExp
= AtaCommandBlock
->AtaCylinderLowExp
;
615 CmdFis
->AhciCFisClyHigh
= AtaCommandBlock
->AtaCylinderHigh
;
616 CmdFis
->AhciCFisClyHighExp
= AtaCommandBlock
->AtaCylinderHighExp
;
618 CmdFis
->AhciCFisSecCount
= AtaCommandBlock
->AtaSectorCount
;
619 CmdFis
->AhciCFisSecCountExp
= AtaCommandBlock
->AtaSectorCountExp
;
621 CmdFis
->AhciCFisDevHead
= (UINT8
) (AtaCommandBlock
->AtaDeviceHead
| 0xE0);
625 Start a PIO data transfer on specific port.
627 @param[in] PciIo The PCI IO protocol instance.
628 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
629 @param[in] Port The number of port.
630 @param[in] PortMultiplier The timeout value of stop.
631 @param[in] AtapiCommand The atapi command will be used for the
633 @param[in] AtapiCommandLength The length of the atapi command.
634 @param[in] Read The transfer direction.
635 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
636 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
637 @param[in, out] MemoryAddr The pointer to the data buffer.
638 @param[in] DataCount The data count to be transferred.
639 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
640 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
641 used by non-blocking mode.
643 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
644 @retval EFI_TIMEOUT The operation is time out.
645 @retval EFI_UNSUPPORTED The device is not ready for transfer.
646 @retval EFI_SUCCESS The PIO data transfer executes successfully.
652 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
653 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
655 IN UINT8 PortMultiplier
,
656 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
657 IN UINT8 AtapiCommandLength
,
659 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
660 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
661 IN OUT VOID
*MemoryAddr
,
664 IN ATA_NONBLOCK_TASK
*Task
670 EFI_PHYSICAL_ADDRESS PhyAddr
;
673 EFI_PCI_IO_PROTOCOL_OPERATION Flag
;
675 EFI_AHCI_COMMAND_FIS CFis
;
676 EFI_AHCI_COMMAND_LIST CmdList
;
679 BOOLEAN InfiniteWait
;
680 BOOLEAN PioFisReceived
;
681 BOOLEAN D2hFisReceived
;
686 InfiniteWait
= FALSE
;
690 Flag
= EfiPciIoOperationBusMasterWrite
;
692 Flag
= EfiPciIoOperationBusMasterRead
;
696 // construct command list and command table with pci bus address
698 MapLength
= DataCount
;
699 Status
= PciIo
->Map (
708 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
709 return EFI_BAD_BUFFER_SIZE
;
713 // Package read needed
715 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
717 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
719 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
720 CmdList
.AhciCmdW
= Read
? 0 : 1;
732 (VOID
*)(UINTN
)PhyAddr
,
736 Status
= AhciStartCommand (
742 if (EFI_ERROR (Status
)) {
747 // Check the status and wait the driver sending data
749 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
751 if (Read
&& (AtapiCommand
== 0)) {
753 // Wait device sends the PIO setup fis before data transfer
755 Status
= EFI_TIMEOUT
;
756 Delay
= DivU64x32 (Timeout
, 1000) + 1;
758 PioFisReceived
= FALSE
;
759 D2hFisReceived
= FALSE
;
760 Offset
= FisBaseAddr
+ EFI_AHCI_PIO_FIS_OFFSET
;
761 Status
= AhciCheckMemSet (Offset
, EFI_AHCI_FIS_TYPE_MASK
, EFI_AHCI_FIS_PIO_SETUP
, NULL
);
762 if (!EFI_ERROR (Status
)) {
763 PioFisReceived
= TRUE
;
766 // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
767 // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device
768 // after the transaction is finished successfully.
769 // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.
770 // By this way, we can know if there is a real error happened.
772 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
773 Status
= AhciCheckMemSet (Offset
, EFI_AHCI_FIS_TYPE_MASK
, EFI_AHCI_FIS_REGISTER_D2H
, NULL
);
774 if (!EFI_ERROR (Status
)) {
775 D2hFisReceived
= TRUE
;
778 if (PioFisReceived
|| D2hFisReceived
) {
779 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
780 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
782 // PxTFD will be updated if there is a D2H or SetupFIS received.
784 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
785 Status
= EFI_DEVICE_ERROR
;
789 PrdCount
= *(volatile UINT32
*) (&(AhciRegisters
->AhciCmdList
[0].AhciCmdPrdbc
));
790 if (PrdCount
== DataCount
) {
791 Status
= EFI_SUCCESS
;
797 // Stall for 100 microseconds.
799 MicroSecondDelay(100);
803 Status
= EFI_TIMEOUT
;
805 } while (InfiniteWait
|| (Delay
> 0));
808 // Wait for D2H Fis is received
810 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
811 Status
= AhciWaitMemSet (
813 EFI_AHCI_FIS_TYPE_MASK
,
814 EFI_AHCI_FIS_REGISTER_D2H
,
818 if (EFI_ERROR (Status
)) {
822 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
823 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
824 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
825 Status
= EFI_DEVICE_ERROR
;
836 AhciDisableFisReceive (
847 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
853 Start a DMA data transfer on specific port
855 @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.
856 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
857 @param[in] Port The number of port.
858 @param[in] PortMultiplier The timeout value of stop.
859 @param[in] AtapiCommand The atapi command will be used for the
861 @param[in] AtapiCommandLength The length of the atapi command.
862 @param[in] Read The transfer direction.
863 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
864 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
865 @param[in, out] MemoryAddr The pointer to the data buffer.
866 @param[in] DataCount The data count to be transferred.
867 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
868 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
869 used by non-blocking mode.
871 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
872 @retval EFI_TIMEOUT The operation is time out.
873 @retval EFI_UNSUPPORTED The device is not ready for transfer.
874 @retval EFI_SUCCESS The DMA data transfer executes successfully.
880 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
,
881 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
883 IN UINT8 PortMultiplier
,
884 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
885 IN UINT8 AtapiCommandLength
,
887 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
888 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
889 IN OUT VOID
*MemoryAddr
,
892 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
;
906 EFI_PCI_IO_PROTOCOL
*PciIo
;
910 PciIo
= Instance
->PciIo
;
913 return EFI_INVALID_PARAMETER
;
917 // Before starting the Blocking BlockIO operation, push to finish all non-blocking
919 // Delay 100us to simulate the blocking time out checking.
921 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
922 while ((Task
== NULL
) && (!IsListEmpty (&Instance
->NonBlockingTaskList
))) {
923 AsyncNonBlockingTransferRoutine (NULL
, Instance
);
927 MicroSecondDelay (100);
929 gBS
->RestoreTPL (OldTpl
);
931 if ((Task
== NULL
) || ((Task
!= NULL
) && (!Task
->IsStart
))) {
933 // Mark the Task to indicate that it has been started.
936 Task
->IsStart
= TRUE
;
939 Flag
= EfiPciIoOperationBusMasterWrite
;
941 Flag
= EfiPciIoOperationBusMasterRead
;
945 // Construct command list and command table with pci bus address.
947 MapLength
= DataCount
;
948 Status
= PciIo
->Map (
957 if (EFI_ERROR (Status
) || (DataCount
!= MapLength
)) {
958 return EFI_BAD_BUFFER_SIZE
;
965 // Package read needed
967 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
969 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
971 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
972 CmdList
.AhciCmdW
= Read
? 0 : 1;
984 (VOID
*)(UINTN
)PhyAddr
,
988 Status
= AhciStartCommand (
994 if (EFI_ERROR (Status
)) {
1000 // Wait for command compelte
1002 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1003 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
1008 Status
= AhciCheckMemSet (
1010 EFI_AHCI_FIS_TYPE_MASK
,
1011 EFI_AHCI_FIS_REGISTER_D2H
,
1015 Status
= AhciWaitMemSet (
1017 EFI_AHCI_FIS_TYPE_MASK
,
1018 EFI_AHCI_FIS_REGISTER_D2H
,
1023 if (EFI_ERROR (Status
)) {
1027 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1028 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
1029 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
1030 Status
= EFI_DEVICE_ERROR
;
1035 // For Blocking mode, the command should be stopped, the Fis should be disabled
1036 // and the PciIo should be unmapped.
1037 // For non-blocking mode, only when a error is happened (if the return status is
1038 // EFI_NOT_READY that means the command doesn't finished, try again.), first do the
1039 // context cleanup, then set the packet's Asb status.
1042 ((Task
!= NULL
) && (Status
!= EFI_NOT_READY
))
1050 AhciDisableFisReceive (
1058 (Task
!= NULL
) ? Task
->Map
: Map
1062 Task
->Packet
->Asb
->AtaStatus
= 0x01;
1066 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1071 Start a non data transfer on specific port.
1073 @param[in] PciIo The PCI IO protocol instance.
1074 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1075 @param[in] Port The number of port.
1076 @param[in] PortMultiplier The timeout value of stop.
1077 @param[in] AtapiCommand The atapi command will be used for the
1079 @param[in] AtapiCommandLength The length of the atapi command.
1080 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
1081 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
1082 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
1083 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
1084 used by non-blocking mode.
1086 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
1087 @retval EFI_TIMEOUT The operation is time out.
1088 @retval EFI_UNSUPPORTED The device is not ready for transfer.
1089 @retval EFI_SUCCESS The non data transfer executes successfully.
1094 AhciNonDataTransfer (
1095 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1096 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1098 IN UINT8 PortMultiplier
,
1099 IN EFI_AHCI_ATAPI_COMMAND
*AtapiCommand OPTIONAL
,
1100 IN UINT8 AtapiCommandLength
,
1101 IN EFI_ATA_COMMAND_BLOCK
*AtaCommandBlock
,
1102 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
,
1104 IN ATA_NONBLOCK_TASK
*Task
1111 EFI_AHCI_COMMAND_FIS CFis
;
1112 EFI_AHCI_COMMAND_LIST CmdList
;
1115 // Package read needed
1117 AhciBuildCommandFis (&CFis
, AtaCommandBlock
);
1119 ZeroMem (&CmdList
, sizeof (EFI_AHCI_COMMAND_LIST
));
1121 CmdList
.AhciCmdCfl
= EFI_AHCI_FIS_REGISTER_H2D_LENGTH
/ 4;
1137 Status
= AhciStartCommand (
1143 if (EFI_ERROR (Status
)) {
1148 // Wait device sends the Response Fis
1150 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1151 Offset
= FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
;
1152 Status
= AhciWaitMemSet (
1154 EFI_AHCI_FIS_TYPE_MASK
,
1155 EFI_AHCI_FIS_REGISTER_D2H
,
1159 if (EFI_ERROR (Status
)) {
1163 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1164 PortTfd
= AhciReadReg (PciIo
, (UINT32
) Offset
);
1165 if ((PortTfd
& EFI_AHCI_PORT_TFD_ERR
) != 0) {
1166 Status
= EFI_DEVICE_ERROR
;
1176 AhciDisableFisReceive (
1182 AhciDumpPortStatus (PciIo
, AhciRegisters
, Port
, AtaStatusBlock
);
1188 Stop command running for giving port
1190 @param PciIo The PCI IO protocol instance.
1191 @param Port The number of port.
1192 @param Timeout The timeout value of stop, uses 100ns as a unit.
1194 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
1195 @retval EFI_TIMEOUT The operation is time out.
1196 @retval EFI_SUCCESS The command stop successfully.
1202 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1210 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1211 Data
= AhciReadReg (PciIo
, Offset
);
1213 if ((Data
& (EFI_AHCI_PORT_CMD_ST
| EFI_AHCI_PORT_CMD_CR
)) == 0) {
1217 if ((Data
& EFI_AHCI_PORT_CMD_ST
) != 0) {
1218 AhciAndReg (PciIo
, Offset
, (UINT32
)~(EFI_AHCI_PORT_CMD_ST
));
1221 return AhciWaitMmioSet (
1224 EFI_AHCI_PORT_CMD_CR
,
1231 Start command for give slot on specific port.
1233 @param PciIo The PCI IO protocol instance.
1234 @param Port The number of port.
1235 @param CommandSlot The number of Command Slot.
1236 @param Timeout The timeout value of start, uses 100ns as a unit.
1238 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
1239 @retval EFI_TIMEOUT The operation is time out.
1240 @retval EFI_SUCCESS The command start successfully.
1246 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1248 IN UINT8 CommandSlot
,
1261 // Collect AHCI controller information
1263 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1265 CmdSlotBit
= (UINT32
) (1 << CommandSlot
);
1267 AhciClearPortStatus (
1272 Status
= AhciEnableFisReceive (
1278 if (EFI_ERROR (Status
)) {
1282 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1283 PortStatus
= AhciReadReg (PciIo
, Offset
);
1286 if ((PortStatus
& EFI_AHCI_PORT_CMD_ALPE
) != 0) {
1287 StartCmd
= AhciReadReg (PciIo
, Offset
);
1288 StartCmd
&= ~EFI_AHCI_PORT_CMD_ICC_MASK
;
1289 StartCmd
|= EFI_AHCI_PORT_CMD_ACTIVE
;
1292 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
1293 PortTfd
= AhciReadReg (PciIo
, Offset
);
1295 if ((PortTfd
& (EFI_AHCI_PORT_TFD_BSY
| EFI_AHCI_PORT_TFD_DRQ
)) != 0) {
1296 if ((Capability
& BIT24
) != 0) {
1297 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1298 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_CLO
);
1303 EFI_AHCI_PORT_CMD_CLO
,
1310 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
1311 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_ST
| StartCmd
);
1314 // Setting the command
1316 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CI
;
1317 AhciAndReg (PciIo
, Offset
, 0);
1318 AhciOrReg (PciIo
, Offset
, CmdSlotBit
);
1327 @param PciIo The PCI IO protocol instance.
1328 @param Timeout The timeout value of reset, uses 100ns as a unit.
1330 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
1331 @retval EFI_TIMEOUT The reset operation is time out.
1332 @retval EFI_SUCCESS AHCI controller is reset successfully.
1338 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1346 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
1348 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1350 if ((Value
& EFI_AHCI_GHC_ENABLE
) == 0) {
1351 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
1354 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_RESET
);
1356 Delay
= DivU64x32(Timeout
, 1000) + 1;
1359 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
1361 if ((Value
& EFI_AHCI_GHC_RESET
) == 0) {
1366 // Stall for 100 microseconds.
1368 MicroSecondDelay(100);
1371 } while (Delay
> 0);
1381 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
1383 @param PciIo The PCI IO protocol instance.
1384 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1385 @param Port The number of port.
1386 @param PortMultiplier The port multiplier port number.
1387 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1389 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
1390 @retval Others Fail to get return status data.
1395 AhciAtaSmartReturnStatusCheck (
1396 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1397 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1399 IN UINT8 PortMultiplier
,
1400 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1404 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1410 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1412 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1413 AtaCommandBlock
.AtaFeatures
= ATA_SMART_RETURN_STATUS
;
1414 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1415 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1418 // Send S.M.A.R.T Read Return Status command to device
1420 Status
= AhciNonDataTransfer (
1424 (UINT8
)PortMultiplier
,
1433 if (EFI_ERROR (Status
)) {
1434 REPORT_STATUS_CODE (
1435 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1436 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_DISABLED
)
1438 return EFI_DEVICE_ERROR
;
1441 REPORT_STATUS_CODE (
1443 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_ENABLE
)
1446 FisBaseAddr
= (UINTN
)AhciRegisters
->AhciRFis
+ Port
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1448 Value
= *(UINT32
*) (FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
);
1450 if ((Value
& EFI_AHCI_FIS_TYPE_MASK
) == EFI_AHCI_FIS_REGISTER_D2H
) {
1451 LBAMid
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[5];
1452 LBAHigh
= ((UINT8
*)(UINTN
)(FisBaseAddr
+ EFI_AHCI_D2H_FIS_OFFSET
))[6];
1454 if ((LBAMid
== 0x4f) && (LBAHigh
== 0xc2)) {
1456 // The threshold exceeded condition is not detected by the device
1458 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
1459 REPORT_STATUS_CODE (
1461 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD
)
1463 } else if ((LBAMid
== 0xf4) && (LBAHigh
== 0x2c)) {
1465 // The threshold exceeded condition is detected by the device
1467 DEBUG ((EFI_D_INFO
, "The S.M.A.R.T threshold exceeded condition is detected\n"));
1468 REPORT_STATUS_CODE (
1470 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD
)
1479 Enable SMART command of the disk if supported.
1481 @param PciIo The PCI IO protocol instance.
1482 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1483 @param Port The number of port.
1484 @param PortMultiplier The port multiplier port number.
1485 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
1486 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
1491 AhciAtaSmartSupport (
1492 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1493 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1495 IN UINT8 PortMultiplier
,
1496 IN EFI_IDENTIFY_DATA
*IdentifyData
,
1497 IN OUT EFI_ATA_STATUS_BLOCK
*AtaStatusBlock
1501 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1504 // Detect if the device supports S.M.A.R.T.
1506 if ((IdentifyData
->AtaData
.command_set_supported_82
& 0x0001) != 0x0001) {
1508 // S.M.A.R.T is not supported by the device
1510 DEBUG ((EFI_D_INFO
, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
1511 Port
, PortMultiplier
));
1512 REPORT_STATUS_CODE (
1513 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1514 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED
)
1518 // Check if the feature is enabled. If not, then enable S.M.A.R.T.
1520 if ((IdentifyData
->AtaData
.command_set_feature_enb_85
& 0x0001) != 0x0001) {
1522 REPORT_STATUS_CODE (
1524 (EFI_IO_BUS_ATA_ATAPI
| EFI_IOB_ATA_BUS_SMART_DISABLE
)
1527 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1529 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1530 AtaCommandBlock
.AtaFeatures
= ATA_SMART_ENABLE_OPERATION
;
1531 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1532 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1535 // Send S.M.A.R.T Enable command to device
1537 Status
= AhciNonDataTransfer (
1541 (UINT8
)PortMultiplier
,
1551 if (!EFI_ERROR (Status
)) {
1553 // Send S.M.A.R.T AutoSave command to device
1555 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1557 AtaCommandBlock
.AtaCommand
= ATA_CMD_SMART
;
1558 AtaCommandBlock
.AtaFeatures
= 0xD2;
1559 AtaCommandBlock
.AtaSectorCount
= 0xF1;
1560 AtaCommandBlock
.AtaCylinderLow
= ATA_CONSTANT_4F
;
1561 AtaCommandBlock
.AtaCylinderHigh
= ATA_CONSTANT_C2
;
1563 Status
= AhciNonDataTransfer (
1567 (UINT8
)PortMultiplier
,
1576 if (!EFI_ERROR (Status
)) {
1577 Status
= AhciAtaSmartReturnStatusCheck (
1581 (UINT8
)PortMultiplier
,
1587 DEBUG ((EFI_D_INFO
, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
1588 Port
, PortMultiplier
));
1595 Send Buffer cmd to specific device.
1597 @param PciIo The PCI IO protocol instance.
1598 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1599 @param Port The number of port.
1600 @param PortMultiplier The port multiplier port number.
1601 @param Buffer The data buffer to store IDENTIFY PACKET data.
1603 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1604 @retval EFI_TIMEOUT The operation is time out.
1605 @retval EFI_UNSUPPORTED The device is not ready for executing.
1606 @retval EFI_SUCCESS The cmd executes successfully.
1612 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1613 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1615 IN UINT8 PortMultiplier
,
1616 IN OUT EFI_IDENTIFY_DATA
*Buffer
1620 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1621 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1623 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
1624 return EFI_INVALID_PARAMETER
;
1627 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1628 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1630 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DRIVE
;
1631 AtaCommandBlock
.AtaSectorCount
= 1;
1633 Status
= AhciPioTransfer (
1644 sizeof (EFI_IDENTIFY_DATA
),
1653 Send Buffer cmd to specific device.
1655 @param PciIo The PCI IO protocol instance.
1656 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1657 @param Port The number of port.
1658 @param PortMultiplier The port multiplier port number.
1659 @param Buffer The data buffer to store IDENTIFY PACKET data.
1661 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1662 @retval EFI_TIMEOUT The operation is time out.
1663 @retval EFI_UNSUPPORTED The device is not ready for executing.
1664 @retval EFI_SUCCESS The cmd executes successfully.
1669 AhciIdentifyPacket (
1670 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1671 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1673 IN UINT8 PortMultiplier
,
1674 IN OUT EFI_IDENTIFY_DATA
*Buffer
1678 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1679 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1681 if (PciIo
== NULL
|| AhciRegisters
== NULL
) {
1682 return EFI_INVALID_PARAMETER
;
1685 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1686 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1688 AtaCommandBlock
.AtaCommand
= ATA_CMD_IDENTIFY_DEVICE
;
1689 AtaCommandBlock
.AtaSectorCount
= 1;
1691 Status
= AhciPioTransfer (
1702 sizeof (EFI_IDENTIFY_DATA
),
1711 Send SET FEATURE cmd on specific device.
1713 @param PciIo The PCI IO protocol instance.
1714 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1715 @param Port The number of port.
1716 @param PortMultiplier The port multiplier port number.
1717 @param Feature The data to send Feature register.
1718 @param FeatureSpecificData The specific data for SET FEATURE cmd.
1719 @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.
1721 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
1722 @retval EFI_TIMEOUT The operation is time out.
1723 @retval EFI_UNSUPPORTED The device is not ready for executing.
1724 @retval EFI_SUCCESS The cmd executes successfully.
1729 AhciDeviceSetFeature (
1730 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1731 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1733 IN UINT8 PortMultiplier
,
1735 IN UINT32 FeatureSpecificData
,
1740 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1741 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1743 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1744 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1746 AtaCommandBlock
.AtaCommand
= ATA_CMD_SET_FEATURES
;
1747 AtaCommandBlock
.AtaFeatures
= (UINT8
) Feature
;
1748 AtaCommandBlock
.AtaFeaturesExp
= (UINT8
) (Feature
>> 8);
1749 AtaCommandBlock
.AtaSectorCount
= (UINT8
) FeatureSpecificData
;
1750 AtaCommandBlock
.AtaSectorNumber
= (UINT8
) (FeatureSpecificData
>> 8);
1751 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (FeatureSpecificData
>> 16);
1752 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (FeatureSpecificData
>> 24);
1754 Status
= AhciNonDataTransfer (
1758 (UINT8
)PortMultiplier
,
1771 This function is used to send out ATAPI commands conforms to the Packet Command
1774 @param PciIo The PCI IO protocol instance.
1775 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1776 @param Port The number of port.
1777 @param PortMultiplier The number of port multiplier.
1778 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
1780 @retval EFI_SUCCESS send out the ATAPI packet command successfully
1781 and device sends data successfully.
1782 @retval EFI_DEVICE_ERROR the device failed to send data.
1787 AhciPacketCommandExecute (
1788 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1789 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
1791 IN UINT8 PortMultiplier
,
1792 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1798 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
1799 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
1802 if (Packet
== NULL
|| Packet
->Cdb
== NULL
) {
1803 return EFI_INVALID_PARAMETER
;
1806 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
1807 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
1808 AtaCommandBlock
.AtaCommand
= ATA_CMD_PACKET
;
1812 AtaCommandBlock
.AtaFeatures
= 0x00;
1814 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
1815 // determine how many data should be transferred.
1817 AtaCommandBlock
.AtaCylinderLow
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
& 0x00ff);
1818 AtaCommandBlock
.AtaCylinderHigh
= (UINT8
) (ATAPI_MAX_BYTE_COUNT
>> 8);
1820 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1821 Buffer
= Packet
->InDataBuffer
;
1822 Length
= Packet
->InTransferLength
;
1825 Buffer
= Packet
->OutDataBuffer
;
1826 Length
= Packet
->OutTransferLength
;
1831 Status
= AhciNonDataTransfer (
1844 Status
= AhciPioTransfer (
1864 Allocate transfer-related data struct which is used at AHCI mode.
1866 @param PciIo The PCI IO protocol instance.
1867 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
1872 AhciCreateTransferDescriptor (
1873 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1874 IN OUT EFI_AHCI_REGISTERS
*AhciRegisters
1882 UINT32 PortImplementBitMap
;
1883 UINT8 MaxPortNumber
;
1884 UINT8 MaxCommandSlotNumber
;
1885 BOOLEAN Support64Bit
;
1886 UINT64 MaxReceiveFisSize
;
1887 UINT64 MaxCommandListSize
;
1888 UINT64 MaxCommandTableSize
;
1889 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr
;
1890 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr
;
1891 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr
;
1895 // Collect AHCI controller information
1897 Capability
= AhciReadReg(PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
1899 // Get the number of command slots per port supported by this HBA.
1901 MaxCommandSlotNumber
= (UINT8
) (((Capability
& 0x1F00) >> 8) + 1);
1902 Support64Bit
= (BOOLEAN
) (((Capability
& BIT31
) != 0) ? TRUE
: FALSE
);
1904 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
1906 // Get the highest bit of implemented ports which decides how many bytes are allocated for recived FIS.
1908 MaxPortNumber
= (UINT8
)(UINTN
)(HighBitSet32(PortImplementBitMap
) + 1);
1909 if (MaxPortNumber
== 0) {
1910 return EFI_DEVICE_ERROR
;
1913 MaxReceiveFisSize
= MaxPortNumber
* sizeof (EFI_AHCI_RECEIVED_FIS
);
1914 Status
= PciIo
->AllocateBuffer (
1917 EfiBootServicesData
,
1918 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
1923 if (EFI_ERROR (Status
)) {
1924 return EFI_OUT_OF_RESOURCES
;
1927 ZeroMem (Buffer
, (UINTN
)MaxReceiveFisSize
);
1929 AhciRegisters
->AhciRFis
= Buffer
;
1930 AhciRegisters
->MaxReceiveFisSize
= MaxReceiveFisSize
;
1931 Bytes
= (UINTN
)MaxReceiveFisSize
;
1933 Status
= PciIo
->Map (
1935 EfiPciIoOperationBusMasterCommonBuffer
,
1939 &AhciRegisters
->MapRFis
1942 if (EFI_ERROR (Status
) || (Bytes
!= MaxReceiveFisSize
)) {
1944 // Map error or unable to map the whole RFis buffer into a contiguous region.
1946 Status
= EFI_OUT_OF_RESOURCES
;
1950 if ((!Support64Bit
) && (AhciRFisPciAddr
> 0x100000000ULL
)) {
1952 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
1954 Status
= EFI_DEVICE_ERROR
;
1957 AhciRegisters
->AhciRFisPciAddr
= (EFI_AHCI_RECEIVED_FIS
*)(UINTN
)AhciRFisPciAddr
;
1960 // Allocate memory for command list
1961 // Note that the implemenation is a single task model which only use a command list for all ports.
1964 MaxCommandListSize
= MaxCommandSlotNumber
* sizeof (EFI_AHCI_COMMAND_LIST
);
1965 Status
= PciIo
->AllocateBuffer (
1968 EfiBootServicesData
,
1969 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
1974 if (EFI_ERROR (Status
)) {
1976 // Free mapped resource.
1978 Status
= EFI_OUT_OF_RESOURCES
;
1982 ZeroMem (Buffer
, (UINTN
)MaxCommandListSize
);
1984 AhciRegisters
->AhciCmdList
= Buffer
;
1985 AhciRegisters
->MaxCommandListSize
= MaxCommandListSize
;
1986 Bytes
= (UINTN
)MaxCommandListSize
;
1988 Status
= PciIo
->Map (
1990 EfiPciIoOperationBusMasterCommonBuffer
,
1993 &AhciCmdListPciAddr
,
1994 &AhciRegisters
->MapCmdList
1997 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandListSize
)) {
1999 // Map error or unable to map the whole cmd list buffer into a contiguous region.
2001 Status
= EFI_OUT_OF_RESOURCES
;
2005 if ((!Support64Bit
) && (AhciCmdListPciAddr
> 0x100000000ULL
)) {
2007 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
2009 Status
= EFI_DEVICE_ERROR
;
2012 AhciRegisters
->AhciCmdListPciAddr
= (EFI_AHCI_COMMAND_LIST
*)(UINTN
)AhciCmdListPciAddr
;
2015 // Allocate memory for command table
2016 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.
2019 MaxCommandTableSize
= sizeof (EFI_AHCI_COMMAND_TABLE
);
2021 Status
= PciIo
->AllocateBuffer (
2024 EfiBootServicesData
,
2025 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
2030 if (EFI_ERROR (Status
)) {
2032 // Free mapped resource.
2034 Status
= EFI_OUT_OF_RESOURCES
;
2038 ZeroMem (Buffer
, (UINTN
)MaxCommandTableSize
);
2040 AhciRegisters
->AhciCommandTable
= Buffer
;
2041 AhciRegisters
->MaxCommandTableSize
= MaxCommandTableSize
;
2042 Bytes
= (UINTN
)MaxCommandTableSize
;
2044 Status
= PciIo
->Map (
2046 EfiPciIoOperationBusMasterCommonBuffer
,
2049 &AhciCommandTablePciAddr
,
2050 &AhciRegisters
->MapCommandTable
2053 if (EFI_ERROR (Status
) || (Bytes
!= MaxCommandTableSize
)) {
2055 // Map error or unable to map the whole cmd list buffer into a contiguous region.
2057 Status
= EFI_OUT_OF_RESOURCES
;
2061 if ((!Support64Bit
) && (AhciCommandTablePciAddr
> 0x100000000ULL
)) {
2063 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
2065 Status
= EFI_DEVICE_ERROR
;
2068 AhciRegisters
->AhciCommandTablePciAddr
= (EFI_AHCI_COMMAND_TABLE
*)(UINTN
)AhciCommandTablePciAddr
;
2072 // Map error or unable to map the whole CmdList buffer into a contiguous region.
2077 AhciRegisters
->MapCommandTable
2082 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandTableSize
),
2083 AhciRegisters
->AhciCommandTable
2088 AhciRegisters
->MapCmdList
2093 EFI_SIZE_TO_PAGES ((UINTN
) MaxCommandListSize
),
2094 AhciRegisters
->AhciCmdList
2099 AhciRegisters
->MapRFis
2104 EFI_SIZE_TO_PAGES ((UINTN
) MaxReceiveFisSize
),
2105 AhciRegisters
->AhciRFis
2112 Read logs from SATA device.
2114 @param PciIo The PCI IO protocol instance.
2115 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2116 @param Port The number of port.
2117 @param PortMultiplier The multiplier of port.
2118 @param Buffer The data buffer to store SATA logs.
2119 @param LogNumber The address of the log.
2120 @param PageNumber The page number of the log.
2122 @retval EFI_INVALID_PARAMETER PciIo, AhciRegisters or Buffer is NULL.
2123 @retval others Return status of AhciPioTransfer().
2127 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2128 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2130 IN UINT8 PortMultiplier
,
2131 IN OUT UINT8
*Buffer
,
2136 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2137 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2139 if (PciIo
== NULL
|| AhciRegisters
== NULL
|| Buffer
== NULL
) {
2140 return EFI_INVALID_PARAMETER
;
2144 /// Read log from device
2146 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2147 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2148 ZeroMem (Buffer
, 512);
2150 AtaCommandBlock
.AtaCommand
= ATA_CMD_READ_LOG_EXT
;
2151 AtaCommandBlock
.AtaSectorCount
= 1;
2152 AtaCommandBlock
.AtaSectorNumber
= LogNumber
;
2153 AtaCommandBlock
.AtaCylinderLow
= PageNumber
;
2155 return AhciPioTransfer (
2173 Enable DEVSLP of the disk if supported.
2175 @param PciIo The PCI IO protocol instance.
2176 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2177 @param Port The number of port.
2178 @param PortMultiplier The multiplier of port.
2179 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
2181 @retval EFI_SUCCESS The DEVSLP is enabled per policy successfully.
2182 @retval EFI_UNSUPPORTED The DEVSLP isn't supported by the controller/device and policy requires to enable it.
2186 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2187 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2189 IN UINT8 PortMultiplier
,
2190 IN EFI_IDENTIFY_DATA
*IdentifyData
2197 DEVSLP_TIMING_VARIABLES DevSlpTiming
;
2201 if (mAtaAtapiPolicy
->DeviceSleepEnable
!= 1) {
2206 // Do not enable DevSlp if DevSlp is not supported.
2208 Capability2
= AhciReadReg (PciIo
, AHCI_CAPABILITY2_OFFSET
);
2209 DEBUG ((DEBUG_INFO
, "AHCI CAPABILITY2 = %08x\n", Capability2
));
2210 if ((Capability2
& AHCI_CAP2_SDS
) == 0) {
2211 return EFI_UNSUPPORTED
;
2215 // Do not enable DevSlp if DevSlp is not present
2216 // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported
2218 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
;
2219 PortCmd
= AhciReadReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
);
2220 PortDevSlp
= AhciReadReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
);
2221 DEBUG ((DEBUG_INFO
, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd
, PortDevSlp
));
2222 if (((PortDevSlp
& AHCI_PORT_DEVSLP_DSP
) == 0) ||
2223 ((PortCmd
& (EFI_AHCI_PORT_CMD_HPCP
| EFI_AHCI_PORT_CMD_MPSP
)) != 0)
2225 return EFI_UNSUPPORTED
;
2229 // Do not enable DevSlp if the device doesn't support DevSlp
2231 DEBUG ((DEBUG_INFO
, "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",
2232 IdentifyData
->AtaData
.reserved_77
,
2233 IdentifyData
->AtaData
.serial_ata_features_supported
, IdentifyData
->AtaData
.serial_ata_features_enabled
));
2234 if ((IdentifyData
->AtaData
.serial_ata_features_supported
& BIT8
) == 0) {
2235 DEBUG ((DEBUG_INFO
, "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",
2236 Port
, PortMultiplier
));
2237 return EFI_UNSUPPORTED
;
2241 // Enable DevSlp when it is not enabled.
2243 if ((IdentifyData
->AtaData
.serial_ata_features_enabled
& BIT8
) != 0) {
2244 Status
= AhciDeviceSetFeature (
2245 PciIo
, AhciRegisters
, Port
, 0, ATA_SUB_CMD_ENABLE_SATA_FEATURE
, 0x09, ATA_ATAPI_TIMEOUT
2247 DEBUG ((DEBUG_INFO
, "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",
2248 Port
, PortMultiplier
, Status
));
2249 if (EFI_ERROR (Status
)) {
2254 Status
= AhciReadLogExt(PciIo
, AhciRegisters
, Port
, PortMultiplier
, LogData
, 0x30, 0x08);
2257 // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.
2259 AhciWriteReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
, PortCmd
& ~EFI_AHCI_PORT_CMD_ST
);
2260 PortDevSlp
&= ~AHCI_PORT_DEVSLP_ADSE
;
2261 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2264 // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.
2266 PortDevSlp
&= ~AHCI_PORT_DEVSLP_DETO_MASK
;
2267 PortDevSlp
&= ~AHCI_PORT_DEVSLP_MDAT_MASK
;
2268 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2269 DEBUG ((DEBUG_INFO
, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port
, PortMultiplier
, Status
));
2270 if (EFI_ERROR (Status
)) {
2272 // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails
2274 ZeroMem (&DevSlpTiming
, sizeof (DevSlpTiming
));
2276 CopyMem (&DevSlpTiming
, &LogData
[48], sizeof (DevSlpTiming
));
2277 DEBUG ((DEBUG_INFO
, "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",
2278 DevSlpTiming
.Supported
, DevSlpTiming
.Deto
, DevSlpTiming
.Madt
));
2282 // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.
2284 if ((DevSlpTiming
.Supported
== 0) || (DevSlpTiming
.Deto
== 0)) {
2285 DevSlpTiming
.Deto
= 20;
2289 // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.
2291 if ((DevSlpTiming
.Supported
== 0) || (DevSlpTiming
.Madt
== 0)) {
2292 DevSlpTiming
.Madt
= 10;
2295 PortDevSlp
|= DevSlpTiming
.Deto
<< 2;
2296 PortDevSlp
|= DevSlpTiming
.Madt
<< 10;
2297 AhciOrReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2299 if (mAtaAtapiPolicy
->AggressiveDeviceSleepEnable
== 1) {
2300 if ((Capability2
& AHCI_CAP2_SADM
) != 0) {
2301 PortDevSlp
&= ~AHCI_PORT_DEVSLP_DITO_MASK
;
2302 PortDevSlp
|= (625 << 15);
2303 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2305 PortDevSlp
|= AHCI_PORT_DEVSLP_ADSE
;
2306 AhciWriteReg (PciIo
, Offset
+ AHCI_PORT_DEVSLP
, PortDevSlp
);
2311 AhciWriteReg (PciIo
, Offset
+ EFI_AHCI_PORT_CMD
, PortCmd
);
2313 DEBUG ((DEBUG_INFO
, "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",
2314 Port
, PortMultiplier
, PortCmd
, PortDevSlp
));
2320 Spin-up disk if IDD was incomplete or PUIS feature is enabled
2322 @param PciIo The PCI IO protocol instance.
2323 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2324 @param Port The number of port.
2325 @param PortMultiplier The multiplier of port.
2326 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
2331 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2332 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2334 IN UINT8 PortMultiplier
,
2335 IN OUT EFI_IDENTIFY_DATA
*IdentifyData
2339 EFI_ATA_COMMAND_BLOCK AtaCommandBlock
;
2340 EFI_ATA_STATUS_BLOCK AtaStatusBlock
;
2343 if (IdentifyData
->AtaData
.specific_config
== ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE
) {
2345 // Use SET_FEATURE subcommand to spin up the device.
2347 Status
= AhciDeviceSetFeature (
2348 PciIo
, AhciRegisters
, Port
, PortMultiplier
,
2349 ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP
, 0x00, ATA_SPINUP_TIMEOUT
2351 DEBUG ((DEBUG_INFO
, "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",
2352 Port
, PortMultiplier
, Status
));
2353 if (EFI_ERROR (Status
)) {
2357 ASSERT (IdentifyData
->AtaData
.specific_config
== ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE
);
2360 // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported
2362 ZeroMem (&AtaCommandBlock
, sizeof (EFI_ATA_COMMAND_BLOCK
));
2363 ZeroMem (&AtaStatusBlock
, sizeof (EFI_ATA_STATUS_BLOCK
));
2365 // Perform READ SECTORS PIO Data-In command to Read LBA 0
2367 AtaCommandBlock
.AtaCommand
= ATA_CMD_READ_SECTORS
;
2368 AtaCommandBlock
.AtaSectorCount
= 0x1;
2370 Status
= AhciPioTransfer (
2385 DEBUG ((DEBUG_INFO
, "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",
2386 Port
, PortMultiplier
, Status
));
2387 if (EFI_ERROR (Status
)) {
2393 // Read the complete IDENTIFY DEVICE data.
2395 ZeroMem (IdentifyData
, sizeof (*IdentifyData
));
2396 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, PortMultiplier
, IdentifyData
);
2397 if (EFI_ERROR (Status
)) {
2398 DEBUG ((DEBUG_ERROR
, "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",
2399 Port
, PortMultiplier
, Status
));
2403 DEBUG ((DEBUG_INFO
, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
2404 IdentifyData
->AtaData
.config
, IdentifyData
->AtaData
.specific_config
,
2405 IdentifyData
->AtaData
.command_set_supported_83
, IdentifyData
->AtaData
.command_set_feature_enb_86
));
2407 // Check if IDD is incomplete
2409 if ((IdentifyData
->AtaData
.config
& BIT2
) != 0) {
2410 return EFI_DEVICE_ERROR
;
2417 Enable/disable/skip PUIS of the disk according to policy.
2419 @param PciIo The PCI IO protocol instance.
2420 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
2421 @param Port The number of port.
2422 @param PortMultiplier The multiplier of port.
2427 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2428 IN EFI_AHCI_REGISTERS
*AhciRegisters
,
2430 IN UINT8 PortMultiplier
2435 Status
= EFI_SUCCESS
;
2436 if (mAtaAtapiPolicy
->PuisEnable
== 0) {
2437 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, PortMultiplier
, ATA_SUB_CMD_DISABLE_PUIS
, 0x00, ATA_ATAPI_TIMEOUT
);
2438 } else if (mAtaAtapiPolicy
->PuisEnable
== 1) {
2439 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, PortMultiplier
, ATA_SUB_CMD_ENABLE_PUIS
, 0x00, ATA_ATAPI_TIMEOUT
);
2441 DEBUG ((DEBUG_INFO
, "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",
2442 (mAtaAtapiPolicy
->PuisEnable
== 0) ? "Disable" : (
2443 (mAtaAtapiPolicy
->PuisEnable
== 1) ? "Enable" : "Skip"
2444 ), Port
, PortMultiplier
, Status
));
2449 Initialize ATA host controller at AHCI mode.
2451 The function is designed to initialize ATA host controller.
2453 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
2458 AhciModeInitialization (
2459 IN ATA_ATAPI_PASS_THRU_INSTANCE
*Instance
2463 EFI_PCI_IO_PROTOCOL
*PciIo
;
2464 EFI_IDE_CONTROLLER_INIT_PROTOCOL
*IdeInit
;
2466 UINT8 MaxPortNumber
;
2467 UINT32 PortImplementBitMap
;
2469 EFI_AHCI_REGISTERS
*AhciRegisters
;
2475 EFI_IDENTIFY_DATA Buffer
;
2476 EFI_ATA_DEVICE_TYPE DeviceType
;
2477 EFI_ATA_COLLECTIVE_MODE
*SupportedModes
;
2478 EFI_ATA_TRANSFER_MODE TransferMode
;
2479 UINT32 PhyDetectDelay
;
2482 if (Instance
== NULL
) {
2483 return EFI_INVALID_PARAMETER
;
2486 PciIo
= Instance
->PciIo
;
2487 IdeInit
= Instance
->IdeControllerInit
;
2489 Status
= AhciReset (PciIo
, EFI_AHCI_BUS_RESET_TIMEOUT
);
2491 if (EFI_ERROR (Status
)) {
2492 return EFI_DEVICE_ERROR
;
2496 // Collect AHCI controller information
2498 Capability
= AhciReadReg (PciIo
, EFI_AHCI_CAPABILITY_OFFSET
);
2501 // Make sure that GHC.AE bit is set before accessing any AHCI registers.
2503 Value
= AhciReadReg(PciIo
, EFI_AHCI_GHC_OFFSET
);
2505 if ((Value
& EFI_AHCI_GHC_ENABLE
) == 0) {
2506 AhciOrReg (PciIo
, EFI_AHCI_GHC_OFFSET
, EFI_AHCI_GHC_ENABLE
);
2510 // Enable 64-bit DMA support in the PCI layer if this controller
2513 if ((Capability
& EFI_AHCI_CAP_S64A
) != 0) {
2514 Status
= PciIo
->Attributes (
2516 EfiPciIoAttributeOperationEnable
,
2517 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
,
2520 if (EFI_ERROR (Status
)) {
2522 "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",
2528 // Get the number of command slots per port supported by this HBA.
2530 MaxPortNumber
= (UINT8
) ((Capability
& 0x1F) + 1);
2533 // Get the bit map of those ports exposed by this HBA.
2534 // It indicates which ports that the HBA supports are available for software to use.
2536 PortImplementBitMap
= AhciReadReg(PciIo
, EFI_AHCI_PI_OFFSET
);
2538 AhciRegisters
= &Instance
->AhciRegisters
;
2539 Status
= AhciCreateTransferDescriptor (PciIo
, AhciRegisters
);
2541 if (EFI_ERROR (Status
)) {
2542 return EFI_OUT_OF_RESOURCES
;
2545 for (Port
= 0; Port
< EFI_AHCI_MAX_PORTS
; Port
++) {
2546 if ((PortImplementBitMap
& (((UINT32
)BIT0
) << Port
)) != 0) {
2548 // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.
2550 if ((MaxPortNumber
--) == 0) {
2552 // Should never be here.
2558 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBeforeChannelEnumeration
, Port
);
2561 // Initialize FIS Base Address Register and Command List Base Address Register for use.
2563 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciRFisPciAddr
) + sizeof (EFI_AHCI_RECEIVED_FIS
) * Port
;
2564 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FB
;
2565 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2566 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_FBU
;
2567 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2569 Data64
.Uint64
= (UINTN
) (AhciRegisters
->AhciCmdListPciAddr
);
2570 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLB
;
2571 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Lower32
);
2572 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CLBU
;
2573 AhciWriteReg (PciIo
, Offset
, Data64
.Uint32
.Upper32
);
2575 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2576 Data
= AhciReadReg (PciIo
, Offset
);
2577 if ((Data
& EFI_AHCI_PORT_CMD_CPD
) != 0) {
2578 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_POD
);
2581 if ((Capability
& EFI_AHCI_CAP_SSS
) != 0) {
2582 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_SUD
);
2586 // Disable aggressive power management.
2588 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SCTL
;
2589 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_SCTL_IPM_INIT
);
2591 // Disable the reporting of the corresponding interrupt to system software.
2593 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_IE
;
2594 AhciAndReg (PciIo
, Offset
, 0);
2597 // Now inform the IDE Controller Init Module.
2599 IdeInit
->NotifyPhase (IdeInit
, EfiIdeBusBeforeDevicePresenceDetection
, Port
);
2602 // Enable FIS Receive DMA engine for the first D2H FIS.
2604 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2605 AhciOrReg (PciIo
, Offset
, EFI_AHCI_PORT_CMD_FRE
);
2608 // Wait for the Phy to detect the presence of a device.
2610 PhyDetectDelay
= EFI_AHCI_BUS_PHY_DETECT_TIMEOUT
;
2611 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SSTS
;
2613 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_SSTS_DET_MASK
;
2614 if ((Data
== EFI_AHCI_PORT_SSTS_DET_PCE
) || (Data
== EFI_AHCI_PORT_SSTS_DET
)) {
2618 MicroSecondDelay (1000);
2620 } while (PhyDetectDelay
> 0);
2622 if (PhyDetectDelay
== 0) {
2624 // No device detected at this port.
2625 // Clear PxCMD.SUD for those ports at which there are no device present.
2627 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_CMD
;
2628 AhciAndReg (PciIo
, Offset
, (UINT32
) ~(EFI_AHCI_PORT_CMD_SUD
));
2633 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
2634 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
2636 PhyDetectDelay
= 16 * 1000;
2638 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SERR
;
2639 if (AhciReadReg(PciIo
, Offset
) != 0) {
2640 AhciWriteReg (PciIo
, Offset
, AhciReadReg(PciIo
, Offset
));
2642 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_TFD
;
2644 Data
= AhciReadReg (PciIo
, Offset
) & EFI_AHCI_PORT_TFD_MASK
;
2649 MicroSecondDelay (1000);
2651 } while (PhyDetectDelay
> 0);
2653 if (PhyDetectDelay
== 0) {
2654 DEBUG ((EFI_D_ERROR
, "Port %d Device presence detected but phy not ready (TFD=0x%X)\n", Port
, Data
));
2659 // When the first D2H register FIS is received, the content of PxSIG register is updated.
2661 Offset
= EFI_AHCI_PORT_START
+ Port
* EFI_AHCI_PORT_REG_WIDTH
+ EFI_AHCI_PORT_SIG
;
2662 Status
= AhciWaitMmioSet (
2667 EFI_TIMER_PERIOD_SECONDS(16)
2669 if (EFI_ERROR (Status
)) {
2673 Data
= AhciReadReg (PciIo
, Offset
);
2674 if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATAPI_DEVICE_SIG
) {
2675 Status
= AhciIdentifyPacket (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2677 if (EFI_ERROR (Status
)) {
2681 DeviceType
= EfiIdeCdrom
;
2682 } else if ((Data
& EFI_AHCI_ATAPI_SIG_MASK
) == EFI_AHCI_ATA_DEVICE_SIG
) {
2683 Status
= AhciIdentify (PciIo
, AhciRegisters
, Port
, 0, &Buffer
);
2685 if (EFI_ERROR (Status
)) {
2686 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_PERIPHERAL_FIXED_MEDIA
| EFI_P_EC_NOT_DETECTED
));
2691 DEBUG_INFO
, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",
2692 Buffer
.AtaData
.config
, Buffer
.AtaData
.specific_config
,
2693 Buffer
.AtaData
.command_set_supported_83
, Buffer
.AtaData
.command_set_feature_enb_86
2695 if ((Buffer
.AtaData
.config
& BIT2
) != 0) {
2697 // SpinUp disk if device reported incomplete IDENTIFY DEVICE.
2699 Status
= AhciSpinUpDisk (
2706 if (EFI_ERROR (Status
)) {
2707 DEBUG ((DEBUG_ERROR
, "Spin up standby device failed - %r\n", Status
));
2712 DeviceType
= EfiIdeHarddisk
;
2716 DEBUG ((EFI_D_INFO
, "port [%d] port mulitplier [%d] has a [%a]\n",
2717 Port
, 0, DeviceType
== EfiIdeCdrom
? "cdrom" : "harddisk"));
2720 // If the device is a hard disk, then try to enable S.M.A.R.T feature
2722 if ((DeviceType
== EfiIdeHarddisk
) && PcdGetBool (PcdAtaSmartEnable
)) {
2723 AhciAtaSmartSupport (
2734 // Submit identify data to IDE controller init driver
2736 IdeInit
->SubmitData (IdeInit
, Port
, 0, &Buffer
);
2739 // Now start to config ide device parameter and transfer mode.
2741 Status
= IdeInit
->CalculateMode (
2747 if (EFI_ERROR (Status
)) {
2748 DEBUG ((EFI_D_ERROR
, "Calculate Mode Fail, Status = %r\n", Status
));
2753 // Set best supported PIO mode on this IDE device
2755 if (SupportedModes
->PioMode
.Mode
<= EfiAtaPioMode2
) {
2756 TransferMode
.ModeCategory
= EFI_ATA_MODE_DEFAULT_PIO
;
2758 TransferMode
.ModeCategory
= EFI_ATA_MODE_FLOW_PIO
;
2761 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->PioMode
.Mode
);
2764 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
2765 // be set together. Only one DMA mode can be set to a device. If setting
2766 // DMA mode operation fails, we can continue moving on because we only use
2767 // PIO mode at boot time. DMA modes are used by certain kind of OS booting
2769 if (SupportedModes
->UdmaMode
.Valid
) {
2770 TransferMode
.ModeCategory
= EFI_ATA_MODE_UDMA
;
2771 TransferMode
.ModeNumber
= (UINT8
) (SupportedModes
->UdmaMode
.Mode
);
2772 } else if (SupportedModes
->MultiWordDmaMode
.Valid
) {
2773 TransferMode
.ModeCategory
= EFI_ATA_MODE_MDMA
;
2774 TransferMode
.ModeNumber
= (UINT8
) SupportedModes
->MultiWordDmaMode
.Mode
;
2777 Status
= AhciDeviceSetFeature (PciIo
, AhciRegisters
, Port
, 0, 0x03, (UINT32
)(*(UINT8
*)&TransferMode
), ATA_ATAPI_TIMEOUT
);
2778 if (EFI_ERROR (Status
)) {
2779 DEBUG ((EFI_D_ERROR
, "Set transfer Mode Fail, Status = %r\n", Status
));
2784 // Found a ATA or ATAPI device, add it into the device list.
2786 CreateNewDeviceInfo (Instance
, Port
, 0xFFFF, DeviceType
, &Buffer
);
2787 if (DeviceType
== EfiIdeHarddisk
) {
2788 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_PERIPHERAL_FIXED_MEDIA
| EFI_P_PC_ENABLE
));
2799 // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).
2801 if ((Buffer
.AtaData
.command_set_supported_83
& BIT5
) != 0) {
2802 Status
= AhciPuisEnable (
2808 if (EFI_ERROR (Status
)) {
2809 DEBUG ((DEBUG_ERROR
, "PUIS enable/disable failed, Status = %r\n", Status
));