add smart health read (#300)
Co-authored-by: Furkan YILMAZ <furkan@apziva.com>
This commit is contained in:
co-authored by
Furkan YILMAZ
parent
4b4f000bdb
commit
f82baea56a
@@ -119,6 +119,52 @@ namespace LibreHardwareMonitor.Hardware.Storage
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads Smart health status of the drive
|
||||
/// </summary>
|
||||
/// <returns>True, if drive is healthy; False, if unhealthy; Null, if it cannot be read</returns>
|
||||
public bool? ReadSmartHealth()
|
||||
{
|
||||
if (_handle.IsClosed)
|
||||
throw new ObjectDisposedException(nameof(WindowsSmart));
|
||||
|
||||
var parameter = new Kernel32.SENDCMDINPARAMS
|
||||
{
|
||||
bDriveNumber = (byte)_driveNumber,
|
||||
irDriveRegs = {
|
||||
bFeaturesReg = Kernel32.SMART_FEATURES.RETURN_SMART_STATUS,
|
||||
bCylLowReg = Kernel32.SMART_LBA_MID,
|
||||
bCylHighReg = Kernel32.SMART_LBA_HI,
|
||||
bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART
|
||||
}
|
||||
};
|
||||
|
||||
bool isValid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_SEND_DRIVE_COMMAND, ref parameter, Marshal.SizeOf(parameter),
|
||||
out Kernel32.STATUSCMDOUTPARAMS result, Marshal.SizeOf<Kernel32.STATUSCMDOUTPARAMS>(), out _, IntPtr.Zero);
|
||||
|
||||
if (!isValid)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// reference: https://github.com/smartmontools/smartmontools/blob/master/smartmontools/atacmds.cpp
|
||||
if (Kernel32.SMART_LBA_HI == result.irDriveRegs.bCylHighReg && Kernel32.SMART_LBA_MID == result.irDriveRegs.bCylLowReg)
|
||||
{
|
||||
// high and mid registers are unchanged, which means that the drive is healthy
|
||||
return true;
|
||||
}
|
||||
else if (Kernel32.SMART_LBA_HI_EXCEEDED == result.irDriveRegs.bCylHighReg && Kernel32.SMART_LBA_MID_EXCEEDED == result.irDriveRegs.bCylLowReg)
|
||||
{
|
||||
// high and mid registers are exceeded, which means that the drive is unhealthy
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// response is not clear
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace LibreHardwareMonitor.Interop
|
||||
internal const uint NVME_PASS_THROUGH_SRB_IO_CODE = 0xe0002000;
|
||||
internal const byte SMART_LBA_HI = 0xC2;
|
||||
internal const byte SMART_LBA_MID = 0x4F;
|
||||
internal const byte SMART_LBA_HI_EXCEEDED = 0x2C;
|
||||
internal const byte SMART_LBA_MID_EXCEEDED = 0xF4;
|
||||
private const string DllName = "kernel32.dll";
|
||||
|
||||
[Flags]
|
||||
@@ -149,6 +151,19 @@ namespace LibreHardwareMonitor.Interop
|
||||
out uint lpBytesReturned,
|
||||
IntPtr lpOverlapped);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeviceIoControl
|
||||
(
|
||||
SafeHandle hDevice,
|
||||
DFP dwIoControlCode,
|
||||
ref SENDCMDINPARAMS lpInBuffer,
|
||||
int nInBufferSize,
|
||||
out STATUSCMDOUTPARAMS lpOutBuffer,
|
||||
int nOutBufferSize,
|
||||
out uint lpBytesReturned,
|
||||
IntPtr lpOverlapped);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeviceIoControl
|
||||
@@ -589,6 +604,14 @@ namespace LibreHardwareMonitor.Interop
|
||||
public SMART_THRESHOLD[] Thresholds;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct STATUSCMDOUTPARAMS
|
||||
{
|
||||
public uint cBufferSize;
|
||||
public DRIVERSTATUS DriverStatus;
|
||||
public IDEREGS irDriveRegs;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct IDENTIFY_DATA
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user