add smart health read (#300)

Co-authored-by: Furkan YILMAZ <furkan@apziva.com>
This commit is contained in:
fyilmazz
2020-10-02 11:26:18 +02:00
committed by GitHub
co-authored by Furkan YILMAZ
parent 4b4f000bdb
commit f82baea56a
2 changed files with 69 additions and 0 deletions
@@ -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
{