Hardware/HDD/SMART.cs
author moel.mich
Tue, 25 May 2010 18:57:28 +0000
changeset 127 76aaf45a01c7
parent 1 361e324a0ed4
child 165 813d8bc3192f
permissions -rw-r--r--
Added a workaround for the "You must keep the stream open for the lifetime of the Image." problem of the Image.FromStream method. This also reduced the overall memory usage (private working set).
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.Collections.Generic;
moel@1
    40
using System.Runtime.InteropServices;
moel@1
    41
moel@1
    42
namespace OpenHardwareMonitor.Hardware.HDD {
moel@1
    43
    
moel@1
    44
  public 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@1
    56
    public enum AttributeID : byte {
moel@1
    57
      ReadErrorRate = 0x01,
moel@1
    58
      ThroughputPerformance = 0x02,
moel@1
    59
      SpinUpTime = 0x03,
moel@1
    60
      StartStopCount = 0x04,
moel@1
    61
      ReallocatedSectorsCount = 0x05,
moel@1
    62
      ReadChannelMargin = 0x06,
moel@1
    63
      SeekErrorRate = 0x07,
moel@1
    64
      SeekTimePerformance = 0x08,
moel@1
    65
      PowerOnHours = 0x09,
moel@1
    66
      SpinRetryCount = 0x0A,
moel@1
    67
      RecalibrationRetries = 0x0B,
moel@1
    68
      PowerCycleCount = 0x0C,
moel@1
    69
      SoftReadErrorRate = 0x0D,
moel@48
    70
      AirflowTemperature = 0xBE,
moel@1
    71
      Temperature = 0xC2,
moel@1
    72
      HardwareECCRecovered = 0xC3,
moel@1
    73
      ReallocationEventCount = 0xC4,
moel@1
    74
      CurrentPendingSectorCount = 0xC5,
moel@1
    75
      UncorrectableSectorCount = 0xC6,
moel@1
    76
      UltraDMACRCErrorCount = 0xC7,
moel@48
    77
      WriteErrorRate = 0xC8,
moel@48
    78
      DriveTemperature = 0xE7
moel@1
    79
    }
moel@1
    80
moel@1
    81
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
    82
    public struct DriveAttribute {
moel@1
    83
      public AttributeID ID;
moel@1
    84
      public Status StatusFlags;
moel@1
    85
      public byte AttrValue;
moel@1
    86
      public byte WorstValue;
moel@1
    87
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
moel@1
    88
      public byte[] RawValue;
moel@1
    89
      public byte Reserved;
moel@1
    90
    };
moel@1
    91
moel@1
    92
    [Flags]
moel@1
    93
    private enum AccessMode : uint {     
moel@1
    94
      Read = 0x80000000,    
moel@1
    95
      Write = 0x40000000,     
moel@1
    96
      Execute = 0x20000000,     
moel@1
    97
      All = 0x10000000
moel@1
    98
    }
moel@1
    99
moel@1
   100
    [Flags]
moel@1
   101
    private enum ShareMode : uint {
moel@1
   102
      None = 0,     
moel@1
   103
      Read = 1,     
moel@1
   104
      Write = 2,    
moel@1
   105
      Delete = 4
moel@1
   106
    }
moel@1
   107
moel@1
   108
    private enum CreationMode : uint {
moel@1
   109
      New = 1,
moel@1
   110
      CreateAlways = 2,    
moel@1
   111
      OpenExisting = 3,    
moel@1
   112
      OpenAlways = 4,    
moel@1
   113
      TruncateExisting = 5
moel@1
   114
    }
moel@1
   115
moel@1
   116
    [Flags]
moel@1
   117
    private enum FileAttribute : uint {
moel@1
   118
      Readonly = 0x00000001,
moel@1
   119
      Hidden = 0x00000002,
moel@1
   120
      System = 0x00000004,
moel@1
   121
      Directory = 0x00000010,
moel@1
   122
      Archive = 0x00000020,
moel@1
   123
      Device = 0x00000040,
moel@1
   124
      Normal = 0x00000080,
moel@1
   125
      Temporary = 0x00000100,
moel@1
   126
      SparseFile = 0x00000200,
moel@1
   127
      ReparsePoint = 0x00000400,
moel@1
   128
      Compressed = 0x00000800,
moel@1
   129
      Offline = 0x00001000,
moel@1
   130
      NotContentIndexed = 0x00002000,
moel@1
   131
      Encrypted = 0x00004000,
moel@1
   132
    }
moel@1
   133
moel@1
   134
    private enum DriveCommand : uint {
moel@1
   135
      GetVersion = 0x00074080,
moel@1
   136
      SendDriveCommand = 0x0007c084,
moel@1
   137
      ReceiveDriveData = 0x0007c088
moel@1
   138
    }
moel@1
   139
moel@1
   140
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   141
    private struct CommandBlockRegisters {
moel@1
   142
      public byte Features;         
moel@1
   143
      public byte SectorCount;      
moel@1
   144
      public byte LBALow;       
moel@1
   145
      public byte LBAMid;           
moel@1
   146
      public byte LBAHigh;        
moel@1
   147
      public byte Device;       
moel@1
   148
      public byte Command;           
moel@1
   149
      public byte Reserved;                  
moel@1
   150
    }
moel@1
   151
moel@1
   152
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   153
    private struct DriveCommandParameter {
moel@1
   154
      private uint BufferSize;           
moel@1
   155
      public CommandBlockRegisters Registers;           
moel@1
   156
      public byte DriveNumber;   
moel@1
   157
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
moel@1
   158
      public byte[] Reserved;                                
moel@1
   159
    }
moel@1
   160
moel@1
   161
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   162
    private struct DriverStatus {
moel@1
   163
      public byte DriverError;   
moel@1
   164
      public byte IDEError;             
moel@1
   165
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
moel@1
   166
      public byte[] Reserved;               
moel@1
   167
    }
moel@1
   168
moel@1
   169
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   170
    private struct DriveCommandResult {
moel@1
   171
      public uint BufferSize;
moel@1
   172
      public DriverStatus DriverStatus;
moel@1
   173
    } 
moel@1
   174
moel@1
   175
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   176
    private struct DriveSmartReadResult {
moel@1
   177
      public uint BufferSize;           
moel@1
   178
      public DriverStatus DriverStatus;
moel@1
   179
      public byte Version;
moel@1
   180
      public byte Reserved;
moel@1
   181
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
moel@1
   182
      public DriveAttribute[] Attributes;                                                                                       
moel@1
   183
    }
moel@1
   184
moel@1
   185
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   186
    private struct Identify {
moel@1
   187
      public ushort GeneralConfiguration;
moel@1
   188
      public ushort NumberOfCylinders;
moel@1
   189
      public ushort Reserved;
moel@1
   190
      public ushort NumberOfHeads;
moel@1
   191
      public ushort UnformattedBytesPerTrack;
moel@1
   192
      public ushort UnformattedBytesPerSector;
moel@1
   193
      public ushort SectorsPerTrack;
moel@1
   194
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
moel@1
   195
      public ushort[] VendorUnique;
moel@1
   196
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@1
   197
      public byte[] SerialNumber;
moel@1
   198
      public ushort BufferType;
moel@1
   199
      public ushort BufferSectorSize;
moel@1
   200
      public ushort NumberOfEccBytes;
moel@1
   201
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
moel@1
   202
      public byte[] FirmwareRevision;
moel@1
   203
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
moel@1
   204
      public byte[] ModelNumber;
moel@1
   205
      public ushort MoreVendorUnique;
moel@1
   206
      public ushort DoubleWordIo;
moel@1
   207
      public ushort Capabilities;
moel@1
   208
      public ushort MoreReserved;
moel@1
   209
      public ushort PioCycleTimingMode;
moel@1
   210
      public ushort DmaCycleTimingMode;
moel@1
   211
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
moel@1
   212
      public byte[] More;
moel@1
   213
    }
moel@1
   214
moel@1
   215
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   216
    private struct DriveIdentifyResult {
moel@1
   217
      public uint BufferSize;
moel@1
   218
      public DriverStatus DriverStatus;
moel@1
   219
      public Identify Identify;
moel@1
   220
    } 
moel@1
   221
moel@1
   222
    public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
moel@1
   223
moel@1
   224
    private const byte SMART_CMD = 0xB0;
moel@1
   225
    private const byte ID_CMD = 0xEC;
moel@1
   226
    
moel@1
   227
    private const byte SMART_READ_DATA = 0xD0;
moel@1
   228
    private const byte SMART_ENABLE_OPERATIONS = 0xD8;
moel@1
   229
    
moel@1
   230
    private const byte SMART_LBA_MID = 0x4F;
moel@1
   231
    private const byte SMART_LBA_HI = 0xC2;
moel@1
   232
moel@1
   233
    private const int MAX_DRIVE_ATTRIBUTES = 512;
moel@1
   234
moel@1
   235
    private const string KERNEL = "kernel32.dll";
moel@1
   236
moel@1
   237
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   238
    private static extern IntPtr CreateFile(string fileName, 
moel@1
   239
      AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
moel@1
   240
      CreationMode creationDisposition, FileAttribute flagsAndAttributes, 
moel@1
   241
      IntPtr templateFilehandle);
moel@1
   242
moel@1
   243
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   244
    public static extern int CloseHandle(IntPtr handle);
moel@1
   245
moel@1
   246
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   247
    private static extern bool DeviceIoControl(IntPtr handle,
moel@1
   248
      DriveCommand command, ref DriveCommandParameter parameter,
moel@1
   249
      int parameterSize, out DriveSmartReadResult result, int resultSize, 
moel@1
   250
      out uint bytesReturned, IntPtr overlapped);
moel@1
   251
moel@1
   252
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   253
    private static extern bool DeviceIoControl(IntPtr handle,
moel@1
   254
      DriveCommand command, ref DriveCommandParameter parameter,
moel@1
   255
      int parameterSize, out DriveCommandResult result, int resultSize,
moel@1
   256
      out uint bytesReturned, IntPtr overlapped);
moel@1
   257
moel@1
   258
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   259
    private static extern bool DeviceIoControl(IntPtr handle,
moel@1
   260
      DriveCommand command, ref DriveCommandParameter parameter,
moel@1
   261
      int parameterSize, out DriveIdentifyResult result, int resultSize,
moel@1
   262
      out uint bytesReturned, IntPtr overlapped);
moel@1
   263
moel@1
   264
    public static IntPtr OpenPhysicalDrive(int driveNumber) {
moel@1
   265
      return CreateFile(@"\\.\PhysicalDrive" + driveNumber,
moel@1
   266
        AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
moel@1
   267
        IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
moel@1
   268
        IntPtr.Zero);
moel@1
   269
    }
moel@1
   270
moel@1
   271
    public static bool EnableSmart(IntPtr handle, int driveNumber) {
moel@1
   272
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   273
      DriveCommandResult result;
moel@1
   274
      uint bytesReturned;
moel@1
   275
moel@1
   276
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   277
      parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
moel@1
   278
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   279
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   280
      parameter.Registers.Command = SMART_CMD;
moel@1
   281
moel@1
   282
      return DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
moel@1
   283
        ref parameter, Marshal.SizeOf(parameter), out result,
moel@1
   284
        Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
moel@1
   285
        IntPtr.Zero);
moel@1
   286
    }
moel@1
   287
moel@1
   288
    public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
moel@1
   289
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   290
      DriveSmartReadResult result;
moel@1
   291
      uint bytesReturned;
moel@1
   292
moel@1
   293
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   294
      parameter.Registers.Features = SMART_READ_DATA;
moel@1
   295
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   296
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   297
      parameter.Registers.Command = SMART_CMD;
moel@1
   298
moel@1
   299
      bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
moel@1
   300
        ref parameter, Marshal.SizeOf(parameter), out result,
moel@1
   301
        Marshal.SizeOf(typeof(DriveSmartReadResult)), out bytesReturned,
moel@1
   302
        IntPtr.Zero);
moel@1
   303
moel@1
   304
      if (!valid)
moel@1
   305
        return null;
moel@1
   306
      else
moel@1
   307
        return result.Attributes;
moel@1
   308
    }
moel@1
   309
moel@1
   310
    public static string ReadName(IntPtr handle, int driveNumber) {
moel@1
   311
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   312
      DriveIdentifyResult result;
moel@1
   313
      uint bytesReturned;
moel@1
   314
moel@1
   315
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   316
      parameter.Registers.Command = ID_CMD;
moel@1
   317
moel@1
   318
      bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
moel@1
   319
        ref parameter, Marshal.SizeOf(parameter), out result,
moel@1
   320
        Marshal.SizeOf(typeof(DriveIdentifyResult)), out bytesReturned,
moel@1
   321
        IntPtr.Zero);
moel@1
   322
moel@1
   323
      if (!valid)
moel@1
   324
        return null;
moel@1
   325
      else {
moel@1
   326
moel@1
   327
        byte[] bytes = result.Identify.ModelNumber;
moel@1
   328
        char[] chars = new char[bytes.Length];
moel@1
   329
        for (int i = 0; i < bytes.Length; i += 2) {
moel@1
   330
          chars[i] = (char)bytes[i + 1];
moel@1
   331
          chars[i + 1] = (char)bytes[i];
moel@1
   332
        }
moel@1
   333
moel@1
   334
        return new string(chars).Trim();
moel@1
   335
      }
moel@1
   336
    }
moel@1
   337
moel@1
   338
  }
moel@1
   339
}