Hardware/HDD/SMART.cs
author moel.mich
Sun, 17 Oct 2010 17:12:38 +0000
changeset 231 30f5a06f5d8a
parent 218 194186efdde9
child 233 c5139c236200
permissions -rw-r--r--
Changed the SMART AttributeID type from an enum to a struct.
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
paulwerelds@218
    22
  Contributor(s): Paul Werelds
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;
paulwerelds@218
    39
using System.Collections.Generic;
moel@1
    40
using System.Runtime.InteropServices;
moel@1
    41
moel@1
    42
namespace OpenHardwareMonitor.Hardware.HDD {
moel@165
    43
moel@165
    44
  internal class SMART {
moel@1
    45
moel@1
    46
    [Flags]
moel@1
    47
    public enum Status : ushort {
moel@1
    48
      PreFailureWarranty = 0x01,
moel@1
    49
      OnLineCollection = 0x02,
moel@1
    50
      Performance = 0x04,
moel@1
    51
      ErrorRate = 0x08,
moel@1
    52
      EventCount = 0x10,
moel@1
    53
      SelfPreserving = 0x20
moel@1
    54
    }
moel@1
    55
moel@231
    56
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@231
    57
    public struct AttributeID {
moel@231
    58
      private byte value;
moel@231
    59
moel@231
    60
      public AttributeID(byte value) {
moel@231
    61
        this.value = value;
moel@231
    62
      }
moel@231
    63
moel@231
    64
      public override bool Equals(Object obj) {
moel@231
    65
        return obj is AttributeID && this == (AttributeID)obj;
moel@231
    66
      }
moel@231
    67
      public override int GetHashCode() {
moel@231
    68
        return value.GetHashCode() ^ value.GetHashCode();
moel@231
    69
      }
moel@231
    70
      public static bool operator ==(AttributeID a, AttributeID b) {
moel@231
    71
        return a.value == b.value;
moel@231
    72
      }
moel@231
    73
      public static bool operator !=(AttributeID a, AttributeID b) {
moel@231
    74
        return !(a == b);
moel@231
    75
      }
moel@231
    76
moel@231
    77
      public string ToString(string format) {
moel@231
    78
        return value.ToString(format);
moel@231
    79
      }
moel@231
    80
moel@231
    81
      public static readonly AttributeID None = new AttributeID(0x00);
moel@1
    82
    }
moel@1
    83
moel@231
    84
    // Common SMART attributes
moel@231
    85
    public static class CommonAttributes {      
moel@231
    86
      public static readonly AttributeID 
moel@231
    87
        ReadErrorRate = new AttributeID(0x01);
moel@231
    88
      public static readonly AttributeID 
moel@231
    89
        ThroughputPerformance = new AttributeID(0x02);
moel@231
    90
      public static readonly AttributeID 
moel@231
    91
        SpinUpTime = new AttributeID(0x03);
moel@231
    92
      public static readonly AttributeID 
moel@231
    93
        StartStopCount = new AttributeID(0x04);
moel@231
    94
      public static readonly AttributeID 
moel@231
    95
        ReallocatedSectorsCount = new AttributeID(0x05);
moel@231
    96
      public static readonly AttributeID 
moel@231
    97
        ReadChannelMargin = new AttributeID(0x06);
moel@231
    98
      public static readonly AttributeID 
moel@231
    99
        SeekErrorRate = new AttributeID(0x07);
moel@231
   100
      public static readonly AttributeID 
moel@231
   101
        SeekTimePerformance = new AttributeID(0x08);
moel@231
   102
      public static readonly AttributeID 
moel@231
   103
        PowerOnHours = new AttributeID(0x09);
moel@231
   104
      public static readonly AttributeID 
moel@231
   105
        SpinRetryCount = new AttributeID(0x0A);
moel@231
   106
      public static readonly AttributeID 
moel@231
   107
        RecalibrationRetries = new AttributeID(0x0B);
moel@231
   108
      public static readonly AttributeID 
moel@231
   109
        PowerCycleCount = new AttributeID(0x0C);
moel@231
   110
      public static readonly AttributeID 
moel@231
   111
        SoftReadErrorRate = new AttributeID(0x0D);
moel@231
   112
      public static readonly AttributeID 
moel@231
   113
        AirflowTemperature = new AttributeID(0xBE);
moel@231
   114
      public static readonly AttributeID 
moel@231
   115
        Temperature = new AttributeID(0xC2);
moel@231
   116
      public static readonly AttributeID 
moel@231
   117
        HardwareECCRecovered = new AttributeID(0xC3);
moel@231
   118
      public static readonly AttributeID 
moel@231
   119
        ReallocationEventCount = new AttributeID(0xC4);
moel@231
   120
      public static readonly AttributeID 
moel@231
   121
        CurrentPendingSectorCount = new AttributeID(0xC5);
moel@231
   122
      public static readonly AttributeID 
moel@231
   123
        UncorrectableSectorCount = new AttributeID(0xC6);
moel@231
   124
      public static readonly AttributeID 
moel@231
   125
        UltraDMACRCErrorCount = new AttributeID(0xC7);
moel@231
   126
      public static readonly AttributeID 
moel@231
   127
        WriteErrorRate = new AttributeID(0xC8);
moel@231
   128
      public static readonly AttributeID 
moel@231
   129
        DriveTemperature = new AttributeID(0xE7);
moel@231
   130
    }
moel@231
   131
moel@231
   132
    // Indilinx SSD SMART attributes
moel@231
   133
    public static class IndilinxAttributes {      
moel@231
   134
      public static readonly AttributeID RemainingLife = new AttributeID(0xD1);
moel@231
   135
    }
moel@231
   136
moel@231
   137
    // Intel SSD SMART attributes
moel@231
   138
    public static class IntelAttributes {      
moel@231
   139
      public static readonly AttributeID RemainingLife = new AttributeID(0xE8);
moel@231
   140
    }
moel@231
   141
moel@231
   142
    // Samsung SSD SMART attributes
moel@231
   143
    public static class SamsungAttributes {      
moel@231
   144
      public static readonly AttributeID RemainingLife = new AttributeID(0xB4);
moel@231
   145
    }
moel@231
   146
moel@231
   147
    // SandForce SSD SMART attributes
moel@231
   148
    public static class SandForceAttributes {      
moel@231
   149
      public static readonly AttributeID RemainingLife = new AttributeID(0xE7);
paulwerelds@218
   150
    }
paulwerelds@218
   151
moel@1
   152
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   153
    public struct DriveAttribute {
moel@1
   154
      public AttributeID ID;
moel@1
   155
      public Status StatusFlags;
moel@1
   156
      public byte AttrValue;
moel@1
   157
      public byte WorstValue;
moel@1
   158
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
moel@1
   159
      public byte[] RawValue;
moel@1
   160
      public byte Reserved;
moel@1
   161
    };
moel@1
   162
moel@1
   163
    [Flags]
moel@195
   164
    protected enum AccessMode : uint {     
moel@1
   165
      Read = 0x80000000,    
moel@1
   166
      Write = 0x40000000,     
moel@1
   167
      Execute = 0x20000000,     
moel@1
   168
      All = 0x10000000
moel@1
   169
    }
moel@1
   170
moel@1
   171
    [Flags]
moel@195
   172
    protected enum ShareMode : uint {
moel@1
   173
      None = 0,     
moel@1
   174
      Read = 1,     
moel@1
   175
      Write = 2,    
moel@1
   176
      Delete = 4
moel@1
   177
    }
moel@1
   178
moel@195
   179
    protected enum CreationMode : uint {
moel@1
   180
      New = 1,
moel@1
   181
      CreateAlways = 2,    
moel@1
   182
      OpenExisting = 3,    
moel@1
   183
      OpenAlways = 4,    
moel@1
   184
      TruncateExisting = 5
moel@1
   185
    }
moel@1
   186
moel@1
   187
    [Flags]
moel@195
   188
    protected enum FileAttribute : uint {
moel@1
   189
      Readonly = 0x00000001,
moel@1
   190
      Hidden = 0x00000002,
moel@1
   191
      System = 0x00000004,
moel@1
   192
      Directory = 0x00000010,
moel@1
   193
      Archive = 0x00000020,
moel@1
   194
      Device = 0x00000040,
moel@1
   195
      Normal = 0x00000080,
moel@1
   196
      Temporary = 0x00000100,
moel@1
   197
      SparseFile = 0x00000200,
moel@1
   198
      ReparsePoint = 0x00000400,
moel@1
   199
      Compressed = 0x00000800,
moel@1
   200
      Offline = 0x00001000,
moel@1
   201
      NotContentIndexed = 0x00002000,
moel@1
   202
      Encrypted = 0x00004000,
moel@1
   203
    }
moel@1
   204
moel@195
   205
    protected enum DriveCommand : uint {
moel@1
   206
      GetVersion = 0x00074080,
moel@1
   207
      SendDriveCommand = 0x0007c084,
moel@1
   208
      ReceiveDriveData = 0x0007c088
moel@1
   209
    }
moel@1
   210
moel@1
   211
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   212
    protected struct CommandBlockRegisters {
moel@1
   213
      public byte Features;         
moel@1
   214
      public byte SectorCount;      
moel@1
   215
      public byte LBALow;       
moel@1
   216
      public byte LBAMid;           
moel@1
   217
      public byte LBAHigh;        
moel@1
   218
      public byte Device;       
moel@1
   219
      public byte Command;           
moel@1
   220
      public byte Reserved;                  
moel@1
   221
    }
moel@1
   222
moel@1
   223
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   224
    protected struct DriveCommandParameter {
moel@195
   225
      public uint BufferSize;           
moel@1
   226
      public CommandBlockRegisters Registers;           
moel@1
   227
      public byte DriveNumber;   
moel@188
   228
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@1
   229
      public byte[] Reserved;                                
moel@1
   230
    }
moel@1
   231
moel@1
   232
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   233
    protected struct DriverStatus {
moel@1
   234
      public byte DriverError;   
moel@1
   235
      public byte IDEError;             
moel@1
   236
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
moel@1
   237
      public byte[] Reserved;               
moel@1
   238
    }
moel@1
   239
moel@1
   240
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   241
    protected struct DriveCommandResult {
moel@1
   242
      public uint BufferSize;
moel@1
   243
      public DriverStatus DriverStatus;
moel@1
   244
    } 
moel@1
   245
moel@1
   246
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   247
    protected struct DriveSmartReadResult {
moel@1
   248
      public uint BufferSize;           
moel@1
   249
      public DriverStatus DriverStatus;
moel@1
   250
      public byte Version;
moel@1
   251
      public byte Reserved;
moel@1
   252
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
moel@1
   253
      public DriveAttribute[] Attributes;                                                                                       
moel@1
   254
    }
moel@1
   255
moel@1
   256
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   257
    protected struct Identify {
moel@1
   258
      public ushort GeneralConfiguration;
moel@1
   259
      public ushort NumberOfCylinders;
moel@1
   260
      public ushort Reserved;
moel@1
   261
      public ushort NumberOfHeads;
moel@1
   262
      public ushort UnformattedBytesPerTrack;
moel@1
   263
      public ushort UnformattedBytesPerSector;
moel@1
   264
      public ushort SectorsPerTrack;
moel@1
   265
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
moel@1
   266
      public ushort[] VendorUnique;
moel@1
   267
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@1
   268
      public byte[] SerialNumber;
moel@1
   269
      public ushort BufferType;
moel@1
   270
      public ushort BufferSectorSize;
moel@1
   271
      public ushort NumberOfEccBytes;
moel@1
   272
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
moel@1
   273
      public byte[] FirmwareRevision;
moel@1
   274
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
moel@1
   275
      public byte[] ModelNumber;
moel@1
   276
      public ushort MoreVendorUnique;
moel@1
   277
      public ushort DoubleWordIo;
moel@1
   278
      public ushort Capabilities;
moel@1
   279
      public ushort MoreReserved;
moel@1
   280
      public ushort PioCycleTimingMode;
moel@1
   281
      public ushort DmaCycleTimingMode;
moel@1
   282
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
moel@1
   283
      public byte[] More;
moel@1
   284
    }
moel@1
   285
moel@1
   286
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   287
    protected struct DriveIdentifyResult {
moel@1
   288
      public uint BufferSize;
moel@1
   289
      public DriverStatus DriverStatus;
moel@1
   290
      public Identify Identify;
moel@1
   291
    } 
moel@1
   292
moel@1
   293
    public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
moel@1
   294
moel@1
   295
    private const byte SMART_CMD = 0xB0;
moel@1
   296
    private const byte ID_CMD = 0xEC;
moel@1
   297
    
moel@1
   298
    private const byte SMART_READ_DATA = 0xD0;
moel@1
   299
    private const byte SMART_ENABLE_OPERATIONS = 0xD8;
moel@1
   300
    
moel@1
   301
    private const byte SMART_LBA_MID = 0x4F;
moel@1
   302
    private const byte SMART_LBA_HI = 0xC2;
moel@1
   303
moel@1
   304
    private const int MAX_DRIVE_ATTRIBUTES = 512;
moel@1
   305
moel@167
   306
    private SMART() { }
moel@1
   307
moel@1
   308
    public static IntPtr OpenPhysicalDrive(int driveNumber) {
moel@167
   309
      return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
moel@1
   310
        AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
moel@1
   311
        IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
moel@1
   312
        IntPtr.Zero);
moel@1
   313
    }
moel@1
   314
moel@1
   315
    public static bool EnableSmart(IntPtr handle, int driveNumber) {
moel@1
   316
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   317
      DriveCommandResult result;
moel@1
   318
      uint bytesReturned;
moel@1
   319
moel@1
   320
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   321
      parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
moel@1
   322
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   323
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   324
      parameter.Registers.Command = SMART_CMD;
moel@1
   325
moel@167
   326
      return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
moel@167
   327
        ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
moel@1
   328
        Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
moel@1
   329
        IntPtr.Zero);
moel@1
   330
    }
moel@1
   331
paulwerelds@218
   332
    public static List<DriveAttribute> ReadSmart(IntPtr handle,
paulwerelds@218
   333
      int driveNumber)
paulwerelds@218
   334
    {
moel@1
   335
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   336
      DriveSmartReadResult result;
moel@1
   337
      uint bytesReturned;
moel@1
   338
moel@1
   339
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   340
      parameter.Registers.Features = SMART_READ_DATA;
moel@1
   341
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   342
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   343
      parameter.Registers.Command = SMART_CMD;
moel@1
   344
paulwerelds@218
   345
      bool isValid = NativeMethods.DeviceIoControl(handle, 
moel@167
   346
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
moel@167
   347
        out result, Marshal.SizeOf(typeof(DriveSmartReadResult)), 
moel@167
   348
        out bytesReturned, IntPtr.Zero);
moel@1
   349
paulwerelds@218
   350
      return (isValid)
paulwerelds@218
   351
        ? new List<DriveAttribute>(result.Attributes)
paulwerelds@218
   352
        : new List<DriveAttribute>();
moel@1
   353
    }
moel@1
   354
moel@1
   355
    public static string ReadName(IntPtr handle, int driveNumber) {
moel@1
   356
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   357
      DriveIdentifyResult result;
moel@1
   358
      uint bytesReturned;
moel@1
   359
moel@1
   360
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   361
      parameter.Registers.Command = ID_CMD;
moel@1
   362
moel@167
   363
      bool valid = NativeMethods.DeviceIoControl(handle, 
moel@167
   364
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
moel@167
   365
        out result, Marshal.SizeOf(typeof(DriveIdentifyResult)), 
moel@167
   366
        out bytesReturned, IntPtr.Zero);
moel@1
   367
moel@1
   368
      if (!valid)
moel@1
   369
        return null;
moel@1
   370
      else {
moel@1
   371
moel@1
   372
        byte[] bytes = result.Identify.ModelNumber;
moel@1
   373
        char[] chars = new char[bytes.Length];
moel@1
   374
        for (int i = 0; i < bytes.Length; i += 2) {
moel@1
   375
          chars[i] = (char)bytes[i + 1];
moel@1
   376
          chars[i + 1] = (char)bytes[i];
moel@1
   377
        }
moel@1
   378
moel@1
   379
        return new string(chars).Trim();
moel@1
   380
      }
moel@1
   381
    }
moel@1
   382
moel@167
   383
    public static int CloseHandle(IntPtr handle) {
moel@167
   384
      return NativeMethods.CloseHandle(handle);
moel@167
   385
    }
moel@167
   386
moel@195
   387
    protected static class NativeMethods {
moel@167
   388
      private const string KERNEL = "kernel32.dll";
moel@167
   389
moel@167
   390
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
moel@167
   391
        CharSet = CharSet.Unicode)]
moel@167
   392
      public static extern IntPtr CreateFile(string fileName,
moel@167
   393
        AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
moel@167
   394
        CreationMode creationDisposition, FileAttribute flagsAndAttributes,
moel@167
   395
        IntPtr templateFilehandle);
moel@167
   396
moel@167
   397
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   398
      public static extern int CloseHandle(IntPtr handle);
moel@167
   399
moel@167
   400
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   401
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   402
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   403
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   404
        int parameterSize, out DriveSmartReadResult result, int resultSize,
moel@167
   405
        out uint bytesReturned, IntPtr overlapped);
moel@167
   406
moel@167
   407
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   408
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   409
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   410
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   411
        int parameterSize, out DriveCommandResult result, int resultSize,
moel@167
   412
        out uint bytesReturned, IntPtr overlapped);
moel@167
   413
moel@167
   414
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   415
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   416
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   417
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   418
        int parameterSize, out DriveIdentifyResult result, int resultSize,
moel@167
   419
        out uint bytesReturned, IntPtr overlapped);
moel@167
   420
    }    
moel@1
   421
  }
moel@1
   422
}