Hardware/HDD/WindowsSmart.cs
author moel.mich
Sun, 08 Jul 2012 19:26:00 +0000
changeset 359 30bb76a1da24
parent 325 4c31341a4800
child 369 5077ed7ddca8
permissions -rw-r--r--
Added a mainboard specific configuration for the Asus P8Z77-V (Issue 347) and added an additional temperature for the Gigabyte GA-MA78LM-S2H (Issue 358).
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	Copyright (C) 2010 Paul Werelds
     9   Copyright (C) 2011 Roland Reinl <roland-reinl@gmx.de>
    10 	
    11 */
    12 
    13 using System;
    14 using System.Collections.Generic;
    15 using System.Runtime.InteropServices;
    16 
    17 namespace OpenHardwareMonitor.Hardware.HDD {
    18 
    19   internal class WindowsSmart : ISmart {
    20     [Flags]
    21     protected enum AccessMode : uint {     
    22       Read = 0x80000000,    
    23       Write = 0x40000000,     
    24       Execute = 0x20000000,     
    25       All = 0x10000000
    26     }
    27 
    28     [Flags]
    29     protected enum ShareMode : uint {
    30       None = 0,     
    31       Read = 1,     
    32       Write = 2,    
    33       Delete = 4
    34     }
    35 
    36     protected enum CreationMode : uint {
    37       New = 1,
    38       CreateAlways = 2,    
    39       OpenExisting = 3,    
    40       OpenAlways = 4,    
    41       TruncateExisting = 5
    42     }
    43 
    44     [Flags]
    45     protected enum FileAttribute : uint {
    46       Readonly = 0x00000001,
    47       Hidden = 0x00000002,
    48       System = 0x00000004,
    49       Directory = 0x00000010,
    50       Archive = 0x00000020,
    51       Device = 0x00000040,
    52       Normal = 0x00000080,
    53       Temporary = 0x00000100,
    54       SparseFile = 0x00000200,
    55       ReparsePoint = 0x00000400,
    56       Compressed = 0x00000800,
    57       Offline = 0x00001000,
    58       NotContentIndexed = 0x00002000,
    59       Encrypted = 0x00004000,
    60     }
    61 
    62     protected enum DriveCommand : uint {
    63       GetVersion = 0x00074080,
    64       SendDriveCommand = 0x0007c084,
    65       ReceiveDriveData = 0x0007c088
    66     }
    67 
    68     protected enum RegisterCommand : byte {
    69       /// <summary>
    70       /// SMART data requested.
    71       /// </summary>
    72       SmartCmd = 0xB0,
    73 
    74       /// <summary>
    75       /// Identify data is requested.
    76       /// </summary>
    77       IdCmd = 0xEC,
    78     }
    79 
    80     protected enum RegisterFeature : byte {
    81       /// <summary>
    82       /// Read SMART data.
    83       /// </summary>
    84       SmartReadData = 0xD0,
    85 
    86       /// <summary>
    87       /// Read SMART thresholds.
    88       /// </summary>
    89       SmartReadThresholds = 0xD1, /* obsolete */
    90 
    91       /// <summary>
    92       /// Autosave SMART data.
    93       /// </summary>
    94       SmartAutosave = 0xD2,
    95 
    96       /// <summary>
    97       /// Save SMART attributes.
    98       /// </summary>
    99       SmartSaveAttr = 0xD3,
   100 
   101       /// <summary>
   102       /// Set SMART to offline immediately.
   103       /// </summary>
   104       SmartImmediateOffline = 0xD4,
   105 
   106       /// <summary>
   107       /// Read SMART log.
   108       /// </summary>
   109       SmartReadLog = 0xD5,
   110 
   111       /// <summary>
   112       /// Write SMART log.
   113       /// </summary>
   114       SmartWriteLog = 0xD6,
   115 
   116       /// <summary>
   117       /// Write SMART thresholds.
   118       /// </summary>
   119       SmartWriteThresholds = 0xD7, /* obsolete */
   120 
   121       /// <summary>
   122       /// Enable SMART.
   123       /// </summary>
   124       SmartEnableOperations = 0xD8,
   125 
   126       /// <summary>
   127       /// Disable SMART.
   128       /// </summary>
   129       SmartDisableOperations = 0xD9,
   130 
   131       /// <summary>
   132       /// Get SMART status.
   133       /// </summary>
   134       SmartStatus = 0xDA,
   135 
   136       /// <summary>
   137       /// Set SMART to offline automatically.
   138       /// </summary>
   139       SmartAutoOffline = 0xDB, /* obsolete */
   140     }
   141 
   142     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   143     protected struct CommandBlockRegisters {
   144       public RegisterFeature Features;         
   145       public byte SectorCount;      
   146       public byte LBALow;       
   147       public byte LBAMid;           
   148       public byte LBAHigh;        
   149       public byte Device;
   150       public RegisterCommand Command;           
   151       public byte Reserved;                  
   152     }
   153 
   154     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   155     protected struct DriveCommandParameter {
   156       public uint BufferSize;           
   157       public CommandBlockRegisters Registers;           
   158       public byte DriveNumber;   
   159       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
   160       public byte[] Reserved;                                
   161     }
   162 
   163     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   164     protected struct DriverStatus {
   165       public byte DriverError;   
   166       public byte IDEError;             
   167       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
   168       public byte[] Reserved;               
   169     }
   170 
   171     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   172     protected struct DriveCommandResult {
   173       public uint BufferSize;
   174       public DriverStatus DriverStatus;
   175     } 
   176 
   177     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   178     protected struct DriveSmartReadDataResult {
   179       public uint BufferSize;           
   180       public DriverStatus DriverStatus;
   181       public byte Version;
   182       public byte Reserved;
   183       [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
   184       public DriveAttributeValue[] Attributes;                                                                                       
   185     }
   186 
   187     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   188     protected struct DriveSmartReadThresholdsResult {
   189       public uint BufferSize;
   190       public DriverStatus DriverStatus;
   191       public byte Version;
   192       public byte Reserved;
   193       [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
   194       public DriveThresholdValue[] Thresholds;
   195     }
   196 
   197     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   198     protected struct Identify {
   199       public ushort GeneralConfiguration;
   200       public ushort NumberOfCylinders;
   201       public ushort Reserved;
   202       public ushort NumberOfHeads;
   203       public ushort UnformattedBytesPerTrack;
   204       public ushort UnformattedBytesPerSector;
   205       public ushort SectorsPerTrack;
   206       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
   207       public ushort[] VendorUnique;
   208       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
   209       public byte[] SerialNumber;
   210       public ushort BufferType;
   211       public ushort BufferSectorSize;
   212       public ushort NumberOfEccBytes;
   213       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
   214       public byte[] FirmwareRevision;
   215       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
   216       public byte[] ModelNumber;
   217       public ushort MoreVendorUnique;
   218       public ushort DoubleWordIo;
   219       public ushort Capabilities;
   220       public ushort MoreReserved;
   221       public ushort PioCycleTimingMode;
   222       public ushort DmaCycleTimingMode;
   223       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
   224       public byte[] More;
   225     }
   226 
   227     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   228     protected struct DriveIdentifyResult {
   229       public uint BufferSize;
   230       public DriverStatus DriverStatus;
   231       public Identify Identify;
   232     }
   233 
   234     public IntPtr InvalidHandle { get { return (IntPtr)(-1); } }
   235 
   236     private const byte SMART_LBA_MID = 0x4F;
   237     private const byte SMART_LBA_HI = 0xC2;
   238 
   239     private const int MAX_DRIVE_ATTRIBUTES = 512;
   240 
   241     public IntPtr OpenDrive(int driveNumber) {
   242       return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
   243         AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
   244         IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
   245         IntPtr.Zero);
   246     }
   247 
   248     public bool EnableSmart(IntPtr handle, int driveNumber) {
   249       DriveCommandParameter parameter = new DriveCommandParameter();
   250       DriveCommandResult result;
   251       uint bytesReturned;
   252 
   253       parameter.DriveNumber = (byte)driveNumber;
   254       parameter.Registers.Features = RegisterFeature.SmartEnableOperations;
   255       parameter.Registers.LBAMid = SMART_LBA_MID;
   256       parameter.Registers.LBAHigh = SMART_LBA_HI;
   257       parameter.Registers.Command = RegisterCommand.SmartCmd;
   258 
   259       return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
   260         ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
   261         Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
   262         IntPtr.Zero);
   263     }
   264 
   265     public DriveAttributeValue[] ReadSmartData(IntPtr handle, int driveNumber) {
   266       DriveCommandParameter parameter = new DriveCommandParameter();
   267       DriveSmartReadDataResult result;
   268       uint bytesReturned;
   269 
   270       parameter.DriveNumber = (byte)driveNumber;
   271       parameter.Registers.Features = RegisterFeature.SmartReadData;
   272       parameter.Registers.LBAMid = SMART_LBA_MID;
   273       parameter.Registers.LBAHigh = SMART_LBA_HI;
   274       parameter.Registers.Command = RegisterCommand.SmartCmd;
   275 
   276       bool isValid = NativeMethods.DeviceIoControl(handle, 
   277         DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
   278         out result, Marshal.SizeOf(typeof(DriveSmartReadDataResult)), 
   279         out bytesReturned, IntPtr.Zero);
   280 
   281       return (isValid) ? result.Attributes : new DriveAttributeValue[0];
   282     }
   283 
   284     public DriveThresholdValue[] ReadSmartThresholds(IntPtr handle,
   285       int driveNumber) 
   286     {
   287       DriveCommandParameter parameter = new DriveCommandParameter();
   288       DriveSmartReadThresholdsResult result;
   289       uint bytesReturned = 0;
   290 
   291       parameter.DriveNumber = (byte)driveNumber;
   292       parameter.Registers.Features = RegisterFeature.SmartReadThresholds;
   293       parameter.Registers.LBAMid = SMART_LBA_MID;
   294       parameter.Registers.LBAHigh = SMART_LBA_HI;
   295       parameter.Registers.Command = RegisterCommand.SmartCmd;
   296 
   297       bool isValid = NativeMethods.DeviceIoControl(handle,
   298         DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
   299         out result, Marshal.SizeOf(typeof(DriveSmartReadThresholdsResult)), 
   300         out bytesReturned, IntPtr.Zero); 
   301 
   302       return (isValid) ? result.Thresholds : new DriveThresholdValue[0];
   303     }
   304 
   305     private string GetString(byte[] bytes) {   
   306       char[] chars = new char[bytes.Length];
   307       for (int i = 0; i < bytes.Length; i += 2) {
   308         chars[i] = (char)bytes[i + 1];
   309         chars[i + 1] = (char)bytes[i];
   310       }
   311       return new string(chars).Trim(new char[] { ' ', '\0' });
   312     }
   313 
   314     public bool ReadNameAndFirmwareRevision(IntPtr handle, int driveNumber, 
   315       out string name, out string firmwareRevision) 
   316     {
   317       DriveCommandParameter parameter = new DriveCommandParameter();
   318       DriveIdentifyResult result;
   319       uint bytesReturned;
   320 
   321       parameter.DriveNumber = (byte)driveNumber;
   322       parameter.Registers.Command = RegisterCommand.IdCmd;
   323 
   324       bool valid = NativeMethods.DeviceIoControl(handle, 
   325         DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
   326         out result, Marshal.SizeOf(typeof(DriveIdentifyResult)), 
   327         out bytesReturned, IntPtr.Zero);
   328 
   329       if (!valid) {
   330         name = null;
   331         firmwareRevision = null;
   332         return false;
   333       }
   334 
   335       name = GetString(result.Identify.ModelNumber);
   336       firmwareRevision = GetString(result.Identify.FirmwareRevision);
   337       return true;
   338     }
   339 
   340     public void CloseHandle(IntPtr handle) {
   341       NativeMethods.CloseHandle(handle);
   342     }
   343 
   344     protected static class NativeMethods {
   345       private const string KERNEL = "kernel32.dll";
   346 
   347       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
   348         CharSet = CharSet.Unicode)]
   349       public static extern IntPtr CreateFile(string fileName,
   350         AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
   351         CreationMode creationDisposition, FileAttribute flagsAndAttributes,
   352         IntPtr templateFilehandle);
   353 
   354       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   355       public static extern int CloseHandle(IntPtr handle);
   356 
   357       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   358       [return: MarshalAsAttribute(UnmanagedType.Bool)]
   359       public static extern bool DeviceIoControl(IntPtr handle,
   360         DriveCommand command, ref DriveCommandParameter parameter,
   361         int parameterSize, out DriveSmartReadDataResult result, int resultSize,
   362         out uint bytesReturned, IntPtr overlapped);
   363 
   364       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   365       [return: MarshalAsAttribute(UnmanagedType.Bool)]
   366       public static extern bool DeviceIoControl(IntPtr handle,
   367         DriveCommand command, ref DriveCommandParameter parameter,
   368         int parameterSize, out DriveSmartReadThresholdsResult result, 
   369         int resultSize, out uint bytesReturned, IntPtr overlapped);
   370 
   371       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   372       [return: MarshalAsAttribute(UnmanagedType.Bool)]
   373       public static extern bool DeviceIoControl(IntPtr handle,
   374         DriveCommand command, ref DriveCommandParameter parameter,
   375         int parameterSize, out DriveCommandResult result, int resultSize,
   376         out uint bytesReturned, IntPtr overlapped);
   377 
   378       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   379       [return: MarshalAsAttribute(UnmanagedType.Bool)]
   380       public static extern bool DeviceIoControl(IntPtr handle,
   381         DriveCommand command, ref DriveCommandParameter parameter,
   382         int parameterSize, out DriveIdentifyResult result, int resultSize,
   383         out uint bytesReturned, IntPtr overlapped);
   384     }    
   385   }
   386 }