Added initial SSD support for Intel, Indilinx, SandForce and Samsung drives. Experimental feature for now!
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 public enum AttributeID : byte {
58 ThroughputPerformance = 0x02,
60 StartStopCount = 0x04,
61 ReallocatedSectorsCount = 0x05,
62 ReadChannelMargin = 0x06,
64 SeekTimePerformance = 0x08,
66 SpinRetryCount = 0x0A,
67 RecalibrationRetries = 0x0B,
68 PowerCycleCount = 0x0C,
69 SoftReadErrorRate = 0x0D,
70 AirflowTemperature = 0xBE,
72 HardwareECCRecovered = 0xC3,
73 ReallocationEventCount = 0xC4,
74 CurrentPendingSectorCount = 0xC5,
75 UncorrectableSectorCount = 0xC6,
76 UltraDMACRCErrorCount = 0xC7,
77 WriteErrorRate = 0xC8,
78 DriveTemperature = 0xE7
81 public enum SSDLifeID {
89 [StructLayout(LayoutKind.Sequential, Pack = 1)]
90 public struct DriveAttribute {
91 public AttributeID ID;
92 public Status StatusFlags;
93 public byte AttrValue;
94 public byte WorstValue;
95 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
96 public byte[] RawValue;
101 protected enum AccessMode : uint {
104 Execute = 0x20000000,
109 protected enum ShareMode : uint {
116 protected enum CreationMode : uint {
125 protected enum FileAttribute : uint {
126 Readonly = 0x00000001,
129 Directory = 0x00000010,
130 Archive = 0x00000020,
133 Temporary = 0x00000100,
134 SparseFile = 0x00000200,
135 ReparsePoint = 0x00000400,
136 Compressed = 0x00000800,
137 Offline = 0x00001000,
138 NotContentIndexed = 0x00002000,
139 Encrypted = 0x00004000,
142 protected enum DriveCommand : uint {
143 GetVersion = 0x00074080,
144 SendDriveCommand = 0x0007c084,
145 ReceiveDriveData = 0x0007c088
148 [StructLayout(LayoutKind.Sequential, Pack = 1)]
149 protected struct CommandBlockRegisters {
150 public byte Features;
151 public byte SectorCount;
157 public byte Reserved;
160 [StructLayout(LayoutKind.Sequential, Pack = 1)]
161 protected struct DriveCommandParameter {
162 public uint BufferSize;
163 public CommandBlockRegisters Registers;
164 public byte DriveNumber;
165 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
166 public byte[] Reserved;
169 [StructLayout(LayoutKind.Sequential, Pack = 1)]
170 protected struct DriverStatus {
171 public byte DriverError;
172 public byte IDEError;
173 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
174 public byte[] Reserved;
177 [StructLayout(LayoutKind.Sequential, Pack = 1)]
178 protected struct DriveCommandResult {
179 public uint BufferSize;
180 public DriverStatus DriverStatus;
183 [StructLayout(LayoutKind.Sequential, Pack = 1)]
184 protected struct DriveSmartReadResult {
185 public uint BufferSize;
186 public DriverStatus DriverStatus;
188 public byte Reserved;
189 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
190 public DriveAttribute[] Attributes;
193 [StructLayout(LayoutKind.Sequential, Pack = 1)]
194 protected struct Identify {
195 public ushort GeneralConfiguration;
196 public ushort NumberOfCylinders;
197 public ushort Reserved;
198 public ushort NumberOfHeads;
199 public ushort UnformattedBytesPerTrack;
200 public ushort UnformattedBytesPerSector;
201 public ushort SectorsPerTrack;
202 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
203 public ushort[] VendorUnique;
204 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
205 public byte[] SerialNumber;
206 public ushort BufferType;
207 public ushort BufferSectorSize;
208 public ushort NumberOfEccBytes;
209 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
210 public byte[] FirmwareRevision;
211 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
212 public byte[] ModelNumber;
213 public ushort MoreVendorUnique;
214 public ushort DoubleWordIo;
215 public ushort Capabilities;
216 public ushort MoreReserved;
217 public ushort PioCycleTimingMode;
218 public ushort DmaCycleTimingMode;
219 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
223 [StructLayout(LayoutKind.Sequential, Pack = 1)]
224 protected struct DriveIdentifyResult {
225 public uint BufferSize;
226 public DriverStatus DriverStatus;
227 public Identify Identify;
230 public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
232 private const byte SMART_CMD = 0xB0;
233 private const byte ID_CMD = 0xEC;
235 private const byte SMART_READ_DATA = 0xD0;
236 private const byte SMART_ENABLE_OPERATIONS = 0xD8;
238 private const byte SMART_LBA_MID = 0x4F;
239 private const byte SMART_LBA_HI = 0xC2;
241 private const int MAX_DRIVE_ATTRIBUTES = 512;
245 public static IntPtr OpenPhysicalDrive(int driveNumber) {
246 return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
247 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
248 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
252 public static bool EnableSmart(IntPtr handle, int driveNumber) {
253 DriveCommandParameter parameter = new DriveCommandParameter();
254 DriveCommandResult result;
257 parameter.DriveNumber = (byte)driveNumber;
258 parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
259 parameter.Registers.LBAMid = SMART_LBA_MID;
260 parameter.Registers.LBAHigh = SMART_LBA_HI;
261 parameter.Registers.Command = SMART_CMD;
263 return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand,
264 ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
265 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
269 public static List<DriveAttribute> ReadSmart(IntPtr handle,
272 DriveCommandParameter parameter = new DriveCommandParameter();
273 DriveSmartReadResult result;
276 parameter.DriveNumber = (byte)driveNumber;
277 parameter.Registers.Features = SMART_READ_DATA;
278 parameter.Registers.LBAMid = SMART_LBA_MID;
279 parameter.Registers.LBAHigh = SMART_LBA_HI;
280 parameter.Registers.Command = SMART_CMD;
282 bool isValid = NativeMethods.DeviceIoControl(handle,
283 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
284 out result, Marshal.SizeOf(typeof(DriveSmartReadResult)),
285 out bytesReturned, IntPtr.Zero);
288 ? new List<DriveAttribute>(result.Attributes)
289 : new List<DriveAttribute>();
292 public static string ReadName(IntPtr handle, int driveNumber) {
293 DriveCommandParameter parameter = new DriveCommandParameter();
294 DriveIdentifyResult result;
297 parameter.DriveNumber = (byte)driveNumber;
298 parameter.Registers.Command = ID_CMD;
300 bool valid = NativeMethods.DeviceIoControl(handle,
301 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
302 out result, Marshal.SizeOf(typeof(DriveIdentifyResult)),
303 out bytesReturned, IntPtr.Zero);
309 byte[] bytes = result.Identify.ModelNumber;
310 char[] chars = new char[bytes.Length];
311 for (int i = 0; i < bytes.Length; i += 2) {
312 chars[i] = (char)bytes[i + 1];
313 chars[i + 1] = (char)bytes[i];
316 return new string(chars).Trim();
320 public static int CloseHandle(IntPtr handle) {
321 return NativeMethods.CloseHandle(handle);
324 protected static class NativeMethods {
325 private const string KERNEL = "kernel32.dll";
327 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
328 CharSet = CharSet.Unicode)]
329 public static extern IntPtr CreateFile(string fileName,
330 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
331 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
332 IntPtr templateFilehandle);
334 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
335 public static extern int CloseHandle(IntPtr handle);
337 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
338 [return: MarshalAsAttribute(UnmanagedType.Bool)]
339 public static extern bool DeviceIoControl(IntPtr handle,
340 DriveCommand command, ref DriveCommandParameter parameter,
341 int parameterSize, out DriveSmartReadResult result, int resultSize,
342 out uint bytesReturned, IntPtr overlapped);
344 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
345 [return: MarshalAsAttribute(UnmanagedType.Bool)]
346 public static extern bool DeviceIoControl(IntPtr handle,
347 DriveCommand command, ref DriveCommandParameter parameter,
348 int parameterSize, out DriveCommandResult result, int resultSize,
349 out uint bytesReturned, IntPtr overlapped);
351 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
352 [return: MarshalAsAttribute(UnmanagedType.Bool)]
353 public static extern bool DeviceIoControl(IntPtr handle,
354 DriveCommand command, ref DriveCommandParameter parameter,
355 int parameterSize, out DriveIdentifyResult result, int resultSize,
356 out uint bytesReturned, IntPtr overlapped);