/** @file\r
The file for AHCI mode of ATA host controller.\r
\r
- Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
)\r
{\r
UINT32 Value;\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
\r
- Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+ Delay = DivU64x32 (Timeout, 1000) + 1;\r
\r
do {\r
//\r
\r
Delay--;\r
\r
- } while (Delay > 0);\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
return EFI_TIMEOUT;\r
}\r
)\r
{\r
UINT32 Value;\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
\r
- Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+ Delay = DivU64x32 (Timeout, 1000) + 1;\r
\r
do {\r
//\r
\r
Delay--;\r
\r
- } while (Delay > 0);\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
return EFI_TIMEOUT;\r
}\r
@param[in] Address The memory address to test.\r
@param[in] MaskValue The mask value of memory.\r
@param[in] TestValue The test value of memory.\r
- @param[in, out] RetryTimes The retry times value for waitting memory set. If 0, then just try once.\r
+ @param[in, out] Task Optional. Pointer to the ATA_NONBLOCK_TASK used by\r
+ non-blocking mode. If NULL, then just try once.\r
\r
@retval EFI_NOTREADY The memory is not set.\r
@retval EFI_TIMEOUT The memory setting retry times out.\r
IN UINTN Address,\r
IN UINT32 MaskValue,\r
IN UINT32 TestValue,\r
- IN OUT UINTN *RetryTimes OPTIONAL\r
+ IN OUT ATA_NONBLOCK_TASK *Task\r
)\r
{\r
UINT32 Value;\r
\r
- if (RetryTimes != NULL) {\r
- (*RetryTimes)--;\r
+ if (Task != NULL) {\r
+ Task->RetryTimes--;\r
}\r
\r
Value = *(volatile UINT32 *) Address;\r
return EFI_SUCCESS;\r
}\r
\r
- if ((RetryTimes != NULL) && (*RetryTimes == 0)) {\r
+ if ((Task != NULL) && !Task->InfiniteWait && (Task->RetryTimes == 0)) {\r
return EFI_TIMEOUT;\r
} else {\r
return EFI_NOT_READY;\r
}\r
}\r
\r
-/**\r
- Check if the device is still on port. It also checks if the AHCI controller\r
- supports the address and data count will be transferred.\r
-\r
- @param PciIo The PCI IO protocol instance.\r
- @param Port The number of port.\r
-\r
- @retval EFI_SUCCESS The device is attached to port and the transfer data is\r
- supported by AHCI controller.\r
- @retval EFI_UNSUPPORTED The transfer address and count is not supported by AHCI\r
- controller.\r
- @retval EFI_NOT_READY The physical communication between AHCI controller and device\r
- is not ready.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciCheckDeviceStatus (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT8 Port\r
- )\r
-{\r
- UINT32 Data;\r
- UINT32 Offset;\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
-\r
- Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
-\r
- if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return EFI_NOT_READY;\r
-}\r
\r
/**\r
\r
in the Status Register, the Error Register's value is also be dumped.\r
\r
@param PciIo The PCI IO protocol instance.\r
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
@param Port The number of port.\r
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
\r
EFIAPI\r
AhciDumpPortStatus (\r
IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_AHCI_REGISTERS *AhciRegisters,\r
IN UINT8 Port,\r
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
)\r
{\r
- UINT32 Offset;\r
+ UINTN Offset;\r
UINT32 Data;\r
+ UINTN FisBaseAddr;\r
+ EFI_STATUS Status;\r
\r
ASSERT (PciIo != NULL);\r
\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
- Data = AhciReadReg (PciIo, Offset);\r
-\r
if (AtaStatusBlock != NULL) {\r
ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
\r
- AtaStatusBlock->AtaStatus = (UINT8)Data;\r
- if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
- AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\r
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+\r
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If D2H FIS is received, update StatusBlock with its content.\r
+ //\r
+ CopyMem (AtaStatusBlock, (UINT8 *)Offset, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ } else {\r
+ //\r
+ // If D2H FIS is not received, only update Status & Error field through PxTFD\r
+ // as there is no other way to get the content of the Shadow Register Block.\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+ Data = AhciReadReg (PciIo, (UINT32)Offset);\r
+\r
+ AtaStatusBlock->AtaStatus = (UINT8)Data;\r
+ if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
+ AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\r
+ }\r
}\r
}\r
}\r
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
\r
- return AhciWaitMmioSet (\r
- PciIo,\r
- Offset,\r
- EFI_AHCI_PORT_CMD_FR,\r
- EFI_AHCI_PORT_CMD_FR,\r
- Timeout\r
- );\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
//\r
// Filling the PRDT\r
//\r
- PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;\r
+ PrdtNumber = (UINT32)DivU64x32 (((UINT64)DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1), EFI_AHCI_MAX_DATA_PER_PRDT);\r
\r
//\r
// According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.\r
\r
CommandList->AhciCmdA = 1;\r
CommandList->AhciCmdP = 1;\r
- CommandList->AhciCmdC = (DataLength == 0) ? 1 : 0;\r
\r
AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
} else {\r
VOID *Map;\r
UINTN MapLength;\r
EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
EFI_AHCI_COMMAND_FIS CFis;\r
EFI_AHCI_COMMAND_LIST CmdList;\r
UINT32 PortTfd;\r
UINT32 PrdCount;\r
+ BOOLEAN InfiniteWait;\r
+ BOOLEAN PioFisReceived;\r
+ BOOLEAN D2hFisReceived;\r
+\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
\r
if (Read) {\r
Flag = EfiPciIoOperationBusMasterWrite;\r
// Wait device sends the PIO setup fis before data transfer\r
//\r
Status = EFI_TIMEOUT;\r
- Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+ Delay = DivU64x32 (Timeout, 1000) + 1;\r
do {\r
+ PioFisReceived = FALSE;\r
+ D2hFisReceived = FALSE;\r
Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
-\r
- Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);\r
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, NULL);\r
if (!EFI_ERROR (Status)) {\r
+ PioFisReceived = TRUE;\r
+ }\r
+ //\r
+ // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.\r
+ // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device\r
+ // after the transaction is finished successfully.\r
+ // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.\r
+ // By this way, we can know if there is a real error happened.\r
+ //\r
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ D2hFisReceived = TRUE;\r
+ }\r
+\r
+ if (PioFisReceived || D2hFisReceived) {\r
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
//\r
- // PxTFD will be updated if there is a D2H or SetupFIS received. \r
- // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.\r
+ // PxTFD will be updated if there is a D2H or SetupFIS received.\r
//\r
if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
Status = EFI_DEVICE_ERROR;\r
\r
PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
if (PrdCount == DataCount) {\r
+ Status = EFI_SUCCESS;\r
break;\r
}\r
}\r
\r
- Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
- Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);\r
- if (!EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- break;\r
- }\r
-\r
//\r
// Stall for 100 microseconds.\r
//\r
MicroSecondDelay(100);\r
\r
Delay--;\r
- } while (Delay > 0);\r
+ if (Delay == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+ } while (InfiniteWait || (Delay > 0));\r
} else {\r
//\r
// Wait for D2H Fis is received\r
Map\r
);\r
\r
- AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
\r
return Status;\r
}\r
//\r
if (Task != NULL) {\r
Task->IsStart = TRUE;\r
- Task->RetryTimes = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
}\r
if (Read) {\r
Flag = EfiPciIoOperationBusMasterWrite;\r
Offset,\r
EFI_AHCI_FIS_TYPE_MASK,\r
EFI_AHCI_FIS_REGISTER_D2H,\r
- (UINTN *) (&Task->RetryTimes)\r
+ Task\r
);\r
} else {\r
Status = AhciWaitMemSet (\r
}\r
}\r
\r
- AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
return Status;\r
}\r
\r
Timeout\r
);\r
\r
- AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
\r
return Status;\r
}\r
//\r
// Setting the command\r
//\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
- AhciAndReg (PciIo, Offset, 0);\r
- AhciOrReg (PciIo, Offset, CmdSlotBit);\r
-\r
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
AhciAndReg (PciIo, Offset, 0);\r
AhciOrReg (PciIo, Offset, CmdSlotBit);\r
return EFI_SUCCESS;\r
}\r
\r
-/**\r
- Do AHCI port reset.\r
-\r
- @param PciIo The PCI IO protocol instance.\r
- @param Port The number of port.\r
- @param Timeout The timeout value of reset, uses 100ns as a unit.\r
-\r
- @retval EFI_DEVICE_ERROR The port reset unsuccessfully\r
- @retval EFI_TIMEOUT The reset operation is time out.\r
- @retval EFI_SUCCESS The port reset successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciPortReset (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT8 Port,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 Offset;\r
-\r
- AhciClearPortStatus (PciIo, Port);\r
-\r
- AhciStopCommand (PciIo, Port, Timeout);\r
-\r
- AhciDisableFisReceive (PciIo, Port, Timeout);\r
-\r
- AhciEnableFisReceive (PciIo, Port, Timeout);\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
-\r
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
-\r
- //\r
- // wait 5 millisecond before de-assert DET\r
- //\r
- MicroSecondDelay (5000);\r
-\r
- AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);\r
-\r
- //\r
- // wait 5 millisecond before de-assert DET\r
- //\r
- MicroSecondDelay (5000);\r
-\r
- //\r
- // Wait for communication to be re-established\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
- Status = AhciWaitMmioSet (\r
- PciIo,\r
- Offset,\r
- EFI_AHCI_PORT_SSTS_DET_MASK,\r
- EFI_AHCI_PORT_SSTS_DET_PCE,\r
- Timeout\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_ERR_CLEAR);\r
-\r
- return EFI_SUCCESS;\r
-}\r
\r
/**\r
Do AHCI HBA reset.\r
IN UINT64 Timeout\r
)\r
{\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
UINT32 Value;\r
\r
- AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+ //\r
+ // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
+ //\r
+ Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
+\r
+ if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+ }\r
\r
AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+ Delay = DivU64x32(Timeout, 1000) + 1;\r
\r
do {\r
Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
@param PciIo The PCI IO protocol instance.\r
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
@param Port The number of port.\r
- @param PortMultiplier The timeout value of stop.\r
+ @param PortMultiplier The port multiplier port number.\r
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
\r
@retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.\r
);\r
\r
if (EFI_ERROR (Status)) {\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
+ );\r
return EFI_DEVICE_ERROR;\r
}\r
\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
+ );\r
+\r
FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
\r
Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
// The threshold exceeded condition is not detected by the device\r
//\r
DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
-\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
+ );\r
} else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
//\r
// The threshold exceeded condition is detected by the device\r
//\r
DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
+ );\r
}\r
}\r
\r
@param PciIo The PCI IO protocol instance.\r
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
@param Port The number of port.\r
- @param PortMultiplier The timeout value of stop.\r
+ @param PortMultiplier The port multiplier port number.\r
@param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
\r
//\r
DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",\r
Port, PortMultiplier));\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
+ );\r
} else {\r
//\r
// Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
//\r
if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
+\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)\r
+ );\r
+\r
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
\r
AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
@param PciIo The PCI IO protocol instance.\r
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
@param Port The number of port.\r
- @param PortMultiplier The timeout value of stop.\r
+ @param PortMultiplier The port multiplier port number.\r
@param Buffer The data buffer to store IDENTIFY PACKET data.\r
\r
@retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
@param PciIo The PCI IO protocol instance.\r
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
@param Port The number of port.\r
- @param PortMultiplier The timeout value of stop.\r
+ @param PortMultiplier The port multiplier port number.\r
@param Buffer The data buffer to store IDENTIFY PACKET data.\r
\r
@retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
@param PciIo The PCI IO protocol instance.\r
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
@param Port The number of port.\r
- @param PortMultiplier The timeout value of stop.\r
+ @param PortMultiplier The port multiplier port number.\r
@param Feature The data to send Feature register.\r
@param FeatureSpecificData The specific data for SET FEATURE cmd.\r
+ @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.\r
\r
@retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
@retval EFI_TIMEOUT The operation is time out.\r
IN UINT8 Port,\r
IN UINT8 PortMultiplier,\r
IN UINT16 Feature,\r
- IN UINT32 FeatureSpecificData\r
+ IN UINT32 FeatureSpecificData,\r
+ IN UINT64 Timeout\r
)\r
{\r
EFI_STATUS Status;\r
0,\r
&AtaCommandBlock,\r
&AtaStatusBlock,\r
- ATA_ATAPI_TIMEOUT,\r
+ Timeout,\r
NULL\r
);\r
\r
VOID *Buffer;\r
\r
UINT32 Capability;\r
+ UINT32 PortImplementBitMap;\r
UINT8 MaxPortNumber;\r
UINT8 MaxCommandSlotNumber;\r
BOOLEAN Support64Bit;\r
// Collect AHCI controller information\r
//\r
Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
- MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
//\r
// Get the number of command slots per port supported by this HBA.\r
//\r
MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
\r
+ PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
+ //\r
+ // Get the highest bit of implemented ports which decides how many bytes are allocated for recived FIS.\r
+ //\r
+ MaxPortNumber = (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1);\r
+ if (MaxPortNumber == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
Status = PciIo->AllocateBuffer (\r
PciIo,\r
return Status;\r
}\r
\r
+/**\r
+ Read logs from SATA device.\r
+\r
+ @param PciIo The PCI IO protocol instance.\r
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The multiplier of port.\r
+ @param Buffer The data buffer to store SATA logs.\r
+ @param LogNumber The address of the log.\r
+ @param PageNumber The page number of the log.\r
+\r
+ @retval EFI_INVALID_PARAMETER PciIo, AhciRegisters or Buffer is NULL.\r
+ @retval others Return status of AhciPioTransfer().\r
+**/\r
+EFI_STATUS\r
+AhciReadLogExt (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_AHCI_REGISTERS *AhciRegisters,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN OUT UINT8 *Buffer,\r
+ IN UINT8 LogNumber,\r
+ IN UINT8 PageNumber\r
+ )\r
+{\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
+\r
+ if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ///\r
+ /// Read log from device\r
+ ///\r
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ ZeroMem (Buffer, 512);\r
+\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_READ_LOG_EXT;\r
+ AtaCommandBlock.AtaSectorCount = 1;\r
+ AtaCommandBlock.AtaSectorNumber = LogNumber;\r
+ AtaCommandBlock.AtaCylinderLow = PageNumber;\r
+\r
+ return AhciPioTransfer (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ PortMultiplier,\r
+ NULL,\r
+ 0,\r
+ TRUE,\r
+ &AtaCommandBlock,\r
+ &AtaStatusBlock,\r
+ Buffer,\r
+ 512,\r
+ ATA_ATAPI_TIMEOUT,\r
+ NULL\r
+ );\r
+}\r
+\r
+/**\r
+ Enable DEVSLP of the disk if supported.\r
+\r
+ @param PciIo The PCI IO protocol instance.\r
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The multiplier of port.\r
+ @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
+\r
+ @retval EFI_SUCCESS The DEVSLP is enabled per policy successfully.\r
+ @retval EFI_UNSUPPORTED The DEVSLP isn't supported by the controller/device and policy requires to enable it.\r
+**/\r
+EFI_STATUS\r
+AhciEnableDevSlp (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_AHCI_REGISTERS *AhciRegisters,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN EFI_IDENTIFY_DATA *IdentifyData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Offset;\r
+ UINT32 Capability2;\r
+ UINT8 LogData[512];\r
+ DEVSLP_TIMING_VARIABLES DevSlpTiming;\r
+ UINT32 PortCmd;\r
+ UINT32 PortDevSlp;\r
+\r
+ if (mAtaAtapiPolicy->DeviceSleepEnable != 1) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Do not enable DevSlp if DevSlp is not supported.\r
+ //\r
+ Capability2 = AhciReadReg (PciIo, AHCI_CAPABILITY2_OFFSET);\r
+ DEBUG ((DEBUG_INFO, "AHCI CAPABILITY2 = %08x\n", Capability2));\r
+ if ((Capability2 & AHCI_CAP2_SDS) == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Do not enable DevSlp if DevSlp is not present\r
+ // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH;\r
+ PortCmd = AhciReadReg (PciIo, Offset + EFI_AHCI_PORT_CMD);\r
+ PortDevSlp = AhciReadReg (PciIo, Offset + AHCI_PORT_DEVSLP);\r
+ DEBUG ((DEBUG_INFO, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd, PortDevSlp));\r
+ if (((PortDevSlp & AHCI_PORT_DEVSLP_DSP) == 0) ||\r
+ ((PortCmd & (EFI_AHCI_PORT_CMD_HPCP | EFI_AHCI_PORT_CMD_MPSP)) != 0)\r
+ ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Do not enable DevSlp if the device doesn't support DevSlp\r
+ //\r
+ DEBUG ((DEBUG_INFO, "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",\r
+ IdentifyData->AtaData.reserved_77,\r
+ IdentifyData->AtaData.serial_ata_features_supported, IdentifyData->AtaData.serial_ata_features_enabled));\r
+ if ((IdentifyData->AtaData.serial_ata_features_supported & BIT8) == 0) {\r
+ DEBUG ((DEBUG_INFO, "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",\r
+ Port, PortMultiplier));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Enable DevSlp when it is not enabled.\r
+ //\r
+ if ((IdentifyData->AtaData.serial_ata_features_enabled & BIT8) != 0) {\r
+ Status = AhciDeviceSetFeature (\r
+ PciIo, AhciRegisters, Port, 0, ATA_SUB_CMD_ENABLE_SATA_FEATURE, 0x09, ATA_ATAPI_TIMEOUT\r
+ );\r
+ DEBUG ((DEBUG_INFO, "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",\r
+ Port, PortMultiplier, Status));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ Status = AhciReadLogExt(PciIo, AhciRegisters, Port, PortMultiplier, LogData, 0x30, 0x08);\r
+\r
+ //\r
+ // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.\r
+ //\r
+ AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd & ~EFI_AHCI_PORT_CMD_ST);\r
+ PortDevSlp &= ~AHCI_PORT_DEVSLP_ADSE;\r
+ AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+ //\r
+ // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.\r
+ //\r
+ PortDevSlp &= ~AHCI_PORT_DEVSLP_DETO_MASK;\r
+ PortDevSlp &= ~AHCI_PORT_DEVSLP_MDAT_MASK;\r
+ AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+ DEBUG ((DEBUG_INFO, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port, PortMultiplier, Status));\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails\r
+ //\r
+ ZeroMem (&DevSlpTiming, sizeof (DevSlpTiming));\r
+ } else {\r
+ CopyMem (&DevSlpTiming, &LogData[48], sizeof (DevSlpTiming));\r
+ DEBUG ((DEBUG_INFO, "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",\r
+ DevSlpTiming.Supported, DevSlpTiming.Deto, DevSlpTiming.Madt));\r
+ }\r
+\r
+ //\r
+ // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.\r
+ //\r
+ if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Deto == 0)) {\r
+ DevSlpTiming.Deto = 20;\r
+ }\r
+\r
+ //\r
+ // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.\r
+ //\r
+ if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Madt == 0)) {\r
+ DevSlpTiming.Madt = 10;\r
+ }\r
+\r
+ PortDevSlp |= DevSlpTiming.Deto << 2;\r
+ PortDevSlp |= DevSlpTiming.Madt << 10;\r
+ AhciOrReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+ if (mAtaAtapiPolicy->AggressiveDeviceSleepEnable == 1) {\r
+ if ((Capability2 & AHCI_CAP2_SADM) != 0) {\r
+ PortDevSlp &= ~AHCI_PORT_DEVSLP_DITO_MASK;\r
+ PortDevSlp |= (625 << 15);\r
+ AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+ PortDevSlp |= AHCI_PORT_DEVSLP_ADSE;\r
+ AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+ }\r
+ }\r
+\r
+\r
+ AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd);\r
+\r
+ DEBUG ((DEBUG_INFO, "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",\r
+ Port, PortMultiplier, PortCmd, PortDevSlp));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Spin-up disk if IDD was incomplete or PUIS feature is enabled\r
+\r
+ @param PciIo The PCI IO protocol instance.\r
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The multiplier of port.\r
+ @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
+\r
+**/\r
+EFI_STATUS\r
+AhciSpinUpDisk (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_AHCI_REGISTERS *AhciRegisters,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier,\r
+ IN OUT EFI_IDENTIFY_DATA *IdentifyData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+ EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
+ UINT8 Buffer[512];\r
+\r
+ if (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE) {\r
+ //\r
+ // Use SET_FEATURE subcommand to spin up the device.\r
+ //\r
+ Status = AhciDeviceSetFeature (\r
+ PciIo, AhciRegisters, Port, PortMultiplier,\r
+ ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP, 0x00, ATA_SPINUP_TIMEOUT\r
+ );\r
+ DEBUG ((DEBUG_INFO, "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+ Port, PortMultiplier, Status));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ ASSERT (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE);\r
+\r
+ //\r
+ // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported\r
+ //\r
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+ ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ //\r
+ // Perform READ SECTORS PIO Data-In command to Read LBA 0\r
+ //\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_READ_SECTORS;\r
+ AtaCommandBlock.AtaSectorCount = 0x1;\r
+\r
+ Status = AhciPioTransfer (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ PortMultiplier,\r
+ NULL,\r
+ 0,\r
+ TRUE,\r
+ &AtaCommandBlock,\r
+ &AtaStatusBlock,\r
+ &Buffer,\r
+ sizeof (Buffer),\r
+ ATA_SPINUP_TIMEOUT,\r
+ NULL\r
+ );\r
+ DEBUG ((DEBUG_INFO, "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+ Port, PortMultiplier, Status));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Read the complete IDENTIFY DEVICE data.\r
+ //\r
+ ZeroMem (IdentifyData, sizeof (*IdentifyData));\r
+ Status = AhciIdentify (PciIo, AhciRegisters, Port, PortMultiplier, IdentifyData);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+ Port, PortMultiplier, Status));\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
+ IdentifyData->AtaData.config, IdentifyData->AtaData.specific_config,\r
+ IdentifyData->AtaData.command_set_supported_83, IdentifyData->AtaData.command_set_feature_enb_86));\r
+ //\r
+ // Check if IDD is incomplete\r
+ //\r
+ if ((IdentifyData->AtaData.config & BIT2) != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Enable/disable/skip PUIS of the disk according to policy.\r
+\r
+ @param PciIo The PCI IO protocol instance.\r
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
+ @param Port The number of port.\r
+ @param PortMultiplier The multiplier of port.\r
+\r
+**/\r
+EFI_STATUS\r
+AhciPuisEnable (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_AHCI_REGISTERS *AhciRegisters,\r
+ IN UINT8 Port,\r
+ IN UINT8 PortMultiplier\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (mAtaAtapiPolicy->PuisEnable == 0) {\r
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_DISABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);\r
+ } else if (mAtaAtapiPolicy->PuisEnable == 1) {\r
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_ENABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);\r
+ }\r
+ DEBUG ((DEBUG_INFO, "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",\r
+ (mAtaAtapiPolicy->PuisEnable == 0) ? "Disable" : (\r
+ (mAtaAtapiPolicy->PuisEnable == 1) ? "Enable" : "Skip"\r
+ ), Port, PortMultiplier, Status));\r
+ return Status;\r
+}\r
+\r
/**\r
Initialize ATA host controller at AHCI mode.\r
\r
EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
EFI_ATA_TRANSFER_MODE TransferMode;\r
UINT32 PhyDetectDelay;\r
+ UINT32 Value;\r
\r
if (Instance == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
//\r
- // Enable AE before accessing any AHCI registers\r
+ // Collect AHCI controller information\r
//\r
- AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+ Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
\r
//\r
- // Collect AHCI controller information\r
+ // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
//\r
- Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
+ Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
+\r
+ if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+ }\r
+\r
+ //\r
+ // Enable 64-bit DMA support in the PCI layer if this controller\r
+ // supports it.\r
+ //\r
+ if ((Capability & EFI_AHCI_CAP_S64A) != 0) {\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_WARN,\r
+ "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",\r
+ Status));\r
+ }\r
+ }\r
\r
//\r
// Get the number of command slots per port supported by this HBA.\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- for (Port = 0; Port < MaxPortNumber; Port ++) {\r
- if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
+ for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {\r
+ if ((PortImplementBitMap & (((UINT32)BIT0) << Port)) != 0) {\r
+ //\r
+ // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.\r
+ //\r
+ if ((MaxPortNumber--) == 0) {\r
+ //\r
+ // Should never be here.\r
+ //\r
+ ASSERT (FALSE);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
\r
//\r
//\r
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
- Status = AhciWaitMmioSet (\r
- PciIo,\r
- Offset,\r
- EFI_AHCI_PORT_CMD_FR,\r
- EFI_AHCI_PORT_CMD_FR,\r
- EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
\r
//\r
- // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.\r
- // It's the requirment from SATA1.0a spec section 5.2.\r
+ // Wait for the Phy to detect the presence of a device.\r
//\r
PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;\r
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
} while (PhyDetectDelay > 0);\r
\r
if (PhyDetectDelay == 0) {\r
+ DEBUG ((EFI_D_ERROR, "Port %d Device presence detected but phy not ready (TFD=0x%X)\n", Port, Data));\r
continue;\r
}\r
\r
continue;\r
}\r
\r
+ DEBUG ((\r
+ DEBUG_INFO, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
+ Buffer.AtaData.config, Buffer.AtaData.specific_config,\r
+ Buffer.AtaData.command_set_supported_83, Buffer.AtaData.command_set_feature_enb_86\r
+ ));\r
+ if ((Buffer.AtaData.config & BIT2) != 0) {\r
+ //\r
+ // SpinUp disk if device reported incomplete IDENTIFY DEVICE.\r
+ //\r
+ Status = AhciSpinUpDisk (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ 0,\r
+ &Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Spin up standby device failed - %r\n", Status));\r
+ continue;\r
+ }\r
+ }\r
+\r
DeviceType = EfiIdeHarddisk;\r
} else {\r
continue;\r
TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
}\r
\r
- Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode), ATA_ATAPI_TIMEOUT);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
continue;\r
//\r
// Found a ATA or ATAPI device, add it into the device list.\r
//\r
- CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
+ CreateNewDeviceInfo (Instance, Port, 0xFFFF, DeviceType, &Buffer);\r
if (DeviceType == EfiIdeHarddisk) {\r
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
+ AhciEnableDevSlp (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ 0,\r
+ &Buffer\r
+ );\r
+ }\r
+\r
+ //\r
+ // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).\r
+ //\r
+ if ((Buffer.AtaData.command_set_supported_83 & BIT5) != 0) {\r
+ Status = AhciPuisEnable (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "PUIS enable/disable failed, Status = %r\n", Status));\r
+ continue;\r
+ }\r
}\r
}\r
}\r