S.M.A.R.T feature enable

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10985 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
erictian 2010-10-28 07:44:11 +00:00
parent cccdc95f79
commit 12873d5766
2 changed files with 376 additions and 0 deletions

View File

@ -1249,6 +1249,191 @@ AhciReset (
return EFI_SUCCESS;
}
/**
Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
@param PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port.
@param PortMultiplier The timeout value of stop.
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
@retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
@retval Others Fail to get return status data.
**/
EFI_STATUS
EFIAPI
AhciAtaSmartReturnStatusCheck (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN EFI_AHCI_REGISTERS *AhciRegisters,
IN UINT8 Port,
IN UINT8 PortMultiplier,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
)
{
EFI_STATUS Status;
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
UINT8 LBAMid;
UINT8 LBAHigh;
UINTN FisBaseAddr;
UINT32 Value;
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;
AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
//
// Send S.M.A.R.T Read Return Status command to device
//
Status = AhciNonDataTransfer (
PciIo,
AhciRegisters,
(UINT8)Port,
(UINT8)PortMultiplier,
NULL,
0,
&AtaCommandBlock,
AtaStatusBlock,
ATA_ATAPI_TIMEOUT
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);
if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {
LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];
LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];
if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
//
// The threshold exceeded condition is not detected by the device
//
DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
} else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {
//
// The threshold exceeded condition is detected by the device
//
DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));
}
}
return EFI_SUCCESS;
}
/**
Enable SMART command of the disk if supported.
@param PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port.
@param PortMultiplier The timeout value of stop.
@param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
**/
VOID
EFIAPI
AhciAtaSmartSupport (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN EFI_AHCI_REGISTERS *AhciRegisters,
IN UINT8 Port,
IN UINT8 PortMultiplier,
IN EFI_IDENTIFY_DATA *IdentifyData,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
)
{
EFI_STATUS Status;
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
//
// Detect if the device supports S.M.A.R.T.
//
if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
//
// S.M.A.R.T is not supported by the device
//
DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",
Port, PortMultiplier));
} else {
//
// Check if the feature is enabled. If not, then enable S.M.A.R.T.
//
if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;
AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
//
// Send S.M.A.R.T Enable command to device
//
Status = AhciNonDataTransfer (
PciIo,
AhciRegisters,
(UINT8)Port,
(UINT8)PortMultiplier,
NULL,
0,
&AtaCommandBlock,
AtaStatusBlock,
ATA_ATAPI_TIMEOUT
);
if (!EFI_ERROR (Status)) {
//
// Send S.M.A.R.T AutoSave command to device
//
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
AtaCommandBlock.AtaFeatures = 0xD2;
AtaCommandBlock.AtaSectorCount = 0xF1;
AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
Status = AhciNonDataTransfer (
PciIo,
AhciRegisters,
(UINT8)Port,
(UINT8)PortMultiplier,
NULL,
0,
&AtaCommandBlock,
AtaStatusBlock,
ATA_ATAPI_TIMEOUT
);
if (!EFI_ERROR (Status)) {
Status = AhciAtaSmartReturnStatusCheck (
PciIo,
AhciRegisters,
(UINT8)Port,
(UINT8)PortMultiplier,
AtaStatusBlock
);
}
}
}
DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",
Port, PortMultiplier));
}
return ;
}
/**
Send Buffer cmd to specific device.
@ -1947,6 +2132,20 @@ AhciModeInitialization (
DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",
Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));
//
// If the device is a hard disk, then try to enable S.M.A.R.T feature
//
if (DeviceType == EfiIdeHarddisk) {
AhciAtaSmartSupport (
PciIo,
AhciRegisters,
Port,
0,
&Buffer,
NULL
);
}
//
// Submit identify data to IDE controller init driver
//

View File

@ -2090,6 +2090,170 @@ SetDriveParameters (
return Status;
}
/**
Send SMART Return Status command to check if the execution of SMART cmd is successful or not.
@param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
@param Channel The channel number of device.
@param Device The device number of device.
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
@retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.
@retval Others Fail to get return status data.
**/
EFI_STATUS
EFIAPI
IdeAtaSmartReturnStatusCheck (
IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
IN UINT8 Channel,
IN UINT8 Device,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
)
{
EFI_STATUS Status;
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
UINT8 LBAMid;
UINT8 LBAHigh;
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;
AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);
//
// Send S.M.A.R.T Read Return Status command to device
//
Status = AtaNonDataCommandIn (
Instance->PciIo,
&Instance->IdeRegisters[Channel],
&AtaCommandBlock,
AtaStatusBlock,
ATA_ATAPI_TIMEOUT
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
LBAMid = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderLsb);
LBAHigh = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderMsb);
if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
//
// The threshold exceeded condition is not detected by the device
//
DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));
} else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {
//
// The threshold exceeded condition is detected by the device
//
DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));
}
return EFI_SUCCESS;
}
/**
Enable SMART command of the disk if supported.
@param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.
@param Channel The channel number of device.
@param Device The device number of device.
@param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.
**/
VOID
EFIAPI
IdeAtaSmartSupport (
IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
IN UINT8 Channel,
IN UINT8 Device,
IN EFI_IDENTIFY_DATA *IdentifyData,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
)
{
EFI_STATUS Status;
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
//
// Detect if the device supports S.M.A.R.T.
//
if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
//
// S.M.A.R.T is not supported by the device
//
DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at [%a] channel [%a] device!\n",
(Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));
} else {
//
// Check if the feature is enabled. If not, then enable S.M.A.R.T.
//
if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;
AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);
//
// Send S.M.A.R.T Enable command to device
//
Status = AtaNonDataCommandIn (
Instance->PciIo,
&Instance->IdeRegisters[Channel],
&AtaCommandBlock,
AtaStatusBlock,
ATA_ATAPI_TIMEOUT
);
if (!EFI_ERROR (Status)) {
//
// Send S.M.A.R.T AutoSave command to device
//
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_SMART;
AtaCommandBlock.AtaFeatures = 0xD2;
AtaCommandBlock.AtaSectorCount = 0xF1;
AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;
AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;
AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);
Status = AtaNonDataCommandIn (
Instance->PciIo,
&Instance->IdeRegisters[Channel],
&AtaCommandBlock,
AtaStatusBlock,
ATA_ATAPI_TIMEOUT
);
if (!EFI_ERROR (Status)) {
Status = IdeAtaSmartReturnStatusCheck (
Instance,
Channel,
Device,
AtaStatusBlock
);
}
}
}
DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at [%a] channel [%a] device!\n",
(Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));
}
return ;
}
/**
Sends out an ATA Identify Command to the specified device.
@ -2333,6 +2497,19 @@ DetectAndConfigIdeDevice (
(IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master",
DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk"));
//
// If the device is a hard disk, then try to enable S.M.A.R.T feature
//
if (DeviceType == EfiIdeHarddisk) {
IdeAtaSmartSupport (
Instance,
IdeChannel,
IdeDevice,
&Buffer,
NULL
);
}
//
// Submit identify data to IDE controller init driver
//