Instantly share code, notes, and snippets.

Embed
What would you like to do?
C# S.M.A.R.T. (Self Monitoring, Analysis and Reporting Technology) Detection Class
public struct SData
{
public string Attribute;
public int RAWValue;
public string RAWValueS;
public int Value;
}
public static class SmartInformation
{
private static Dictionary<string, Dictionary<string, SData>> SmartDataCache = new Dictionary<string, Dictionary<string, SData>>();
public static Dictionary<string, Dictionary<string, SData>> SmartInfo
{
get
{
if (SmartDataCache.Count == 0)
SmartDataCache = SmartData.GetSmartData();
return SmartDataCache;
}
}
public static void ClearCache()
{
if (SmartDataCache.Count > 0)
SmartDataCache.Clear();
}
/// <summary>
/// SmartData class used to access SMART data attributes for SMART enabled devices
/// https://en.wikipedia.org/wiki/S.M.A.R.T.
/// </summary>
private class SmartData
{
public enum SmartAttributeType : byte
{
ReadErrorRate = 0x01,
ThroughputPerformance = 0x02,
SpinUpTime = 0x03,
StartStopCount = 0x04,
ReallocatedSectorsCount = 0x05,
ReadChannelMargin = 0x06,
SeekErrorRate = 0x07,
SeekTimePerformance = 0x08,
PowerOnHoursPOH = 0x09,
SpinRetryCount = 0x0A,
CalibrationRetryCount = 0x0B,
PowerCycleCount = 0x0C,
SoftReadErrorRate = 0x0D,
CurrentHeliumLevel = 0x16,
AvailableReservedSpace = 0xAA,
SSDProgramFailCount = 0xAB,
SSDEraseFailCount = 0xAC,
SSDWearLevelingCount = 0xAD,
UnexpectedPowerLossCount = 0xAE,
PowerLossProtectionFailure = 0xAF,
EraseFailCount = 0xB0,
WearRangeDelta = 0xB1,
UsedReservedBlockCountTotal = 0xB3,
UnusedReservedBlockCountTotal = 0xB4,
ProgramFailCountTotalorNon4KAlignedAccessCount = 0xB5,
EraseFailCountSamsung = 0xB6,
SATADownshiftErrorCount = 0xB7,
EndtoEnderror = 0xB8,
HeadStability = 0xB9,
InducedOpVibrationDetection = 0xBA,
ReportedUncorrectableErrors = 0xBB,
CommandTimeout = 0xBC,
HighFlyWrites = 0xBD,
//AirflowTemperatureWDC = 0xBE,**OBSOLETE**
TemperatureDifferencefrom100 = 0xBE,
Gsenseerrorrate = 0xBF,
PoweroffRetractCount = 0xC0,
LoadCycleCount = 0xC1,
Temperature = 0xC2,
HardwareECCRecovered = 0xC3,
ReallocationEventCount = 0xC4,
CurrentPendingSectorCount = 0xC5,
UncorrectableSectorCount = 0xC6,
UltraDMACRCErrorCount = 0xC7,
MultiZoneErrorRate = 0xC8,
//WriteErrorRateFujitsu = 0xC8,
OffTrackSoftReadErrorRate = 0xC9,
DataAddressMarkerrors = 0xCA,
RunOutCancel = 0xCB,
SoftECCCorrection = 0xCC,
ThermalAsperityRateTAR = 0xCD,
FlyingHeight = 0xCE,
SpinHighCurrent = 0xCF,
SpinBuzz = 0xD0,
OfflineSeekPerformance = 0xD1,
VibrationDuringWrite = 0xD3,
ShockDuringWrite = 0xD4,
DiskShift = 0xDC,
GSenseErrorRate = 0xDD,
LoadedHours = 0xDE,
LoadUnloadRetryCount = 0xDF,
LoadFriction = 0xE0,
LoadUnloadCycleCount = 0xE1,
LoadInTime = 0xE2,
TorqueAmplificationCount = 0xE3,
PowerOffRetractCycle = 0xE4,
LifeCurveStatus = 0xE6,
SSDLifeLeft = 0xE7,
EnduranceRemaining = 0xE8,
MediaWearoutIndicator = 0xE9,
AverageEraseCountANDMaximumEraseCount = 0xEA,
GoodBlockCountANDSystemFreeBlockCount = 0xEB,
HeadFlyingHours = 0xF0,
//TransferErrorRateFujitsu = 0xF0,
LifetimeWritesFromHostGiB = 0xF1,
LiftetimeReadsFromHostGiB = 0xF2,
TotalLBAsWrittenExpanded = 0xF3,
TotalLBAsReadExpanded = 0xF4,
NANDWrites1GiB = 0xF9,
ReadErrorRetryRate = 0xFA,
MinimumSparesRemaining = 0xFB,
NewlyAddedBadFlashBlock = 0xFC,
FreeFallProtection = 0xFE
}
private readonly Dictionary<SmartAttributeType, SmartAttribute> attributes;
private ushort StructureVersion { get; }
public SmartAttribute this[SmartAttributeType v] => attributes[v];
private IEnumerable<SmartAttribute> Attributes => attributes.Values;
private SmartData(byte[] arrVendorSpecific)
{
attributes = new Dictionary<SmartAttributeType, SmartAttribute>();
for (var offset = 2; offset < arrVendorSpecific.Length;)
{
var a = FromBytes<SmartAttribute>(arrVendorSpecific, ref offset, 12);
attributes[a.AttributeType] = a;
}
StructureVersion = (ushort) (arrVendorSpecific[0] * 256 + arrVendorSpecific[1]);
}
/// <summary>
/// Gets the available SMART data for available disks
/// </summary>
public static Dictionary<string, Dictionary<string, SData>> GetSmartData()
{
var SC = new Dictionary<string, Dictionary<string, SData>>();
var DSKI = DiskInformation.DiskInfo;
foreach (var v in DSKI)
try
{
var model = "";
try
{
model = v.Value.Model.Substring(0, v.Value.Model.SuperIndexOf(" ", 1));
}
catch
{
model = v.Value.Model;
}
var tl = GetAttribList(model);
var td = tl.ToDictionary(v1 => v1.Attribute);
SC.Add(v.Value.Disk, td);
}
catch (Exception ex)
{
ExceptionLog.ExLog(ex, "SmartInformation", "GetSmartData");
}
return SC;
}
private static T FromBytes<T>(byte[] bytearray, ref int offset, int count)
{
var ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(count);
Marshal.Copy(bytearray, offset, ptr, count);
offset += count;
return (T) Marshal.PtrToStructure(ptr, typeof(T));
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
}
private static IEnumerable<SData> GetAttribList(string DriveTypeName)
{
var Lst = new List<SData>();
try
{
foreach (ManagementObject queryObj in new ManagementObjectSearcher("root\\WMI", "SELECT * FROM MSStorageDriver_ATAPISmartData").Get())
{
var a = queryObj["InstanceName"].ToString();
if (a.IndexOf(DriveTypeName, StringComparison.OrdinalIgnoreCase) == -1)
continue;
var arrVendorSpecific = (byte[]) queryObj.GetPropertyValue("VendorSpecific");
var d = new SmartData(arrVendorSpecific);
foreach (var b in d.Attributes)
{
var dt = new SData();
string att = $"{b.AttributeType}";
dt.Attribute = att;
if (att.IndexOf("Temperature", StringComparison.OrdinalIgnoreCase) != -1)
dt.RAWValue = Convert.ToInt32(b.VendorData[0]);
else
dt.RAWValue = BitConverter.ToInt32(b.VendorData, 0);
dt.Value = b.Value;
dt.RAWValueS = $"{b.VendorData}";
Lst.Add(dt);
}
break;
}
}
catch
{
}
return Lst;
}
[StructLayout(LayoutKind.Sequential)]
public struct SmartAttribute
{
public readonly SmartAttributeType AttributeType;
public readonly ushort Flags;
public readonly byte Value;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public readonly byte[] VendorData;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment