Hardware/HDD/SMART.cs
author moel.mich
Wed, 08 Dec 2010 19:23:13 +0000
changeset 246 59024371cd50
parent 231 30f5a06f5d8a
child 308 d882720734bf
permissions -rw-r--r--
Fixed the temperature reading and improved the report for the Nuvoton NCT6771F super I/O chip.
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
}