Created
February 25, 2018 14:39
-
-
Save mjs3339/d47f73bbbf35dcacf06c48e63ba27eec to your computer and use it in GitHub Desktop.
C# S.M.A.R.T. (Self Monitoring, Analysis and Reporting Technology) Detection Class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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