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 +}