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