mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-07 13:54:31 +02:00
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:
parent
cccdc95f79
commit
12873d5766
@ -1249,6 +1249,191 @@ AhciReset (
|
|||||||
return EFI_SUCCESS;
|
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.
|
Send Buffer cmd to specific device.
|
||||||
|
|
||||||
@ -1947,6 +2132,20 @@ AhciModeInitialization (
|
|||||||
DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",
|
DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",
|
||||||
Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));
|
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
|
// Submit identify data to IDE controller init driver
|
||||||
//
|
//
|
||||||
|
@ -2090,6 +2090,170 @@ SetDriveParameters (
|
|||||||
return Status;
|
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.
|
Sends out an ATA Identify Command to the specified device.
|
||||||
|
|
||||||
@ -2333,6 +2497,19 @@ DetectAndConfigIdeDevice (
|
|||||||
(IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master",
|
(IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master",
|
||||||
DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk"));
|
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
|
// Submit identify data to IDE controller init driver
|
||||||
//
|
//
|
||||||
|
Loading…
x
Reference in New Issue
Block a user