Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Mon, 13 Feb 2012 21:56:29 +0000
changeset 339 07a6126a4796
parent 328 f837f9f0973e
child 340 600962f8a298
permissions -rw-r--r--
Added additional smart attribute identification and a write amplification sensor for Sandforce based SSDs.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     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
     8  
     9   http://www.mozilla.org/MPL/
    10 
    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.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    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.
    21 
    22   Contributor(s): 
    23     Paul Werelds
    24     Roland Reinl <roland-reinl@gmx.de>
    25 
    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.
    37  
    38 */
    39 
    40 using System;
    41 using System.Collections.Generic;
    42 using System.Globalization;
    43 using System.Text;
    44 using OpenHardwareMonitor.Collections;
    45 
    46 namespace OpenHardwareMonitor.Hardware.HDD {
    47   internal abstract class AbstractHarddrive : Hardware {
    48 
    49     private const int UPDATE_DIVIDER = 30; // update only every 30s
    50 
    51     // array of all harddrive types, matching type is searched in this order
    52     private static Type[] hddTypes = {       
    53       typeof(SSDPlextor),
    54       typeof(SSDIntel),
    55       typeof(SSDSandforce),
    56       typeof(SSDIndilinx),
    57       typeof(SSDSamsung),
    58       typeof(GenericHarddisk)
    59     };
    60 
    61     private string firmwareRevision;
    62     private readonly ISmart smart;
    63 
    64     private readonly IntPtr handle;
    65     private readonly int index;
    66     private int count;
    67 
    68     private IList<SmartAttribute> smartAttributes;
    69     private IDictionary<SmartAttribute, Sensor> sensors;
    70 
    71     protected AbstractHarddrive(ISmart smart, string name, 
    72       string firmwareRevision, int index, 
    73       IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
    74       : base(name, new Identifier("hdd",
    75         index.ToString(CultureInfo.InvariantCulture)), settings)
    76     {
    77       this.firmwareRevision = firmwareRevision;
    78       this.smart = smart;
    79       handle = smart.OpenDrive(index);
    80 
    81       smart.EnableSmart(handle, index);
    82 
    83       this.index = index;
    84       this.count = 0;
    85 
    86       this.smartAttributes = new List<SmartAttribute>(smartAttributes);
    87 
    88       CreateSensors();
    89     }
    90 
    91     public static AbstractHarddrive CreateInstance(ISmart smart, 
    92       int driveIndex, ISettings settings) 
    93     {
    94       IntPtr deviceHandle = smart.OpenDrive(driveIndex);
    95 
    96       if (deviceHandle == smart.InvalidHandle) 
    97         return null;
    98 
    99       string name;
   100       string firmwareRevision;
   101       bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
   102         driveIndex, out name, out firmwareRevision);
   103       bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
   104 
   105       DriveAttributeValue[] values = {};
   106       if (smartEnabled)
   107         values = smart.ReadSmartData(deviceHandle, driveIndex);
   108 
   109       smart.CloseHandle(deviceHandle);
   110 
   111       if (!nameValid || string.IsNullOrEmpty(name)) 
   112         return null;
   113 
   114       foreach (Type type in hddTypes) {
   115         // get the array of name prefixes for the current type
   116         NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
   117           typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
   118 
   119         // get the array of the required SMART attributes for the current type
   120         RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
   121           typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
   122 
   123         // check if all required attributes are present
   124         bool allRequiredAttributesFound = true;
   125         foreach (var requireAttribute in requiredAttributes) {
   126           bool adttributeFound = false;
   127           foreach (DriveAttributeValue value in values) {
   128             if (value.Identifier == requireAttribute.AttributeId) {
   129               adttributeFound = true;
   130               break;
   131             }
   132           }
   133           if (!adttributeFound) {
   134             allRequiredAttributesFound = false;
   135             break;
   136           }
   137         }
   138 
   139         // if an attribute is missing, then try the next type
   140         if (!allRequiredAttributesFound)
   141           continue;        
   142 
   143         // check if there is a matching name prefix for this type
   144         foreach (NamePrefixAttribute prefix in namePrefixes) {
   145           if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
   146             return Activator.CreateInstance(type, smart, name, firmwareRevision,
   147               driveIndex, settings) as AbstractHarddrive;
   148         }
   149       }
   150 
   151       // no matching type has been found
   152       return null;
   153     }
   154 
   155     private void CreateSensors() {
   156       sensors = new Dictionary<SmartAttribute, Sensor>();
   157 
   158       IList<Pair<SensorType, int>> sensorTypeAndChannels = 
   159         new List<Pair<SensorType, int>>();
   160 
   161       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   162 
   163       foreach (SmartAttribute attribute in smartAttributes) {
   164         if (!attribute.SensorType.HasValue) 
   165           continue;
   166 
   167         bool found = false;
   168         foreach (DriveAttributeValue value in values) {
   169           if (value.Identifier == attribute.Identifier) {
   170             found = true;
   171             break;
   172           }
   173         }
   174         if (!found)
   175           continue;
   176 
   177         Pair<SensorType, int> pair = new Pair<SensorType, int>(
   178           attribute.SensorType.Value, attribute.SensorChannel);
   179 
   180         if (!sensorTypeAndChannels.Contains(pair)) {
   181           Sensor sensor = new Sensor(attribute.Name, 
   182             attribute.SensorChannel, attribute.SensorType.Value, this, 
   183             settings);
   184 
   185           sensors.Add(attribute, sensor);
   186           ActivateSensor(sensor);
   187           sensorTypeAndChannels.Add(pair);
   188         }     
   189       }
   190     }
   191 
   192     public override HardwareType HardwareType {
   193       get { return HardwareType.HDD; }
   194     }
   195 
   196     public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
   197 
   198     public override void Update() {
   199       if (count == 0) {
   200         DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   201 
   202         foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
   203           SmartAttribute attribute = keyValuePair.Key;          
   204           foreach (DriveAttributeValue value in values) {
   205             if (value.Identifier == attribute.Identifier) {
   206               Sensor sensor = keyValuePair.Value;
   207               sensor.Value = attribute.ConvertValue(value);
   208             }
   209           }
   210         }
   211 
   212         UpdateAdditionalSensors(values);
   213       }
   214 
   215       count++; 
   216       count %= UPDATE_DIVIDER; 
   217     }
   218 
   219     public override string GetReport() {
   220       StringBuilder r = new StringBuilder();
   221       DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
   222       DriveThresholdValue[] thresholds = 
   223         smart.ReadSmartThresholds(handle, index);
   224 
   225       if (values.Length > 0) {
   226         r.AppendLine(this.GetType().Name);
   227         r.AppendLine();
   228         r.AppendLine("Drive name: " + name);
   229         r.AppendLine("Firmware version: " + firmwareRevision);
   230         r.AppendLine();
   231         r.AppendFormat(CultureInfo.InvariantCulture, 
   232           " {0}{1}{2}{3}{4}{5}{6}{7}",
   233           ("ID").PadRight(3),
   234           ("Description").PadRight(35),
   235           ("Raw Value").PadRight(13),
   236           ("Worst").PadRight(6),
   237           ("Value").PadRight(6),
   238           ("Thres").PadRight(6),
   239           ("Physical").PadRight(8),
   240           Environment.NewLine);
   241 
   242         foreach (DriveAttributeValue value in values) {
   243           if (value.Identifier == 0x00) 
   244             break;
   245 
   246           byte? threshold = null;
   247           foreach (DriveThresholdValue t in thresholds) {
   248             if (t.Identifier == value.Identifier) {
   249               threshold = t.Threshold;
   250             }
   251           }
   252 
   253           string description = "Unknown";
   254           float? physical = null;
   255           foreach (SmartAttribute a in smartAttributes) {
   256             if (a.Identifier == value.Identifier) {
   257               description = a.Name;
   258               if (a.HasRawValueConversion | a.SensorType.HasValue)
   259                 physical = a.ConvertValue(value);
   260               else
   261                 physical = null;
   262             }
   263           }
   264 
   265           string raw = BitConverter.ToString(value.RawValue);
   266           r.AppendFormat(CultureInfo.InvariantCulture, 
   267             " {0}{1}{2}{3}{4}{5}{6}{7}",
   268             value.Identifier.ToString("X2").PadRight(3),
   269             description.PadRight(35),
   270             raw.Replace("-", "").PadRight(13),
   271             value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   272             value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
   273             (threshold.HasValue ? threshold.Value.ToString(
   274               CultureInfo.InvariantCulture) : "-").PadRight(6),
   275             (physical.HasValue ? physical.Value.ToString(
   276               CultureInfo.InvariantCulture) : "-").PadRight(8),
   277             Environment.NewLine);
   278         }
   279         r.AppendLine();
   280       }
   281 
   282       return r.ToString();
   283     }
   284 
   285     protected static float RawToInt(byte[] raw, byte value) {
   286       return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
   287     }
   288 
   289     public override void Close() {
   290       smart.CloseHandle(handle);
   291       base.Close();
   292     }
   293 
   294     public override void Traverse(IVisitor visitor) {
   295       foreach (ISensor sensor in Sensors)
   296         sensor.Accept(visitor);
   297     }
   298   }
   299 }