Changed the SMART AttributeID type from an enum to a struct.
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 // Common SMART attributes
85 public static class CommonAttributes {
86 public static readonly AttributeID
87 ReadErrorRate = new AttributeID(0x01);
88 public static readonly AttributeID
89 ThroughputPerformance = new AttributeID(0x02);
90 public static readonly AttributeID
91 SpinUpTime = new AttributeID(0x03);
92 public static readonly AttributeID
93 StartStopCount = new AttributeID(0x04);
94 public static readonly AttributeID
95 ReallocatedSectorsCount = new AttributeID(0x05);
96 public static readonly AttributeID
97 ReadChannelMargin = new AttributeID(0x06);
98 public static readonly AttributeID
99 SeekErrorRate = new AttributeID(0x07);
100 public static readonly AttributeID
101 SeekTimePerformance = new AttributeID(0x08);
102 public static readonly AttributeID
103 PowerOnHours = new AttributeID(0x09);
104 public static readonly AttributeID
105 SpinRetryCount = new AttributeID(0x0A);
106 public static readonly AttributeID
107 RecalibrationRetries = new AttributeID(0x0B);
108 public static readonly AttributeID
109 PowerCycleCount = new AttributeID(0x0C);
110 public static readonly AttributeID
111 SoftReadErrorRate = new AttributeID(0x0D);
112 public static readonly AttributeID
113 AirflowTemperature = new AttributeID(0xBE);
114 public static readonly AttributeID
115 Temperature = new AttributeID(0xC2);
116 public static readonly AttributeID
117 HardwareECCRecovered = new AttributeID(0xC3);
118 public static readonly AttributeID
119 ReallocationEventCount = new AttributeID(0xC4);
120 public static readonly AttributeID
121 CurrentPendingSectorCount = new AttributeID(0xC5);
122 public static readonly AttributeID
123 UncorrectableSectorCount = new AttributeID(0xC6);
124 public static readonly AttributeID
125 UltraDMACRCErrorCount = new AttributeID(0xC7);
126 public static readonly AttributeID
127 WriteErrorRate = new AttributeID(0xC8);
128 public static readonly AttributeID
129 DriveTemperature = new AttributeID(0xE7);
132 // Indilinx SSD SMART attributes
133 public static class IndilinxAttributes {
134 public static readonly AttributeID RemainingLife = new AttributeID(0xD1);
137 // Intel SSD SMART attributes
138 public static class IntelAttributes {
139 public static readonly AttributeID RemainingLife = new AttributeID(0xE8);
142 // Samsung SSD SMART attributes
143 public static class SamsungAttributes {
144 public static readonly AttributeID RemainingLife = new AttributeID(0xB4);
147 // SandForce SSD SMART attributes
148 public static class SandForceAttributes {
149 public static readonly AttributeID RemainingLife = new AttributeID(0xE7);
152 [StructLayout(LayoutKind.Sequential, Pack = 1)]
153 public struct DriveAttribute {
154 public AttributeID ID;
155 public Status StatusFlags;
156 public byte AttrValue;
157 public byte WorstValue;
158 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
159 public byte[] RawValue;
160 public byte Reserved;
164 protected enum AccessMode : uint {
167 Execute = 0x20000000,
172 protected enum ShareMode : uint {
179 protected enum CreationMode : uint {
188 protected enum FileAttribute : uint {
189 Readonly = 0x00000001,
192 Directory = 0x00000010,
193 Archive = 0x00000020,
196 Temporary = 0x00000100,
197 SparseFile = 0x00000200,
198 ReparsePoint = 0x00000400,
199 Compressed = 0x00000800,
200 Offline = 0x00001000,
201 NotContentIndexed = 0x00002000,
202 Encrypted = 0x00004000,
205 protected enum DriveCommand : uint {
206 GetVersion = 0x00074080,
207 SendDriveCommand = 0x0007c084,
208 ReceiveDriveData = 0x0007c088
211 [StructLayout(LayoutKind.Sequential, Pack = 1)]
212 protected struct CommandBlockRegisters {
213 public byte Features;
214 public byte SectorCount;
220 public byte Reserved;
223 [StructLayout(LayoutKind.Sequential, Pack = 1)]
224 protected struct DriveCommandParameter {
225 public uint BufferSize;
226 public CommandBlockRegisters Registers;
227 public byte DriveNumber;
228 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
229 public byte[] Reserved;
232 [StructLayout(LayoutKind.Sequential, Pack = 1)]
233 protected struct DriverStatus {
234 public byte DriverError;
235 public byte IDEError;
236 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
237 public byte[] Reserved;
240 [StructLayout(LayoutKind.Sequential, Pack = 1)]
241 protected struct DriveCommandResult {
242 public uint BufferSize;
243 public DriverStatus DriverStatus;
246 [StructLayout(LayoutKind.Sequential, Pack = 1)]
247 protected struct DriveSmartReadResult {
248 public uint BufferSize;
249 public DriverStatus DriverStatus;
251 public byte Reserved;
252 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
253 public DriveAttribute[] Attributes;
256 [StructLayout(LayoutKind.Sequential, Pack = 1)]
257 protected struct Identify {
258 public ushort GeneralConfiguration;
259 public ushort NumberOfCylinders;
260 public ushort Reserved;
261 public ushort NumberOfHeads;
262 public ushort UnformattedBytesPerTrack;
263 public ushort UnformattedBytesPerSector;
264 public ushort SectorsPerTrack;
265 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
266 public ushort[] VendorUnique;
267 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
268 public byte[] SerialNumber;
269 public ushort BufferType;
270 public ushort BufferSectorSize;
271 public ushort NumberOfEccBytes;
272 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
273 public byte[] FirmwareRevision;
274 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
275 public byte[] ModelNumber;
276 public ushort MoreVendorUnique;
277 public ushort DoubleWordIo;
278 public ushort Capabilities;
279 public ushort MoreReserved;
280 public ushort PioCycleTimingMode;
281 public ushort DmaCycleTimingMode;
282 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
286 [StructLayout(LayoutKind.Sequential, Pack = 1)]
287 protected struct DriveIdentifyResult {
288 public uint BufferSize;
289 public DriverStatus DriverStatus;
290 public Identify Identify;
293 public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
295 private const byte SMART_CMD = 0xB0;
296 private const byte ID_CMD = 0xEC;
298 private const byte SMART_READ_DATA = 0xD0;
299 private const byte SMART_ENABLE_OPERATIONS = 0xD8;
301 private const byte SMART_LBA_MID = 0x4F;
302 private const byte SMART_LBA_HI = 0xC2;
304 private const int MAX_DRIVE_ATTRIBUTES = 512;
308 public static IntPtr OpenPhysicalDrive(int driveNumber) {
309 return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
310 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
311 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
315 public static bool EnableSmart(IntPtr handle, int driveNumber) {
316 DriveCommandParameter parameter = new DriveCommandParameter();
317 DriveCommandResult result;
320 parameter.DriveNumber = (byte)driveNumber;
321 parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
322 parameter.Registers.LBAMid = SMART_LBA_MID;
323 parameter.Registers.LBAHigh = SMART_LBA_HI;
324 parameter.Registers.Command = SMART_CMD;
326 return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand,
327 ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
328 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
332 public static List<DriveAttribute> ReadSmart(IntPtr handle,
335 DriveCommandParameter parameter = new DriveCommandParameter();
336 DriveSmartReadResult result;
339 parameter.DriveNumber = (byte)driveNumber;
340 parameter.Registers.Features = SMART_READ_DATA;
341 parameter.Registers.LBAMid = SMART_LBA_MID;
342 parameter.Registers.LBAHigh = SMART_LBA_HI;
343 parameter.Registers.Command = SMART_CMD;
345 bool isValid = NativeMethods.DeviceIoControl(handle,
346 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
347 out result, Marshal.SizeOf(typeof(DriveSmartReadResult)),
348 out bytesReturned, IntPtr.Zero);
351 ? new List<DriveAttribute>(result.Attributes)
352 : new List<DriveAttribute>();
355 public static string ReadName(IntPtr handle, int driveNumber) {
356 DriveCommandParameter parameter = new DriveCommandParameter();
357 DriveIdentifyResult result;
360 parameter.DriveNumber = (byte)driveNumber;
361 parameter.Registers.Command = ID_CMD;
363 bool valid = NativeMethods.DeviceIoControl(handle,
364 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
365 out result, Marshal.SizeOf(typeof(DriveIdentifyResult)),
366 out bytesReturned, IntPtr.Zero);
372 byte[] bytes = result.Identify.ModelNumber;
373 char[] chars = new char[bytes.Length];
374 for (int i = 0; i < bytes.Length; i += 2) {
375 chars[i] = (char)bytes[i + 1];
376 chars[i + 1] = (char)bytes[i];
379 return new string(chars).Trim();
383 public static int CloseHandle(IntPtr handle) {
384 return NativeMethods.CloseHandle(handle);
387 protected static class NativeMethods {
388 private const string KERNEL = "kernel32.dll";
390 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
391 CharSet = CharSet.Unicode)]
392 public static extern IntPtr CreateFile(string fileName,
393 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
394 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
395 IntPtr templateFilehandle);
397 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
398 public static extern int CloseHandle(IntPtr handle);
400 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
401 [return: MarshalAsAttribute(UnmanagedType.Bool)]
402 public static extern bool DeviceIoControl(IntPtr handle,
403 DriveCommand command, ref DriveCommandParameter parameter,
404 int parameterSize, out DriveSmartReadResult result, int resultSize,
405 out uint bytesReturned, IntPtr overlapped);
407 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
408 [return: MarshalAsAttribute(UnmanagedType.Bool)]
409 public static extern bool DeviceIoControl(IntPtr handle,
410 DriveCommand command, ref DriveCommandParameter parameter,
411 int parameterSize, out DriveCommandResult result, int resultSize,
412 out uint bytesReturned, IntPtr overlapped);
414 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
415 [return: MarshalAsAttribute(UnmanagedType.Bool)]
416 public static extern bool DeviceIoControl(IntPtr handle,
417 DriveCommand command, ref DriveCommandParameter parameter,
418 int parameterSize, out DriveIdentifyResult result, int resultSize,
419 out uint bytesReturned, IntPtr overlapped);