Hardware/HDD/SMART.cs
author moel.mich
Sat, 02 Oct 2010 18:15:46 +0000
changeset 206 1fa8eddc24a7
parent 188 6ce1c13899e1
child 218 194186efdde9
permissions -rw-r--r--
Replaced HttpUtility.UrlEncode with Uri.EscapeDataString and deleted the reference to the System.Web assembly. The System.Web assembly seems to be missing on some .NET 4.0 installations (and the overhead of using it is a bit large, just for the UrlEncode method).
moel@1
     1
/*
moel@1
     2
  
moel@1
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1
     4
moel@1
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@1
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@1
     7
  the License. You may obtain a copy of the License at
moel@1
     8
 
moel@1
     9
  http://www.mozilla.org/MPL/
moel@1
    10
moel@1
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@1
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1
    13
  for the specific language governing rights and limitations under the License.
moel@1
    14
moel@1
    15
  The Original Code is the Open Hardware Monitor code.
moel@1
    16
moel@1
    17
  The Initial Developer of the Original Code is 
moel@1
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@1
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@1
    20
  the Initial Developer. All Rights Reserved.
moel@1
    21
moel@1
    22
  Contributor(s):
moel@1
    23
moel@1
    24
  Alternatively, the contents of this file may be used under the terms of
moel@1
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@1
    28
  of those above. If you wish to allow use of your version of this file only
moel@1
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@1
    30
  use your version of this file under the terms of the MPL, indicate your
moel@1
    31
  decision by deleting the provisions above and replace them with the notice
moel@1
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@1
    33
  the provisions above, a recipient may use your version of this file under
moel@1
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@1
    35
 
moel@1
    36
*/
moel@1
    37
moel@1
    38
using System;
moel@1
    39
using System.Runtime.InteropServices;
moel@1
    40
moel@1
    41
namespace OpenHardwareMonitor.Hardware.HDD {
moel@165
    42
moel@165
    43
  internal class SMART {
moel@1
    44
moel@1
    45
    [Flags]
moel@1
    46
    public enum Status : ushort {
moel@1
    47
      PreFailureWarranty = 0x01,
moel@1
    48
      OnLineCollection = 0x02,
moel@1
    49
      Performance = 0x04,
moel@1
    50
      ErrorRate = 0x08,
moel@1
    51
      EventCount = 0x10,
moel@1
    52
      SelfPreserving = 0x20
moel@1
    53
    }
moel@1
    54
moel@1
    55
    public enum AttributeID : byte {
moel@1
    56
      ReadErrorRate = 0x01,
moel@1
    57
      ThroughputPerformance = 0x02,
moel@1
    58
      SpinUpTime = 0x03,
moel@1
    59
      StartStopCount = 0x04,
moel@1
    60
      ReallocatedSectorsCount = 0x05,
moel@1
    61
      ReadChannelMargin = 0x06,
moel@1
    62
      SeekErrorRate = 0x07,
moel@1
    63
      SeekTimePerformance = 0x08,
moel@1
    64
      PowerOnHours = 0x09,
moel@1
    65
      SpinRetryCount = 0x0A,
moel@1
    66
      RecalibrationRetries = 0x0B,
moel@1
    67
      PowerCycleCount = 0x0C,
moel@1
    68
      SoftReadErrorRate = 0x0D,
moel@48
    69
      AirflowTemperature = 0xBE,
moel@1
    70
      Temperature = 0xC2,
moel@1
    71
      HardwareECCRecovered = 0xC3,
moel@1
    72
      ReallocationEventCount = 0xC4,
moel@1
    73
      CurrentPendingSectorCount = 0xC5,
moel@1
    74
      UncorrectableSectorCount = 0xC6,
moel@1
    75
      UltraDMACRCErrorCount = 0xC7,
moel@48
    76
      WriteErrorRate = 0xC8,
moel@48
    77
      DriveTemperature = 0xE7
moel@1
    78
    }
moel@1
    79
moel@1
    80
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
    81
    public struct DriveAttribute {
moel@1
    82
      public AttributeID ID;
moel@1
    83
      public Status StatusFlags;
moel@1
    84
      public byte AttrValue;
moel@1
    85
      public byte WorstValue;
moel@1
    86
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
moel@1
    87
      public byte[] RawValue;
moel@1
    88
      public byte Reserved;
moel@1
    89
    };
moel@1
    90
moel@1
    91
    [Flags]
moel@195
    92
    protected enum AccessMode : uint {     
moel@1
    93
      Read = 0x80000000,    
moel@1
    94
      Write = 0x40000000,     
moel@1
    95
      Execute = 0x20000000,     
moel@1
    96
      All = 0x10000000
moel@1
    97
    }
moel@1
    98
moel@1
    99
    [Flags]
moel@195
   100
    protected enum ShareMode : uint {
moel@1
   101
      None = 0,     
moel@1
   102
      Read = 1,     
moel@1
   103
      Write = 2,    
moel@1
   104
      Delete = 4
moel@1
   105
    }
moel@1
   106
moel@195
   107
    protected enum CreationMode : uint {
moel@1
   108
      New = 1,
moel@1
   109
      CreateAlways = 2,    
moel@1
   110
      OpenExisting = 3,    
moel@1
   111
      OpenAlways = 4,    
moel@1
   112
      TruncateExisting = 5
moel@1
   113
    }
moel@1
   114
moel@1
   115
    [Flags]
moel@195
   116
    protected enum FileAttribute : uint {
moel@1
   117
      Readonly = 0x00000001,
moel@1
   118
      Hidden = 0x00000002,
moel@1
   119
      System = 0x00000004,
moel@1
   120
      Directory = 0x00000010,
moel@1
   121
      Archive = 0x00000020,
moel@1
   122
      Device = 0x00000040,
moel@1
   123
      Normal = 0x00000080,
moel@1
   124
      Temporary = 0x00000100,
moel@1
   125
      SparseFile = 0x00000200,
moel@1
   126
      ReparsePoint = 0x00000400,
moel@1
   127
      Compressed = 0x00000800,
moel@1
   128
      Offline = 0x00001000,
moel@1
   129
      NotContentIndexed = 0x00002000,
moel@1
   130
      Encrypted = 0x00004000,
moel@1
   131
    }
moel@1
   132
moel@195
   133
    protected enum DriveCommand : uint {
moel@1
   134
      GetVersion = 0x00074080,
moel@1
   135
      SendDriveCommand = 0x0007c084,
moel@1
   136
      ReceiveDriveData = 0x0007c088
moel@1
   137
    }
moel@1
   138
moel@1
   139
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   140
    protected struct CommandBlockRegisters {
moel@1
   141
      public byte Features;         
moel@1
   142
      public byte SectorCount;      
moel@1
   143
      public byte LBALow;       
moel@1
   144
      public byte LBAMid;           
moel@1
   145
      public byte LBAHigh;        
moel@1
   146
      public byte Device;       
moel@1
   147
      public byte Command;           
moel@1
   148
      public byte Reserved;                  
moel@1
   149
    }
moel@1
   150
moel@1
   151
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   152
    protected struct DriveCommandParameter {
moel@195
   153
      public uint BufferSize;           
moel@1
   154
      public CommandBlockRegisters Registers;           
moel@1
   155
      public byte DriveNumber;   
moel@188
   156
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@1
   157
      public byte[] Reserved;                                
moel@1
   158
    }
moel@1
   159
moel@1
   160
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   161
    protected struct DriverStatus {
moel@1
   162
      public byte DriverError;   
moel@1
   163
      public byte IDEError;             
moel@1
   164
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
moel@1
   165
      public byte[] Reserved;               
moel@1
   166
    }
moel@1
   167
moel@1
   168
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   169
    protected struct DriveCommandResult {
moel@1
   170
      public uint BufferSize;
moel@1
   171
      public DriverStatus DriverStatus;
moel@1
   172
    } 
moel@1
   173
moel@1
   174
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   175
    protected struct DriveSmartReadResult {
moel@1
   176
      public uint BufferSize;           
moel@1
   177
      public DriverStatus DriverStatus;
moel@1
   178
      public byte Version;
moel@1
   179
      public byte Reserved;
moel@1
   180
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
moel@1
   181
      public DriveAttribute[] Attributes;                                                                                       
moel@1
   182
    }
moel@1
   183
moel@1
   184
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   185
    protected struct Identify {
moel@1
   186
      public ushort GeneralConfiguration;
moel@1
   187
      public ushort NumberOfCylinders;
moel@1
   188
      public ushort Reserved;
moel@1
   189
      public ushort NumberOfHeads;
moel@1
   190
      public ushort UnformattedBytesPerTrack;
moel@1
   191
      public ushort UnformattedBytesPerSector;
moel@1
   192
      public ushort SectorsPerTrack;
moel@1
   193
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
moel@1
   194
      public ushort[] VendorUnique;
moel@1
   195
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@1
   196
      public byte[] SerialNumber;
moel@1
   197
      public ushort BufferType;
moel@1
   198
      public ushort BufferSectorSize;
moel@1
   199
      public ushort NumberOfEccBytes;
moel@1
   200
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
moel@1
   201
      public byte[] FirmwareRevision;
moel@1
   202
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
moel@1
   203
      public byte[] ModelNumber;
moel@1
   204
      public ushort MoreVendorUnique;
moel@1
   205
      public ushort DoubleWordIo;
moel@1
   206
      public ushort Capabilities;
moel@1
   207
      public ushort MoreReserved;
moel@1
   208
      public ushort PioCycleTimingMode;
moel@1
   209
      public ushort DmaCycleTimingMode;
moel@1
   210
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
moel@1
   211
      public byte[] More;
moel@1
   212
    }
moel@1
   213
moel@1
   214
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   215
    protected struct DriveIdentifyResult {
moel@1
   216
      public uint BufferSize;
moel@1
   217
      public DriverStatus DriverStatus;
moel@1
   218
      public Identify Identify;
moel@1
   219
    } 
moel@1
   220
moel@1
   221
    public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
moel@1
   222
moel@1
   223
    private const byte SMART_CMD = 0xB0;
moel@1
   224
    private const byte ID_CMD = 0xEC;
moel@1
   225
    
moel@1
   226
    private const byte SMART_READ_DATA = 0xD0;
moel@1
   227
    private const byte SMART_ENABLE_OPERATIONS = 0xD8;
moel@1
   228
    
moel@1
   229
    private const byte SMART_LBA_MID = 0x4F;
moel@1
   230
    private const byte SMART_LBA_HI = 0xC2;
moel@1
   231
moel@1
   232
    private const int MAX_DRIVE_ATTRIBUTES = 512;
moel@1
   233
moel@167
   234
    private SMART() { }
moel@1
   235
moel@1
   236
    public static IntPtr OpenPhysicalDrive(int driveNumber) {
moel@167
   237
      return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
moel@1
   238
        AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
moel@1
   239
        IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
moel@1
   240
        IntPtr.Zero);
moel@1
   241
    }
moel@1
   242
moel@1
   243
    public static bool EnableSmart(IntPtr handle, int driveNumber) {
moel@1
   244
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   245
      DriveCommandResult result;
moel@1
   246
      uint bytesReturned;
moel@1
   247
moel@1
   248
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   249
      parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
moel@1
   250
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   251
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   252
      parameter.Registers.Command = SMART_CMD;
moel@1
   253
moel@167
   254
      return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
moel@167
   255
        ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
moel@1
   256
        Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
moel@1
   257
        IntPtr.Zero);
moel@1
   258
    }
moel@1
   259
moel@1
   260
    public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
moel@1
   261
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   262
      DriveSmartReadResult result;
moel@1
   263
      uint bytesReturned;
moel@1
   264
moel@1
   265
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   266
      parameter.Registers.Features = SMART_READ_DATA;
moel@1
   267
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   268
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   269
      parameter.Registers.Command = SMART_CMD;
moel@1
   270
moel@167
   271
      bool valid = NativeMethods.DeviceIoControl(handle, 
moel@167
   272
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
moel@167
   273
        out result, Marshal.SizeOf(typeof(DriveSmartReadResult)), 
moel@167
   274
        out bytesReturned, IntPtr.Zero);
moel@1
   275
moel@1
   276
      if (!valid)
moel@1
   277
        return null;
moel@1
   278
      else
moel@1
   279
        return result.Attributes;
moel@1
   280
    }
moel@1
   281
moel@1
   282
    public static string ReadName(IntPtr handle, int driveNumber) {
moel@1
   283
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   284
      DriveIdentifyResult result;
moel@1
   285
      uint bytesReturned;
moel@1
   286
moel@1
   287
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   288
      parameter.Registers.Command = ID_CMD;
moel@1
   289
moel@167
   290
      bool valid = NativeMethods.DeviceIoControl(handle, 
moel@167
   291
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
moel@167
   292
        out result, Marshal.SizeOf(typeof(DriveIdentifyResult)), 
moel@167
   293
        out bytesReturned, IntPtr.Zero);
moel@1
   294
moel@1
   295
      if (!valid)
moel@1
   296
        return null;
moel@1
   297
      else {
moel@1
   298
moel@1
   299
        byte[] bytes = result.Identify.ModelNumber;
moel@1
   300
        char[] chars = new char[bytes.Length];
moel@1
   301
        for (int i = 0; i < bytes.Length; i += 2) {
moel@1
   302
          chars[i] = (char)bytes[i + 1];
moel@1
   303
          chars[i + 1] = (char)bytes[i];
moel@1
   304
        }
moel@1
   305
moel@1
   306
        return new string(chars).Trim();
moel@1
   307
      }
moel@1
   308
    }
moel@1
   309
moel@167
   310
    public static int CloseHandle(IntPtr handle) {
moel@167
   311
      return NativeMethods.CloseHandle(handle);
moel@167
   312
    }
moel@167
   313
moel@195
   314
    protected static class NativeMethods {
moel@167
   315
      private const string KERNEL = "kernel32.dll";
moel@167
   316
moel@167
   317
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
moel@167
   318
        CharSet = CharSet.Unicode)]
moel@167
   319
      public static extern IntPtr CreateFile(string fileName,
moel@167
   320
        AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
moel@167
   321
        CreationMode creationDisposition, FileAttribute flagsAndAttributes,
moel@167
   322
        IntPtr templateFilehandle);
moel@167
   323
moel@167
   324
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   325
      public static extern int CloseHandle(IntPtr handle);
moel@167
   326
moel@167
   327
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   328
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   329
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   330
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   331
        int parameterSize, out DriveSmartReadResult result, int resultSize,
moel@167
   332
        out uint bytesReturned, IntPtr overlapped);
moel@167
   333
moel@167
   334
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   335
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   336
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   337
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   338
        int parameterSize, out DriveCommandResult result, int resultSize,
moel@167
   339
        out uint bytesReturned, IntPtr overlapped);
moel@167
   340
moel@167
   341
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   342
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   343
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   344
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   345
        int parameterSize, out DriveIdentifyResult result, int resultSize,
moel@167
   346
        out uint bytesReturned, IntPtr overlapped);
moel@167
   347
    }    
moel@1
   348
  }
moel@1
   349
}