Hardware/HDD/SMART.cs
author moel.mich
Fri, 12 Feb 2010 22:46:31 +0000
changeset 42 47385d4fc990
child 48 eb04985b7b6a
permissions -rw-r--r--
Tray sensor display default color is black and color can be changed now. Fixed CPU load reading for AMD CPUs and added additional misc device for AMD core temperature reading.
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@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@1
    76
      WriteErrorRate = 0xC8
moel@1
    77
    }
moel@1
    78
moel@1
    79
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
    80
    public struct DriveAttribute {
moel@1
    81
      public AttributeID ID;
moel@1
    82
      public Status StatusFlags;
moel@1
    83
      public byte AttrValue;
moel@1
    84
      public byte WorstValue;
moel@1
    85
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
moel@1
    86
      public byte[] RawValue;
moel@1
    87
      public byte Reserved;
moel@1
    88
    };
moel@1
    89
moel@1
    90
    [Flags]
moel@1
    91
    private enum AccessMode : uint {     
moel@1
    92
      Read = 0x80000000,    
moel@1
    93
      Write = 0x40000000,     
moel@1
    94
      Execute = 0x20000000,     
moel@1
    95
      All = 0x10000000
moel@1
    96
    }
moel@1
    97
moel@1
    98
    [Flags]
moel@1
    99
    private enum ShareMode : uint {
moel@1
   100
      None = 0,     
moel@1
   101
      Read = 1,     
moel@1
   102
      Write = 2,    
moel@1
   103
      Delete = 4
moel@1
   104
    }
moel@1
   105
moel@1
   106
    private enum CreationMode : uint {
moel@1
   107
      New = 1,
moel@1
   108
      CreateAlways = 2,    
moel@1
   109
      OpenExisting = 3,    
moel@1
   110
      OpenAlways = 4,    
moel@1
   111
      TruncateExisting = 5
moel@1
   112
    }
moel@1
   113
moel@1
   114
    [Flags]
moel@1
   115
    private enum FileAttribute : uint {
moel@1
   116
      Readonly = 0x00000001,
moel@1
   117
      Hidden = 0x00000002,
moel@1
   118
      System = 0x00000004,
moel@1
   119
      Directory = 0x00000010,
moel@1
   120
      Archive = 0x00000020,
moel@1
   121
      Device = 0x00000040,
moel@1
   122
      Normal = 0x00000080,
moel@1
   123
      Temporary = 0x00000100,
moel@1
   124
      SparseFile = 0x00000200,
moel@1
   125
      ReparsePoint = 0x00000400,
moel@1
   126
      Compressed = 0x00000800,
moel@1
   127
      Offline = 0x00001000,
moel@1
   128
      NotContentIndexed = 0x00002000,
moel@1
   129
      Encrypted = 0x00004000,
moel@1
   130
    }
moel@1
   131
moel@1
   132
    private enum DriveCommand : uint {
moel@1
   133
      GetVersion = 0x00074080,
moel@1
   134
      SendDriveCommand = 0x0007c084,
moel@1
   135
      ReceiveDriveData = 0x0007c088
moel@1
   136
    }
moel@1
   137
moel@1
   138
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   139
    private struct CommandBlockRegisters {
moel@1
   140
      public byte Features;         
moel@1
   141
      public byte SectorCount;      
moel@1
   142
      public byte LBALow;       
moel@1
   143
      public byte LBAMid;           
moel@1
   144
      public byte LBAHigh;        
moel@1
   145
      public byte Device;       
moel@1
   146
      public byte Command;           
moel@1
   147
      public byte Reserved;                  
moel@1
   148
    }
moel@1
   149
moel@1
   150
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   151
    private struct DriveCommandParameter {
moel@1
   152
      private uint BufferSize;           
moel@1
   153
      public CommandBlockRegisters Registers;           
moel@1
   154
      public byte DriveNumber;   
moel@1
   155
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
moel@1
   156
      public byte[] Reserved;                                
moel@1
   157
    }
moel@1
   158
moel@1
   159
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   160
    private struct DriverStatus {
moel@1
   161
      public byte DriverError;   
moel@1
   162
      public byte IDEError;             
moel@1
   163
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
moel@1
   164
      public byte[] Reserved;               
moel@1
   165
    }
moel@1
   166
moel@1
   167
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   168
    private struct DriveCommandResult {
moel@1
   169
      public uint BufferSize;
moel@1
   170
      public DriverStatus DriverStatus;
moel@1
   171
    } 
moel@1
   172
moel@1
   173
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   174
    private struct DriveSmartReadResult {
moel@1
   175
      public uint BufferSize;           
moel@1
   176
      public DriverStatus DriverStatus;
moel@1
   177
      public byte Version;
moel@1
   178
      public byte Reserved;
moel@1
   179
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
moel@1
   180
      public DriveAttribute[] Attributes;                                                                                       
moel@1
   181
    }
moel@1
   182
moel@1
   183
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   184
    private struct Identify {
moel@1
   185
      public ushort GeneralConfiguration;
moel@1
   186
      public ushort NumberOfCylinders;
moel@1
   187
      public ushort Reserved;
moel@1
   188
      public ushort NumberOfHeads;
moel@1
   189
      public ushort UnformattedBytesPerTrack;
moel@1
   190
      public ushort UnformattedBytesPerSector;
moel@1
   191
      public ushort SectorsPerTrack;
moel@1
   192
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
moel@1
   193
      public ushort[] VendorUnique;
moel@1
   194
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@1
   195
      public byte[] SerialNumber;
moel@1
   196
      public ushort BufferType;
moel@1
   197
      public ushort BufferSectorSize;
moel@1
   198
      public ushort NumberOfEccBytes;
moel@1
   199
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
moel@1
   200
      public byte[] FirmwareRevision;
moel@1
   201
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
moel@1
   202
      public byte[] ModelNumber;
moel@1
   203
      public ushort MoreVendorUnique;
moel@1
   204
      public ushort DoubleWordIo;
moel@1
   205
      public ushort Capabilities;
moel@1
   206
      public ushort MoreReserved;
moel@1
   207
      public ushort PioCycleTimingMode;
moel@1
   208
      public ushort DmaCycleTimingMode;
moel@1
   209
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
moel@1
   210
      public byte[] More;
moel@1
   211
    }
moel@1
   212
moel@1
   213
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   214
    private struct DriveIdentifyResult {
moel@1
   215
      public uint BufferSize;
moel@1
   216
      public DriverStatus DriverStatus;
moel@1
   217
      public Identify Identify;
moel@1
   218
    } 
moel@1
   219
moel@1
   220
    public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
moel@1
   221
moel@1
   222
    private const byte SMART_CMD = 0xB0;
moel@1
   223
    private const byte ID_CMD = 0xEC;
moel@1
   224
    
moel@1
   225
    private const byte SMART_READ_DATA = 0xD0;
moel@1
   226
    private const byte SMART_ENABLE_OPERATIONS = 0xD8;
moel@1
   227
    
moel@1
   228
    private const byte SMART_LBA_MID = 0x4F;
moel@1
   229
    private const byte SMART_LBA_HI = 0xC2;
moel@1
   230
moel@1
   231
    private const int MAX_DRIVE_ATTRIBUTES = 512;
moel@1
   232
moel@1
   233
    private const string KERNEL = "kernel32.dll";
moel@1
   234
moel@1
   235
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   236
    private static extern IntPtr CreateFile(string fileName, 
moel@1
   237
      AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
moel@1
   238
      CreationMode creationDisposition, FileAttribute flagsAndAttributes, 
moel@1
   239
      IntPtr templateFilehandle);
moel@1
   240
moel@1
   241
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   242
    public static extern int CloseHandle(IntPtr handle);
moel@1
   243
moel@1
   244
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   245
    private static extern bool DeviceIoControl(IntPtr handle,
moel@1
   246
      DriveCommand command, ref DriveCommandParameter parameter,
moel@1
   247
      int parameterSize, out DriveSmartReadResult result, int resultSize, 
moel@1
   248
      out uint bytesReturned, IntPtr overlapped);
moel@1
   249
moel@1
   250
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   251
    private static extern bool DeviceIoControl(IntPtr handle,
moel@1
   252
      DriveCommand command, ref DriveCommandParameter parameter,
moel@1
   253
      int parameterSize, out DriveCommandResult result, int resultSize,
moel@1
   254
      out uint bytesReturned, IntPtr overlapped);
moel@1
   255
moel@1
   256
    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@1
   257
    private static extern bool DeviceIoControl(IntPtr handle,
moel@1
   258
      DriveCommand command, ref DriveCommandParameter parameter,
moel@1
   259
      int parameterSize, out DriveIdentifyResult result, int resultSize,
moel@1
   260
      out uint bytesReturned, IntPtr overlapped);
moel@1
   261
moel@1
   262
    public static IntPtr OpenPhysicalDrive(int driveNumber) {
moel@1
   263
      return CreateFile(@"\\.\PhysicalDrive" + driveNumber,
moel@1
   264
        AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
moel@1
   265
        IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
moel@1
   266
        IntPtr.Zero);
moel@1
   267
    }
moel@1
   268
moel@1
   269
    public static bool EnableSmart(IntPtr handle, int driveNumber) {
moel@1
   270
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   271
      DriveCommandResult result;
moel@1
   272
      uint bytesReturned;
moel@1
   273
moel@1
   274
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   275
      parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
moel@1
   276
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   277
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   278
      parameter.Registers.Command = SMART_CMD;
moel@1
   279
moel@1
   280
      return DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
moel@1
   281
        ref parameter, Marshal.SizeOf(parameter), out result,
moel@1
   282
        Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
moel@1
   283
        IntPtr.Zero);
moel@1
   284
    }
moel@1
   285
moel@1
   286
    public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
moel@1
   287
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   288
      DriveSmartReadResult result;
moel@1
   289
      uint bytesReturned;
moel@1
   290
moel@1
   291
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   292
      parameter.Registers.Features = SMART_READ_DATA;
moel@1
   293
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   294
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   295
      parameter.Registers.Command = SMART_CMD;
moel@1
   296
moel@1
   297
      bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
moel@1
   298
        ref parameter, Marshal.SizeOf(parameter), out result,
moel@1
   299
        Marshal.SizeOf(typeof(DriveSmartReadResult)), out bytesReturned,
moel@1
   300
        IntPtr.Zero);
moel@1
   301
moel@1
   302
      if (!valid)
moel@1
   303
        return null;
moel@1
   304
      else
moel@1
   305
        return result.Attributes;
moel@1
   306
    }
moel@1
   307
moel@1
   308
    public static string ReadName(IntPtr handle, int driveNumber) {
moel@1
   309
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   310
      DriveIdentifyResult result;
moel@1
   311
      uint bytesReturned;
moel@1
   312
moel@1
   313
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   314
      parameter.Registers.Command = ID_CMD;
moel@1
   315
moel@1
   316
      bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
moel@1
   317
        ref parameter, Marshal.SizeOf(parameter), out result,
moel@1
   318
        Marshal.SizeOf(typeof(DriveIdentifyResult)), out bytesReturned,
moel@1
   319
        IntPtr.Zero);
moel@1
   320
moel@1
   321
      if (!valid)
moel@1
   322
        return null;
moel@1
   323
      else {
moel@1
   324
moel@1
   325
        byte[] bytes = result.Identify.ModelNumber;
moel@1
   326
        char[] chars = new char[bytes.Length];
moel@1
   327
        for (int i = 0; i < bytes.Length; i += 2) {
moel@1
   328
          chars[i] = (char)bytes[i + 1];
moel@1
   329
          chars[i + 1] = (char)bytes[i];
moel@1
   330
        }
moel@1
   331
moel@1
   332
        return new string(chars).Trim();
moel@1
   333
      }
moel@1
   334
    }
moel@1
   335
moel@1
   336
  }
moel@1
   337
}