Hardware/HDD/SMART.cs
author moel.mich
Sun, 08 May 2011 22:10:13 +0000
changeset 279 6bce967ba1b5
parent 231 30f5a06f5d8a
child 308 d882720734bf
permissions -rw-r--r--
Fixed the bus and core clock reading on AMD family 10h model Ah CPUs. The new "Core Performance Boost" feature of these CPUs resulted in very low accuracy of the bus speed (and as a consequence also an inaccurate TSC multiplier). This fixed Issue 205.
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
paulwerelds@233
    84
    // These are the more-or-less standard S.M.A.R.T attributes
paulwerelds@233
    85
    // TODO: Filter out unused/obscure ones; some are interpreted differently
paulwerelds@233
    86
    // between manufacturers
paulwerelds@233
    87
    public static class CommonAttributes {
paulwerelds@233
    88
      public static readonly AttributeID
paulwerelds@233
    89
        ReadErrorRate = new AttributeID(0x01),
paulwerelds@233
    90
        ThroughputPerformance = new AttributeID(0x02),
paulwerelds@233
    91
        SpinUpTime = new AttributeID(0x03),
paulwerelds@233
    92
        StartStopCount = new AttributeID(0x04),
paulwerelds@233
    93
        ReallocatedSectorsCount = new AttributeID(0x05),
paulwerelds@233
    94
        ReadChannelMargin = new AttributeID(0x06),
paulwerelds@233
    95
        SeekErrorRate = new AttributeID(0x07),
paulwerelds@233
    96
        SeekTimePerformance = new AttributeID(0x08),
paulwerelds@233
    97
        PowerOnHours = new AttributeID(0x09),
paulwerelds@233
    98
        SpinRetryCount = new AttributeID(0x0A),
paulwerelds@233
    99
        RecalibrationRetries = new AttributeID(0x0B),
paulwerelds@233
   100
        PowerCycleCount = new AttributeID(0x0C),
paulwerelds@233
   101
        SoftReadErrorRate = new AttributeID(0x0D),
paulwerelds@233
   102
        SataDownshiftErrorCount = new AttributeID(0xB7),
paulwerelds@233
   103
        EndToEndError = new AttributeID(0xB8),
paulwerelds@233
   104
        HeadStability = new AttributeID(0xB9),
paulwerelds@233
   105
        InducedOpVibrationDetection = new AttributeID(0xBA),
paulwerelds@233
   106
        ReportedUncorrectableErrors = new AttributeID(0xBB),
paulwerelds@233
   107
        CommandTimeout = new AttributeID(0xBC),
paulwerelds@233
   108
        HighFlyWrites = new AttributeID(0xBD),
paulwerelds@233
   109
        AirflowTemperature = new AttributeID(0xBE),
paulwerelds@233
   110
        GSenseErrorRate = new AttributeID(0xBF),
paulwerelds@233
   111
        PowerOffRetractCount = new AttributeID(0xC0),
paulwerelds@233
   112
        LoadCycleCount = new AttributeID(0xC1),
paulwerelds@233
   113
        Temperature = new AttributeID(0xC2),
paulwerelds@233
   114
        HardwareEccRecovered = new AttributeID(0xC3),
paulwerelds@233
   115
        ReallocationEventCount = new AttributeID(0xC4),
paulwerelds@233
   116
        CurrentPendingSectorCount = new AttributeID(0xC5),
paulwerelds@233
   117
        UncorrectableSectorCount = new AttributeID(0xC6),
paulwerelds@233
   118
        UltraDmaCrcErrorCount = new AttributeID(0xC7),
paulwerelds@233
   119
        WriteErrorRate = new AttributeID(0xC8),
paulwerelds@233
   120
        DataAddressMarkerrors = new AttributeID(0xCA),
paulwerelds@233
   121
        RunOutCancel = new AttributeID(0xCB),
paulwerelds@233
   122
        SoftEccCorrection = new AttributeID(0xCC),
paulwerelds@233
   123
        ThermalAsperityRate = new AttributeID(0xCD),
paulwerelds@233
   124
        FlyingHeight = new AttributeID(0xCE),
paulwerelds@233
   125
        SpinHighCurrent = new AttributeID(0xCF),
paulwerelds@233
   126
        SpinBuzz = new AttributeID(0xD0),
paulwerelds@233
   127
        OfflineSeekPerformance = new AttributeID(0xD1),
paulwerelds@233
   128
        VibrationDuringWrite = new AttributeID(0xD3),
paulwerelds@233
   129
        ShockDuringWrite = new AttributeID(0xD4),
paulwerelds@233
   130
        DiskShift = new AttributeID(0xDC),
paulwerelds@233
   131
        GSenseErrorRateAlt = new AttributeID(0xDD), // Alternative to 0xBF
paulwerelds@233
   132
        LoadedHours = new AttributeID(0xDE),
paulwerelds@233
   133
        LoadUnloadRetryCount = new AttributeID(0xDF),
paulwerelds@233
   134
        LoadFriction = new AttributeID(0xE0),
paulwerelds@233
   135
        LoadUnloadCycleCount = new AttributeID(0xE1),
paulwerelds@233
   136
        LoadInTime = new AttributeID(0xE2),
paulwerelds@233
   137
        TorqueAmplificationCount = new AttributeID(0xE3),
paulwerelds@233
   138
        PowerOffRetractCycle = new AttributeID(0xE4),
paulwerelds@233
   139
        GMRHeadAmplitude = new AttributeID(0xE6),
paulwerelds@233
   140
        DriveTemperature = new AttributeID(0xE7),
paulwerelds@233
   141
        HeadFlyingHours = new AttributeID(0xF0),
paulwerelds@233
   142
        LBAsWrittenTotal = new AttributeID(0xF1),
paulwerelds@233
   143
        LBAsReadTotal = new AttributeID(0xF2),
paulwerelds@233
   144
        ReadErrorRetryRate = new AttributeID(0xFA),
paulwerelds@233
   145
        FreeFallProtection = new AttributeID(0xFE)
paulwerelds@233
   146
      ;
moel@231
   147
    }
moel@231
   148
moel@231
   149
    // Indilinx SSD SMART attributes
paulwerelds@233
   150
    // TODO: Find out the purpose of attribute 0xD2
paulwerelds@233
   151
    // Seems to be unique to Indilinx drives, hence its name of UnknownUnique.
paulwerelds@233
   152
    public static class IndilinxAttributes {
paulwerelds@233
   153
      public static readonly AttributeID
paulwerelds@233
   154
        ReadErrorRate = CommonAttributes.ReadErrorRate,
paulwerelds@233
   155
        PowerOnHours = CommonAttributes.PowerOnHours,
paulwerelds@233
   156
        PowerCycleCount = CommonAttributes.PowerCycleCount,
paulwerelds@233
   157
        InitialBadBlockCount = new AttributeID(0xB8),
paulwerelds@233
   158
        RemainingLife = new AttributeID(0xD1),
paulwerelds@233
   159
        ProgramFailure = new AttributeID(0xC3),
paulwerelds@233
   160
        EraseFailure = new AttributeID(0xC4),
paulwerelds@233
   161
        ReadFailure = new AttributeID(0xC5),
paulwerelds@233
   162
        SectorsRead = new AttributeID(0xC6),
paulwerelds@233
   163
        SectorsWritten = new AttributeID(0xC7),
paulwerelds@233
   164
        ReadCommands = new AttributeID(0xC8),
paulwerelds@233
   165
        WriteCommands = new AttributeID(0xC9),
paulwerelds@233
   166
        BitErrors = new AttributeID(0xCA),
paulwerelds@233
   167
        CorrectedErrors = new AttributeID(0xCB),
paulwerelds@233
   168
        BadBlockFullFlag = new AttributeID(0xCC),
paulwerelds@233
   169
        MaxCellcycles = new AttributeID(0xCD),
paulwerelds@233
   170
        MinErase = new AttributeID(0xCE),
paulwerelds@233
   171
        MaxErase = new AttributeID(0xCF),
paulwerelds@233
   172
        AverageEraseCount = new AttributeID(0xD0),
paulwerelds@233
   173
        UnknownUnique = new AttributeID(0xD2),
paulwerelds@233
   174
        SataErrorCountCRC = new AttributeID(0xD3),
paulwerelds@233
   175
        SataErrorCountHandshake = new AttributeID(0xD4)
paulwerelds@233
   176
      ;
moel@231
   177
    }
moel@231
   178
moel@231
   179
    // Intel SSD SMART attributes
paulwerelds@233
   180
    // TODO: Find out the meaning behind 0xE2, 0xE3 and 0xE4
paulwerelds@233
   181
    public static class IntelAttributes {
paulwerelds@233
   182
      public static readonly AttributeID
paulwerelds@233
   183
        ReadErrorRate = CommonAttributes.ReadErrorRate,
paulwerelds@233
   184
        SpinUpTime = CommonAttributes.SpinUpTime,
paulwerelds@233
   185
        StartStopCount = CommonAttributes.StartStopCount,
paulwerelds@233
   186
        ReallocatedSectorsCount = CommonAttributes.ReallocatedSectorsCount,
paulwerelds@233
   187
        PowerOnHours = CommonAttributes.PowerOnHours,
paulwerelds@233
   188
        PowerCycleCount = CommonAttributes.PowerCycleCount,
paulwerelds@233
   189
        EndToEndError = CommonAttributes.EndToEndError, // Only on G2 drives!
paulwerelds@233
   190
paulwerelds@233
   191
        // Different from the common attribute PowerOffRetractCount, same ID
paulwerelds@233
   192
        UnsafeShutdownCount = new AttributeID(0xC0),
paulwerelds@233
   193
        HostWrites = new AttributeID(0xE1),
paulwerelds@233
   194
        RemainingLife = new AttributeID(0xE8),
paulwerelds@233
   195
        MediaWearOutIndicator = new AttributeID(0xE9)
paulwerelds@233
   196
      ;
moel@231
   197
    }
moel@231
   198
moel@231
   199
    // Samsung SSD SMART attributes
paulwerelds@233
   200
    // TODO: AF, B0, B1, B5, B6, BB, C3, C6, C7, E8, E9
paulwerelds@233
   201
    public static class SamsungAttributes {
paulwerelds@233
   202
      public static readonly AttributeID
paulwerelds@233
   203
        PowerOnHours = CommonAttributes.PowerOnHours,
paulwerelds@233
   204
        PowerCycleCount = CommonAttributes.PowerCycleCount,
paulwerelds@233
   205
        UsedReservedBlockCountChip = new AttributeID(0xB2), // Unique
paulwerelds@233
   206
        UsedReservedBlockCountTotal = new AttributeID(0xB3), // Unique
paulwerelds@233
   207
        RemainingLife = new AttributeID(0xB4), // Unique
paulwerelds@233
   208
        RuntimeBadBlockTotal = new AttributeID(0xB7)
paulwerelds@233
   209
      ;
moel@231
   210
    }
moel@231
   211
moel@231
   212
    // SandForce SSD SMART attributes
paulwerelds@233
   213
    // Note: 0xE9 and 0xEA are reserved attributes and unique
paulwerelds@233
   214
    public static class SandForceAttributes {
paulwerelds@233
   215
      public static readonly AttributeID
paulwerelds@233
   216
        ReadErrorRate = CommonAttributes.ReadErrorRate,
paulwerelds@233
   217
        RetiredBlockCount = new AttributeID(0x05),
paulwerelds@233
   218
        PowerOnHours = CommonAttributes.PowerOnHours,
paulwerelds@233
   219
        PowerCycleCount = CommonAttributes.PowerCycleCount,
paulwerelds@233
   220
        ProgramFailCount = new AttributeID(0xAB), // Unique
paulwerelds@233
   221
        EraseFailCount = new AttributeID(0xAC), // Unique
paulwerelds@233
   222
        UnexpectedPowerLossCount = new AttributeID(0xAE), // Unique
paulwerelds@233
   223
        WearRangeDelta = new AttributeID(0xB1), // Unique
paulwerelds@233
   224
        ProgramFailCountAlt = new AttributeID(0xB5), // Same as 0xAB
paulwerelds@233
   225
        EraseFailCountAlt = new AttributeID(0xB6), // Same as 0xAC
paulwerelds@233
   226
        ReportedUncorrectableErrors =
paulwerelds@233
   227
          CommonAttributes.ReportedUncorrectableErrors,
paulwerelds@233
   228
        
paulwerelds@233
   229
        Temperature = CommonAttributes.Temperature, // SF-1500 only!
paulwerelds@233
   230
        
paulwerelds@233
   231
        // Opposite of the common attribute HardwareECCRecovered
paulwerelds@233
   232
        UnrecoverableECC = new AttributeID(0xC3),
paulwerelds@233
   233
        ReallocationEventCount = new AttributeID(0xC4),
paulwerelds@233
   234
        RemainingLife = new AttributeID(0xE7),
paulwerelds@233
   235
        LifetimeWrites = new AttributeID(0xF1),
paulwerelds@233
   236
        LifetimeReads = new AttributeID(0xF2)
paulwerelds@233
   237
      ;
paulwerelds@218
   238
    }
paulwerelds@218
   239
moel@1
   240
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@1
   241
    public struct DriveAttribute {
moel@1
   242
      public AttributeID ID;
moel@1
   243
      public Status StatusFlags;
moel@1
   244
      public byte AttrValue;
moel@1
   245
      public byte WorstValue;
moel@1
   246
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
moel@1
   247
      public byte[] RawValue;
moel@1
   248
      public byte Reserved;
moel@1
   249
    };
moel@1
   250
moel@1
   251
    [Flags]
moel@195
   252
    protected enum AccessMode : uint {     
moel@1
   253
      Read = 0x80000000,    
moel@1
   254
      Write = 0x40000000,     
moel@1
   255
      Execute = 0x20000000,     
moel@1
   256
      All = 0x10000000
moel@1
   257
    }
moel@1
   258
moel@1
   259
    [Flags]
moel@195
   260
    protected enum ShareMode : uint {
moel@1
   261
      None = 0,     
moel@1
   262
      Read = 1,     
moel@1
   263
      Write = 2,    
moel@1
   264
      Delete = 4
moel@1
   265
    }
moel@1
   266
moel@195
   267
    protected enum CreationMode : uint {
moel@1
   268
      New = 1,
moel@1
   269
      CreateAlways = 2,    
moel@1
   270
      OpenExisting = 3,    
moel@1
   271
      OpenAlways = 4,    
moel@1
   272
      TruncateExisting = 5
moel@1
   273
    }
moel@1
   274
moel@1
   275
    [Flags]
moel@195
   276
    protected enum FileAttribute : uint {
moel@1
   277
      Readonly = 0x00000001,
moel@1
   278
      Hidden = 0x00000002,
moel@1
   279
      System = 0x00000004,
moel@1
   280
      Directory = 0x00000010,
moel@1
   281
      Archive = 0x00000020,
moel@1
   282
      Device = 0x00000040,
moel@1
   283
      Normal = 0x00000080,
moel@1
   284
      Temporary = 0x00000100,
moel@1
   285
      SparseFile = 0x00000200,
moel@1
   286
      ReparsePoint = 0x00000400,
moel@1
   287
      Compressed = 0x00000800,
moel@1
   288
      Offline = 0x00001000,
moel@1
   289
      NotContentIndexed = 0x00002000,
moel@1
   290
      Encrypted = 0x00004000,
moel@1
   291
    }
moel@1
   292
moel@195
   293
    protected enum DriveCommand : uint {
moel@1
   294
      GetVersion = 0x00074080,
moel@1
   295
      SendDriveCommand = 0x0007c084,
moel@1
   296
      ReceiveDriveData = 0x0007c088
moel@1
   297
    }
moel@1
   298
moel@1
   299
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   300
    protected struct CommandBlockRegisters {
moel@1
   301
      public byte Features;         
moel@1
   302
      public byte SectorCount;      
moel@1
   303
      public byte LBALow;       
moel@1
   304
      public byte LBAMid;           
moel@1
   305
      public byte LBAHigh;        
moel@1
   306
      public byte Device;       
moel@1
   307
      public byte Command;           
moel@1
   308
      public byte Reserved;                  
moel@1
   309
    }
moel@1
   310
moel@1
   311
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   312
    protected struct DriveCommandParameter {
moel@195
   313
      public uint BufferSize;           
moel@1
   314
      public CommandBlockRegisters Registers;           
moel@1
   315
      public byte DriveNumber;   
moel@188
   316
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@1
   317
      public byte[] Reserved;                                
moel@1
   318
    }
moel@1
   319
moel@1
   320
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   321
    protected struct DriverStatus {
moel@1
   322
      public byte DriverError;   
moel@1
   323
      public byte IDEError;             
moel@1
   324
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
moel@1
   325
      public byte[] Reserved;               
moel@1
   326
    }
moel@1
   327
moel@1
   328
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   329
    protected struct DriveCommandResult {
moel@1
   330
      public uint BufferSize;
moel@1
   331
      public DriverStatus DriverStatus;
moel@1
   332
    } 
moel@1
   333
moel@1
   334
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   335
    protected struct DriveSmartReadResult {
moel@1
   336
      public uint BufferSize;           
moel@1
   337
      public DriverStatus DriverStatus;
moel@1
   338
      public byte Version;
moel@1
   339
      public byte Reserved;
moel@1
   340
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
moel@1
   341
      public DriveAttribute[] Attributes;                                                                                       
moel@1
   342
    }
moel@1
   343
moel@1
   344
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   345
    protected struct Identify {
moel@1
   346
      public ushort GeneralConfiguration;
moel@1
   347
      public ushort NumberOfCylinders;
moel@1
   348
      public ushort Reserved;
moel@1
   349
      public ushort NumberOfHeads;
moel@1
   350
      public ushort UnformattedBytesPerTrack;
moel@1
   351
      public ushort UnformattedBytesPerSector;
moel@1
   352
      public ushort SectorsPerTrack;
moel@1
   353
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
moel@1
   354
      public ushort[] VendorUnique;
moel@1
   355
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
moel@1
   356
      public byte[] SerialNumber;
moel@1
   357
      public ushort BufferType;
moel@1
   358
      public ushort BufferSectorSize;
moel@1
   359
      public ushort NumberOfEccBytes;
moel@1
   360
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
moel@1
   361
      public byte[] FirmwareRevision;
moel@1
   362
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
moel@1
   363
      public byte[] ModelNumber;
moel@1
   364
      public ushort MoreVendorUnique;
moel@1
   365
      public ushort DoubleWordIo;
moel@1
   366
      public ushort Capabilities;
moel@1
   367
      public ushort MoreReserved;
moel@1
   368
      public ushort PioCycleTimingMode;
moel@1
   369
      public ushort DmaCycleTimingMode;
moel@1
   370
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
moel@1
   371
      public byte[] More;
moel@1
   372
    }
moel@1
   373
moel@1
   374
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@195
   375
    protected struct DriveIdentifyResult {
moel@1
   376
      public uint BufferSize;
moel@1
   377
      public DriverStatus DriverStatus;
moel@1
   378
      public Identify Identify;
moel@1
   379
    } 
moel@1
   380
moel@1
   381
    public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
moel@1
   382
moel@1
   383
    private const byte SMART_CMD = 0xB0;
moel@1
   384
    private const byte ID_CMD = 0xEC;
moel@1
   385
    
moel@1
   386
    private const byte SMART_READ_DATA = 0xD0;
moel@1
   387
    private const byte SMART_ENABLE_OPERATIONS = 0xD8;
moel@1
   388
    
moel@1
   389
    private const byte SMART_LBA_MID = 0x4F;
moel@1
   390
    private const byte SMART_LBA_HI = 0xC2;
moel@1
   391
moel@1
   392
    private const int MAX_DRIVE_ATTRIBUTES = 512;
moel@1
   393
moel@167
   394
    private SMART() { }
moel@1
   395
moel@1
   396
    public static IntPtr OpenPhysicalDrive(int driveNumber) {
moel@167
   397
      return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
moel@1
   398
        AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
moel@1
   399
        IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
moel@1
   400
        IntPtr.Zero);
moel@1
   401
    }
moel@1
   402
moel@1
   403
    public static bool EnableSmart(IntPtr handle, int driveNumber) {
moel@1
   404
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   405
      DriveCommandResult result;
moel@1
   406
      uint bytesReturned;
moel@1
   407
moel@1
   408
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   409
      parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
moel@1
   410
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   411
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   412
      parameter.Registers.Command = SMART_CMD;
moel@1
   413
moel@167
   414
      return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
moel@167
   415
        ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
moel@1
   416
        Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
moel@1
   417
        IntPtr.Zero);
moel@1
   418
    }
moel@1
   419
paulwerelds@233
   420
    public static DriveAttribute[] ReadSmart(IntPtr handle,
paulwerelds@218
   421
      int driveNumber)
paulwerelds@218
   422
    {
moel@1
   423
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   424
      DriveSmartReadResult result;
moel@1
   425
      uint bytesReturned;
moel@1
   426
moel@1
   427
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   428
      parameter.Registers.Features = SMART_READ_DATA;
moel@1
   429
      parameter.Registers.LBAMid = SMART_LBA_MID;
moel@1
   430
      parameter.Registers.LBAHigh = SMART_LBA_HI;
moel@1
   431
      parameter.Registers.Command = SMART_CMD;
moel@1
   432
paulwerelds@218
   433
      bool isValid = NativeMethods.DeviceIoControl(handle, 
moel@167
   434
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
moel@167
   435
        out result, Marshal.SizeOf(typeof(DriveSmartReadResult)), 
moel@167
   436
        out bytesReturned, IntPtr.Zero);
moel@1
   437
paulwerelds@233
   438
      return (isValid) ? result.Attributes : new DriveAttribute[0];
moel@1
   439
    }
moel@1
   440
moel@1
   441
    public static string ReadName(IntPtr handle, int driveNumber) {
moel@1
   442
      DriveCommandParameter parameter = new DriveCommandParameter();
moel@1
   443
      DriveIdentifyResult result;
moel@1
   444
      uint bytesReturned;
moel@1
   445
moel@1
   446
      parameter.DriveNumber = (byte)driveNumber;
moel@1
   447
      parameter.Registers.Command = ID_CMD;
moel@1
   448
moel@167
   449
      bool valid = NativeMethods.DeviceIoControl(handle, 
moel@167
   450
        DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
moel@167
   451
        out result, Marshal.SizeOf(typeof(DriveIdentifyResult)), 
moel@167
   452
        out bytesReturned, IntPtr.Zero);
moel@1
   453
moel@1
   454
      if (!valid)
moel@1
   455
        return null;
moel@1
   456
      else {
moel@1
   457
moel@1
   458
        byte[] bytes = result.Identify.ModelNumber;
moel@1
   459
        char[] chars = new char[bytes.Length];
moel@1
   460
        for (int i = 0; i < bytes.Length; i += 2) {
moel@1
   461
          chars[i] = (char)bytes[i + 1];
moel@1
   462
          chars[i + 1] = (char)bytes[i];
moel@1
   463
        }
moel@1
   464
moel@1
   465
        return new string(chars).Trim();
moel@1
   466
      }
moel@1
   467
    }
moel@1
   468
moel@167
   469
    public static int CloseHandle(IntPtr handle) {
moel@167
   470
      return NativeMethods.CloseHandle(handle);
moel@167
   471
    }
moel@167
   472
moel@195
   473
    protected static class NativeMethods {
moel@167
   474
      private const string KERNEL = "kernel32.dll";
moel@167
   475
moel@167
   476
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
moel@167
   477
        CharSet = CharSet.Unicode)]
moel@167
   478
      public static extern IntPtr CreateFile(string fileName,
moel@167
   479
        AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
moel@167
   480
        CreationMode creationDisposition, FileAttribute flagsAndAttributes,
moel@167
   481
        IntPtr templateFilehandle);
moel@167
   482
moel@167
   483
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   484
      public static extern int CloseHandle(IntPtr handle);
moel@167
   485
moel@167
   486
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   487
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   488
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   489
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   490
        int parameterSize, out DriveSmartReadResult result, int resultSize,
moel@167
   491
        out uint bytesReturned, IntPtr overlapped);
moel@167
   492
moel@167
   493
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   494
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   495
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   496
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   497
        int parameterSize, out DriveCommandResult result, int resultSize,
moel@167
   498
        out uint bytesReturned, IntPtr overlapped);
moel@167
   499
moel@167
   500
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@167
   501
      [return: MarshalAsAttribute(UnmanagedType.Bool)]
moel@167
   502
      public static extern bool DeviceIoControl(IntPtr handle,
moel@167
   503
        DriveCommand command, ref DriveCommandParameter parameter,
moel@167
   504
        int parameterSize, out DriveIdentifyResult result, int resultSize,
moel@167
   505
        out uint bytesReturned, IntPtr overlapped);
moel@167
   506
    }    
moel@1
   507
  }
moel@1
   508
}