Hardware/HDD/SMART.cs
changeset 1 361e324a0ed4
child 48 eb04985b7b6a
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Hardware/HDD/SMART.cs	Tue Jan 26 22:37:48 2010 +0000
     1.3 @@ -0,0 +1,337 @@
     1.4 +/*
     1.5 +  
     1.6 +  Version: MPL 1.1/GPL 2.0/LGPL 2.1
     1.7 +
     1.8 +  The contents of this file are subject to the Mozilla Public License Version
     1.9 +  1.1 (the "License"); you may not use this file except in compliance with
    1.10 +  the License. You may obtain a copy of the License at
    1.11 + 
    1.12 +  http://www.mozilla.org/MPL/
    1.13 +
    1.14 +  Software distributed under the License is distributed on an "AS IS" basis,
    1.15 +  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    1.16 +  for the specific language governing rights and limitations under the License.
    1.17 +
    1.18 +  The Original Code is the Open Hardware Monitor code.
    1.19 +
    1.20 +  The Initial Developer of the Original Code is 
    1.21 +  Michael Möller <m.moeller@gmx.ch>.
    1.22 +  Portions created by the Initial Developer are Copyright (C) 2009-2010
    1.23 +  the Initial Developer. All Rights Reserved.
    1.24 +
    1.25 +  Contributor(s):
    1.26 +
    1.27 +  Alternatively, the contents of this file may be used under the terms of
    1.28 +  either the GNU General Public License Version 2 or later (the "GPL"), or
    1.29 +  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    1.30 +  in which case the provisions of the GPL or the LGPL are applicable instead
    1.31 +  of those above. If you wish to allow use of your version of this file only
    1.32 +  under the terms of either the GPL or the LGPL, and not to allow others to
    1.33 +  use your version of this file under the terms of the MPL, indicate your
    1.34 +  decision by deleting the provisions above and replace them with the notice
    1.35 +  and other provisions required by the GPL or the LGPL. If you do not delete
    1.36 +  the provisions above, a recipient may use your version of this file under
    1.37 +  the terms of any one of the MPL, the GPL or the LGPL.
    1.38 + 
    1.39 +*/
    1.40 +
    1.41 +using System;
    1.42 +using System.Collections.Generic;
    1.43 +using System.Runtime.InteropServices;
    1.44 +
    1.45 +namespace OpenHardwareMonitor.Hardware.HDD {
    1.46 +    
    1.47 +  public class SMART {
    1.48 +
    1.49 +    [Flags]
    1.50 +    public enum Status : ushort {
    1.51 +      PreFailureWarranty = 0x01,
    1.52 +      OnLineCollection = 0x02,
    1.53 +      Performance = 0x04,
    1.54 +      ErrorRate = 0x08,
    1.55 +      EventCount = 0x10,
    1.56 +      SelfPreserving = 0x20
    1.57 +    }
    1.58 +
    1.59 +    public enum AttributeID : byte {
    1.60 +      ReadErrorRate = 0x01,
    1.61 +      ThroughputPerformance = 0x02,
    1.62 +      SpinUpTime = 0x03,
    1.63 +      StartStopCount = 0x04,
    1.64 +      ReallocatedSectorsCount = 0x05,
    1.65 +      ReadChannelMargin = 0x06,
    1.66 +      SeekErrorRate = 0x07,
    1.67 +      SeekTimePerformance = 0x08,
    1.68 +      PowerOnHours = 0x09,
    1.69 +      SpinRetryCount = 0x0A,
    1.70 +      RecalibrationRetries = 0x0B,
    1.71 +      PowerCycleCount = 0x0C,
    1.72 +      SoftReadErrorRate = 0x0D,
    1.73 +      Temperature = 0xC2,
    1.74 +      HardwareECCRecovered = 0xC3,
    1.75 +      ReallocationEventCount = 0xC4,
    1.76 +      CurrentPendingSectorCount = 0xC5,
    1.77 +      UncorrectableSectorCount = 0xC6,
    1.78 +      UltraDMACRCErrorCount = 0xC7,
    1.79 +      WriteErrorRate = 0xC8
    1.80 +    }
    1.81 +
    1.82 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    1.83 +    public struct DriveAttribute {
    1.84 +      public AttributeID ID;
    1.85 +      public Status StatusFlags;
    1.86 +      public byte AttrValue;
    1.87 +      public byte WorstValue;
    1.88 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    1.89 +      public byte[] RawValue;
    1.90 +      public byte Reserved;
    1.91 +    };
    1.92 +
    1.93 +    [Flags]
    1.94 +    private enum AccessMode : uint {     
    1.95 +      Read = 0x80000000,    
    1.96 +      Write = 0x40000000,     
    1.97 +      Execute = 0x20000000,     
    1.98 +      All = 0x10000000
    1.99 +    }
   1.100 +
   1.101 +    [Flags]
   1.102 +    private enum ShareMode : uint {
   1.103 +      None = 0,     
   1.104 +      Read = 1,     
   1.105 +      Write = 2,    
   1.106 +      Delete = 4
   1.107 +    }
   1.108 +
   1.109 +    private enum CreationMode : uint {
   1.110 +      New = 1,
   1.111 +      CreateAlways = 2,    
   1.112 +      OpenExisting = 3,    
   1.113 +      OpenAlways = 4,    
   1.114 +      TruncateExisting = 5
   1.115 +    }
   1.116 +
   1.117 +    [Flags]
   1.118 +    private enum FileAttribute : uint {
   1.119 +      Readonly = 0x00000001,
   1.120 +      Hidden = 0x00000002,
   1.121 +      System = 0x00000004,
   1.122 +      Directory = 0x00000010,
   1.123 +      Archive = 0x00000020,
   1.124 +      Device = 0x00000040,
   1.125 +      Normal = 0x00000080,
   1.126 +      Temporary = 0x00000100,
   1.127 +      SparseFile = 0x00000200,
   1.128 +      ReparsePoint = 0x00000400,
   1.129 +      Compressed = 0x00000800,
   1.130 +      Offline = 0x00001000,
   1.131 +      NotContentIndexed = 0x00002000,
   1.132 +      Encrypted = 0x00004000,
   1.133 +    }
   1.134 +
   1.135 +    private enum DriveCommand : uint {
   1.136 +      GetVersion = 0x00074080,
   1.137 +      SendDriveCommand = 0x0007c084,
   1.138 +      ReceiveDriveData = 0x0007c088
   1.139 +    }
   1.140 +
   1.141 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
   1.142 +    private struct CommandBlockRegisters {
   1.143 +      public byte Features;         
   1.144 +      public byte SectorCount;      
   1.145 +      public byte LBALow;       
   1.146 +      public byte LBAMid;           
   1.147 +      public byte LBAHigh;        
   1.148 +      public byte Device;       
   1.149 +      public byte Command;           
   1.150 +      public byte Reserved;                  
   1.151 +    }
   1.152 +
   1.153 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
   1.154 +    private struct DriveCommandParameter {
   1.155 +      private uint BufferSize;           
   1.156 +      public CommandBlockRegisters Registers;           
   1.157 +      public byte DriveNumber;   
   1.158 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
   1.159 +      public byte[] Reserved;                                
   1.160 +    }
   1.161 +
   1.162 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
   1.163 +    private struct DriverStatus {
   1.164 +      public byte DriverError;   
   1.165 +      public byte IDEError;             
   1.166 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
   1.167 +      public byte[] Reserved;               
   1.168 +    }
   1.169 +
   1.170 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
   1.171 +    private struct DriveCommandResult {
   1.172 +      public uint BufferSize;
   1.173 +      public DriverStatus DriverStatus;
   1.174 +    } 
   1.175 +
   1.176 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
   1.177 +    private struct DriveSmartReadResult {
   1.178 +      public uint BufferSize;           
   1.179 +      public DriverStatus DriverStatus;
   1.180 +      public byte Version;
   1.181 +      public byte Reserved;
   1.182 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
   1.183 +      public DriveAttribute[] Attributes;                                                                                       
   1.184 +    }
   1.185 +
   1.186 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
   1.187 +    private struct Identify {
   1.188 +      public ushort GeneralConfiguration;
   1.189 +      public ushort NumberOfCylinders;
   1.190 +      public ushort Reserved;
   1.191 +      public ushort NumberOfHeads;
   1.192 +      public ushort UnformattedBytesPerTrack;
   1.193 +      public ushort UnformattedBytesPerSector;
   1.194 +      public ushort SectorsPerTrack;
   1.195 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
   1.196 +      public ushort[] VendorUnique;
   1.197 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
   1.198 +      public byte[] SerialNumber;
   1.199 +      public ushort BufferType;
   1.200 +      public ushort BufferSectorSize;
   1.201 +      public ushort NumberOfEccBytes;
   1.202 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
   1.203 +      public byte[] FirmwareRevision;
   1.204 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
   1.205 +      public byte[] ModelNumber;
   1.206 +      public ushort MoreVendorUnique;
   1.207 +      public ushort DoubleWordIo;
   1.208 +      public ushort Capabilities;
   1.209 +      public ushort MoreReserved;
   1.210 +      public ushort PioCycleTimingMode;
   1.211 +      public ushort DmaCycleTimingMode;
   1.212 +      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
   1.213 +      public byte[] More;
   1.214 +    }
   1.215 +
   1.216 +    [StructLayout(LayoutKind.Sequential, Pack = 1)]
   1.217 +    private struct DriveIdentifyResult {
   1.218 +      public uint BufferSize;
   1.219 +      public DriverStatus DriverStatus;
   1.220 +      public Identify Identify;
   1.221 +    } 
   1.222 +
   1.223 +    public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
   1.224 +
   1.225 +    private const byte SMART_CMD = 0xB0;
   1.226 +    private const byte ID_CMD = 0xEC;
   1.227 +    
   1.228 +    private const byte SMART_READ_DATA = 0xD0;
   1.229 +    private const byte SMART_ENABLE_OPERATIONS = 0xD8;
   1.230 +    
   1.231 +    private const byte SMART_LBA_MID = 0x4F;
   1.232 +    private const byte SMART_LBA_HI = 0xC2;
   1.233 +
   1.234 +    private const int MAX_DRIVE_ATTRIBUTES = 512;
   1.235 +
   1.236 +    private const string KERNEL = "kernel32.dll";
   1.237 +
   1.238 +    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   1.239 +    private static extern IntPtr CreateFile(string fileName, 
   1.240 +      AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
   1.241 +      CreationMode creationDisposition, FileAttribute flagsAndAttributes, 
   1.242 +      IntPtr templateFilehandle);
   1.243 +
   1.244 +    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   1.245 +    public static extern int CloseHandle(IntPtr handle);
   1.246 +
   1.247 +    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   1.248 +    private static extern bool DeviceIoControl(IntPtr handle,
   1.249 +      DriveCommand command, ref DriveCommandParameter parameter,
   1.250 +      int parameterSize, out DriveSmartReadResult result, int resultSize, 
   1.251 +      out uint bytesReturned, IntPtr overlapped);
   1.252 +
   1.253 +    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   1.254 +    private static extern bool DeviceIoControl(IntPtr handle,
   1.255 +      DriveCommand command, ref DriveCommandParameter parameter,
   1.256 +      int parameterSize, out DriveCommandResult result, int resultSize,
   1.257 +      out uint bytesReturned, IntPtr overlapped);
   1.258 +
   1.259 +    [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   1.260 +    private static extern bool DeviceIoControl(IntPtr handle,
   1.261 +      DriveCommand command, ref DriveCommandParameter parameter,
   1.262 +      int parameterSize, out DriveIdentifyResult result, int resultSize,
   1.263 +      out uint bytesReturned, IntPtr overlapped);
   1.264 +
   1.265 +    public static IntPtr OpenPhysicalDrive(int driveNumber) {
   1.266 +      return CreateFile(@"\\.\PhysicalDrive" + driveNumber,
   1.267 +        AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
   1.268 +        IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
   1.269 +        IntPtr.Zero);
   1.270 +    }
   1.271 +
   1.272 +    public static bool EnableSmart(IntPtr handle, int driveNumber) {
   1.273 +      DriveCommandParameter parameter = new DriveCommandParameter();
   1.274 +      DriveCommandResult result;
   1.275 +      uint bytesReturned;
   1.276 +
   1.277 +      parameter.DriveNumber = (byte)driveNumber;
   1.278 +      parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
   1.279 +      parameter.Registers.LBAMid = SMART_LBA_MID;
   1.280 +      parameter.Registers.LBAHigh = SMART_LBA_HI;
   1.281 +      parameter.Registers.Command = SMART_CMD;
   1.282 +
   1.283 +      return DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
   1.284 +        ref parameter, Marshal.SizeOf(parameter), out result,
   1.285 +        Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
   1.286 +        IntPtr.Zero);
   1.287 +    }
   1.288 +
   1.289 +    public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
   1.290 +      DriveCommandParameter parameter = new DriveCommandParameter();
   1.291 +      DriveSmartReadResult result;
   1.292 +      uint bytesReturned;
   1.293 +
   1.294 +      parameter.DriveNumber = (byte)driveNumber;
   1.295 +      parameter.Registers.Features = SMART_READ_DATA;
   1.296 +      parameter.Registers.LBAMid = SMART_LBA_MID;
   1.297 +      parameter.Registers.LBAHigh = SMART_LBA_HI;
   1.298 +      parameter.Registers.Command = SMART_CMD;
   1.299 +
   1.300 +      bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
   1.301 +        ref parameter, Marshal.SizeOf(parameter), out result,
   1.302 +        Marshal.SizeOf(typeof(DriveSmartReadResult)), out bytesReturned,
   1.303 +        IntPtr.Zero);
   1.304 +
   1.305 +      if (!valid)
   1.306 +        return null;
   1.307 +      else
   1.308 +        return result.Attributes;
   1.309 +    }
   1.310 +
   1.311 +    public static string ReadName(IntPtr handle, int driveNumber) {
   1.312 +      DriveCommandParameter parameter = new DriveCommandParameter();
   1.313 +      DriveIdentifyResult result;
   1.314 +      uint bytesReturned;
   1.315 +
   1.316 +      parameter.DriveNumber = (byte)driveNumber;
   1.317 +      parameter.Registers.Command = ID_CMD;
   1.318 +
   1.319 +      bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
   1.320 +        ref parameter, Marshal.SizeOf(parameter), out result,
   1.321 +        Marshal.SizeOf(typeof(DriveIdentifyResult)), out bytesReturned,
   1.322 +        IntPtr.Zero);
   1.323 +
   1.324 +      if (!valid)
   1.325 +        return null;
   1.326 +      else {
   1.327 +
   1.328 +        byte[] bytes = result.Identify.ModelNumber;
   1.329 +        char[] chars = new char[bytes.Length];
   1.330 +        for (int i = 0; i < bytes.Length; i += 2) {
   1.331 +          chars[i] = (char)bytes[i + 1];
   1.332 +          chars[i + 1] = (char)bytes[i];
   1.333 +        }
   1.334 +
   1.335 +        return new string(chars).Trim();
   1.336 +      }
   1.337 +    }
   1.338 +
   1.339 +  }
   1.340 +}