/** @file\r
The file for AHCI mode of ATA host controller.\r
\r
- Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2010 - 2013, 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
IN UINT8 AtapiCommandLength,\r
IN UINT8 CommandSlotNumber,\r
IN OUT VOID *DataPhysicalAddr,\r
- IN UINT64 DataLength\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
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
\r
RemainedData = (UINTN) DataLength;\r
MemAddr = (UINTN) DataPhysicalAddr;\r
- CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
+ CommandList->AhciCmdPrdtl = PrdtNumber;\r
\r
for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {\r
Status = EFI_TIMEOUT;\r
Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
do {\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
- PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
-\r
- if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
- Status = EFI_DEVICE_ERROR;\r
- break;\r
- }\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
if (!EFI_ERROR (Status)) {\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
+ //\r
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+\r
PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
if (PrdCount == DataCount) {\r
break;\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
//\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
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
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- for (Port = 0; Port < MaxPortNumber; Port ++) {\r
+ for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {\r
if ((PortImplementBitMap & (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
if (PhyDetectDelay == 0) {\r
//\r
// No device detected at this port.\r
+ // Clear PxCMD.SUD for those ports at which there are no device present.\r
//\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
//\r
// If the device is a hard disk, then try to enable S.M.A.R.T feature\r
//\r
- if (DeviceType == EfiIdeHarddisk) {\r
+ if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {\r
AhciAtaSmartSupport (\r
PciIo,\r
AhciRegisters,\r