/** @file\r
The file for AHCI mode of ATA host controller.\r
- \r
- Copyright (c) 2010 - 2011, 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 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP<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
\r
**/\r
\r
UINT32 Data;\r
\r
ASSERT (PciIo != NULL);\r
- \r
+\r
Data = 0;\r
\r
PciIo->Mem.Read (\r
)\r
{\r
UINT32 Data;\r
- \r
+\r
ASSERT (PciIo != NULL);\r
\r
Data = AhciReadReg (PciIo, Offset);\r
}\r
\r
/**\r
- Wait for memory set to the test value.\r
- \r
+ Wait for the value of the specified MMIO register set to the test value.\r
+\r
@param PciIo The PCI IO protocol instance.\r
- @param Offset The memory address to test.\r
+ @param Offset The MMIO address to test.\r
@param MaskValue The mask value of memory.\r
@param TestValue The test value of memory.\r
- @param Timeout The time out value for wait memory set.\r
+ @param Timeout The time out value for wait memory set, uses 100ns as a unit.\r
\r
- @retval EFI_DEVICE_ERROR The memory is not set.\r
- @retval EFI_TIMEOUT The memory setting is time out.\r
- @retval EFI_SUCCESS The memory is correct set.\r
+ @retval EFI_TIMEOUT The MMIO setting is time out.\r
+ @retval EFI_SUCCESS The MMIO is correct set.\r
\r
**/\r
EFI_STATUS\r
EFIAPI\r
-AhciWaitMemSet (\r
+AhciWaitMmioSet (\r
IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT32 Offset,\r
+ IN UINTN Offset,\r
IN UINT32 MaskValue,\r
IN UINT32 TestValue,\r
IN UINT64 Timeout\r
)\r
{\r
- UINT32 Value; \r
- UINT32 Delay;\r
+ UINT32 Value;\r
+ UINT64 Delay;\r
+ BOOLEAN InfiniteWait;\r
\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ Delay = DivU64x32 (Timeout, 1000) + 1;\r
\r
do {\r
- Value = AhciReadReg (PciIo, Offset) & MaskValue;\r
+ //\r
+ // Access PCI MMIO space to see if the value is the tested one.\r
+ //\r
+ Value = AhciReadReg (PciIo, (UINT32) Offset) & MaskValue;\r
\r
if (Value == TestValue) {\r
return EFI_SUCCESS;\r
\r
Delay--;\r
\r
- } while (Delay > 0);\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Wait for the value of the specified system memory set to the test value.\r
+\r
+ @param Address The system memory address to test.\r
+ @param MaskValue The mask value of memory.\r
+ @param TestValue The test value of memory.\r
+ @param Timeout The time out value for wait memory set, uses 100ns as a unit.\r
+\r
+ @retval EFI_TIMEOUT The system memory setting is time out.\r
+ @retval EFI_SUCCESS The system memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciWaitMemSet (\r
+ IN EFI_PHYSICAL_ADDRESS Address,\r
+ IN UINT32 MaskValue,\r
+ IN UINT32 TestValue,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ UINT32 Value;\r
+ UINT64 Delay;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
}\r
\r
- return EFI_DEVICE_ERROR;\r
+ Delay = DivU64x32 (Timeout, 1000) + 1;\r
+\r
+ do {\r
+ //\r
+ // Access sytem memory to see if the value is the tested one.\r
+ //\r
+ // The system memory pointed by Address will be updated by the\r
+ // SATA Host Controller, "volatile" is introduced to prevent\r
+ // compiler from optimizing the access to the memory address\r
+ // to only read once.\r
+ //\r
+ Value = *(volatile UINT32 *) (UINTN) Address;\r
+ Value &= MaskValue;\r
+\r
+ if (Value == TestValue) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Stall for 100 microseconds.\r
+ //\r
+ MicroSecondDelay (100);\r
+\r
+ Delay--;\r
+\r
+ } while (InfiniteWait || (Delay > 0));\r
+\r
+ return EFI_TIMEOUT;\r
}\r
\r
/**\r
Check the memory status to the test value.\r
- \r
- @param[in] PciIo The PCI IO protocol instance.\r
- @param[in] Offset The memory address to test.\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.\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
EFI_STATUS\r
EFIAPI\r
AhciCheckMemSet (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT32 Offset,\r
- IN UINT32 MaskValue,\r
- IN UINT32 TestValue,\r
- IN UINTN *RetryTimes\r
+ IN UINTN Address,\r
+ IN UINT32 MaskValue,\r
+ IN UINT32 TestValue,\r
+ IN OUT ATA_NONBLOCK_TASK *Task\r
)\r
{\r
UINT32 Value;\r
\r
- (*RetryTimes) --;\r
- \r
- Value = AhciReadReg (PciIo, Offset) & MaskValue;\r
+ if (Task != NULL) {\r
+ Task->RetryTimes--;\r
+ }\r
+\r
+ Value = *(volatile UINT32 *) Address;\r
+ Value &= MaskValue;\r
\r
if (Value == TestValue) {\r
return EFI_SUCCESS;\r
}\r
\r
- if ((*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
- Check if the device is still on port. It also checks if the AHCI controller \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
+ @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
\r
Clear the port interrupt and error status. It will also clear\r
HBA interrupt status.\r
- \r
+\r
@param PciIo The PCI IO protocol instance.\r
@param Port The number of port.\r
- \r
-**/ \r
+\r
+**/\r
VOID\r
EFIAPI\r
AhciClearPortStatus (\r
IN EFI_PCI_IO_PROTOCOL *PciIo,\r
IN UINT8 Port\r
- ) \r
+ )\r
{\r
UINT32 Offset;\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
\r
/**\r
Enable the FIS running for giving port.\r
- \r
+\r
@param PciIo The PCI IO protocol instance.\r
@param Port The number of port.\r
- @param Timeout The timeout value of enabling FIS.\r
+ @param Timeout The timeout value of enabling FIS, uses 100ns as a unit.\r
\r
@retval EFI_DEVICE_ERROR The FIS enable setting fails.\r
@retval EFI_TIMEOUT The FIS enable setting is time out.\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 AhciWaitMemSet (\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
@param PciIo The PCI IO protocol instance.\r
@param Port The number of port.\r
- @param Timeout The timeout value of disabling FIS.\r
+ @param Timeout The timeout value of disabling FIS, uses 100ns as a unit.\r
\r
@retval EFI_DEVICE_ERROR The FIS disable setting fails.\r
@retval EFI_TIMEOUT The FIS disable setting is time out.\r
IN EFI_PCI_IO_PROTOCOL *PciIo,\r
IN UINT8 Port,\r
IN UINT64 Timeout\r
- ) \r
+ )\r
{\r
UINT32 Offset;\r
UINT32 Data;\r
if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
return EFI_UNSUPPORTED;\r
}\r
- \r
+\r
//\r
// Check if the Fis receive DMA engine for the port is running.\r
//\r
\r
AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
\r
- return AhciWaitMemSet (\r
+ return AhciWaitMmioSet (\r
PciIo,\r
Offset,\r
EFI_AHCI_PORT_CMD_FR,\r
\r
/**\r
Build the command list, command table and prepare the fis receiver.\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 DataPhysicalAddr The pointer to the data buffer pci bus master address.\r
@param DataLength The data count to be transferred.\r
\r
-**/ \r
+**/\r
VOID\r
EFIAPI\r
AhciBuildCommand (\r
IN UINT8 AtapiCommandLength,\r
IN UINT8 CommandSlotNumber,\r
IN OUT VOID *DataPhysicalAddr,\r
- IN UINT64 DataLength\r
- ) \r
+ IN UINT32 DataLength\r
+ )\r
{\r
UINT64 BaseAddr;\r
- UINT64 PrdtNumber;\r
- UINT64 PrdtIndex;\r
+ UINT32 PrdtNumber;\r
+ UINT32 PrdtIndex;\r
UINTN RemainedData;\r
UINTN MemAddr;\r
DATA_64 Data64;\r
\r
//\r
// Filling the PRDT\r
- // \r
- PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;\r
+ //\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
Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
\r
BaseAddr = Data64.Uint64;\r
- \r
+\r
ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
- \r
+\r
ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
\r
CommandFis->AhciCFisPmNum = PortMultiplier;\r
- \r
+\r
CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
\r
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\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
AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
}\r
- \r
+\r
RemainedData = (UINTN) DataLength;\r
MemAddr = (UINTN) DataPhysicalAddr;\r
- CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
- \r
+ CommandList->AhciCmdPrdtl = PrdtNumber;\r
+\r
for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {\r
AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
(VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
CommandList,\r
sizeof (EFI_AHCI_COMMAND_LIST)\r
- ); \r
+ );\r
\r
Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;\r
AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;\r
\r
/**\r
Buid a command FIS.\r
- \r
+\r
@param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.\r
@param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.\r
\r
//\r
// Indicator it's a command\r
//\r
- CmdFis->AhciCFisCmdInd = 0x1; \r
+ CmdFis->AhciCFisCmdInd = 0x1;\r
CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;\r
\r
CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;\r
\r
/**\r
Start a PIO data transfer on specific port.\r
- \r
+\r
@param[in] PciIo The PCI IO protocol instance.\r
@param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
@param[in] Port The number of port.\r
@param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
@param[in, out] MemoryAddr The pointer to the data buffer.\r
@param[in] DataCount The data count to be transferred.\r
- @param[in] Timeout The timeout value of non data transfer.\r
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
@param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
used by non-blocking mode.\r
\r
IN UINT8 Port,\r
IN UINT8 PortMultiplier,\r
IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
- IN UINT8 AtapiCommandLength, \r
- IN BOOLEAN Read, \r
+ IN UINT8 AtapiCommandLength,\r
+ IN BOOLEAN Read,\r
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
IN OUT VOID *MemoryAddr,\r
{\r
EFI_STATUS Status;\r
UINTN FisBaseAddr;\r
- UINT32 Offset;\r
- UINT32 Value;\r
+ UINTN Offset;\r
EFI_PHYSICAL_ADDRESS PhyAddr;\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
);\r
\r
if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
- return EFI_OUT_OF_RESOURCES;\r
+ return EFI_BAD_BUFFER_SIZE;\r
}\r
- \r
+\r
//\r
// Package read needed\r
//\r
0,\r
(VOID *)(UINTN)PhyAddr,\r
DataCount\r
- ); \r
- \r
+ );\r
+\r
Status = AhciStartCommand (\r
PciIo,\r
Port,\r
// Check the status and wait the driver sending data\r
//\r
FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
- //\r
- // Wait device sends the PIO setup fis before data transfer\r
- //\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
- do {\r
- Value = *(volatile UINT32 *) (FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET);\r
-\r
- if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_PIO_SETUP) {\r
- break;\r
- }\r
\r
+ if (Read && (AtapiCommand == 0)) {\r
//\r
- // Stall for 100 microseconds.\r
+ // Wait device sends the PIO setup fis before data transfer\r
//\r
- MicroSecondDelay(100);\r
+ Status = EFI_TIMEOUT;\r
+ Delay = DivU64x32 (Timeout, 1000) + 1;\r
+ do {\r
+ PioFisReceived = FALSE;\r
+ D2hFisReceived = FALSE;\r
+ Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\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
- Delay--;\r
- } while (Delay > 0);\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
+ //\r
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
\r
- if (Delay == 0) {\r
- Status = EFI_TIMEOUT;\r
- goto Exit;\r
- }\r
+ PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
+ if (PrdCount == DataCount) {\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
\r
- //\r
- // Wait for command compelte\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
- Status = AhciWaitMemSet (\r
- PciIo,\r
- Offset,\r
- 0xFFFFFFFF,\r
- 0,\r
- Timeout\r
- );\r
+ //\r
+ // Stall for 100 microseconds.\r
+ //\r
+ MicroSecondDelay(100);\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Exit;\r
- }\r
+ Delay--;\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
+ //\r
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+ Status = AhciWaitMemSet (\r
+ Offset,\r
+ EFI_AHCI_FIS_TYPE_MASK,\r
+ EFI_AHCI_FIS_REGISTER_D2H,\r
+ Timeout\r
+ );\r
\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
- Status = AhciWaitMemSet (\r
- PciIo,\r
- Offset,\r
- EFI_AHCI_PORT_IS_PSS,\r
- EFI_AHCI_PORT_IS_PSS,\r
- Timeout\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Exit;\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
}\r
\r
Exit:\r
Port,\r
Timeout\r
);\r
- \r
+\r
AhciDisableFisReceive (\r
PciIo,\r
Port,\r
Map\r
);\r
\r
- AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
\r
return Status;\r
}\r
@param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
@param[in, out] MemoryAddr The pointer to the data buffer.\r
@param[in] DataCount The data count to be transferred.\r
- @param[in] Timeout The timeout value of non data transfer.\r
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
@param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
used by non-blocking mode.\r
\r
IN UINT8 PortMultiplier,\r
IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
IN UINT8 AtapiCommandLength,\r
- IN BOOLEAN Read, \r
+ IN BOOLEAN Read,\r
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
IN OUT VOID *MemoryAddr,\r
- IN UINTN DataCount,\r
+ IN UINT32 DataCount,\r
IN UINT64 Timeout,\r
IN ATA_NONBLOCK_TASK *Task\r
)\r
{\r
EFI_STATUS Status;\r
- UINT32 Offset;\r
+ UINTN Offset;\r
EFI_PHYSICAL_ADDRESS PhyAddr;\r
VOID *Map;\r
UINTN MapLength;\r
EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
EFI_AHCI_COMMAND_FIS CFis;\r
EFI_AHCI_COMMAND_LIST CmdList;\r
+ UINTN FisBaseAddr;\r
+ UINT32 PortTfd;\r
\r
- EFI_PCI_IO_PROTOCOL *PciIo;\r
- EFI_TPL OldTpl;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_TPL OldTpl;\r
\r
Map = NULL;\r
PciIo = Instance->PciIo;\r
// BlockIO tasks.\r
// Delay 100us to simulate the blocking time out checking.\r
//\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
AsyncNonBlockingTransferRoutine (NULL, Instance);\r
- gBS->RestoreTPL (OldTpl); \r
//\r
// Stall for 100us.\r
//\r
MicroSecondDelay (100);\r
}\r
+ gBS->RestoreTPL (OldTpl);\r
\r
if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {\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
);\r
\r
if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
- return EFI_OUT_OF_RESOURCES;\r
+ return EFI_BAD_BUFFER_SIZE;\r
}\r
\r
if (Task != NULL) {\r
if (EFI_ERROR (Status)) {\r
goto Exit;\r
}\r
-\r
- //\r
- // Wait device PRD processed\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
- Status = AhciWaitMemSet (\r
- PciIo,\r
- Offset,\r
- EFI_AHCI_PORT_IS_DPS,\r
- EFI_AHCI_PORT_IS_DPS,\r
- Timeout\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Exit;\r
- }\r
}\r
\r
//\r
// Wait for command compelte\r
//\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
if (Task != NULL) {\r
//\r
// For Non-blocking\r
//\r
Status = AhciCheckMemSet (\r
- PciIo,\r
Offset,\r
- 0xFFFFFFFF,\r
- 0,\r
- (UINTN *) (&Task->RetryTimes)\r
+ EFI_AHCI_FIS_TYPE_MASK,\r
+ EFI_AHCI_FIS_REGISTER_D2H,\r
+ Task\r
);\r
} else {\r
Status = AhciWaitMemSet (\r
- PciIo,\r
Offset,\r
- 0xFFFFFFFF,\r
- 0,\r
+ EFI_AHCI_FIS_TYPE_MASK,\r
+ EFI_AHCI_FIS_REGISTER_D2H,\r
Timeout\r
);\r
}\r
goto Exit;\r
}\r
\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
-\r
- if (Task != NULL) {\r
- //\r
- // For Non-blocking\r
- //\r
- Status = AhciCheckMemSet (\r
- PciIo,\r
- Offset,\r
- EFI_AHCI_PORT_IS_DHRS,\r
- EFI_AHCI_PORT_IS_DHRS,\r
- (UINTN *) (&Task->RetryTimes)\r
- );\r
- } else {\r
- Status = AhciWaitMemSet (\r
- PciIo,\r
- Offset,\r
- EFI_AHCI_PORT_IS_DHRS,\r
- EFI_AHCI_PORT_IS_DHRS,\r
- Timeout\r
- );\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Exit;\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
}\r
\r
Exit:\r
//\r
// For Blocking mode, the command should be stopped, the Fis should be disabled\r
// and the PciIo should be unmapped.\r
- // For non-blocking mode, only when a error is happened (if the return status is \r
- // EFI_NOT_READY that means the command doesn't finished, try again.), first do the \r
+ // For non-blocking mode, only when a error is happened (if the return status is\r
+ // EFI_NOT_READY that means the command doesn't finished, try again.), first do the\r
// context cleanup, then set the packet's Asb status.\r
//\r
if (Task == NULL ||\r
((Task != NULL) && (Status != EFI_NOT_READY))\r
) {\r
AhciStopCommand (\r
- PciIo, \r
+ PciIo,\r
Port,\r
Timeout\r
);\r
\r
AhciDisableFisReceive (\r
- PciIo, \r
+ PciIo,\r
Port,\r
Timeout\r
);\r
}\r
}\r
\r
- AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
return Status;\r
}\r
\r
/**\r
Start a non data transfer on specific port.\r
- \r
+\r
@param[in] PciIo The PCI IO protocol instance.\r
@param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
@param[in] Port The number of port.\r
@param[in] AtapiCommandLength The length of the atapi command.\r
@param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
@param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
- @param[in] Timeout The timeout value of non data transfer.\r
+ @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
@param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
used by non-blocking mode.\r
\r
@retval EFI_UNSUPPORTED The device is not ready for transfer.\r
@retval EFI_SUCCESS The non data transfer executes successfully.\r
\r
-**/ \r
+**/\r
EFI_STATUS\r
EFIAPI\r
AhciNonDataTransfer (\r
{\r
EFI_STATUS Status;\r
UINTN FisBaseAddr;\r
- UINT32 Offset;\r
- UINT32 Value;\r
- UINT32 Delay;\r
-\r
+ UINTN Offset;\r
+ UINT32 PortTfd;\r
EFI_AHCI_COMMAND_FIS CFis;\r
EFI_AHCI_COMMAND_LIST CmdList;\r
\r
// Wait device sends the Response Fis\r
//\r
FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
- //\r
- // Wait device sends the PIO setup fis before data transfer\r
- //\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
- do {\r
- Value = *(volatile UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
-\r
- if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
- break;\r
- }\r
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+ Status = AhciWaitMemSet (\r
+ Offset,\r
+ EFI_AHCI_FIS_TYPE_MASK,\r
+ EFI_AHCI_FIS_REGISTER_D2H,\r
+ Timeout\r
+ );\r
\r
- //\r
- // Stall for 100 microseconds.\r
- //\r
- MicroSecondDelay(100);\r
-\r
- Delay --;\r
- } while (Delay > 0);\r
-\r
- if (Delay == 0) {\r
- Status = EFI_TIMEOUT;\r
+ if (EFI_ERROR (Status)) {\r
goto Exit;\r
}\r
\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
-\r
- Status = AhciWaitMemSet (\r
- PciIo,\r
- Offset,\r
- 0xFFFFFFFF,\r
- 0,\r
- Timeout\r
- );\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+ PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
\r
Exit:\r
AhciStopCommand (\r
Timeout\r
);\r
\r
- AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+ AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
\r
return Status;\r
}\r
\r
/**\r
Stop command running for giving port\r
- \r
+\r
@param PciIo The PCI IO protocol instance.\r
@param Port The number of port.\r
- @param Timeout The timeout value of stop.\r
- \r
+ @param Timeout The timeout value of stop, uses 100ns as a unit.\r
+\r
@retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
@retval EFI_TIMEOUT The operation is time out.\r
@retval EFI_SUCCESS The command stop successfully.\r
AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
}\r
\r
- return AhciWaitMemSet (\r
+ return AhciWaitMmioSet (\r
PciIo,\r
Offset,\r
EFI_AHCI_PORT_CMD_CR,\r
@param PciIo The PCI IO protocol instance.\r
@param Port The number of port.\r
@param CommandSlot The number of Command Slot.\r
- @param Timeout The timeout value of start.\r
+ @param Timeout The timeout value of start, uses 100ns as a unit.\r
\r
@retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
@retval EFI_TIMEOUT The operation is time out.\r
);\r
\r
Status = AhciEnableFisReceive (\r
- PciIo, \r
+ PciIo,\r
Port,\r
Timeout\r
);\r
if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
if ((Capability & BIT24) != 0) {\r
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);\r
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);\r
\r
- AhciWaitMemSet (\r
+ AhciWaitMmioSet (\r
PciIo,\r
Offset,\r
- EFI_AHCI_PORT_CMD_COL,\r
+ EFI_AHCI_PORT_CMD_CLO,\r
0,\r
Timeout\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
\r
@param PciIo The PCI IO protocol instance.\r
@param Port The number of port.\r
- @param Timeout The timeout value of reset.\r
- \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
// 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 = AhciWaitMemSet (\r
+ Status = AhciWaitMmioSet (\r
PciIo,\r
Offset,\r
EFI_AHCI_PORT_SSTS_DET_MASK,\r
);\r
\r
if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Port %d COMRESET failed: %r\n", Port, Status));\r
return Status;\r
}\r
\r
Do AHCI HBA reset.\r
\r
@param PciIo The PCI IO protocol instance.\r
- @param Timeout The timeout value of reset.\r
+ @param Timeout The timeout value of reset, uses 100ns as a unit.\r
\r
@retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.\r
@retval EFI_TIMEOUT The reset operation is time out.\r
AhciReset (\r
IN EFI_PCI_IO_PROTOCOL *PciIo,\r
IN UINT64 Timeout\r
- ) \r
+ )\r
{\r
- EFI_STATUS Status;\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
- AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
+ if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
+ AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+ }\r
\r
- Status = EFI_TIMEOUT;\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
// S.M.A.R.T is not supported by the device\r
//\r
- DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n", \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
\r
/**\r
Send Buffer cmd to specific device.\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 Buffer The data buffer to store IDENTIFY PACKET data.\r
\r
@retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
IN EFI_AHCI_REGISTERS *AhciRegisters,\r
IN UINT8 Port,\r
IN UINT8 PortMultiplier,\r
- IN OUT EFI_IDENTIFY_DATA *Buffer \r
+ IN OUT EFI_IDENTIFY_DATA *Buffer\r
)\r
{\r
EFI_STATUS Status;\r
&AtaStatusBlock,\r
Buffer,\r
sizeof (EFI_IDENTIFY_DATA),\r
- ATA_ATAPI_TIMEOUT, \r
+ ATA_ATAPI_TIMEOUT,\r
NULL\r
);\r
\r
\r
/**\r
Send Buffer cmd to specific device.\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 Buffer The data buffer to store IDENTIFY PACKET data.\r
\r
@retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
IN EFI_AHCI_REGISTERS *AhciRegisters,\r
IN UINT8 Port,\r
IN UINT8 PortMultiplier,\r
- IN OUT EFI_IDENTIFY_DATA *Buffer \r
+ IN OUT EFI_IDENTIFY_DATA *Buffer\r
)\r
{\r
EFI_STATUS Status;\r
\r
/**\r
Send SET FEATURE cmd on specific device.\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 Feature The data to send Feature register.\r
@param FeatureSpecificData The specific data for SET FEATURE cmd.\r
\r
0,\r
&AtaCommandBlock,\r
&AtaStatusBlock,\r
- ATA_ATAPI_TIMEOUT, \r
+ ATA_ATAPI_TIMEOUT,\r
NULL\r
);\r
\r
}\r
\r
/**\r
- This function is used to send out ATAPI commands conforms to the Packet Command \r
+ This function is used to send out ATAPI commands conforms to the Packet Command\r
with PIO Protocol.\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 Port The number of port.\r
@param PortMultiplier The number of port multiplier.\r
@param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
\r
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
BOOLEAN Read;\r
- UINT8 Retry;\r
\r
if (Packet == NULL || Packet->Cdb == NULL) {\r
return EFI_INVALID_PARAMETER;\r
Packet->CdbLength,\r
&AtaCommandBlock,\r
&AtaStatusBlock,\r
- Packet->Timeout, \r
+ Packet->Timeout,\r
NULL\r
);\r
} else {\r
- //\r
- // READ_CAPACITY cmd may execute failure. Retry 5 times\r
- //\r
- if (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_READ_CAPACITY) {\r
- Retry = 5;\r
- } else {\r
- Retry = 1;\r
- }\r
- do {\r
- Status = AhciPioTransfer (\r
- PciIo,\r
- AhciRegisters,\r
- Port,\r
- PortMultiplier,\r
- Packet->Cdb,\r
- Packet->CdbLength,\r
- Read,\r
- &AtaCommandBlock,\r
- &AtaStatusBlock,\r
- Buffer,\r
- Length,\r
- Packet->Timeout, \r
- NULL\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- break;\r
- }\r
- Retry--;\r
- } while (Retry != 0);\r
+ Status = AhciPioTransfer (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ PortMultiplier,\r
+ Packet->Cdb,\r
+ Packet->CdbLength,\r
+ Read,\r
+ &AtaCommandBlock,\r
+ &AtaStatusBlock,\r
+ Buffer,\r
+ Length,\r
+ Packet->Timeout,\r
+ NULL\r
+ );\r
}\r
return Status;\r
}\r
\r
/**\r
Allocate transfer-related data struct which is used at AHCI mode.\r
- \r
+\r
@param PciIo The PCI IO protocol instance.\r
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\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
\r
if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
//\r
- // Map error or unable to map the whole RFis buffer into a contiguous region. \r
+ // Map error or unable to map the whole RFis buffer into a contiguous region.\r
//\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Error6;\r
\r
if (EFI_ERROR (Status)) {\r
//\r
- // Free mapped resource. \r
+ // Free mapped resource.\r
//\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Error5;\r
\r
if (EFI_ERROR (Status)) {\r
//\r
- // Free mapped resource. \r
+ // Free mapped resource.\r
//\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Error3;\r
\r
return EFI_SUCCESS;\r
//\r
- // Map error or unable to map the whole CmdList buffer into a contiguous region. \r
+ // Map error or unable to map the whole CmdList buffer into a contiguous region.\r
//\r
Error1:\r
PciIo->Unmap (\r
/**\r
Initialize ATA host controller at AHCI mode.\r
\r
- The function is designed to initialize ATA host controller. \r
- \r
+ The function is designed to initialize ATA host controller.\r
+\r
@param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
\r
**/\r
UINT32 Capability;\r
UINT8 MaxPortNumber;\r
UINT32 PortImplementBitMap;\r
- UINT8 MaxCommandSlotNumber;\r
- BOOLEAN Support64Bit;\r
\r
EFI_AHCI_REGISTERS *AhciRegisters;\r
\r
EFI_ATA_DEVICE_TYPE DeviceType;\r
EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
EFI_ATA_TRANSFER_MODE TransferMode;\r
- \r
+ UINT32 PhyDetectDelay;\r
+ UINT32 Value;\r
+\r
if (Instance == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
PciIo = Instance->PciIo;\r
IdeInit = Instance->IdeControllerInit;\r
\r
- Status = AhciReset (PciIo, ATA_ATAPI_TIMEOUT); \r
+ Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT);\r
\r
if (EFI_ERROR (Status)) {\r
return EFI_DEVICE_ERROR;\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
//\r
- MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
- Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
+ MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
\r
//\r
// Get the bit map of those ports exposed by this HBA.\r
- // It indicates which ports that the HBA supports are available for software to use. \r
+ // It indicates which ports that the HBA supports are available for software to use.\r
//\r
PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
- MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
- \r
+\r
AhciRegisters = &Instance->AhciRegisters;\r
Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- for (Port = 0; Port < MaxPortNumber; Port ++) { \r
- Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
- \r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
- \r
- //\r
- // Single task envrionment, we only use one command table for all port\r
- //\r
- Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
- \r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
- \r
+ for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {\r
if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- \r
- if ((Capability & EFI_AHCI_PORT_CMD_ASP) != 0) {\r
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\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
+ // Initialize FIS Base Address Register and Command List Base Address Register for use.\r
+ //\r
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
+\r
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
+\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
Data = AhciReadReg (PciIo, Offset);\r
if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
}\r
- \r
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE|EFI_AHCI_PORT_CMD_COL|EFI_AHCI_PORT_CMD_ST));\r
- }\r
- \r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_MASK));\r
- \r
- AhciAndReg (PciIo, Offset,(UINT32) ~(EFI_AHCI_PORT_SCTL_IPM_PSD));\r
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_PSD);\r
- \r
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_SSD));\r
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_SSD);\r
- \r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
- AhciAndReg (PciIo, Offset, 0);\r
- \r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
- AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
- }\r
-\r
- //\r
- // Stall for 100 milliseconds.\r
- //\r
- MicroSecondDelay(100000);\r
- \r
- IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
- \r
- for (Port = 0; Port < MaxPortNumber; Port ++) { \r
- if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
- \r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
- Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
\r
- if (Data == 0) {\r
- continue;\r
+ if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
}\r
+\r
//\r
- // Found device in the port\r
+ // Disable aggressive power management.\r
//\r
- if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
-\r
- Status = AhciWaitMemSet (\r
- PciIo, \r
- Offset,\r
- 0x0000FFFF,\r
- 0x00000101,\r
- ATA_ATAPI_TIMEOUT\r
- );\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
+ //\r
+ // Disable the reporting of the corresponding interrupt to system software.\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
+ AhciAndReg (PciIo, Offset, 0);\r
+\r
+ //\r
+ // Now inform the IDE Controller Init Module.\r
+ //\r
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
+\r
+ //\r
+ // Enable FIS Receive DMA engine for the first D2H FIS.\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
+ //\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
+ //\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
+ do {\r
+ Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
+ if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {\r
+ break;\r
}\r
\r
+ MicroSecondDelay (1000);\r
+ PhyDetectDelay--;\r
+ } while (PhyDetectDelay > 0);\r
+\r
+ if (PhyDetectDelay == 0) {\r
//\r
- // Now inform the IDE Controller Init Module.\r
+ // No device detected at this port.\r
+ // Clear PxCMD.SUD for those ports at which there are no device present.\r
//\r
- IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
-\r
- Data = AhciReadReg (PciIo, Offset);\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+ AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_SUD));\r
+ continue;\r
+ }\r
\r
- if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
- Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
+ //\r
+ // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
+ // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
+ //\r
+ PhyDetectDelay = 16 * 1000;\r
+ do {\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+ if (AhciReadReg(PciIo, Offset) != 0) {\r
+ AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));\r
+ }\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
+ Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
+ if (Data == 0) {\r
+ break;\r
+ }\r
\r
- DeviceType = EfiIdeCdrom;\r
- } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
- Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
+ MicroSecondDelay (1000);\r
+ PhyDetectDelay--;\r
+ } while (PhyDetectDelay > 0);\r
\r
- if (EFI_ERROR (Status)) {\r
- continue;\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
- DeviceType = EfiIdeHarddisk;\r
- } else {\r
- continue;\r
- }\r
+ //\r
+ // When the first D2H register FIS is received, the content of PxSIG register is updated.\r
+ //\r
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
+ Status = AhciWaitMmioSet (\r
+ PciIo,\r
+ Offset,\r
+ 0x0000FFFF,\r
+ 0x00000101,\r
+ EFI_TIMER_PERIOD_SECONDS(16)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
\r
- DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
- Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
+ Data = AhciReadReg (PciIo, Offset);\r
+ if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
+ Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
\r
- //\r
- // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
- //\r
- if (DeviceType == EfiIdeHarddisk) {\r
- AhciAtaSmartSupport (\r
- PciIo,\r
- AhciRegisters,\r
- Port,\r
- 0,\r
- &Buffer,\r
- NULL\r
- );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
}\r
\r
- //\r
- // Submit identify data to IDE controller init driver\r
- //\r
- IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
+ DeviceType = EfiIdeCdrom;\r
+ } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
+ Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
\r
- //\r
- // Now start to config ide device parameter and transfer mode.\r
- //\r
- Status = IdeInit->CalculateMode (\r
- IdeInit,\r
- Port,\r
- 0,\r
- &SupportedModes\r
- );\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
continue;\r
}\r
\r
- //\r
- // Set best supported PIO mode on this IDE device\r
- //\r
- if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
- TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
- } else {\r
- TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
- }\r
+ DeviceType = EfiIdeHarddisk;\r
+ } else {\r
+ continue;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",\r
+ Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
\r
- TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
- \r
- //\r
- // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
- // be set together. Only one DMA mode can be set to a device. If setting\r
- // DMA mode operation fails, we can continue moving on because we only use\r
- // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
- //\r
- if (SupportedModes->UdmaMode.Valid) {\r
- TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
- TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
- } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
- TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
- TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; \r
- }\r
+ //\r
+ // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
+ //\r
+ if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {\r
+ AhciAtaSmartSupport (\r
+ PciIo,\r
+ AhciRegisters,\r
+ Port,\r
+ 0,\r
+ &Buffer,\r
+ NULL\r
+ );\r
+ }\r
\r
- Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+ //\r
+ // Submit identify data to IDE controller init driver\r
+ //\r
+ IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
- continue;\r
- }\r
- //\r
- // Found a ATA or ATAPI device, add it into the device list.\r
- //\r
- CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
+ //\r
+ // Now start to config ide device parameter and transfer mode.\r
+ //\r
+ Status = IdeInit->CalculateMode (\r
+ IdeInit,\r
+ Port,\r
+ 0,\r
+ &SupportedModes\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Set best supported PIO mode on this IDE device\r
+ //\r
+ if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
+ TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
+ } else {\r
+ TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
+ }\r
+\r
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
+\r
+ //\r
+ // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
+ // be set together. Only one DMA mode can be set to a device. If setting\r
+ // DMA mode operation fails, we can continue moving on because we only use\r
+ // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
+ //\r
+ if (SupportedModes->UdmaMode.Valid) {\r
+ TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
+ } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
+ TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
+ TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
+ }\r
+\r
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Found a ATA or ATAPI device, add it into the device list.\r
+ //\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
}\r
}\r
}\r
+\r
return EFI_SUCCESS;\r
}\r
\r