Added support for SSDs with a controller from Micron.
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/.
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>
14 using System.Collections.Generic;
15 using System.Runtime.InteropServices;
17 namespace OpenHardwareMonitor.Hardware.HDD {
19 internal class WindowsSmart : ISmart {
21 protected enum AccessMode : uint {
29 protected enum ShareMode : uint {
36 protected enum CreationMode : uint {
45 protected enum FileAttribute : uint {
46 Readonly = 0x00000001,
49 Directory = 0x00000010,
53 Temporary = 0x00000100,
54 SparseFile = 0x00000200,
55 ReparsePoint = 0x00000400,
56 Compressed = 0x00000800,
58 NotContentIndexed = 0x00002000,
59 Encrypted = 0x00004000,
62 protected enum DriveCommand : uint {
63 GetVersion = 0x00074080,
64 SendDriveCommand = 0x0007c084,
65 ReceiveDriveData = 0x0007c088
68 protected enum RegisterCommand : byte {
70 /// SMART data requested.
75 /// Identify data is requested.
80 protected enum RegisterFeature : byte {
87 /// Read SMART thresholds.
89 SmartReadThresholds = 0xD1, /* obsolete */
92 /// Autosave SMART data.
97 /// Save SMART attributes.
102 /// Set SMART to offline immediately.
104 SmartImmediateOffline = 0xD4,
114 SmartWriteLog = 0xD6,
117 /// Write SMART thresholds.
119 SmartWriteThresholds = 0xD7, /* obsolete */
124 SmartEnableOperations = 0xD8,
129 SmartDisableOperations = 0xD9,
132 /// Get SMART status.
137 /// Set SMART to offline automatically.
139 SmartAutoOffline = 0xDB, /* obsolete */
142 [StructLayout(LayoutKind.Sequential, Pack = 1)]
143 protected struct CommandBlockRegisters {
144 public RegisterFeature Features;
145 public byte SectorCount;
150 public RegisterCommand Command;
151 public byte Reserved;
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;
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;
171 [StructLayout(LayoutKind.Sequential, Pack = 1)]
172 protected struct DriveCommandResult {
173 public uint BufferSize;
174 public DriverStatus DriverStatus;
177 [StructLayout(LayoutKind.Sequential, Pack = 1)]
178 protected struct DriveSmartReadDataResult {
179 public uint BufferSize;
180 public DriverStatus DriverStatus;
182 public byte Reserved;
183 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
184 public DriveAttributeValue[] Attributes;
187 [StructLayout(LayoutKind.Sequential, Pack = 1)]
188 protected struct DriveSmartReadThresholdsResult {
189 public uint BufferSize;
190 public DriverStatus DriverStatus;
192 public byte Reserved;
193 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
194 public DriveThresholdValue[] Thresholds;
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)]
227 [StructLayout(LayoutKind.Sequential, Pack = 1)]
228 protected struct DriveIdentifyResult {
229 public uint BufferSize;
230 public DriverStatus DriverStatus;
231 public Identify Identify;
234 public IntPtr InvalidHandle { get { return (IntPtr)(-1); } }
236 private const byte SMART_LBA_MID = 0x4F;
237 private const byte SMART_LBA_HI = 0xC2;
239 private const int MAX_DRIVE_ATTRIBUTES = 512;
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,
248 public bool EnableSmart(IntPtr handle, int driveNumber) {
249 DriveCommandParameter parameter = new DriveCommandParameter();
250 DriveCommandResult result;
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;
259 return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand,
260 ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
261 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
265 public DriveAttributeValue[] ReadSmartData(IntPtr handle, int driveNumber) {
266 DriveCommandParameter parameter = new DriveCommandParameter();
267 DriveSmartReadDataResult result;
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;
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);
281 return (isValid) ? result.Attributes : new DriveAttributeValue[0];
284 public DriveThresholdValue[] ReadSmartThresholds(IntPtr handle,
287 DriveCommandParameter parameter = new DriveCommandParameter();
288 DriveSmartReadThresholdsResult result;
289 uint bytesReturned = 0;
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;
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);
302 return (isValid) ? result.Thresholds : new DriveThresholdValue[0];
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];
311 return new string(chars).Trim(new char[] { ' ', '\0' });
314 public bool ReadNameAndFirmwareRevision(IntPtr handle, int driveNumber,
315 out string name, out string firmwareRevision)
317 DriveCommandParameter parameter = new DriveCommandParameter();
318 DriveIdentifyResult result;
321 parameter.DriveNumber = (byte)driveNumber;
322 parameter.Registers.Command = RegisterCommand.IdCmd;
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);
331 firmwareRevision = null;
335 name = GetString(result.Identify.ModelNumber);
336 firmwareRevision = GetString(result.Identify.FirmwareRevision);
340 public void CloseHandle(IntPtr handle) {
341 NativeMethods.CloseHandle(handle);
344 protected static class NativeMethods {
345 private const string KERNEL = "kernel32.dll";
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);
354 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
355 public static extern int CloseHandle(IntPtr handle);
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);
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);
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);
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);