Added SMART support for Samsung SSDs.
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
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
9 http://www.mozilla.org/MPL/
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.
15 The Original Code is the Open Hardware Monitor code.
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-2012
20 the Initial Developer. All Rights Reserved.
24 Roland Reinl <roland-reinl@gmx.de>
26 Alternatively, the contents of this file may be used under the terms of
27 either the GNU General Public License Version 2 or later (the "GPL"), or
28 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 in which case the provisions of the GPL or the LGPL are applicable instead
30 of those above. If you wish to allow use of your version of this file only
31 under the terms of either the GPL or the LGPL, and not to allow others to
32 use your version of this file under the terms of the MPL, indicate your
33 decision by deleting the provisions above and replace them with the notice
34 and other provisions required by the GPL or the LGPL. If you do not delete
35 the provisions above, a recipient may use your version of this file under
36 the terms of any one of the MPL, the GPL or the LGPL.
41 using System.Collections.Generic;
42 using System.Runtime.InteropServices;
44 namespace OpenHardwareMonitor.Hardware.HDD {
46 internal class WindowsSmart : ISmart {
48 protected enum AccessMode : uint {
56 protected enum ShareMode : uint {
63 protected enum CreationMode : uint {
72 protected enum FileAttribute : uint {
73 Readonly = 0x00000001,
76 Directory = 0x00000010,
80 Temporary = 0x00000100,
81 SparseFile = 0x00000200,
82 ReparsePoint = 0x00000400,
83 Compressed = 0x00000800,
85 NotContentIndexed = 0x00002000,
86 Encrypted = 0x00004000,
89 protected enum DriveCommand : uint {
90 GetVersion = 0x00074080,
91 SendDriveCommand = 0x0007c084,
92 ReceiveDriveData = 0x0007c088
95 protected enum RegisterCommand : byte {
97 /// SMART data requested.
102 /// Identify data is requested.
107 protected enum RegisterFeature : byte {
111 SmartReadData = 0xD0,
114 /// Read SMART thresholds.
116 SmartReadThresholds = 0xD1, /* obsolete */
119 /// Autosave SMART data.
121 SmartAutosave = 0xD2,
124 /// Save SMART attributes.
126 SmartSaveAttr = 0xD3,
129 /// Set SMART to offline immediately.
131 SmartImmediateOffline = 0xD4,
141 SmartWriteLog = 0xD6,
144 /// Write SMART thresholds.
146 SmartWriteThresholds = 0xD7, /* obsolete */
151 SmartEnableOperations = 0xD8,
156 SmartDisableOperations = 0xD9,
159 /// Get SMART status.
164 /// Set SMART to offline automatically.
166 SmartAutoOffline = 0xDB, /* obsolete */
169 [StructLayout(LayoutKind.Sequential, Pack = 1)]
170 protected struct CommandBlockRegisters {
171 public RegisterFeature Features;
172 public byte SectorCount;
177 public RegisterCommand Command;
178 public byte Reserved;
181 [StructLayout(LayoutKind.Sequential, Pack = 1)]
182 protected struct DriveCommandParameter {
183 public uint BufferSize;
184 public CommandBlockRegisters Registers;
185 public byte DriveNumber;
186 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
187 public byte[] Reserved;
190 [StructLayout(LayoutKind.Sequential, Pack = 1)]
191 protected struct DriverStatus {
192 public byte DriverError;
193 public byte IDEError;
194 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
195 public byte[] Reserved;
198 [StructLayout(LayoutKind.Sequential, Pack = 1)]
199 protected struct DriveCommandResult {
200 public uint BufferSize;
201 public DriverStatus DriverStatus;
204 [StructLayout(LayoutKind.Sequential, Pack = 1)]
205 protected struct DriveSmartReadDataResult {
206 public uint BufferSize;
207 public DriverStatus DriverStatus;
209 public byte Reserved;
210 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
211 public DriveAttributeValue[] Attributes;
214 [StructLayout(LayoutKind.Sequential, Pack = 1)]
215 protected struct DriveSmartReadThresholdsResult {
216 public uint BufferSize;
217 public DriverStatus DriverStatus;
219 public byte Reserved;
220 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
221 public DriveThresholdValue[] Thresholds;
224 [StructLayout(LayoutKind.Sequential, Pack = 1)]
225 protected struct Identify {
226 public ushort GeneralConfiguration;
227 public ushort NumberOfCylinders;
228 public ushort Reserved;
229 public ushort NumberOfHeads;
230 public ushort UnformattedBytesPerTrack;
231 public ushort UnformattedBytesPerSector;
232 public ushort SectorsPerTrack;
233 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
234 public ushort[] VendorUnique;
235 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
236 public byte[] SerialNumber;
237 public ushort BufferType;
238 public ushort BufferSectorSize;
239 public ushort NumberOfEccBytes;
240 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
241 public byte[] FirmwareRevision;
242 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
243 public byte[] ModelNumber;
244 public ushort MoreVendorUnique;
245 public ushort DoubleWordIo;
246 public ushort Capabilities;
247 public ushort MoreReserved;
248 public ushort PioCycleTimingMode;
249 public ushort DmaCycleTimingMode;
250 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
254 [StructLayout(LayoutKind.Sequential, Pack = 1)]
255 protected struct DriveIdentifyResult {
256 public uint BufferSize;
257 public DriverStatus DriverStatus;
258 public Identify Identify;
261 public IntPtr InvalidHandle { get { return (IntPtr)(-1); } }
263 private const byte SMART_LBA_MID = 0x4F;
264 private const byte SMART_LBA_HI = 0xC2;
266 private const int MAX_DRIVE_ATTRIBUTES = 512;
268 public IntPtr OpenDrive(int driveNumber) {
269 return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
270 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
271 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
275 public bool EnableSmart(IntPtr handle, int driveNumber) {
276 DriveCommandParameter parameter = new DriveCommandParameter();
277 DriveCommandResult result;
280 parameter.DriveNumber = (byte)driveNumber;
281 parameter.Registers.Features = RegisterFeature.SmartEnableOperations;
282 parameter.Registers.LBAMid = SMART_LBA_MID;
283 parameter.Registers.LBAHigh = SMART_LBA_HI;
284 parameter.Registers.Command = RegisterCommand.SmartCmd;
286 return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand,
287 ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
288 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
292 public DriveAttributeValue[] ReadSmartData(IntPtr handle, int driveNumber) {
293 DriveCommandParameter parameter = new DriveCommandParameter();
294 DriveSmartReadDataResult result;
297 parameter.DriveNumber = (byte)driveNumber;
298 parameter.Registers.Features = RegisterFeature.SmartReadData;
299 parameter.Registers.LBAMid = SMART_LBA_MID;
300 parameter.Registers.LBAHigh = SMART_LBA_HI;
301 parameter.Registers.Command = RegisterCommand.SmartCmd;
303 bool isValid = NativeMethods.DeviceIoControl(handle,
304 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
305 out result, Marshal.SizeOf(typeof(DriveSmartReadDataResult)),
306 out bytesReturned, IntPtr.Zero);
308 return (isValid) ? result.Attributes : new DriveAttributeValue[0];
311 public DriveThresholdValue[] ReadSmartThresholds(IntPtr handle,
314 DriveCommandParameter parameter = new DriveCommandParameter();
315 DriveSmartReadThresholdsResult result;
316 uint bytesReturned = 0;
318 parameter.DriveNumber = (byte)driveNumber;
319 parameter.Registers.Features = RegisterFeature.SmartReadThresholds;
320 parameter.Registers.LBAMid = SMART_LBA_MID;
321 parameter.Registers.LBAHigh = SMART_LBA_HI;
322 parameter.Registers.Command = RegisterCommand.SmartCmd;
324 bool isValid = NativeMethods.DeviceIoControl(handle,
325 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
326 out result, Marshal.SizeOf(typeof(DriveSmartReadThresholdsResult)),
327 out bytesReturned, IntPtr.Zero);
329 return (isValid) ? result.Thresholds : new DriveThresholdValue[0];
332 private string GetString(byte[] bytes) {
333 char[] chars = new char[bytes.Length];
334 for (int i = 0; i < bytes.Length; i += 2) {
335 chars[i] = (char)bytes[i + 1];
336 chars[i + 1] = (char)bytes[i];
338 return new string(chars).Trim(new char[] { ' ', '\0' });
341 public bool ReadNameAndFirmwareRevision(IntPtr handle, int driveNumber,
342 out string name, out string firmwareRevision)
344 DriveCommandParameter parameter = new DriveCommandParameter();
345 DriveIdentifyResult result;
348 parameter.DriveNumber = (byte)driveNumber;
349 parameter.Registers.Command = RegisterCommand.IdCmd;
351 bool valid = NativeMethods.DeviceIoControl(handle,
352 DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
353 out result, Marshal.SizeOf(typeof(DriveIdentifyResult)),
354 out bytesReturned, IntPtr.Zero);
358 firmwareRevision = null;
362 name = GetString(result.Identify.ModelNumber);
363 firmwareRevision = GetString(result.Identify.FirmwareRevision);
367 public void CloseHandle(IntPtr handle) {
368 NativeMethods.CloseHandle(handle);
371 protected static class NativeMethods {
372 private const string KERNEL = "kernel32.dll";
374 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
375 CharSet = CharSet.Unicode)]
376 public static extern IntPtr CreateFile(string fileName,
377 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
378 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
379 IntPtr templateFilehandle);
381 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
382 public static extern int CloseHandle(IntPtr handle);
384 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
385 [return: MarshalAsAttribute(UnmanagedType.Bool)]
386 public static extern bool DeviceIoControl(IntPtr handle,
387 DriveCommand command, ref DriveCommandParameter parameter,
388 int parameterSize, out DriveSmartReadDataResult result, int resultSize,
389 out uint bytesReturned, IntPtr overlapped);
391 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
392 [return: MarshalAsAttribute(UnmanagedType.Bool)]
393 public static extern bool DeviceIoControl(IntPtr handle,
394 DriveCommand command, ref DriveCommandParameter parameter,
395 int parameterSize, out DriveSmartReadThresholdsResult result,
396 int resultSize, out uint bytesReturned, IntPtr overlapped);
398 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
399 [return: MarshalAsAttribute(UnmanagedType.Bool)]
400 public static extern bool DeviceIoControl(IntPtr handle,
401 DriveCommand command, ref DriveCommandParameter parameter,
402 int parameterSize, out DriveCommandResult result, int resultSize,
403 out uint bytesReturned, IntPtr overlapped);
405 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
406 [return: MarshalAsAttribute(UnmanagedType.Bool)]
407 public static extern bool DeviceIoControl(IntPtr handle,
408 DriveCommand command, ref DriveCommandParameter parameter,
409 int parameterSize, out DriveIdentifyResult result, int resultSize,
410 out uint bytesReturned, IntPtr overlapped);