Updated attribute maps for the 4 SSD controllers we figured out so far.
Also switched back to an array of DriveAttribute rather than a generic list.
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 The contents of this file are subject to the Mozilla Public License Version
6 1.1 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 for the specific language governing rights and limitations under the License.
15 The Original Code is the Open Hardware Monitor code.
17 The Initial Developer of the Original Code is
18 Michael Möller <m.moeller@gmx.ch>.
19 Portions created by the Initial Developer are Copyright (C) 2009-2010
20 the Initial Developer. All Rights Reserved.
22 Contributor(s): Paul Werelds
24 Alternatively, the contents of this file may be used under the terms of
25 either the GNU General Public License Version 2 or later (the "GPL"), or
26 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 in which case the provisions of the GPL or the LGPL are applicable instead
28 of those above. If you wish to allow use of your version of this file only
29 under the terms of either the GPL or the LGPL, and not to allow others to
30 use your version of this file under the terms of the MPL, indicate your
31 decision by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL or the LGPL. If you do not delete
33 the provisions above, a recipient may use your version of this file under
34 the terms of any one of the MPL, the GPL or the LGPL.
39 using System.Collections.Generic;
40 using System.Runtime.InteropServices;
42 namespace OpenHardwareMonitor.Hardware.HDD {
44 internal class SMART {
47 public enum Status : ushort {
48 PreFailureWarranty = 0x01,
49 OnLineCollection = 0x02,
56 [StructLayout(LayoutKind.Sequential, Pack = 1)]
57 public struct AttributeID {
60 public AttributeID(byte value) {
64 public override bool Equals(Object obj) {
65 return obj is AttributeID && this == (AttributeID)obj;
67 public override int GetHashCode() {
68 return value.GetHashCode() ^ value.GetHashCode();
70 public static bool operator ==(AttributeID a, AttributeID b) {
71 return a.value == b.value;
73 public static bool operator !=(AttributeID a, AttributeID b) {
77 public string ToString(string format) {
78 return value.ToString(format);
81 public static readonly AttributeID None = new AttributeID(0x00);
84 // These are the more-or-less standard S.M.A.R.T attributes
85 // TODO: Filter out unused/obscure ones; some are interpreted differently
86 // between manufacturers
87 public static class CommonAttributes {
88 public static readonly AttributeID
89 ReadErrorRate = new AttributeID(0x01),
90 ThroughputPerformance = new AttributeID(0x02),
91 SpinUpTime = new AttributeID(0x03),
92 StartStopCount = new AttributeID(0x04),
93 ReallocatedSectorsCount = new AttributeID(0x05),
94 ReadChannelMargin = new AttributeID(0x06),
95 SeekErrorRate = new AttributeID(0x07),
96 SeekTimePerformance = new AttributeID(0x08),
97 PowerOnHours = new AttributeID(0x09),
98 SpinRetryCount = new AttributeID(0x0A),
99 RecalibrationRetries = new AttributeID(0x0B),
100 PowerCycleCount = new AttributeID(0x0C),
101 SoftReadErrorRate = new AttributeID(0x0D),
102 SataDownshiftErrorCount = new AttributeID(0xB7),
103 EndToEndError = new AttributeID(0xB8),
104 HeadStability = new AttributeID(0xB9),
105 InducedOpVibrationDetection = new AttributeID(0xBA),
106 ReportedUncorrectableErrors = new AttributeID(0xBB),
107 CommandTimeout = new AttributeID(0xBC),
108 HighFlyWrites = new AttributeID(0xBD),
109 AirflowTemperature = new AttributeID(0xBE),
110 GSenseErrorRate = new AttributeID(0xBF),
111 PowerOffRetractCount = new AttributeID(0xC0),
112 LoadCycleCount = new AttributeID(0xC1),
113 Temperature = new AttributeID(0xC2),
114 HardwareEccRecovered = new AttributeID(0xC3),
115 ReallocationEventCount = new AttributeID(0xC4),
116 CurrentPendingSectorCount = new AttributeID(0xC5),
117 UncorrectableSectorCount = new AttributeID(0xC6),
118 UltraDmaCrcErrorCount = new AttributeID(0xC7),
119 WriteErrorRate = new AttributeID(0xC8),
120 DataAddressMarkerrors = new AttributeID(0xCA),
121 RunOutCancel = new AttributeID(0xCB),
122 SoftEccCorrection = new AttributeID(0xCC),
123 ThermalAsperityRate = new AttributeID(0xCD),
124 FlyingHeight = new AttributeID(0xCE),
125 SpinHighCurrent = new AttributeID(0xCF),
126 SpinBuzz = new AttributeID(0xD0),
127 OfflineSeekPerformance = new AttributeID(0xD1),
128 VibrationDuringWrite = new AttributeID(0xD3),
129 ShockDuringWrite = new AttributeID(0xD4),
130 DiskShift = new AttributeID(0xDC),
131 GSenseErrorRateAlt = new AttributeID(0xDD), // Alternative to 0xBF
132 LoadedHours = new AttributeID(0xDE),
133 LoadUnloadRetryCount = new AttributeID(0xDF),
134 LoadFriction = new AttributeID(0xE0),
135 LoadUnloadCycleCount = new AttributeID(0xE1),
136 LoadInTime = new AttributeID(0xE2),
137 TorqueAmplificationCount = new AttributeID(0xE3),
138 PowerOffRetractCycle = new AttributeID(0xE4),
139 GMRHeadAmplitude = new AttributeID(0xE6),
140 DriveTemperature = new AttributeID(0xE7),
141 HeadFlyingHours = new AttributeID(0xF0),
142 LBAsWrittenTotal = new AttributeID(0xF1),
143 LBAsReadTotal = new AttributeID(0xF2),
144 ReadErrorRetryRate = new AttributeID(0xFA),
145 FreeFallProtection = new AttributeID(0xFE)
149 // Indilinx SSD SMART attributes
150 // TODO: Find out the purpose of attribute 0xD2
151 // Seems to be unique to Indilinx drives, hence its name of UnknownUnique.
152 public static class IndilinxAttributes {
153 public static readonly AttributeID
154 ReadErrorRate = CommonAttributes.ReadErrorRate,
155 PowerOnHours = CommonAttributes.PowerOnHours,
156 PowerCycleCount = CommonAttributes.PowerCycleCount,
157 InitialBadBlockCount = new AttributeID(0xB8),
158 RemainingLife = new AttributeID(0xD1),
159 ProgramFailure = new AttributeID(0xC3),
160 EraseFailure = new AttributeID(0xC4),
161 ReadFailure = new AttributeID(0xC5),
162 SectorsRead = new AttributeID(0xC6),
163 SectorsWritten = new AttributeID(0xC7),
164 ReadCommands = new AttributeID(0xC8),
165 WriteCommands = new AttributeID(0xC9),
166 BitErrors = new AttributeID(0xCA),
167 CorrectedErrors = new AttributeID(0xCB),
168 BadBlockFullFlag = new AttributeID(0xCC),
169 MaxCellcycles = new AttributeID(0xCD),
170 MinErase = new AttributeID(0xCE),
171 MaxErase = new AttributeID(0xCF),
172 AverageEraseCount = new AttributeID(0xD0),
173 UnknownUnique = new AttributeID(0xD2),
174 SataErrorCountCRC = new AttributeID(0xD3),
175 SataErrorCountHandshake = new AttributeID(0xD4)
179 // Intel SSD SMART attributes
180 // TODO: Find out the meaning behind 0xE2, 0xE3 and 0xE4
181 public static class IntelAttributes {
182 public static readonly AttributeID
183 ReadErrorRate = CommonAttributes.ReadErrorRate,
184 SpinUpTime = CommonAttributes.SpinUpTime,
185 StartStopCount = CommonAttributes.StartStopCount,
186 ReallocatedSectorsCount = CommonAttributes.ReallocatedSectorsCount,
187 PowerOnHours = CommonAttributes.PowerOnHours,
188 PowerCycleCount = CommonAttributes.PowerCycleCount,
189 EndToEndError = CommonAttributes.EndToEndError, // Only on G2 drives!
191 // Different from the common attribute PowerOffRetractCount, same ID
192 UnsafeShutdownCount = new AttributeID(0xC0),
193 HostWrites = new AttributeID(0xE1),
194 RemainingLife = new AttributeID(0xE8),
195 MediaWearOutIndicator = new AttributeID(0xE9)
199 // Samsung SSD SMART attributes
200 // TODO: AF, B0, B1, B5, B6, BB, C3, C6, C7, E8, E9
201 public static class SamsungAttributes {
202 public static readonly AttributeID
203 PowerOnHours = CommonAttributes.PowerOnHours,
204 PowerCycleCount = CommonAttributes.PowerCycleCount,
205 UsedReservedBlockCountChip = new AttributeID(0xB2), // Unique
206 UsedReservedBlockCountTotal = new AttributeID(0xB3), // Unique
207 RemainingLife = new AttributeID(0xB4), // Unique
208 RuntimeBadBlockTotal = new AttributeID(0xB7)
212 // SandForce SSD SMART attributes
213 // Note: 0xE9 and 0xEA are reserved attributes and unique
214 public static class SandForceAttributes {
215 public static readonly AttributeID
216 ReadErrorRate = CommonAttributes.ReadErrorRate,
217 RetiredBlockCount = new AttributeID(0x05),
218 PowerOnHours = CommonAttributes.PowerOnHours,
219 PowerCycleCount = CommonAttributes.PowerCycleCount,
220 ProgramFailCount = new AttributeID(0xAB), // Unique
221 EraseFailCount = new AttributeID(0xAC), // Unique
222 UnexpectedPowerLossCount = new AttributeID(0xAE), // Unique
223 WearRangeDelta = new AttributeID(0xB1), // Unique
224 ProgramFailCountAlt = new AttributeID(0xB5), // Same as 0xAB
225 EraseFailCountAlt = new AttributeID(0xB6), // Same as 0xAC
226 ReportedUncorrectableErrors =
227 CommonAttributes.ReportedUncorrectableErrors,
229 Temperature = CommonAttributes.Temperature, // SF-1500 only!
231 // Opposite of the common attribute HardwareECCRecovered
232 UnrecoverableECC = new AttributeID(0xC3),
233 ReallocationEventCount = new AttributeID(0xC4),
234 RemainingLife = new AttributeID(0xE7),
235 LifetimeWrites = new AttributeID(0xF1),
236 LifetimeReads = new AttributeID(0xF2)
240 [StructLayout(LayoutKind.Sequential, Pack = 1)]
241 public struct DriveAttribute {
242 public AttributeID ID;
243 public Status StatusFlags;
244 public byte AttrValue;
245 public byte WorstValue;
246 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
247 public byte[] RawValue;
248 public byte Reserved;
252 protected enum AccessMode : uint {
255 Execute = 0x20000000,
260 protected enum ShareMode : uint {
267 protected enum CreationMode : uint {
276 protected enum FileAttribute : uint {
277 Readonly = 0x00000001,
280 Directory = 0x00000010,
281 Archive = 0x00000020,
284 Temporary = 0x00000100,
285 SparseFile = 0x00000200,
286 ReparsePoint = 0x00000400,
287 Compressed = 0x00000800,
288 Offline = 0x00001000,
289 NotContentIndexed = 0x00002000,
290 Encrypted = 0x00004000,
293 protected enum DriveCommand : uint {
294 GetVersion = 0x00074080,
295 SendDriveCommand = 0x0007c084,
296 ReceiveDriveData = 0x0007c088
299 [StructLayout(LayoutKind.Sequential, Pack = 1)]
300 protected struct CommandBlockRegisters {
301 public byte Features;
302 public byte SectorCount;
308 public byte Reserved;
311 [StructLayout(LayoutKind.Sequential, Pack = 1)]
312 protected struct DriveCommandParameter {
313 public uint BufferSize;
314 public CommandBlockRegisters Registers;
315 public byte DriveNumber;
316 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
317 public byte[] Reserved;
320 [StructLayout(LayoutKind.Sequential, Pack = 1)]
321 protected struct DriverStatus {
322 public byte DriverError;
323 public byte IDEError;
324 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
325 public byte[] Reserved;
328 [StructLayout(LayoutKind.Sequential, Pack = 1)]
329 protected struct DriveCommandResult {
330 public uint BufferSize;
331 public DriverStatus DriverStatus;
334 [StructLayout(LayoutKind.Sequential, Pack = 1)]
335 protected struct DriveSmartReadResult {
336 public uint BufferSize;
337 public DriverStatus DriverStatus;
339 public byte Reserved;
340 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
341 public DriveAttribute[] Attributes;
344 [StructLayout(LayoutKind.Sequential, Pack = 1)]
345 protected struct Identify {
346 public ushort GeneralConfiguration;
347 public ushort NumberOfCylinders;
348 public ushort Reserved;
349 public ushort NumberOfHeads;
350 public ushort UnformattedBytesPerTrack;
351 public ushort UnformattedBytesPerSector;
352 public ushort SectorsPerTrack;
353 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
354 public ushort[] VendorUnique;
355 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
356 public byte[] SerialNumber;
357 public ushort BufferType;
358 public ushort BufferSectorSize;
359 public ushort NumberOfEccBytes;
360 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
361 public byte[] FirmwareRevision;
362 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
363 public byte[] ModelNumber;
364 public ushort MoreVendorUnique;
365 public ushort DoubleWordIo;
366 public ushort Capabilities;
367 public ushort MoreReserved;
368 public ushort PioCycleTimingMode;
369 public ushort DmaCycleTimingMode;
370 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
374 [StructLayout(LayoutKind.Sequential, Pack = 1)]
375 protected struct DriveIdentifyResult {
376 public uint BufferSize;
377 public DriverStatus DriverStatus;
378 public Identify Identify;
381 public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
383 private const byte SMART_CMD = 0xB0;
384 private const byte ID_CMD = 0xEC;
386 private const byte SMART_READ_DATA = 0xD0;
387 private const byte SMART_ENABLE_OPERATIONS = 0xD8;
389 private const byte SMART_LBA_MID = 0x4F;
390 private const byte SMART_LBA_HI = 0xC2;
392 private const int MAX_DRIVE_ATTRIBUTES = 512;
396 public static IntPtr OpenPhysicalDrive(int driveNumber) {
397 return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
398 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
399 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
403 public static bool EnableSmart(IntPtr handle, int driveNumber) {
404 DriveCommandParameter parameter = new DriveCommandParameter();
405 DriveCommandResult result;
408 parameter.DriveNumber = (byte)driveNumber;
409 parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
410 parameter.Registers.LBAMid = SMART_LBA_MID;
411 parameter.Registers.LBAHigh = SMART_LBA_HI;
412 parameter.Registers.Command = SMART_CMD;
414 return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand,
415 ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
416 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
420 public static DriveAttribute[] ReadSmart(IntPtr handle,
423 DriveCommandParameter parameter = new DriveCommandParameter();
424 DriveSmartReadResult result;
427 parameter.DriveNumber = (byte)driveNumber;
428 parameter.Registers.Features = SMART_READ_DATA;
429 parameter.Registers.LBAMid = SMART_LBA_MID;
430 parameter.Registers.LBAHigh = SMART_LBA_HI;
431 parameter.Registers.Command = SMART_CMD;
433 bool isValid = NativeMethods.DeviceIoControl(handle,
434 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
435 out result, Marshal.SizeOf(typeof(DriveSmartReadResult)),
436 out bytesReturned, IntPtr.Zero);
438 return (isValid) ? result.Attributes : new DriveAttribute[0];
441 public static string ReadName(IntPtr handle, int driveNumber) {
442 DriveCommandParameter parameter = new DriveCommandParameter();
443 DriveIdentifyResult result;
446 parameter.DriveNumber = (byte)driveNumber;
447 parameter.Registers.Command = ID_CMD;
449 bool valid = NativeMethods.DeviceIoControl(handle,
450 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
451 out result, Marshal.SizeOf(typeof(DriveIdentifyResult)),
452 out bytesReturned, IntPtr.Zero);
458 byte[] bytes = result.Identify.ModelNumber;
459 char[] chars = new char[bytes.Length];
460 for (int i = 0; i < bytes.Length; i += 2) {
461 chars[i] = (char)bytes[i + 1];
462 chars[i + 1] = (char)bytes[i];
465 return new string(chars).Trim();
469 public static int CloseHandle(IntPtr handle) {
470 return NativeMethods.CloseHandle(handle);
473 protected static class NativeMethods {
474 private const string KERNEL = "kernel32.dll";
476 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
477 CharSet = CharSet.Unicode)]
478 public static extern IntPtr CreateFile(string fileName,
479 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
480 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
481 IntPtr templateFilehandle);
483 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
484 public static extern int CloseHandle(IntPtr handle);
486 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
487 [return: MarshalAsAttribute(UnmanagedType.Bool)]
488 public static extern bool DeviceIoControl(IntPtr handle,
489 DriveCommand command, ref DriveCommandParameter parameter,
490 int parameterSize, out DriveSmartReadResult result, int resultSize,
491 out uint bytesReturned, IntPtr overlapped);
493 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
494 [return: MarshalAsAttribute(UnmanagedType.Bool)]
495 public static extern bool DeviceIoControl(IntPtr handle,
496 DriveCommand command, ref DriveCommandParameter parameter,
497 int parameterSize, out DriveCommandResult result, int resultSize,
498 out uint bytesReturned, IntPtr overlapped);
500 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
501 [return: MarshalAsAttribute(UnmanagedType.Bool)]
502 public static extern bool DeviceIoControl(IntPtr handle,
503 DriveCommand command, ref DriveCommandParameter parameter,
504 int parameterSize, out DriveIdentifyResult result, int resultSize,
505 out uint bytesReturned, IntPtr overlapped);