X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FBus%2FAta%2FAtaAtapiPassThru%2FAhciMode.c;h=4d01c1dd7fca2c70d97250e9bace7840135e4d09;hp=06b280a001af3f48506388228f29c4f557629822;hb=6052a15f4a4297b430cf03f2456e51f8d3bb4598;hpb=5dec0c688ea92257e721eecdaf4fe4bcb15274dc
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
index 06b280a001..4d01c1dd7f 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
@@ -1,14 +1,15 @@
/** @file
The file for AHCI mode of ATA host controller.
-
- Copyright (c) 2010, Intel Corporation. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
@@ -33,7 +34,7 @@ AhciReadReg (
UINT32 Data;
ASSERT (PciIo != NULL);
-
+
Data = 0;
PciIo->Mem.Read (
@@ -95,7 +96,7 @@ AhciAndReg (
)
{
UINT32 Data;
-
+
ASSERT (PciIo != NULL);
Data = AhciReadReg (PciIo, Offset);
@@ -133,36 +134,45 @@ AhciOrReg (
}
/**
- Wait for memory set to the test value.
-
+ Wait for the value of the specified MMIO register set to the test value.
+
@param PciIo The PCI IO protocol instance.
- @param Offset The memory address to test.
+ @param Offset The MMIO address to test.
@param MaskValue The mask value of memory.
@param TestValue The test value of memory.
- @param Timeout The time out value for wait memory set.
+ @param Timeout The time out value for wait memory set, uses 100ns as a unit.
- @retval EFI_DEVICE_ERROR The memory is not set.
- @retval EFI_TIMEOUT The memory setting is time out.
- @retval EFI_SUCCESS The memory is correct set.
+ @retval EFI_TIMEOUT The MMIO setting is time out.
+ @retval EFI_SUCCESS The MMIO is correct set.
**/
EFI_STATUS
EFIAPI
-AhciWaitMemSet (
+AhciWaitMmioSet (
IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINT32 Offset,
+ IN UINTN Offset,
IN UINT32 MaskValue,
IN UINT32 TestValue,
IN UINT64 Timeout
)
{
- UINT32 Value;
- UINT32 Delay;
+ UINT32 Value;
+ UINT64 Delay;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+ Delay = DivU64x32 (Timeout, 1000) + 1;
do {
- Value = AhciReadReg (PciIo, Offset) & MaskValue;
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Value = AhciReadReg (PciIo, (UINT32) Offset) & MaskValue;
if (Value == TestValue) {
return EFI_SUCCESS;
@@ -175,23 +185,123 @@ AhciWaitMemSet (
Delay--;
- } while (Delay > 0);
+ } while (InfiniteWait || (Delay > 0));
- if (Delay == 0) {
- return EFI_TIMEOUT;
+ return EFI_TIMEOUT;
+}
+
+/**
+ Wait for the value of the specified system memory set to the test value.
+
+ @param Address The system memory address to test.
+ @param MaskValue The mask value of memory.
+ @param TestValue The test value of memory.
+ @param Timeout The time out value for wait memory set, uses 100ns as a unit.
+
+ @retval EFI_TIMEOUT The system memory setting is time out.
+ @retval EFI_SUCCESS The system memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciWaitMemSet (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT64 Delay;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ Delay = DivU64x32 (Timeout, 1000) + 1;
+
+ do {
+ //
+ // Access sytem memory to see if the value is the tested one.
+ //
+ // The system memory pointed by Address will be updated by the
+ // SATA Host Controller, "volatile" is introduced to prevent
+ // compiler from optimizing the access to the memory address
+ // to only read once.
+ //
+ Value = *(volatile UINT32 *) (UINTN) Address;
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (InfiniteWait || (Delay > 0));
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Check the memory status to the test value.
+
+ @param[in] Address The memory address to test.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in, out] Task Optional. Pointer to the ATA_NONBLOCK_TASK used by
+ non-blocking mode. If NULL, then just try once.
+
+ @retval EFI_NOTREADY The memory is not set.
+ @retval EFI_TIMEOUT The memory setting retry times out.
+ @retval EFI_SUCCESS The memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciCheckMemSet (
+ IN UINTN Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN OUT ATA_NONBLOCK_TASK *Task
+ )
+{
+ UINT32 Value;
+
+ if (Task != NULL) {
+ Task->RetryTimes--;
+ }
+
+ Value = *(volatile UINT32 *) Address;
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
}
- return EFI_DEVICE_ERROR;
+ if ((Task != NULL) && !Task->InfiniteWait && (Task->RetryTimes == 0)) {
+ return EFI_TIMEOUT;
+ } else {
+ return EFI_NOT_READY;
+ }
}
/**
- Check if the device is still on port. It also checks if the AHCI controller
- supports the address and data count will be transfered.
+ Check if the device is still on port. It also checks if the AHCI controller
+ supports the address and data count will be transferred.
@param PciIo The PCI IO protocol instance.
@param Port The number of port.
- @retval EFI_SUCCESS The device is attached to port and the transfer data is
+ @retval EFI_SUCCESS The device is attached to port and the transfer data is
supported by AHCI controller.
@retval EFI_UNSUPPORTED The transfer address and count is not supported by AHCI
controller.
@@ -206,7 +316,7 @@ AhciCheckDeviceStatus (
IN UINT8 Port
)
{
- UINT32 Data;
+ UINT32 Data;
UINT32 Offset;
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
@@ -214,7 +324,7 @@ AhciCheckDeviceStatus (
Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {
- return EFI_SUCCESS;
+ return EFI_SUCCESS;
}
return EFI_NOT_READY;
@@ -224,23 +334,23 @@ AhciCheckDeviceStatus (
Clear the port interrupt and error status. It will also clear
HBA interrupt status.
-
+
@param PciIo The PCI IO protocol instance.
@param Port The number of port.
-
-**/
+
+**/
VOID
EFIAPI
AhciClearPortStatus (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Port
- )
+ )
{
UINT32 Offset;
//
// Clear any error status
- //
+ //
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));
@@ -256,12 +366,67 @@ AhciClearPortStatus (
AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));
}
+/**
+ This function is used to dump the Status Registers and if there is ERR bit set
+ in the Status Register, the Error Register's value is also be dumped.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+**/
+VOID
+EFIAPI
+AhciDumpPortStatus (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ UINTN Offset;
+ UINT32 Data;
+ UINTN FisBaseAddr;
+ EFI_STATUS Status;
+
+ ASSERT (PciIo != NULL);
+
+ if (AtaStatusBlock != NULL) {
+ ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
+
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If D2H FIS is received, update StatusBlock with its content.
+ //
+ CopyMem (AtaStatusBlock, (UINT8 *)Offset, sizeof (EFI_ATA_STATUS_BLOCK));
+ } else {
+ //
+ // If D2H FIS is not received, only update Status & Error field through PxTFD
+ // as there is no other way to get the content of the Shadow Register Block.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ Data = AhciReadReg (PciIo, (UINT32)Offset);
+
+ AtaStatusBlock->AtaStatus = (UINT8)Data;
+ if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {
+ AtaStatusBlock->AtaError = (UINT8)(Data >> 8);
+ }
+ }
+ }
+}
+
+
/**
Enable the FIS running for giving port.
-
+
@param PciIo The PCI IO protocol instance.
@param Port The number of port.
- @param Timeout The timeout value of enabling FIS.
+ @param Timeout The timeout value of enabling FIS, uses 100ns as a unit.
@retval EFI_DEVICE_ERROR The FIS enable setting fails.
@retval EFI_TIMEOUT The FIS enable setting is time out.
@@ -274,20 +439,14 @@ AhciEnableFisReceive (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Port,
IN UINT64 Timeout
- )
-{
+ )
+{
UINT32 Offset;
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);
- return AhciWaitMemSet (
- PciIo,
- Offset,
- EFI_AHCI_PORT_CMD_FR,
- EFI_AHCI_PORT_CMD_FR,
- Timeout
- );
+ return EFI_SUCCESS;
}
/**
@@ -295,7 +454,7 @@ AhciEnableFisReceive (
@param PciIo The PCI IO protocol instance.
@param Port The number of port.
- @param Timeout The timeout value of disabling FIS.
+ @param Timeout The timeout value of disabling FIS, uses 100ns as a unit.
@retval EFI_DEVICE_ERROR The FIS disable setting fails.
@retval EFI_TIMEOUT The FIS disable setting is time out.
@@ -309,7 +468,7 @@ AhciDisableFisReceive (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Port,
IN UINT64 Timeout
- )
+ )
{
UINT32 Offset;
UINT32 Data;
@@ -323,7 +482,7 @@ AhciDisableFisReceive (
if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {
return EFI_UNSUPPORTED;
}
-
+
//
// Check if the Fis receive DMA engine for the port is running.
//
@@ -333,20 +492,20 @@ AhciDisableFisReceive (
AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
- return AhciWaitMemSet (
- PciIo,
+ return AhciWaitMmioSet (
+ PciIo,
Offset,
EFI_AHCI_PORT_CMD_FR,
0,
Timeout
- );
+ );
}
/**
Build the command list, command table and prepare the fis receiver.
-
+
@param PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port.
@@ -359,7 +518,7 @@ AhciDisableFisReceive (
@param DataPhysicalAddr The pointer to the data buffer pci bus master address.
@param DataLength The data count to be transferred.
-**/
+**/
VOID
EFIAPI
AhciBuildCommand (
@@ -373,12 +532,12 @@ AhciBuildCommand (
IN UINT8 AtapiCommandLength,
IN UINT8 CommandSlotNumber,
IN OUT VOID *DataPhysicalAddr,
- IN UINT64 DataLength
- )
+ IN UINT32 DataLength
+ )
{
- UINT64 BaseAddr;
- UINT64 PrdtNumber;
- UINT64 PrdtIndex;
+ UINT64 BaseAddr;
+ UINT32 PrdtNumber;
+ UINT32 PrdtIndex;
UINTN RemainedData;
UINTN MemAddr;
DATA_64 Data64;
@@ -386,8 +545,8 @@ AhciBuildCommand (
//
// Filling the PRDT
- //
- PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;
+ //
+ PrdtNumber = (UINT32)DivU64x32 (((UINT64)DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1), EFI_AHCI_MAX_DATA_PER_PRDT);
//
// According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.
@@ -399,13 +558,13 @@ AhciBuildCommand (
Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
BaseAddr = Data64.Uint64;
-
- ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
-
+
+ ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
+
ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));
CommandFis->AhciCFisPmNum = PortMultiplier;
-
+
CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
@@ -418,19 +577,18 @@ AhciBuildCommand (
CommandList->AhciCmdA = 1;
CommandList->AhciCmdP = 1;
- CommandList->AhciCmdC = (DataLength == 0) ? 1 : 0;
AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
} else {
AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
}
-
+
RemainedData = (UINTN) DataLength;
MemAddr = (UINTN) DataPhysicalAddr;
- CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;
-
+ CommandList->AhciCmdPrdtl = PrdtNumber;
+
for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {
- if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {
+ if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {
AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;
} else {
AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;
@@ -439,7 +597,7 @@ AhciBuildCommand (
Data64.Uint64 = (UINT64)MemAddr;
AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32;
AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;
- RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;
+ RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;
MemAddr += EFI_AHCI_MAX_DATA_PER_PRDT;
}
@@ -454,7 +612,7 @@ AhciBuildCommand (
(VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
CommandList,
sizeof (EFI_AHCI_COMMAND_LIST)
- );
+ );
Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;
AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;
@@ -465,7 +623,7 @@ AhciBuildCommand (
/**
Buid a command FIS.
-
+
@param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.
@param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.
@@ -483,7 +641,7 @@ AhciBuildCommandFis (
//
// Indicator it's a command
//
- CmdFis->AhciCFisCmdInd = 0x1;
+ CmdFis->AhciCFisCmdInd = 0x1;
CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;
CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;
@@ -506,19 +664,22 @@ AhciBuildCommandFis (
/**
Start a PIO data transfer on specific port.
-
- @param PciIo The PCI IO protocol instance.
- @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
- @param Port The number of port.
- @param PortMultiplier The timeout value of stop.
- @param AtapiCommand The atapi command will be used for the transfer.
- @param AtapiCommandLength The length of the atapi command.
- @param Read The transfer direction.
- @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
- @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
- @param MemoryAddr The pointer to the data buffer.
- @param DataCount The data count to be transferred.
- @param Timeout The timeout value of non data transfer.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] Read The transfer direction.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in, out] MemoryAddr The pointer to the data buffer.
+ @param[in] DataCount The data count to be transferred.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
@retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.
@retval EFI_TIMEOUT The operation is time out.
@@ -534,26 +695,37 @@ AhciPioTransfer (
IN UINT8 Port,
IN UINT8 PortMultiplier,
IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
- IN UINT8 AtapiCommandLength,
- IN BOOLEAN Read,
+ IN UINT8 AtapiCommandLength,
+ IN BOOLEAN Read,
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
IN OUT VOID *MemoryAddr,
IN UINT32 DataCount,
- IN UINT64 Timeout
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
)
{
EFI_STATUS Status;
UINTN FisBaseAddr;
- UINT32 Offset;
- UINT32 Value;
+ UINTN Offset;
EFI_PHYSICAL_ADDRESS PhyAddr;
VOID *Map;
UINTN MapLength;
EFI_PCI_IO_PROTOCOL_OPERATION Flag;
- UINT32 Delay;
+ UINT64 Delay;
EFI_AHCI_COMMAND_FIS CFis;
EFI_AHCI_COMMAND_LIST CmdList;
+ UINT32 PortTfd;
+ UINT32 PrdCount;
+ BOOLEAN InfiniteWait;
+ BOOLEAN PioFisReceived;
+ BOOLEAN D2hFisReceived;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
if (Read) {
Flag = EfiPciIoOperationBusMasterWrite;
@@ -575,9 +747,9 @@ AhciPioTransfer (
);
if (EFI_ERROR (Status) || (DataCount != MapLength)) {
- return EFI_OUT_OF_RESOURCES;
+ return EFI_BAD_BUFFER_SIZE;
}
-
+
//
// Package read needed
//
@@ -600,83 +772,110 @@ AhciPioTransfer (
0,
(VOID *)(UINTN)PhyAddr,
DataCount
- );
-
+ );
+
Status = AhciStartCommand (
- PciIo,
- Port,
+ PciIo,
+ Port,
0,
Timeout
);
if (EFI_ERROR (Status)) {
goto Exit;
}
-
+
//
- // Checking the status and wait the driver sending data
+ // Check the status and wait the driver sending data
//
FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
- //
- // Wait device sends the PIO setup fis before data transfer
- //
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
- do {
- Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET);
-
- if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_PIO_SETUP) {
- break;
- }
+ if (Read && (AtapiCommand == 0)) {
//
- // Stall for 100 microseconds.
+ // Wait device sends the PIO setup fis before data transfer
//
- MicroSecondDelay(100);
+ Status = EFI_TIMEOUT;
+ Delay = DivU64x32 (Timeout, 1000) + 1;
+ do {
+ PioFisReceived = FALSE;
+ D2hFisReceived = FALSE;
+ Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, NULL);
+ if (!EFI_ERROR (Status)) {
+ PioFisReceived = TRUE;
+ }
+ //
+ // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.
+ // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device
+ // after the transaction is finished successfully.
+ // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.
+ // By this way, we can know if there is a real error happened.
+ //
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);
+ if (!EFI_ERROR (Status)) {
+ D2hFisReceived = TRUE;
+ }
- Delay--;
- } while (Delay > 0);
+ if (PioFisReceived || D2hFisReceived) {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
+ //
+ // PxTFD will be updated if there is a D2H or SetupFIS received.
+ //
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
- if (Delay == 0) {
- Status = EFI_TIMEOUT;
- goto Exit;
- }
+ PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
+ if (PrdCount == DataCount) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
- //
- // Wait for command compelte
- //
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
- Status = AhciWaitMemSet (
- PciIo,
- Offset,
- 0xFFFFFFFF,
- 0,
- Timeout
- );
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay(100);
- if (EFI_ERROR (Status)) {
- goto Exit;
- }
+ Delay--;
+ if (Delay == 0) {
+ Status = EFI_TIMEOUT;
+ }
+ } while (InfiniteWait || (Delay > 0));
+ } else {
+ //
+ // Wait for D2H Fis is received
+ //
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ Status = AhciWaitMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
- Status = AhciWaitMemSet (
- PciIo,
- Offset,
- EFI_AHCI_PORT_IS_PSS,
- EFI_AHCI_PORT_IS_PSS,
- Timeout
- );
- if (EFI_ERROR (Status)) {
- goto Exit;
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
}
-Exit:
+Exit:
AhciStopCommand (
- PciIo,
+ PciIo,
Port,
Timeout
);
-
+
AhciDisableFisReceive (
- PciIo,
+ PciIo,
Port,
Timeout
);
@@ -686,197 +885,251 @@ Exit:
Map
);
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);
+
return Status;
}
/**
Start a DMA data transfer on specific port
- @param PciIo The PCI IO protocol instance.
- @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
- @param Port The number of port.
- @param PortMultiplier The timeout value of stop.
- @param AtapiCommand The atapi command will be used for the transfer.
- @param AtapiCommandLength The length of the atapi command.
- @param Read The transfer direction.
- @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
- @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
- @param MemoryAddr The pointer to the data buffer.
- @param DataCount The data count to be transferred.
- @param Timeout The timeout value of non data transfer.
+ @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] Read The transfer direction.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in, out] MemoryAddr The pointer to the data buffer.
+ @param[in] DataCount The data count to be transferred.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
@retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.
@retval EFI_TIMEOUT The operation is time out.
@retval EFI_UNSUPPORTED The device is not ready for transfer.
@retval EFI_SUCCESS The DMA data transfer executes successfully.
-
+
**/
EFI_STATUS
EFIAPI
AhciDmaTransfer (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
IN EFI_AHCI_REGISTERS *AhciRegisters,
IN UINT8 Port,
IN UINT8 PortMultiplier,
IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
IN UINT8 AtapiCommandLength,
- IN BOOLEAN Read,
+ IN BOOLEAN Read,
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
IN OUT VOID *MemoryAddr,
- IN UINTN DataCount,
- IN UINT64 Timeout
+ IN UINT32 DataCount,
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
)
{
EFI_STATUS Status;
- UINT32 Offset;
+ UINTN Offset;
EFI_PHYSICAL_ADDRESS PhyAddr;
VOID *Map;
UINTN MapLength;
EFI_PCI_IO_PROTOCOL_OPERATION Flag;
EFI_AHCI_COMMAND_FIS CFis;
EFI_AHCI_COMMAND_LIST CmdList;
+ UINTN FisBaseAddr;
+ UINT32 PortTfd;
- if (Read) {
- Flag = EfiPciIoOperationBusMasterWrite;
- } else {
- Flag = EfiPciIoOperationBusMasterRead;
- }
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_TPL OldTpl;
- //
- // construct command list and command table with pci bus address
- //
- MapLength = DataCount;
- Status = PciIo->Map (
- PciIo,
- Flag,
- MemoryAddr,
- &MapLength,
- &PhyAddr,
- &Map
- );
+ Map = NULL;
+ PciIo = Instance->PciIo;
- if (EFI_ERROR (Status) || (DataCount != MapLength)) {
- return EFI_OUT_OF_RESOURCES;
+ if (PciIo == NULL) {
+ return EFI_INVALID_PARAMETER;
}
//
- // Package read needed
+ // Before starting the Blocking BlockIO operation, push to finish all non-blocking
+ // BlockIO tasks.
+ // Delay 100us to simulate the blocking time out checking.
//
- AhciBuildCommandFis (&CFis, AtaCommandBlock);
-
- ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {
+ AsyncNonBlockingTransferRoutine (NULL, Instance);
+ //
+ // Stall for 100us.
+ //
+ MicroSecondDelay (100);
+ }
+ gBS->RestoreTPL (OldTpl);
- CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
- CmdList.AhciCmdW = Read ? 0 : 1;
+ if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {
+ //
+ // Mark the Task to indicate that it has been started.
+ //
+ if (Task != NULL) {
+ Task->IsStart = TRUE;
+ }
+ if (Read) {
+ Flag = EfiPciIoOperationBusMasterWrite;
+ } else {
+ Flag = EfiPciIoOperationBusMasterRead;
+ }
- AhciBuildCommand (
- PciIo,
- AhciRegisters,
- Port,
- PortMultiplier,
- &CFis,
- &CmdList,
- AtapiCommand,
- AtapiCommandLength,
- 0,
- (VOID *)(UINTN)PhyAddr,
- DataCount
- );
-
- Status = AhciStartCommand (
- PciIo,
- Port,
- 0,
- Timeout
- );
- if (EFI_ERROR (Status)) {
- goto Exit;
- }
-
- //
- // Wait device PRD processed
- //
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
- Status = AhciWaitMemSet (
- PciIo,
- Offset,
- EFI_AHCI_PORT_IS_DPS,
- EFI_AHCI_PORT_IS_DPS,
- Timeout
- );
-
- if (EFI_ERROR (Status)) {
- goto Exit;
+ //
+ // Construct command list and command table with pci bus address.
+ //
+ MapLength = DataCount;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ MemoryAddr,
+ &MapLength,
+ &PhyAddr,
+ &Map
+ );
+
+ if (EFI_ERROR (Status) || (DataCount != MapLength)) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Task != NULL) {
+ Task->Map = Map;
+ }
+ //
+ // Package read needed
+ //
+ AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+ ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+ CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+ CmdList.AhciCmdW = Read ? 0 : 1;
+
+ AhciBuildCommand (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ &CFis,
+ &CmdList,
+ AtapiCommand,
+ AtapiCommandLength,
+ 0,
+ (VOID *)(UINTN)PhyAddr,
+ DataCount
+ );
+
+ Status = AhciStartCommand (
+ PciIo,
+ Port,
+ 0,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
}
//
// Wait for command compelte
//
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
- Status = AhciWaitMemSet (
- PciIo,
- Offset,
- 0xFFFFFFFF,
- 0,
- Timeout
- );
- if (EFI_ERROR (Status)) {
- goto Exit;
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ if (Task != NULL) {
+ //
+ // For Non-blocking
+ //
+ Status = AhciCheckMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Task
+ );
+ } else {
+ Status = AhciWaitMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
}
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
- Status = AhciWaitMemSet (
- PciIo,
- Offset,
- EFI_AHCI_PORT_IS_DHRS,
- EFI_AHCI_PORT_IS_DHRS,
- Timeout
- );
if (EFI_ERROR (Status)) {
goto Exit;
}
-Exit:
- AhciStopCommand (
- PciIo,
- Port,
- Timeout
- );
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
- AhciDisableFisReceive (
- PciIo,
- Port,
- Timeout
- );
+Exit:
+ //
+ // For Blocking mode, the command should be stopped, the Fis should be disabled
+ // and the PciIo should be unmapped.
+ // For non-blocking mode, only when a error is happened (if the return status is
+ // EFI_NOT_READY that means the command doesn't finished, try again.), first do the
+ // context cleanup, then set the packet's Asb status.
+ //
+ if (Task == NULL ||
+ ((Task != NULL) && (Status != EFI_NOT_READY))
+ ) {
+ AhciStopCommand (
+ PciIo,
+ Port,
+ Timeout
+ );
- PciIo->Unmap (
- PciIo,
- Map
- );
-
+ AhciDisableFisReceive (
+ PciIo,
+ Port,
+ Timeout
+ );
+
+ PciIo->Unmap (
+ PciIo,
+ (Task != NULL) ? Task->Map : Map
+ );
+
+ if (Task != NULL) {
+ Task->Packet->Asb->AtaStatus = 0x01;
+ }
+ }
+
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);
return Status;
}
/**
Start a non data transfer on specific port.
-
- @param PciIo The PCI IO protocol instance.
- @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
- @param Port The number of port.
- @param PortMultiplier The timeout value of stop.
- @param AtapiCommand The atapi command will be used for the transfer.
- @param AtapiCommandLength The length of the atapi command.
- @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
- @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
- @param Timeout The timeout value of non data transfer.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The number of port.
+ @param[in] PortMultiplier The timeout value of stop.
+ @param[in] AtapiCommand The atapi command will be used for the
+ transfer.
+ @param[in] AtapiCommandLength The length of the atapi command.
+ @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
+ @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.
+ @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK
+ used by non-blocking mode.
@retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.
@retval EFI_TIMEOUT The operation is time out.
@retval EFI_UNSUPPORTED The device is not ready for transfer.
@retval EFI_SUCCESS The non data transfer executes successfully.
-**/
+**/
EFI_STATUS
EFIAPI
AhciNonDataTransfer (
@@ -888,15 +1141,14 @@ AhciNonDataTransfer (
IN UINT8 AtapiCommandLength,
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
- IN UINT64 Timeout
- )
+ IN UINT64 Timeout,
+ IN ATA_NONBLOCK_TASK *Task
+ )
{
- EFI_STATUS Status;
+ EFI_STATUS Status;
UINTN FisBaseAddr;
- UINT32 Offset;
- UINT32 Value;
- UINT32 Delay;
-
+ UINTN Offset;
+ UINT32 PortTfd;
EFI_AHCI_COMMAND_FIS CFis;
EFI_AHCI_COMMAND_LIST CmdList;
@@ -921,79 +1173,65 @@ AhciNonDataTransfer (
0,
NULL,
0
- );
-
+ );
+
Status = AhciStartCommand (
- PciIo,
- Port,
+ PciIo,
+ Port,
0,
Timeout
);
if (EFI_ERROR (Status)) {
goto Exit;
}
-
+
//
// Wait device sends the Response Fis
//
FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
- //
- // Wait device sends the PIO setup fis before data transfer
- //
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
- do {
- Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);
-
- if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {
- break;
- }
-
- //
- // Stall for 100 microseconds.
- //
- MicroSecondDelay(100);
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ Status = AhciWaitMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
- Delay --;
- } while (Delay > 0);
-
- if (Delay == 0) {
- Status = EFI_TIMEOUT;
+ if (EFI_ERROR (Status)) {
goto Exit;
}
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
- Status = AhciWaitMemSet (
- PciIo,
- Offset,
- 0xFFFFFFFF,
- 0,
- Timeout
- );
-
-Exit:
+Exit:
AhciStopCommand (
- PciIo,
+ PciIo,
Port,
Timeout
);
AhciDisableFisReceive (
- PciIo,
+ PciIo,
Port,
Timeout
);
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);
+
return Status;
}
/**
Stop command running for giving port
-
+
@param PciIo The PCI IO protocol instance.
@param Port The number of port.
- @param Timeout The timeout value of stop.
-
+ @param Timeout The timeout value of stop, uses 100ns as a unit.
+
@retval EFI_DEVICE_ERROR The command stop unsuccessfully.
@retval EFI_TIMEOUT The operation is time out.
@retval EFI_SUCCESS The command stop successfully.
@@ -1014,30 +1252,30 @@ AhciStopCommand (
Data = AhciReadReg (PciIo, Offset);
if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {
- return EFI_SUCCESS;
+ return EFI_SUCCESS;
}
if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));
}
- return AhciWaitMemSet (
- PciIo,
+ return AhciWaitMmioSet (
+ PciIo,
Offset,
EFI_AHCI_PORT_CMD_CR,
0,
Timeout
- );
+ );
}
/**
Start command for give slot on specific port.
-
+
@param PciIo The PCI IO protocol instance.
@param Port The number of port.
- @param CommandSlot The number of CommandSlot.
- @param Timeout The timeout value of start.
-
+ @param CommandSlot The number of Command Slot.
+ @param Timeout The timeout value of start, uses 100ns as a unit.
+
@retval EFI_DEVICE_ERROR The command start unsuccessfully.
@retval EFI_TIMEOUT The operation is time out.
@retval EFI_SUCCESS The command start successfully.
@@ -1073,29 +1311,18 @@ AhciStartCommand (
);
Status = AhciEnableFisReceive (
- PciIo,
+ PciIo,
Port,
Timeout
);
-
+
if (EFI_ERROR (Status)) {
return Status;
}
- //
- // Setting the command
- //
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;
- AhciAndReg (PciIo, Offset, 0);
- AhciOrReg (PciIo, Offset, CmdSlotBit);
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
- AhciAndReg (PciIo, Offset, 0);
- AhciOrReg (PciIo, Offset, CmdSlotBit);
-
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
PortStatus = AhciReadReg (PciIo, Offset);
-
+
StartCmd = 0;
if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
StartCmd = AhciReadReg (PciIo, Offset);
@@ -1109,21 +1336,28 @@ AhciStartCommand (
if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {
if ((Capability & BIT24) != 0) {
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);
- AhciWaitMemSet (
- PciIo,
+ AhciWaitMmioSet (
+ PciIo,
Offset,
- EFI_AHCI_PORT_CMD_COL,
+ EFI_AHCI_PORT_CMD_CLO,
0,
Timeout
- );
+ );
}
}
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);
+ //
+ // Setting the command
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
+ AhciAndReg (PciIo, Offset, 0);
+ AhciOrReg (PciIo, Offset, CmdSlotBit);
+
return EFI_SUCCESS;
}
@@ -1132,8 +1366,8 @@ AhciStartCommand (
@param PciIo The PCI IO protocol instance.
@param Port The number of port.
- @param Timeout The timeout value of reset.
-
+ @param Timeout The timeout value of reset, uses 100ns as a unit.
+
@retval EFI_DEVICE_ERROR The port reset unsuccessfully
@retval EFI_TIMEOUT The reset operation is time out.
@retval EFI_SUCCESS The port reset successfully.
@@ -1148,8 +1382,8 @@ AhciPortReset (
)
{
EFI_STATUS Status;
- UINT32 Offset;
-
+ UINT32 Offset;
+
AhciClearPortStatus (PciIo, Port);
AhciStopCommand (PciIo, Port, Timeout);
@@ -1163,14 +1397,14 @@ AhciPortReset (
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);
//
- // wait 5 milliseceond before de-assert DET
+ // wait 5 millisecond before de-assert DET
//
MicroSecondDelay (5000);
AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);
//
- // wait 5 milliseceond before de-assert DET
+ // wait 5 millisecond before de-assert DET
//
MicroSecondDelay (5000);
@@ -1178,15 +1412,16 @@ AhciPortReset (
// Wait for communication to be re-established
//
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
- Status = AhciWaitMemSet (
+ Status = AhciWaitMmioSet (
PciIo,
Offset,
EFI_AHCI_PORT_SSTS_DET_MASK,
EFI_AHCI_PORT_SSTS_DET_PCE,
Timeout
- );
+ );
if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Port %d COMRESET failed: %r\n", Port, Status));
return Status;
}
@@ -1198,11 +1433,10 @@ AhciPortReset (
/**
Do AHCI HBA reset.
-
+
@param PciIo The PCI IO protocol instance.
- @param Timeout The timeout value of reset.
-
-
+ @param Timeout The timeout value of reset, uses 100ns as a unit.
+
@retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
@retval EFI_TIMEOUT The reset operation is time out.
@retval EFI_SUCCESS AHCI controller is reset successfully.
@@ -1213,19 +1447,23 @@ EFIAPI
AhciReset (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT64 Timeout
- )
+ )
{
- EFI_STATUS Status;
- UINT32 Delay;
+ UINT64 Delay;
UINT32 Value;
- AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
+ //
+ // Make sure that GHC.AE bit is set before accessing any AHCI registers.
+ //
+ Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);
- AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
+ if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
+ }
- Status = EFI_TIMEOUT;
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+ Delay = DivU64x32(Timeout, 1000) + 1;
do {
Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);
@@ -1249,13 +1487,227 @@ AhciReset (
return EFI_SUCCESS;
}
+/**
+ Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The port multiplier port number.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+ @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
+ @retval Others Fail to get return status data.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAtaSmartReturnStatusCheck (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+ UINT8 LBAMid;
+ UINT8 LBAHigh;
+ UINTN FisBaseAddr;
+ UINT32 Value;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+
+ //
+ // Send S.M.A.R.T Read Return Status command to device
+ //
+ Status = AhciNonDataTransfer (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ NULL,
+ 0,
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)
+ );
+
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
+
+ Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);
+
+ if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {
+ LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];
+ LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];
+
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
+ //
+ // The threshold exceeded condition is not detected by the device
+ //
+ DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)
+ );
+ } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {
+ //
+ // The threshold exceeded condition is detected by the device
+ //
+ DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enable SMART command of the disk if supported.
+
+ @param PciIo The PCI IO protocol instance.
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The port multiplier port number.
+ @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
+
+**/
+VOID
+EFIAPI
+AhciAtaSmartSupport (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_IDENTIFY_DATA *IdentifyData,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ //
+ // Detect if the device supports S.M.A.R.T.
+ //
+ if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
+ //
+ // S.M.A.R.T is not supported by the device
+ //
+ DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
+ Port, PortMultiplier));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)
+ );
+ } else {
+ //
+ // Check if the feature is enabled. If not, then enable S.M.A.R.T.
+ //
+ if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {
+
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)
+ );
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+
+ //
+ // Send S.M.A.R.T Enable command to device
+ //
+ Status = AhciNonDataTransfer (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ NULL,
+ 0,
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Send S.M.A.R.T AutoSave command to device
+ //
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
+ AtaCommandBlock.AtaFeatures = 0xD2;
+ AtaCommandBlock.AtaSectorCount = 0xF1;
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
+
+ Status = AhciNonDataTransfer (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ NULL,
+ 0,
+ &AtaCommandBlock,
+ AtaStatusBlock,
+ ATA_ATAPI_TIMEOUT,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = AhciAtaSmartReturnStatusCheck (
+ PciIo,
+ AhciRegisters,
+ (UINT8)Port,
+ (UINT8)PortMultiplier,
+ AtaStatusBlock
+ );
+ }
+ }
+ }
+ DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
+ Port, PortMultiplier));
+ }
+
+ return ;
+}
+
/**
Send Buffer cmd to specific device.
-
+
@param PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port.
- @param PortMultiplier The timeout value of stop.
+ @param PortMultiplier The port multiplier port number.
@param Buffer The data buffer to store IDENTIFY PACKET data.
@retval EFI_DEVICE_ERROR The cmd abort with error occurs.
@@ -1271,7 +1723,7 @@ AhciIdentify (
IN EFI_AHCI_REGISTERS *AhciRegisters,
IN UINT8 Port,
IN UINT8 PortMultiplier,
- IN OUT EFI_IDENTIFY_DATA *Buffer
+ IN OUT EFI_IDENTIFY_DATA *Buffer
)
{
EFI_STATUS Status;
@@ -1284,7 +1736,7 @@ AhciIdentify (
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
-
+
AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
AtaCommandBlock.AtaSectorCount = 1;
@@ -1300,7 +1752,8 @@ AhciIdentify (
&AtaStatusBlock,
Buffer,
sizeof (EFI_IDENTIFY_DATA),
- ATA_ATAPI_TIMEOUT
+ ATA_ATAPI_TIMEOUT,
+ NULL
);
return Status;
@@ -1308,11 +1761,11 @@ AhciIdentify (
/**
Send Buffer cmd to specific device.
-
+
@param PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port.
- @param PortMultiplier The timeout value of stop.
+ @param PortMultiplier The port multiplier port number.
@param Buffer The data buffer to store IDENTIFY PACKET data.
@retval EFI_DEVICE_ERROR The cmd abort with error occurs.
@@ -1328,7 +1781,7 @@ AhciIdentifyPacket (
IN EFI_AHCI_REGISTERS *AhciRegisters,
IN UINT8 Port,
IN UINT8 PortMultiplier,
- IN OUT EFI_IDENTIFY_DATA *Buffer
+ IN OUT EFI_IDENTIFY_DATA *Buffer
)
{
EFI_STATUS Status;
@@ -1338,7 +1791,7 @@ AhciIdentifyPacket (
if (PciIo == NULL || AhciRegisters == NULL) {
return EFI_INVALID_PARAMETER;
}
-
+
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
@@ -1357,7 +1810,8 @@ AhciIdentifyPacket (
&AtaStatusBlock,
Buffer,
sizeof (EFI_IDENTIFY_DATA),
- ATA_ATAPI_TIMEOUT
+ ATA_ATAPI_TIMEOUT,
+ NULL
);
return Status;
@@ -1365,11 +1819,11 @@ AhciIdentifyPacket (
/**
Send SET FEATURE cmd on specific device.
-
+
@param PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port.
- @param PortMultiplier The timeout value of stop.
+ @param PortMultiplier The port multiplier port number.
@param Feature The data to send Feature register.
@param FeatureSpecificData The specific data for SET FEATURE cmd.
@@ -1396,7 +1850,7 @@ AhciDeviceSetFeature (
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
-
+
AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;
AtaCommandBlock.AtaFeatures = (UINT8) Feature;
AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8);
@@ -1414,19 +1868,20 @@ AhciDeviceSetFeature (
0,
&AtaCommandBlock,
&AtaStatusBlock,
- ATA_ATAPI_TIMEOUT
+ ATA_ATAPI_TIMEOUT,
+ NULL
);
return Status;
}
/**
- This function is used to send out ATAPI commands conforms to the Packet Command
+ This function is used to send out ATAPI commands conforms to the Packet Command
with PIO Protocol.
@param PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
- @param Port The number of port.
+ @param Port The number of port.
@param PortMultiplier The number of port multiplier.
@param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
@@ -1451,7 +1906,6 @@ AhciPacketCommandExecute (
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
EFI_ATA_STATUS_BLOCK AtaStatusBlock;
BOOLEAN Read;
- UINT8 Retry;
if (Packet == NULL || Packet->Cdb == NULL) {
return EFI_INVALID_PARAMETER;
@@ -1481,7 +1935,7 @@ AhciPacketCommandExecute (
Read = FALSE;
}
- if (Length == 0) {
+ if (Length == 0) {
Status = AhciNonDataTransfer (
PciIo,
AhciRegisters,
@@ -1491,44 +1945,32 @@ AhciPacketCommandExecute (
Packet->CdbLength,
&AtaCommandBlock,
&AtaStatusBlock,
- Packet->Timeout
+ Packet->Timeout,
+ NULL
);
} else {
- //
- // READ_CAPACITY cmd may execute failure. Retry 5 times
- //
- if (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_READ_CAPACITY) {
- Retry = 5;
- } else {
- Retry = 1;
- }
- do {
- Status = AhciPioTransfer (
- PciIo,
- AhciRegisters,
- Port,
- PortMultiplier,
- Packet->Cdb,
- Packet->CdbLength,
- Read,
- &AtaCommandBlock,
- &AtaStatusBlock,
- Buffer,
- Length,
- Packet->Timeout
- );
- if (!EFI_ERROR (Status)) {
- break;
- }
- Retry--;
- } while (Retry != 0);
+ Status = AhciPioTransfer (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ Packet->Cdb,
+ Packet->CdbLength,
+ Read,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ Buffer,
+ Length,
+ Packet->Timeout,
+ NULL
+ );
}
return Status;
}
/**
Allocate transfer-related data struct which is used at AHCI mode.
-
+
@param PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@@ -1545,31 +1987,43 @@ AhciCreateTransferDescriptor (
VOID *Buffer;
UINT32 Capability;
+ UINT32 PortImplementBitMap;
UINT8 MaxPortNumber;
UINT8 MaxCommandSlotNumber;
BOOLEAN Support64Bit;
UINT64 MaxReceiveFisSize;
UINT64 MaxCommandListSize;
UINT64 MaxCommandTableSize;
+ EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;
+ EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;
+ EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;
Buffer = NULL;
//
// Collect AHCI controller information
//
Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);
- MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);
//
// Get the number of command slots per port supported by this HBA.
//
MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);
Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);
+
+ PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);
+ //
+ // Get the highest bit of implemented ports which decides how many bytes are allocated for recived FIS.
+ //
+ MaxPortNumber = (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1);
+ if (MaxPortNumber == 0) {
+ return EFI_DEVICE_ERROR;
+ }
MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);
Status = PciIo->AllocateBuffer (
PciIo,
AllocateAnyPages,
EfiBootServicesData,
- (UINTN)EFI_SIZE_TO_PAGES (MaxReceiveFisSize),
+ EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),
&Buffer,
0
);
@@ -1589,25 +2043,26 @@ AhciCreateTransferDescriptor (
EfiPciIoOperationBusMasterCommonBuffer,
Buffer,
&Bytes,
- (EFI_PHYSICAL_ADDRESS *) &AhciRegisters->AhciRFisPciAddr,
+ &AhciRFisPciAddr,
&AhciRegisters->MapRFis
);
if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {
//
- // Map error or unable to map the whole RFis buffer into a contiguous region.
+ // Map error or unable to map the whole RFis buffer into a contiguous region.
//
Status = EFI_OUT_OF_RESOURCES;
goto Error6;
}
- if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciRFisPciAddr > 0x100000000ULL)) {
+ if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {
//
// The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
//
Status = EFI_DEVICE_ERROR;
goto Error5;
}
+ AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;
//
// Allocate memory for command list
@@ -1619,14 +2074,14 @@ AhciCreateTransferDescriptor (
PciIo,
AllocateAnyPages,
EfiBootServicesData,
- (UINTN)EFI_SIZE_TO_PAGES (MaxCommandListSize),
+ EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),
&Buffer,
0
);
if (EFI_ERROR (Status)) {
//
- // Free mapped resource.
+ // Free mapped resource.
//
Status = EFI_OUT_OF_RESOURCES;
goto Error5;
@@ -1643,7 +2098,7 @@ AhciCreateTransferDescriptor (
EfiPciIoOperationBusMasterCommonBuffer,
Buffer,
&Bytes,
- (EFI_PHYSICAL_ADDRESS *)&AhciRegisters->AhciCmdListPciAddr,
+ &AhciCmdListPciAddr,
&AhciRegisters->MapCmdList
);
@@ -1655,13 +2110,14 @@ AhciCreateTransferDescriptor (
goto Error4;
}
- if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciCmdListPciAddr > 0x100000000ULL)) {
+ if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {
//
// The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
//
Status = EFI_DEVICE_ERROR;
goto Error3;
}
+ AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;
//
// Allocate memory for command table
@@ -1674,14 +2130,14 @@ AhciCreateTransferDescriptor (
PciIo,
AllocateAnyPages,
EfiBootServicesData,
- (UINTN)EFI_SIZE_TO_PAGES (MaxCommandTableSize),
+ EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),
&Buffer,
0
);
if (EFI_ERROR (Status)) {
//
- // Free mapped resource.
+ // Free mapped resource.
//
Status = EFI_OUT_OF_RESOURCES;
goto Error3;
@@ -1698,7 +2154,7 @@ AhciCreateTransferDescriptor (
EfiPciIoOperationBusMasterCommonBuffer,
Buffer,
&Bytes,
- (EFI_PHYSICAL_ADDRESS *)&AhciRegisters->AhciCommandTablePciAddr,
+ &AhciCommandTablePciAddr,
&AhciRegisters->MapCommandTable
);
@@ -1710,17 +2166,18 @@ AhciCreateTransferDescriptor (
goto Error2;
}
- if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciCommandTablePciAddr > 0x100000000ULL)) {
+ if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {
//
// The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.
//
Status = EFI_DEVICE_ERROR;
goto Error1;
}
+ AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;
return EFI_SUCCESS;
//
- // Map error or unable to map the whole CmdList buffer into a contiguous region.
+ // Map error or unable to map the whole CmdList buffer into a contiguous region.
//
Error1:
PciIo->Unmap (
@@ -1730,7 +2187,7 @@ Error1:
Error2:
PciIo->FreeBuffer (
PciIo,
- (UINTN)EFI_SIZE_TO_PAGES (MaxCommandTableSize),
+ EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),
AhciRegisters->AhciCommandTable
);
Error3:
@@ -1741,7 +2198,7 @@ Error3:
Error4:
PciIo->FreeBuffer (
PciIo,
- (UINTN)EFI_SIZE_TO_PAGES (MaxCommandListSize),
+ EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),
AhciRegisters->AhciCmdList
);
Error5:
@@ -1752,7 +2209,7 @@ Error5:
Error6:
PciIo->FreeBuffer (
PciIo,
- (UINTN)EFI_SIZE_TO_PAGES (MaxReceiveFisSize),
+ EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),
AhciRegisters->AhciRFis
);
@@ -1762,8 +2219,8 @@ Error6:
/**
Initialize ATA host controller at AHCI mode.
- The function is designed to initialize ATA host controller.
-
+ The function is designed to initialize ATA host controller.
+
@param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.
**/
@@ -1779,8 +2236,6 @@ AhciModeInitialization (
UINT32 Capability;
UINT8 MaxPortNumber;
UINT32 PortImplementBitMap;
- UINT8 MaxCommandSlotNumber;
- BOOLEAN Support64Bit;
EFI_AHCI_REGISTERS *AhciRegisters;
@@ -1792,7 +2247,9 @@ AhciModeInitialization (
EFI_ATA_DEVICE_TYPE DeviceType;
EFI_ATA_COLLECTIVE_MODE *SupportedModes;
EFI_ATA_TRANSFER_MODE TransferMode;
-
+ UINT32 PhyDetectDelay;
+ UINT32 Value;
+
if (Instance == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -1800,35 +2257,55 @@ AhciModeInitialization (
PciIo = Instance->PciIo;
IdeInit = Instance->IdeControllerInit;
- Status = AhciReset (PciIo, ATA_ATAPI_TIMEOUT);
+ Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
//
- // Enable AE before accessing any AHCI registers
+ // Collect AHCI controller information
//
- AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
+ Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);
//
- // Collect AHCI controller information
+ // Make sure that GHC.AE bit is set before accessing any AHCI registers.
//
- Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);
+ Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);
+
+ if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
+ }
+
+ //
+ // Enable 64-bit DMA support in the PCI layer if this controller
+ // supports it.
+ //
+ if ((Capability & EFI_AHCI_CAP_S64A) != 0) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_WARN,
+ "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",
+ Status));
+ }
+ }
//
// Get the number of command slots per port supported by this HBA.
//
- MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);
- Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);
+ MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);
//
// Get the bit map of those ports exposed by this HBA.
- // It indicates which ports that the HBA supports are available for software to use.
+ // It indicates which ports that the HBA supports are available for software to use.
//
PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);
- MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);
-
+
AhciRegisters = &Instance->AhciRegisters;
Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);
@@ -1836,174 +2313,233 @@ AhciModeInitialization (
return EFI_OUT_OF_RESOURCES;
}
- for (Port = 0; Port < MaxPortNumber; Port ++) {
- Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
-
- //
- // Single task envrionment, we only use one command table for all port
- //
- Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
-
+ for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {
if ((PortImplementBitMap & (BIT0 << Port)) != 0) {
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-
- if ((Capability & EFI_AHCI_PORT_CMD_ASP) != 0) {
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);
+ //
+ // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.
+ //
+ if ((MaxPortNumber--) == 0) {
+ //
+ // Should never be here.
+ //
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
}
+
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);
+
+ //
+ // Initialize FIS Base Address Register and Command List Base Address Register for use.
+ //
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
+
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
Data = AhciReadReg (PciIo, Offset);
if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);
}
-
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE|EFI_AHCI_PORT_CMD_COL|EFI_AHCI_PORT_CMD_ST));
- }
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_MASK));
-
- AhciAndReg (PciIo, Offset,(UINT32) ~(EFI_AHCI_PORT_SCTL_IPM_PSD));
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_PSD);
-
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_SSD));
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_SSD);
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
- AhciAndReg (PciIo, Offset, 0);
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
- AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));
- }
- //
- // Stall for 100 milliseconds.
- //
- MicroSecondDelay(100000);
-
- IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);
-
- for (Port = 0; Port < MaxPortNumber; Port ++) {
- if ((PortImplementBitMap & (BIT0 << Port)) != 0) {
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
- Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
-
- if (Data == 0) {
- continue;
+ if ((Capability & EFI_AHCI_CAP_SSS) != 0) {
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);
}
+
//
- // Found device in the port
+ // Disable aggressive power management.
//
- if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
-
- Status = AhciWaitMemSet (
- PciIo,
- Offset,
- 0x0000FFFF,
- 0x00000101,
- ATA_ATAPI_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- continue;
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
+ //
+ // Disable the reporting of the corresponding interrupt to system software.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
+ AhciAndReg (PciIo, Offset, 0);
+
+ //
+ // Now inform the IDE Controller Init Module.
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);
+
+ //
+ // Enable FIS Receive DMA engine for the first D2H FIS.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);
+
+ //
+ // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.
+ // It's the requirment from SATA1.0a spec section 5.2.
+ //
+ PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
+ do {
+ Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
+ if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {
+ break;
}
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
+
+ if (PhyDetectDelay == 0) {
//
- // Now inform the IDE Controller Init Module.
+ // No device detected at this port.
+ // Clear PxCMD.SUD for those ports at which there are no device present.
//
- IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_SUD));
+ continue;
+ }
- Data = AhciReadReg (PciIo, Offset);
+ //
+ // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
+ // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
+ //
+ PhyDetectDelay = 16 * 1000;
+ do {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
+ if (AhciReadReg(PciIo, Offset) != 0) {
+ AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));
+ }
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
- if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {
- Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);
+ Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;
+ if (Data == 0) {
+ break;
+ }
- if (EFI_ERROR (Status)) {
- continue;
- }
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
- DeviceType = EfiIdeCdrom;
- } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {
- Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);
+ if (PhyDetectDelay == 0) {
+ DEBUG ((EFI_D_ERROR, "Port %d Device presence detected but phy not ready (TFD=0x%X)\n", Port, Data));
+ continue;
+ }
+
+ //
+ // When the first D2H register FIS is received, the content of PxSIG register is updated.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
+ Status = AhciWaitMmioSet (
+ PciIo,
+ Offset,
+ 0x0000FFFF,
+ 0x00000101,
+ EFI_TIMER_PERIOD_SECONDS(16)
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
- if (EFI_ERROR (Status)) {
- continue;
- }
+ Data = AhciReadReg (PciIo, Offset);
+ if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {
+ Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);
- DeviceType = EfiIdeHarddisk;
- } else {
+ if (EFI_ERROR (Status)) {
continue;
}
- DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",
- Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));
-
- //
- // Submit identify data to IDE controller init driver
- //
- IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);
+ DeviceType = EfiIdeCdrom;
+ } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {
+ Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);
- //
- // Now start to config ide device parameter and transfer mode.
- //
- Status = IdeInit->CalculateMode (
- IdeInit,
- Port,
- 0,
- &SupportedModes
- );
if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));
continue;
}
- //
- // Set best supported PIO mode on this IDE device
- //
- if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {
- TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;
- } else {
- TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;
- }
+ DeviceType = EfiIdeHarddisk;
+ } else {
+ continue;
+ }
+ DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",
+ Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));
- TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
-
- //
- // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
- // be set together. Only one DMA mode can be set to a device. If setting
- // DMA mode operation fails, we can continue moving on because we only use
- // PIO mode at boot time. DMA modes are used by certain kind of OS booting
- //
- if (SupportedModes->UdmaMode.Valid) {
- TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;
- TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
- } else if (SupportedModes->MultiWordDmaMode.Valid) {
- TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;
- TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
- }
+ //
+ // If the device is a hard disk, then try to enable S.M.A.R.T feature
+ //
+ if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {
+ AhciAtaSmartSupport (
+ PciIo,
+ AhciRegisters,
+ Port,
+ 0,
+ &Buffer,
+ NULL
+ );
+ }
- Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));
+ //
+ // Submit identify data to IDE controller init driver
+ //
+ IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
- continue;
- }
- //
- // Found a ATA or ATAPI device, add it into the device list.
- //
- CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);
+ //
+ // Now start to config ide device parameter and transfer mode.
+ //
+ Status = IdeInit->CalculateMode (
+ IdeInit,
+ Port,
+ 0,
+ &SupportedModes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+
+ //
+ // Set best supported PIO mode on this IDE device
+ //
+ if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;
+ } else {
+ TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;
+ }
+
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
+
+ //
+ // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
+ // be set together. Only one DMA mode can be set to a device. If setting
+ // DMA mode operation fails, we can continue moving on because we only use
+ // PIO mode at boot time. DMA modes are used by certain kind of OS booting
+ //
+ if (SupportedModes->UdmaMode.Valid) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
+ } else if (SupportedModes->MultiWordDmaMode.Valid) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;
+ TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
+ }
+
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+
+ //
+ // Found a ATA or ATAPI device, add it into the device list.
+ //
+ CreateNewDeviceInfo (Instance, Port, 0xFFFF, DeviceType, &Buffer);
+ if (DeviceType == EfiIdeHarddisk) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));
}
}
}
+
return EFI_SUCCESS;
}