Hardware/HDD/WindowsSmart.cs
author moel.mich
Sat, 14 Jul 2012 19:24:04 +0000
changeset 363 daa9590e1bee
parent 325 4c31341a4800
child 369 5077ed7ddca8
permissions -rw-r--r--
Fixed Issue 269.
moel@324
     1
/*
moel@324
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@324
     6
 
moel@344
     7
  Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	Copyright (C) 2010 Paul Werelds
moel@344
     9
  Copyright (C) 2011 Roland Reinl <roland-reinl@gmx.de>
moel@344
    10
	
moel@324
    11
*/
moel@324
    12
moel@324
    13
using System;
moel@324
    14
using System.Collections.Generic;
moel@324
    15
using System.Runtime.InteropServices;
moel@324
    16
moel@324
    17
namespace OpenHardwareMonitor.Hardware.HDD {
moel@324
    18
moel@324
    19
  internal class WindowsSmart : ISmart {
moel@324
    20
    [Flags]
moel@324
    21
    protected enum AccessMode : uint {     
moel@324
    22
      Read = 0x80000000,    
moel@324
    23
      Write = 0x40000000,     
moel@324
    24
      Execute = 0x20000000,     
moel@324
    25
      All = 0x10000000
moel@324
    26
    }
moel@324
    27
moel@324
    28
    [Flags]
moel@324
    29
    protected enum ShareMode : uint {
moel@324
    30
      None = 0,     
moel@324
    31
      Read = 1,     
moel@324
    32
      Write = 2,    
moel@324
    33
      Delete = 4
moel@324
    34
    }
moel@324
    35
moel@324
    36
    protected enum CreationMode : uint {
moel@324
    37
      New = 1,
moel@324
    38
      CreateAlways = 2,    
moel@324
    39
      OpenExisting = 3,    
moel@324
    40
      OpenAlways = 4,    
moel@324
    41
      TruncateExisting = 5
moel@324
    42
    }
moel@324
    43
moel@324
    44
    [Flags]
moel@324
    45
    protected enum FileAttribute : uint {
moel@324
    46
      Readonly = 0x00000001,
moel@324
    47
      Hidden = 0x00000002,
moel@324
    48
      System = 0x00000004,
moel@324
    49
      Directory = 0x00000010,
moel@324
    50
      Archive = 0x00000020,
moel@324
    51
      Device = 0x00000040,
moel@324
    52
      Normal = 0x00000080,
moel@324
    53
      Temporary = 0x00000100,
moel@324
    54
      SparseFile = 0x00000200,
moel@324
    55
      ReparsePoint = 0x00000400,
moel@324
    56
      Compressed = 0x00000800,
moel@324
    57
      Offline = 0x00001000,
moel@324
    58
      NotContentIndexed = 0x00002000,
moel@324
    59
      Encrypted = 0x00004000,
moel@324
    60
    }
moel@324
    61
moel@324
    62
    protected enum DriveCommand : uint {
moel@324
    63
      GetVersion = 0x00074080,
moel@324
    64
      SendDriveCommand = 0x0007c084,
moel@324
    65
      ReceiveDriveData = 0x0007c088
moel@324
    66
    }
moel@324
    67
moel@324
    68
    protected enum RegisterCommand : byte {
moel@324
    69
      /// <summary>
moel@324
    70
      /// SMART data requested.
moel@324
    71
      /// </summary>
moel@324
    72
      SmartCmd = 0xB0,
moel@324
    73
moel@324
    74
      /// <summary>
moel@324
    75
      /// Identify data is requested.
moel@324
    76
      /// </summary>
moel@324
    77
      IdCmd = 0xEC,
moel@324
    78
    }
moel@324
    79
moel@324
    80
    protected enum RegisterFeature : byte {
moel@324
    81
      /// <summary>
moel@324
    82
      /// Read SMART data.
moel@324
    83
      /// </summary>
moel@324
    84
      SmartReadData = 0xD0,
moel@324
    85
moel@324
    86
      /// <summary>
moel@324
    87
      /// Read SMART thresholds.
moel@324
    88
      /// </summary>
moel@324
    89
      SmartReadThresholds = 0xD1, /* obsolete */
moel@324
    90
moel@324
    91
      /// <summary>
moel@324
    92
      /// Autosave SMART data.
moel@324
    93
      /// </summary>
moel@324
    94
      SmartAutosave = 0xD2,
moel@324
    95
moel@324
    96
      /// <summary>
moel@324
    97
      /// Save SMART attributes.
moel@324
    98
      /// </summary>
moel@324
    99
      SmartSaveAttr = 0xD3,
moel@324
   100
moel@324
   101
      /// <summary>
moel@324
   102
      /// Set SMART to offline immediately.
moel@324
   103
      /// </summary>
moel@324
   104
      SmartImmediateOffline = 0xD4,
moel@324
   105
moel@324
   106
      /// <summary>
moel@324
   107
      /// Read SMART log.
moel@324
   108
      /// </summary>
moel@324
   109
      SmartReadLog = 0xD5,
moel@324
   110
moel@324
   111
      /// <summary>
moel@324
   112
      /// Write SMART log.
moel@324
   113
      /// </summary>
moel@324
   114
      SmartWriteLog = 0xD6,
moel@324
   115
moel@324
   116
      /// <summary>
moel@324
   117
      /// Write SMART thresholds.
moel@324
   118
      /// </summary>
moel@324
   119
      SmartWriteThresholds = 0xD7, /* obsolete */
moel@324
   120
moel@324
   121
      /// <summary>
moel@324
   122
      /// Enable SMART.
moel@324
   123
      /// </summary>
moel@324
   124
      SmartEnableOperations = 0xD8,
moel@324
   125
moel@324
   126
      /// <summary>
moel@324
   127
      /// Disable SMART.
moel@324
   128
      /// </summary>
moel@324
   129
      SmartDisableOperations = 0xD9,
moel@324
   130
moel@324
   131
      /// <summary>
moel@324
   132
      /// Get SMART status.
moel@324
   133
      /// </summary>
moel@324
   134
      SmartStatus = 0xDA,
moel@324
   135
moel@324
   136
      /// <summary>
moel@324
   137
      /// Set SMART to offline automatically.
moel@324
   138
      /// </summary>
moel@324
   139
      SmartAutoOffline = 0xDB, /* obsolete */
moel@324
   140
    }
moel@324
   141
moel@324
   142
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@324
   143
    protected struct CommandBlockRegisters {
moel@324
   144
      public RegisterFeature Features;         
moel@324
   145
      public byte SectorCount;      
moel@324
   146
      public byte LBALow;       
moel@324
   147
      public byte LBAMid;           
moel@324
   148
      public byte LBAHigh;        
moel@324
   149
      public byte Device;
moel@324
   150
      public RegisterCommand Command;           
moel@324
   151
      public byte Reserved;                  
moel@324
   152
    }
moel@324
   153
moel@324
   154
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@324
   155
    protected struct DriveCommandParameter {
moel@324
   156
      public uint BufferSize;           
moel@324
   157
      public CommandBlockRegisters Registers;           
moel@324
   158
      public byte DriveNumber;   
moel@324
   159
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@324
   160
      public byte[] Reserved;                                
moel@324
   161
    }
moel@324
   162
moel@324
   163
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@324
   164
    protected struct DriverStatus {
moel@324
   165
      public byte DriverError;   
moel@324
   166
      public byte IDEError;             
moel@324
   167
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
moel@324
   168
      public byte[] Reserved;               
moel@324
   169
    }
moel@324
   170
moel@324
   171
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@324
   172
    protected struct DriveCommandResult {
moel@324
   173
      public uint BufferSize;
moel@324
   174
      public DriverStatus DriverStatus;
moel@324
   175
    } 
moel@324
   176
moel@324
   177
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@324
   178
    protected struct DriveSmartReadDataResult {
moel@324
   179
      public uint BufferSize;           
moel@324
   180
      public DriverStatus DriverStatus;
moel@324
   181
      public byte Version;
moel@324
   182
      public byte Reserved;
moel@324
   183
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
moel@324
   184
      public DriveAttributeValue[] Attributes;                                                                                       
moel@324
   185
    }
moel@324
   186
moel@324
   187
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@324
   188
    protected struct DriveSmartReadThresholdsResult {
moel@324
   189
      public uint BufferSize;
moel@324
   190
      public DriverStatus DriverStatus;
moel@324
   191
      public byte Version;
moel@324
   192
      public byte Reserved;
moel@324
   193
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
moel@324
   194
      public DriveThresholdValue[] Thresholds;
moel@324
   195
    }
moel@324
   196
moel@324
   197
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@324
   198
    protected struct Identify {
moel@324
   199
      public ushort GeneralConfiguration;
moel@324
   200
      public ushort NumberOfCylinders;
moel@324
   201
      public ushort Reserved;
moel@324
   202
      public ushort NumberOfHeads;
moel@324
   203
      public ushort UnformattedBytesPerTrack;
moel@324
   204
      public ushort UnformattedBytesPerSector;
moel@324
   205
      public ushort SectorsPerTrack;
moel@324
   206
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
moel@324
   207
      public ushort[] VendorUnique;
moel@324
   208
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@324
   209
      public byte[] SerialNumber;
moel@324
   210
      public ushort BufferType;
moel@324
   211
      public ushort BufferSectorSize;
moel@324
   212
      public ushort NumberOfEccBytes;
moel@324
   213
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
moel@324
   214
      public byte[] FirmwareRevision;
moel@324
   215
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
moel@324
   216
      public byte[] ModelNumber;
moel@324
   217
      public ushort MoreVendorUnique;
moel@324
   218
      public ushort DoubleWordIo;
moel@324
   219
      public ushort Capabilities;
moel@324
   220
      public ushort MoreReserved;
moel@324
   221
      public ushort PioCycleTimingMode;
moel@324
   222
      public ushort DmaCycleTimingMode;
moel@324
   223
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
moel@324
   224
      public byte[] More;
moel@324
   225
    }
moel@324
   226
moel@324
   227
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@324
   228
    protected struct DriveIdentifyResult {
moel@324
   229
      public uint BufferSize;
moel@324
   230
      public DriverStatus DriverStatus;
moel@324
   231
      public Identify Identify;
moel@324
   232
    }
moel@324
   233
moel@324
   234
    public IntPtr InvalidHandle { get { return (IntPtr)(-1); } }
moel@324
   235
moel@324
   236
    private const byte SMART_LBA_MID = 0x4F;
moel@324
   237
    private const byte SMART_LBA_HI = 0xC2;
moel@324
   238
moel@324
   239
    private const int MAX_DRIVE_ATTRIBUTES = 512;
moel@324
   240
moel@324
   241
    public IntPtr OpenDrive(int driveNumber) {
moel@324
   242
      return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
moel@324
   243
        AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
moel@324
   244
        IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
moel@324
   245
        IntPtr.Zero);
moel@324
   246
    }
moel@324
   247
moel@324
   248
    public bool EnableSmart(IntPtr handle, int driveNumber) {
moel@324
   249
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@324
   250
      DriveCommandResult result;
moel@324
   251
      uint bytesReturned;
moel@324
   252
moel@324
   253
      parameter.DriveNumber = (byte)driveNumber;
moel@324
   254
      parameter.Registers.Features = RegisterFeature.SmartEnableOperations;
moel@324
   255
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@324
   256
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@324
   257
      parameter.Registers.Command = RegisterCommand.SmartCmd;
moel@324
   258
moel@324
   259
      return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
moel@324
   260
        ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
moel@324
   261
        Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
moel@324
   262
        IntPtr.Zero);
moel@324
   263
    }
moel@324
   264
moel@324
   265
    public DriveAttributeValue[] ReadSmartData(IntPtr handle, int driveNumber) {
moel@324
   266
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@324
   267
      DriveSmartReadDataResult result;
moel@324
   268
      uint bytesReturned;
moel@324
   269
moel@324
   270
      parameter.DriveNumber = (byte)driveNumber;
moel@324
   271
      parameter.Registers.Features = RegisterFeature.SmartReadData;
moel@324
   272
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@324
   273
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@324
   274
      parameter.Registers.Command = RegisterCommand.SmartCmd;
moel@324
   275
moel@324
   276
      bool isValid = NativeMethods.DeviceIoControl(handle, 
moel@324
   277
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
moel@324
   278
        out result, Marshal.SizeOf(typeof(DriveSmartReadDataResult)), 
moel@324
   279
        out bytesReturned, IntPtr.Zero);
moel@324
   280
moel@324
   281
      return (isValid) ? result.Attributes : new DriveAttributeValue[0];
moel@324
   282
    }
moel@324
   283
moel@324
   284
    public DriveThresholdValue[] ReadSmartThresholds(IntPtr handle,
moel@324
   285
      int driveNumber) 
moel@324
   286
    {
moel@324
   287
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@324
   288
      DriveSmartReadThresholdsResult result;
moel@324
   289
      uint bytesReturned = 0;
moel@324
   290
moel@324
   291
      parameter.DriveNumber = (byte)driveNumber;
moel@324
   292
      parameter.Registers.Features = RegisterFeature.SmartReadThresholds;
moel@324
   293
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@324
   294
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@324
   295
      parameter.Registers.Command = RegisterCommand.SmartCmd;
moel@324
   296
moel@324
   297
      bool isValid = NativeMethods.DeviceIoControl(handle,
moel@324
   298
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
moel@324
   299
        out result, Marshal.SizeOf(typeof(DriveSmartReadThresholdsResult)), 
moel@324
   300
        out bytesReturned, IntPtr.Zero); 
moel@324
   301
moel@324
   302
      return (isValid) ? result.Thresholds : new DriveThresholdValue[0];
moel@325
   303
    }
moel@324
   304
moel@325
   305
    private string GetString(byte[] bytes) {   
moel@325
   306
      char[] chars = new char[bytes.Length];
moel@325
   307
      for (int i = 0; i < bytes.Length; i += 2) {
moel@325
   308
        chars[i] = (char)bytes[i + 1];
moel@325
   309
        chars[i + 1] = (char)bytes[i];
moel@325
   310
      }
moel@325
   311
      return new string(chars).Trim(new char[] { ' ', '\0' });
moel@325
   312
    }
moel@325
   313
moel@325
   314
    public bool ReadNameAndFirmwareRevision(IntPtr handle, int driveNumber, 
moel@325
   315
      out string name, out string firmwareRevision) 
moel@325
   316
    {
moel@324
   317
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@324
   318
      DriveIdentifyResult result;
moel@324
   319
      uint bytesReturned;
moel@324
   320
moel@324
   321
      parameter.DriveNumber = (byte)driveNumber;
moel@324
   322
      parameter.Registers.Command = RegisterCommand.IdCmd;
moel@324
   323
moel@324
   324
      bool valid = NativeMethods.DeviceIoControl(handle, 
moel@324
   325
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
moel@324
   326
        out result, Marshal.SizeOf(typeof(DriveIdentifyResult)), 
moel@324
   327
        out bytesReturned, IntPtr.Zero);
moel@324
   328
moel@325
   329
      if (!valid) {
moel@325
   330
        name = null;
moel@325
   331
        firmwareRevision = null;
moel@325
   332
        return false;
moel@325
   333
      }
moel@324
   334
moel@325
   335
      name = GetString(result.Identify.ModelNumber);
moel@325
   336
      firmwareRevision = GetString(result.Identify.FirmwareRevision);
moel@325
   337
      return true;
moel@324
   338
    }
moel@324
   339
moel@324
   340
    public void CloseHandle(IntPtr handle) {
moel@324
   341
      NativeMethods.CloseHandle(handle);
moel@324
   342
    }
moel@324
   343
moel@324
   344
    protected static class NativeMethods {
moel@324
   345
      private const string KERNEL = "kernel32.dll";
moel@324
   346
moel@324
   347
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
moel@324
   348
        CharSet = CharSet.Unicode)]
moel@324
   349
      public static extern IntPtr CreateFile(string fileName,
moel@324
   350
        AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
moel@324
   351
        CreationMode creationDisposition, FileAttribute flagsAndAttributes,
moel@324
   352
        IntPtr templateFilehandle);
moel@324
   353
moel@324
   354
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@324
   355
      public static extern int CloseHandle(IntPtr handle);
moel@324
   356
moel@324
   357
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@324
   358
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@324
   359
      public static extern bool DeviceIoControl(IntPtr handle,
moel@324
   360
        DriveCommand command, ref DriveCommandParameter parameter,
moel@324
   361
        int parameterSize, out DriveSmartReadDataResult result, int resultSize,
moel@324
   362
        out uint bytesReturned, IntPtr overlapped);
moel@324
   363
moel@324
   364
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@324
   365
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@324
   366
      public static extern bool DeviceIoControl(IntPtr handle,
moel@324
   367
        DriveCommand command, ref DriveCommandParameter parameter,
moel@324
   368
        int parameterSize, out DriveSmartReadThresholdsResult result, 
moel@324
   369
        int resultSize, out uint bytesReturned, IntPtr overlapped);
moel@324
   370
moel@324
   371
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@324
   372
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@324
   373
      public static extern bool DeviceIoControl(IntPtr handle,
moel@324
   374
        DriveCommand command, ref DriveCommandParameter parameter,
moel@324
   375
        int parameterSize, out DriveCommandResult result, int resultSize,
moel@324
   376
        out uint bytesReturned, IntPtr overlapped);
moel@324
   377
moel@324
   378
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@324
   379
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@324
   380
      public static extern bool DeviceIoControl(IntPtr handle,
moel@324
   381
        DriveCommand command, ref DriveCommandParameter parameter,
moel@324
   382
        int parameterSize, out DriveIdentifyResult result, int resultSize,
moel@324
   383
        out uint bytesReturned, IntPtr overlapped);
moel@324
   384
    }    
moel@324
   385
  }
moel@324
   386
}