Corrected the size of the DriveCommandParameter structure to match the documentation of SENDCMDINPARAMS http://msdn.microsoft.com/en-us/library/ff565401%28VS.85%29.aspx
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.
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 [StructLayout(LayoutKind.Sequential, Pack = 1)]
82 public struct DriveAttribute {
83 public AttributeID ID;
84 public Status StatusFlags;
85 public byte AttrValue;
86 public byte WorstValue;
87 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
88 public byte[] RawValue;
93 private enum AccessMode : uint {
101 private enum ShareMode : uint {
108 private enum CreationMode : uint {
117 private enum FileAttribute : uint {
118 Readonly = 0x00000001,
121 Directory = 0x00000010,
122 Archive = 0x00000020,
125 Temporary = 0x00000100,
126 SparseFile = 0x00000200,
127 ReparsePoint = 0x00000400,
128 Compressed = 0x00000800,
129 Offline = 0x00001000,
130 NotContentIndexed = 0x00002000,
131 Encrypted = 0x00004000,
134 private enum DriveCommand : uint {
135 GetVersion = 0x00074080,
136 SendDriveCommand = 0x0007c084,
137 ReceiveDriveData = 0x0007c088
140 [StructLayout(LayoutKind.Sequential, Pack = 1)]
141 private struct CommandBlockRegisters {
142 public byte Features;
143 public byte SectorCount;
149 public byte Reserved;
152 [StructLayout(LayoutKind.Sequential, Pack = 1)]
153 private struct DriveCommandParameter {
154 private uint BufferSize;
155 public CommandBlockRegisters Registers;
156 public byte DriveNumber;
157 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
158 public byte[] Reserved;
161 [StructLayout(LayoutKind.Sequential, Pack = 1)]
162 private struct DriverStatus {
163 public byte DriverError;
164 public byte IDEError;
165 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
166 public byte[] Reserved;
169 [StructLayout(LayoutKind.Sequential, Pack = 1)]
170 private struct DriveCommandResult {
171 public uint BufferSize;
172 public DriverStatus DriverStatus;
175 [StructLayout(LayoutKind.Sequential, Pack = 1)]
176 private struct DriveSmartReadResult {
177 public uint BufferSize;
178 public DriverStatus DriverStatus;
180 public byte Reserved;
181 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
182 public DriveAttribute[] Attributes;
185 [StructLayout(LayoutKind.Sequential, Pack = 1)]
186 private struct Identify {
187 public ushort GeneralConfiguration;
188 public ushort NumberOfCylinders;
189 public ushort Reserved;
190 public ushort NumberOfHeads;
191 public ushort UnformattedBytesPerTrack;
192 public ushort UnformattedBytesPerSector;
193 public ushort SectorsPerTrack;
194 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
195 public ushort[] VendorUnique;
196 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
197 public byte[] SerialNumber;
198 public ushort BufferType;
199 public ushort BufferSectorSize;
200 public ushort NumberOfEccBytes;
201 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
202 public byte[] FirmwareRevision;
203 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
204 public byte[] ModelNumber;
205 public ushort MoreVendorUnique;
206 public ushort DoubleWordIo;
207 public ushort Capabilities;
208 public ushort MoreReserved;
209 public ushort PioCycleTimingMode;
210 public ushort DmaCycleTimingMode;
211 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
215 [StructLayout(LayoutKind.Sequential, Pack = 1)]
216 private struct DriveIdentifyResult {
217 public uint BufferSize;
218 public DriverStatus DriverStatus;
219 public Identify Identify;
222 public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
224 private const byte SMART_CMD = 0xB0;
225 private const byte ID_CMD = 0xEC;
227 private const byte SMART_READ_DATA = 0xD0;
228 private const byte SMART_ENABLE_OPERATIONS = 0xD8;
230 private const byte SMART_LBA_MID = 0x4F;
231 private const byte SMART_LBA_HI = 0xC2;
233 private const int MAX_DRIVE_ATTRIBUTES = 512;
237 public static IntPtr OpenPhysicalDrive(int driveNumber) {
238 return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
239 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
240 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
244 public static bool EnableSmart(IntPtr handle, int driveNumber) {
245 DriveCommandParameter parameter = new DriveCommandParameter();
246 DriveCommandResult result;
249 parameter.DriveNumber = (byte)driveNumber;
250 parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
251 parameter.Registers.LBAMid = SMART_LBA_MID;
252 parameter.Registers.LBAHigh = SMART_LBA_HI;
253 parameter.Registers.Command = SMART_CMD;
255 return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand,
256 ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
257 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
261 public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
262 DriveCommandParameter parameter = new DriveCommandParameter();
263 DriveSmartReadResult result;
266 parameter.DriveNumber = (byte)driveNumber;
267 parameter.Registers.Features = SMART_READ_DATA;
268 parameter.Registers.LBAMid = SMART_LBA_MID;
269 parameter.Registers.LBAHigh = SMART_LBA_HI;
270 parameter.Registers.Command = SMART_CMD;
272 bool valid = NativeMethods.DeviceIoControl(handle,
273 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
274 out result, Marshal.SizeOf(typeof(DriveSmartReadResult)),
275 out bytesReturned, IntPtr.Zero);
280 return result.Attributes;
283 public static string ReadName(IntPtr handle, int driveNumber) {
284 DriveCommandParameter parameter = new DriveCommandParameter();
285 DriveIdentifyResult result;
288 parameter.DriveNumber = (byte)driveNumber;
289 parameter.Registers.Command = ID_CMD;
291 bool valid = NativeMethods.DeviceIoControl(handle,
292 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
293 out result, Marshal.SizeOf(typeof(DriveIdentifyResult)),
294 out bytesReturned, IntPtr.Zero);
300 byte[] bytes = result.Identify.ModelNumber;
301 char[] chars = new char[bytes.Length];
302 for (int i = 0; i < bytes.Length; i += 2) {
303 chars[i] = (char)bytes[i + 1];
304 chars[i + 1] = (char)bytes[i];
307 return new string(chars).Trim();
311 public static int CloseHandle(IntPtr handle) {
312 return NativeMethods.CloseHandle(handle);
315 private static class NativeMethods {
316 private const string KERNEL = "kernel32.dll";
318 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
319 CharSet = CharSet.Unicode)]
320 public static extern IntPtr CreateFile(string fileName,
321 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
322 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
323 IntPtr templateFilehandle);
325 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
326 public static extern int CloseHandle(IntPtr handle);
328 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
329 [return: MarshalAsAttribute(UnmanagedType.Bool)]
330 public static extern bool DeviceIoControl(IntPtr handle,
331 DriveCommand command, ref DriveCommandParameter parameter,
332 int parameterSize, out DriveSmartReadResult result, int resultSize,
333 out uint bytesReturned, IntPtr overlapped);
335 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
336 [return: MarshalAsAttribute(UnmanagedType.Bool)]
337 public static extern bool DeviceIoControl(IntPtr handle,
338 DriveCommand command, ref DriveCommandParameter parameter,
339 int parameterSize, out DriveCommandResult result, int resultSize,
340 out uint bytesReturned, IntPtr overlapped);
342 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
343 [return: MarshalAsAttribute(UnmanagedType.Bool)]
344 public static extern bool DeviceIoControl(IntPtr handle,
345 DriveCommand command, ref DriveCommandParameter parameter,
346 int parameterSize, out DriveIdentifyResult result, int resultSize,
347 out uint bytesReturned, IntPtr overlapped);