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