return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\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 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
+ @retval Others Fail to get return status data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciAtaSmartReturnStatusCheck (\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_ATA_STATUS_BLOCK *AtaStatusBlock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+ UINT8 LBAMid;\r
+ UINT8 LBAHigh;\r
+ UINTN FisBaseAddr;\r
+ UINT32 Value;\r
+\r
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
+ AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+ //\r
+ // Send S.M.A.R.T Read Return Status command to device\r
+ //\r
+ Status = AhciNonDataTransfer (\r
+ PciIo,\r
+ AhciRegisters,\r
+ (UINT8)Port,\r
+ (UINT8)PortMultiplier,\r
+ NULL,\r
+ 0,\r
+ &AtaCommandBlock,\r
+ AtaStatusBlock,\r
+ ATA_ATAPI_TIMEOUT\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+\r
+ Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
+\r
+ if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
+ LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
+ LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
+\r
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+ //\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
+ } 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
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Enable SMART command 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 timeout value of stop.\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
+VOID\r
+EFIAPI\r
+AhciAtaSmartSupport (\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
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+\r
+ //\r
+ // Detect if the device supports S.M.A.R.T.\r
+ //\r
+ if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\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
+ Port, PortMultiplier));\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
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
+ AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+ //\r
+ // Send S.M.A.R.T Enable command to device\r
+ //\r
+ Status = AhciNonDataTransfer (\r
+ PciIo,\r
+ AhciRegisters,\r
+ (UINT8)Port,\r
+ (UINT8)PortMultiplier,\r
+ NULL,\r
+ 0,\r
+ &AtaCommandBlock,\r
+ AtaStatusBlock,\r
+ ATA_ATAPI_TIMEOUT\r
+ );\r
+\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Send S.M.A.R.T AutoSave command to device\r
+ //\r
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
+ AtaCommandBlock.AtaFeatures = 0xD2;\r
+ AtaCommandBlock.AtaSectorCount = 0xF1;\r
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+ Status = AhciNonDataTransfer (\r
+ PciIo,\r
+ AhciRegisters,\r
+ (UINT8)Port,\r
+ (UINT8)PortMultiplier,\r
+ NULL,\r
+ 0,\r
+ &AtaCommandBlock,\r
+ AtaStatusBlock,\r
+ ATA_ATAPI_TIMEOUT\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = AhciAtaSmartReturnStatusCheck (\r
+ PciIo,\r
+ AhciRegisters,\r
+ (UINT8)Port,\r
+ (UINT8)PortMultiplier,\r
+ AtaStatusBlock\r
+ );\r
+ }\r
+ }\r
+ }\r
+ DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n", \r
+ Port, PortMultiplier));\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
/**\r
Send Buffer cmd to specific device.\r
\r
DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\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
+ }\r
+\r
//\r
// Submit identify data to IDE controller init driver\r
//\r
return Status;\r
}\r
\r
+/**\r
+ Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
+\r
+ @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+ @param Channel The channel number of device.\r
+ @param Device The device number of device.\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
+ @retval Others Fail to get return status data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IdeAtaSmartReturnStatusCheck (\r
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
+ IN UINT8 Channel,\r
+ IN UINT8 Device,\r
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+ UINT8 LBAMid;\r
+ UINT8 LBAHigh;\r
+\r
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
+ AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+ AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+ //\r
+ // Send S.M.A.R.T Read Return Status command to device\r
+ //\r
+ Status = AtaNonDataCommandIn (\r
+ Instance->PciIo,\r
+ &Instance->IdeRegisters[Channel],\r
+ &AtaCommandBlock,\r
+ AtaStatusBlock,\r
+ ATA_ATAPI_TIMEOUT\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ LBAMid = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderLsb);\r
+ LBAHigh = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderMsb);\r
+\r
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+ //\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
+ } 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
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Enable SMART command of the disk if supported.\r
+\r
+ @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+ @param Channel The channel number of device.\r
+ @param Device The device number of device.\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
+VOID\r
+EFIAPI\r
+IdeAtaSmartSupport (\r
+ IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
+ IN UINT8 Channel,\r
+ IN UINT8 Device,\r
+ IN EFI_IDENTIFY_DATA *IdentifyData,\r
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
+\r
+ //\r
+ // Detect if the device supports S.M.A.R.T.\r
+ //\r
+ if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\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 [%a] channel [%a] device!\n", \r
+ (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\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
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
+ AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+ AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+ //\r
+ // Send S.M.A.R.T Enable command to device\r
+ //\r
+ Status = AtaNonDataCommandIn (\r
+ Instance->PciIo,\r
+ &Instance->IdeRegisters[Channel],\r
+ &AtaCommandBlock,\r
+ AtaStatusBlock,\r
+ ATA_ATAPI_TIMEOUT\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Send S.M.A.R.T AutoSave command to device\r
+ //\r
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+ AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
+ AtaCommandBlock.AtaFeatures = 0xD2;\r
+ AtaCommandBlock.AtaSectorCount = 0xF1;\r
+ AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
+ AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+ AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+ Status = AtaNonDataCommandIn (\r
+ Instance->PciIo,\r
+ &Instance->IdeRegisters[Channel],\r
+ &AtaCommandBlock,\r
+ AtaStatusBlock,\r
+ ATA_ATAPI_TIMEOUT\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = IdeAtaSmartReturnStatusCheck (\r
+ Instance,\r
+ Channel,\r
+ Device,\r
+ AtaStatusBlock\r
+ );\r
+ }\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at [%a] channel [%a] device!\n", \r
+ (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\r
+\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
/**\r
Sends out an ATA Identify Command to the specified device.\r
\r
(IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master",\r
DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk"));\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
+ IdeAtaSmartSupport (\r
+ Instance,\r
+ IdeChannel,\r
+ IdeDevice,\r
+ &Buffer,\r
+ NULL\r
+ );\r
+ }\r
+\r
//\r
// Submit identify data to IDE controller init driver\r
//\r