Modified and extended version of the patch v4 by Roland Reinl (see Issue 256). Main differences to the original patch: DeviceIoControl refactorings removed, SmartAttribute is now descriptive only and does not hold any state, report is written as one 80 columns table, sensors are created only for meaningful values and without duplicates (remaining life, temperatures, host writes and reads). Also the current implementation should really preserve all the functionality of the old system. Additionally there is now a simple SMART devices emulation class (DebugSmart) that can be used in place of WindowsSmart for testing with reported data.
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-2011
20 the Initial Developer. All Rights Reserved.
24 Roland Reinl <roland-reinl@gmx.de>
26 Alternatively, the contents of this file may be used under the terms of
27 either the GNU General Public License Version 2 or later (the "GPL"), or
28 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 in which case the provisions of the GPL or the LGPL are applicable instead
30 of those above. If you wish to allow use of your version of this file only
31 under the terms of either the GPL or the LGPL, and not to allow others to
32 use your version of this file under the terms of the MPL, indicate your
33 decision by deleting the provisions above and replace them with the notice
34 and other provisions required by the GPL or the LGPL. If you do not delete
35 the provisions above, a recipient may use your version of this file under
36 the terms of any one of the MPL, the GPL or the LGPL.
41 using System.Collections.Generic;
42 using System.Runtime.InteropServices;
44 namespace OpenHardwareMonitor.Hardware.HDD {
46 internal class WindowsSmart : ISmart {
48 protected enum AccessMode : uint {
56 protected enum ShareMode : uint {
63 protected enum CreationMode : uint {
72 protected enum FileAttribute : uint {
73 Readonly = 0x00000001,
76 Directory = 0x00000010,
80 Temporary = 0x00000100,
81 SparseFile = 0x00000200,
82 ReparsePoint = 0x00000400,
83 Compressed = 0x00000800,
85 NotContentIndexed = 0x00002000,
86 Encrypted = 0x00004000,
89 protected enum DriveCommand : uint {
90 GetVersion = 0x00074080,
91 SendDriveCommand = 0x0007c084,
92 ReceiveDriveData = 0x0007c088
95 protected enum RegisterCommand : byte {
97 /// SMART data requested.
102 /// Identify data is requested.
107 protected enum RegisterFeature : byte {
111 SmartReadData = 0xD0,
114 /// Read SMART thresholds.
116 SmartReadThresholds = 0xD1, /* obsolete */
119 /// Autosave SMART data.
121 SmartAutosave = 0xD2,
124 /// Save SMART attributes.
126 SmartSaveAttr = 0xD3,
129 /// Set SMART to offline immediately.
131 SmartImmediateOffline = 0xD4,
141 SmartWriteLog = 0xD6,
144 /// Write SMART thresholds.
146 SmartWriteThresholds = 0xD7, /* obsolete */
151 SmartEnableOperations = 0xD8,
156 SmartDisableOperations = 0xD9,
159 /// Get SMART status.
164 /// Set SMART to offline automatically.
166 SmartAutoOffline = 0xDB, /* obsolete */
169 [StructLayout(LayoutKind.Sequential, Pack = 1)]
170 protected struct CommandBlockRegisters {
171 public RegisterFeature Features;
172 public byte SectorCount;
177 public RegisterCommand Command;
178 public byte Reserved;
181 [StructLayout(LayoutKind.Sequential, Pack = 1)]
182 protected struct DriveCommandParameter {
183 public uint BufferSize;
184 public CommandBlockRegisters Registers;
185 public byte DriveNumber;
186 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
187 public byte[] Reserved;
190 [StructLayout(LayoutKind.Sequential, Pack = 1)]
191 protected struct DriverStatus {
192 public byte DriverError;
193 public byte IDEError;
194 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
195 public byte[] Reserved;
198 [StructLayout(LayoutKind.Sequential, Pack = 1)]
199 protected struct DriveCommandResult {
200 public uint BufferSize;
201 public DriverStatus DriverStatus;
204 [StructLayout(LayoutKind.Sequential, Pack = 1)]
205 protected struct DriveSmartReadDataResult {
206 public uint BufferSize;
207 public DriverStatus DriverStatus;
209 public byte Reserved;
210 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
211 public DriveAttributeValue[] Attributes;
214 [StructLayout(LayoutKind.Sequential, Pack = 1)]
215 protected struct DriveSmartReadThresholdsResult {
216 public uint BufferSize;
217 public DriverStatus DriverStatus;
219 public byte Reserved;
220 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
221 public DriveThresholdValue[] Thresholds;
224 [StructLayout(LayoutKind.Sequential, Pack = 1)]
225 protected struct Identify {
226 public ushort GeneralConfiguration;
227 public ushort NumberOfCylinders;
228 public ushort Reserved;
229 public ushort NumberOfHeads;
230 public ushort UnformattedBytesPerTrack;
231 public ushort UnformattedBytesPerSector;
232 public ushort SectorsPerTrack;
233 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
234 public ushort[] VendorUnique;
235 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
236 public byte[] SerialNumber;
237 public ushort BufferType;
238 public ushort BufferSectorSize;
239 public ushort NumberOfEccBytes;
240 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
241 public byte[] FirmwareRevision;
242 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
243 public byte[] ModelNumber;
244 public ushort MoreVendorUnique;
245 public ushort DoubleWordIo;
246 public ushort Capabilities;
247 public ushort MoreReserved;
248 public ushort PioCycleTimingMode;
249 public ushort DmaCycleTimingMode;
250 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
254 [StructLayout(LayoutKind.Sequential, Pack = 1)]
255 protected struct DriveIdentifyResult {
256 public uint BufferSize;
257 public DriverStatus DriverStatus;
258 public Identify Identify;
261 public IntPtr InvalidHandle { get { return (IntPtr)(-1); } }
263 private const byte SMART_LBA_MID = 0x4F;
264 private const byte SMART_LBA_HI = 0xC2;
266 private const int MAX_DRIVE_ATTRIBUTES = 512;
268 public IntPtr OpenDrive(int driveNumber) {
269 return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
270 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
271 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
275 public bool EnableSmart(IntPtr handle, int driveNumber) {
276 DriveCommandParameter parameter = new DriveCommandParameter();
277 DriveCommandResult result;
280 parameter.DriveNumber = (byte)driveNumber;
281 parameter.Registers.Features = RegisterFeature.SmartEnableOperations;
282 parameter.Registers.LBAMid = SMART_LBA_MID;
283 parameter.Registers.LBAHigh = SMART_LBA_HI;
284 parameter.Registers.Command = RegisterCommand.SmartCmd;
286 return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand,
287 ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
288 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
292 public DriveAttributeValue[] ReadSmartData(IntPtr handle, int driveNumber) {
293 DriveCommandParameter parameter = new DriveCommandParameter();
294 DriveSmartReadDataResult result;
297 parameter.DriveNumber = (byte)driveNumber;
298 parameter.Registers.Features = RegisterFeature.SmartReadData;
299 parameter.Registers.LBAMid = SMART_LBA_MID;
300 parameter.Registers.LBAHigh = SMART_LBA_HI;
301 parameter.Registers.Command = RegisterCommand.SmartCmd;
303 bool isValid = NativeMethods.DeviceIoControl(handle,
304 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
305 out result, Marshal.SizeOf(typeof(DriveSmartReadDataResult)),
306 out bytesReturned, IntPtr.Zero);
308 return (isValid) ? result.Attributes : new DriveAttributeValue[0];
311 public DriveThresholdValue[] ReadSmartThresholds(IntPtr handle,
314 DriveCommandParameter parameter = new DriveCommandParameter();
315 DriveSmartReadThresholdsResult result;
316 uint bytesReturned = 0;
318 parameter.DriveNumber = (byte)driveNumber;
319 parameter.Registers.Features = RegisterFeature.SmartReadThresholds;
320 parameter.Registers.LBAMid = SMART_LBA_MID;
321 parameter.Registers.LBAHigh = SMART_LBA_HI;
322 parameter.Registers.Command = RegisterCommand.SmartCmd;
324 bool isValid = NativeMethods.DeviceIoControl(handle,
325 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
326 out result, Marshal.SizeOf(typeof(DriveSmartReadThresholdsResult)),
327 out bytesReturned, IntPtr.Zero);
329 return (isValid) ? result.Thresholds : new DriveThresholdValue[0];
332 public string ReadName(IntPtr handle, int driveNumber) {
333 DriveCommandParameter parameter = new DriveCommandParameter();
334 DriveIdentifyResult result;
337 parameter.DriveNumber = (byte)driveNumber;
338 parameter.Registers.Command = RegisterCommand.IdCmd;
340 bool valid = NativeMethods.DeviceIoControl(handle,
341 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
342 out result, Marshal.SizeOf(typeof(DriveIdentifyResult)),
343 out bytesReturned, IntPtr.Zero);
349 byte[] bytes = result.Identify.ModelNumber;
350 char[] chars = new char[bytes.Length];
351 for (int i = 0; i < bytes.Length; i += 2) {
352 chars[i] = (char)bytes[i + 1];
353 chars[i + 1] = (char)bytes[i];
356 return new string(chars).Trim(new char[] {' ', '\0'});
360 public void CloseHandle(IntPtr handle) {
361 NativeMethods.CloseHandle(handle);
364 protected static class NativeMethods {
365 private const string KERNEL = "kernel32.dll";
367 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
368 CharSet = CharSet.Unicode)]
369 public static extern IntPtr CreateFile(string fileName,
370 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
371 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
372 IntPtr templateFilehandle);
374 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
375 public static extern int CloseHandle(IntPtr handle);
377 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
378 [return: MarshalAsAttribute(UnmanagedType.Bool)]
379 public static extern bool DeviceIoControl(IntPtr handle,
380 DriveCommand command, ref DriveCommandParameter parameter,
381 int parameterSize, out DriveSmartReadDataResult result, int resultSize,
382 out uint bytesReturned, IntPtr overlapped);
384 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
385 [return: MarshalAsAttribute(UnmanagedType.Bool)]
386 public static extern bool DeviceIoControl(IntPtr handle,
387 DriveCommand command, ref DriveCommandParameter parameter,
388 int parameterSize, out DriveSmartReadThresholdsResult result,
389 int resultSize, out uint bytesReturned, IntPtr overlapped);
391 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
392 [return: MarshalAsAttribute(UnmanagedType.Bool)]
393 public static extern bool DeviceIoControl(IntPtr handle,
394 DriveCommand command, ref DriveCommandParameter parameter,
395 int parameterSize, out DriveCommandResult result, int resultSize,
396 out uint bytesReturned, IntPtr overlapped);
398 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
399 [return: MarshalAsAttribute(UnmanagedType.Bool)]
400 public static extern bool DeviceIoControl(IntPtr handle,
401 DriveCommand command, ref DriveCommandParameter parameter,
402 int parameterSize, out DriveIdentifyResult result, int resultSize,
403 out uint bytesReturned, IntPtr overlapped);