File indexing completed on 2024-04-28 05:45:46

0001 /*
0002     SPDX-FileCopyrightText: 2010 Volker Lanz <vl@fidra.de>
0003     SPDX-FileCopyrightText: 2016-2018 Andrius Štikonas <andrius@stikonas.eu>
0004     SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com>
0005     SPDX-FileCopyrightText: 2018 Anthony Fieroni <bvbfan@abv.bg>
0006 
0007     SPDX-License-Identifier: GPL-3.0-or-later
0008 */
0009 
0010 #include "core/smartattribute.h"
0011 #include "core/smartstatus.h"
0012 #include "core/smartattributeparseddata.h"
0013 
0014 #include <QLocale>
0015 
0016 #include <KLocalizedString>
0017 #include <KFormat>
0018 
0019 static QString getAttrName(qint32 id);
0020 static QString getAttrDescription(qint32 id);
0021 static QString getPrettyValue(quint64 value, SmartAttributeUnit unit);
0022 static SmartAttribute::Assessment getAssessment(const SmartAttributeParsedData& a);
0023 static QString getRaw(quint64 raw);
0024 
0025 SmartAttribute::SmartAttribute(const SmartAttributeParsedData& a) :
0026     m_Id(a.id()),
0027     m_Name(getAttrName(a.id())),
0028     m_Desc(getAttrDescription(a.id())),
0029     m_FailureType(a.prefailure() ? FailureType::PreFailure : FailureType::OldAge),
0030     m_UpdateType(a.online() ? UpdateType::Online : UpdateType::Offline),
0031     m_Current(a.currentValueValid() ?  a.currentValue() : -1),
0032     m_Worst(a.worstValueValid() ? a.worstValue() : -1),
0033     m_Threshold(a.thresholdValid() ? a.threshold() : -1),
0034     m_Raw(getRaw(a.raw())),
0035     m_Assessment(getAssessment(a)),
0036     m_Value(getPrettyValue(a.prettyValue(), a.prettyUnit()))
0037 {
0038 
0039 }
0040 
0041 QString SmartAttribute::assessmentToString(Assessment a)
0042 {
0043     switch (a) {
0044     case Assessment::Failing:
0045         return xi18nc("@item:intable", "failing");
0046 
0047     case Assessment::HasFailed:
0048         return xi18nc("@item:intable", "has failed");
0049 
0050     case Assessment::Warning:
0051         return xi18nc("@item:intable", "warning");
0052 
0053     case Assessment::Good:
0054         return xi18nc("@item:intable", "good");
0055 
0056     case Assessment::NotApplicable:
0057     default:
0058         return xi18nc("@item:intable not applicable", "N/A");
0059     }
0060 }
0061 
0062 static QString getPrettyValue(quint64 value, SmartAttributeUnit unit)
0063 {
0064     QString rval;
0065 
0066     switch (unit) {
0067     case SmartAttributeUnit::Miliseconds:
0068         rval = KFormat().formatSpelloutDuration(value);
0069         break;
0070 
0071     case SmartAttributeUnit::Sectors:
0072         rval = xi18ncp("@item:intable", "%1 sector", "%1 sectors", value);
0073         break;
0074 
0075     case SmartAttributeUnit::Milikelvin:
0076         rval = SmartStatus::tempToString(value);
0077         break;
0078 
0079     case SmartAttributeUnit::None:
0080         rval = QLocale().toString(value);
0081         break;
0082 
0083     case SmartAttributeUnit::Unknown:
0084     default:
0085         rval = xi18nc("@item:intable not applicable", "N/A");
0086         break;
0087     }
0088 
0089     return rval;
0090 }
0091 
0092 typedef struct {
0093     qint32 id;
0094     const QString name;
0095     const QString desc;
0096 } AttrDetails;
0097 
0098 static const AttrDetails* attrDetails()
0099 {
0100     static const AttrDetails details[] = {
0101         { 1,  i18nc("SMART attr name", "Read Error Rate"), i18nc("SMART attr description", "Rate of hardware read errors while reading data from the disk surface.")  },
0102         { 2,  i18nc("SMART attr name", "Throughput Performance"), i18nc("SMART attr description", "Overall (general) throughput performance of a hard disk drive. If the value of this attribute is decreasing there is a high probability that there is a problem with the disk.")  },
0103         { 3,  i18nc("SMART attr name", "Spin-Up Time"), i18nc("SMART attr description", "Average time of spindle spin up from zero RPM to fully operational.")  },
0104         { 4,  i18nc("SMART attr name", "Start/Stop Count"), i18nc("SMART attr description", "A tally of spindle start/stop cycles.")  },
0105         { 5,  i18nc("SMART attr name", "Reallocated Sectors Count"), i18nc("SMART attr description", "Count of reallocated sectors. When the hard drive finds a read/write/verification error, it marks this sector as &quot;reallocated&quot; and transfers data to a special reserved area (spare area).")  },
0106         { 6,  i18nc("SMART attr name", "Read Channel Margin"), i18nc("SMART attr description", "Margin of a channel while reading data. The function of this attribute is not specified.")  },
0107         { 7,  i18nc("SMART attr name", "Seek Error Rate"), i18nc("SMART attr description", "Rate of seek errors of the magnetic heads. If there is a partial failure in the mechanical positioning system, then seek errors will arise.")  },
0108         { 8,  i18nc("SMART attr name", "Seek Time Performance"), i18nc("SMART attr description", "Average performance of seek operations of the magnetic heads. If this attribute is decreasing, it is a sign of problems in the mechanical subsystem.")  },
0109         { 9,  i18nc("SMART attr name", "Power-On Hours"), i18nc("SMART attr description", "Count of hours in power-on state.")  },
0110         { 10,  i18nc("SMART attr name", "Spin Retry Count"), i18nc("SMART attr description", "Count of retry of spin start attempts if the first attempt was unsuccessful. An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem.")  },
0111         { 11,  i18nc("SMART attr name", "Recalibration Retries"), i18nc("SMART attr description", "Count of recalibrations requested if the first attempt was unsuccessful. An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem.")  },
0112         { 12,  i18nc("SMART attr name", "Power Cycle Count"), i18nc("SMART attr description", "Count of full hard disk power on/off cycles.")  },
0113         { 13,  i18nc("SMART attr name", "Soft Read Error Rate"), i18nc("SMART attr description", "Uncorrected read errors reported to the operating system.")  },
0114         { 170,  i18nc("SMART attr name", "SSD Available Reserved Space"), i18nc("SMART attr description", "Number of available reserved space as a percentage of reserved space.")  },
0115         { 171,  i18nc("SMART attr name", "SSD Program Fail Count"), i18nc("SMART attr description", "Number of flash program operation failures since the drive was deployed.") },
0116         { 172,  i18nc("SMART attr name", "SSD Erase Fail Count"), i18nc("SMART attr description", "Number of flash erase operation failures since the drive was deployed.") },
0117         { 173,  i18nc("SMART attr name", "SSD Wear Leveling Count"), i18nc("SMART attr description", "Counts the maximum worst erase count on any block.") },
0118         { 174,  i18nc("SMART attr name", "SSD Unexpected power loss count"), i18nc("SMART attr description", "Number of shutdowns without STANDBY IMMEDIATE as the last command (regardless of PLI activity using capacitor power). Normalized value is always 100.") },
0119         { 175,  i18nc("SMART attr name", "SSD Power Loss Protection Failure"), i18nc("SMART attr description", "Last test result, saturated at its maximum value. Bytes 0-1: last test result as microseconds to discharge cap in range [25, 5000000], lower indicates specific error code. Bytes 2-3: minutes since last test. Bytes 4-5: lifetime number of tests. Normalized value is set to 1 on test failure or 11 if the capacitor has been tested in an excessive temperature condition, otherwise 100.") },
0120         { 176,  i18nc("SMART attr name", "SSD Erase Fail Count (chip)"), i18nc("SMART attr description", "Number of flash erase command failures.") },
0121         { 177,  i18nc("SMART attr name", "SSD Wear Range Delta"), i18nc("SMART attr description", "Delta between most-worn and least-worn flash blocks.") },
0122         { 178,  i18nc("SMART attr name", "SSD Used Reserved Block Count Total"), i18nc("SMART attr description", "\"Pre-Fail\" Samsung attribute.") },
0123         { 179,  i18nc("SMART attr name", "SSD Used Reserved Block Count Total"), i18nc("SMART attr description", "\"Pre-Fail\" Samsung attribute.") },
0124         { 180,  i18nc("SMART attr name", "SSD Unused Reserved Block Count Total"), i18nc("SMART attr description", "\"Pre-Fail\" HP attribute.") },
0125         { 181,  i18nc("SMART attr name", "SSD Program Fail Count Total or Non-4K Aligned Access Count"), i18nc("SMART attr description", "Number of flash program operation failures since the drive was deployed.") },
0126         { 182,  i18nc("SMART attr name", "SSD Erase Fail Count"), i18nc("SMART attr description", "\"Pre-Fail\" Samsung attribute.") },
0127         { 183,  i18nc("SMART attr name", "SATA Downshift Error Count"), i18nc("SMART attr description", "Western Digital and Samsung attribute.")  },
0128         { 184,  i18nc("SMART attr name", "End-to-End Error"), i18nc("SMART attr description", "Part of HP's SMART IV technology: After transferring through the cache RAM data buffer the parity data between the host and the hard drive did not match.")  },
0129         { 185,  i18nc("SMART attr name", "Head Stability"), i18nc("SMART attr description", "Western Digital attribute.")  },
0130         { 186,  i18nc("SMART attr name", "Induced Op-Vibration Detection"), i18nc("SMART attr description", "Western Digital attribute.")  },
0131         { 187,  i18nc("SMART attr name", "Reported Uncorrectable Errors"), i18nc("SMART attr description", "Count of errors that could not be recovered using hardware ECC.")  },
0132         { 188,  i18nc("SMART attr name", "Command Timeout"), i18nc("SMART attr description", "Count of aborted operations due to HDD timeout.")  },
0133         { 189,  i18nc("SMART attr name", "High Fly Writes"), i18nc("SMART attr description", "Count of fly height errors detected.")  },
0134         { 190,  i18nc("SMART attr name", "Temperature Difference From 100"), i18nc("SMART attr description", "Value is equal to (100 &ndash; temp. °C), allowing manufacturer to set a minimum threshold which corresponds to a maximum temperature.")  },
0135         { 191,  i18nc("SMART attr name", "G-sense Error Rate"), i18nc("SMART attr description", "Count of errors resulting from externally-induced shock and vibration.")  },
0136         { 192,  i18nc("SMART attr name", "Power Off Retract Count"), i18nc("SMART attr description", "Count of power-off or emergency retract cycles")  },
0137         { 193,  i18nc("SMART attr name", "Load Cycle Count"), i18nc("SMART attr description", "Count of load/unload cycles into head landing zone position.")  },
0138         { 194,  i18nc("SMART attr name", "Temperature"), i18nc("SMART attr description", "Current internal temperature.")  },
0139         { 195,  i18nc("SMART attr name", "Hardware ECC Recovered"), i18nc("SMART attr description", "Count of errors that could be recovered using hardware ECC.")  },
0140         { 196,  i18nc("SMART attr name", "Reallocation Event Count"), i18nc("SMART attr description", "Count of remap operations. The raw value of this attribute shows the total number of attempts to transfer data from reallocated sectors to a spare area.")  },
0141         { 197,  i18nc("SMART attr name", "Current Pending Sector Count"), i18nc("SMART attr description", "Number of &quot;unstable&quot; sectors (waiting to be remapped, because of read errors).")  },
0142         { 198,  i18nc("SMART attr name", "Uncorrectable Sector Count"), i18nc("SMART attr description", "Count of uncorrectable errors when reading/writing a sector.")  },
0143         { 199,  i18nc("SMART attr name", "UltraDMA CRC Error Count"), i18nc("SMART attr description", "Count of errors in data transfer via the interface cable as determined by ICRC.")  },
0144         { 200,  i18nc("SMART attr name", "Multi-Zone Error Rate<br/>Write Error Rate"), i18nc("SMART attr description", "The total number of errors when writing a sector.")  },
0145         { 201,  i18nc("SMART attr name", "Soft Read Error Rate"), i18nc("SMART attr description", "Number of off-track errors.")  },
0146         { 202,  i18nc("SMART attr name", "Data Address Mark Errors"), i18nc("SMART attr description", "Number of Data Address Mark errors (or vendor-specific).")  },
0147         { 203,  i18nc("SMART attr name", "Run Out Cancel"), i18nc("SMART attr description", "Number of ECC errors")  },
0148         { 204,  i18nc("SMART attr name", "Soft ECC Correction"), i18nc("SMART attr description", "Number of errors corrected by software ECC")  },
0149         { 205,  i18nc("SMART attr name", "Thermal Asperity Rate"), i18nc("SMART attr description", "Number of errors due to high temperature.")  },
0150         { 206,  i18nc("SMART attr name", "Flying Height"), i18nc("SMART attr description", "Height of heads above the disk surface. A flying height that is too low increases the chances of a head crash while a flying height that is too high increases the chances of a read/write error.")  },
0151         { 207,  i18nc("SMART attr name", "Spin High Current"), i18nc("SMART attr description", "Amount of surge current used to spin up the drive.")  },
0152         { 208,  i18nc("SMART attr name", "Spin Buzz"), i18nc("SMART attr description", "Number of buzz routines needed to spin up the drive due to insufficient power.")  },
0153         { 209,  i18nc("SMART attr name", "Offline Seek Performance"), i18nc("SMART attr description", "Drive's seek performance during its internal tests.")  },
0154         { 211,  i18nc("SMART attr name", "Vibration During Write"), i18nc("SMART attr description", "Vibration During Write")  },
0155         { 212,  i18nc("SMART attr name", "Shock During Write"), i18nc("SMART attr description", "Shock During Write")  },
0156         { 220,  i18nc("SMART attr name", "Disk Shift"), i18nc("SMART attr description", "Distance the disk has shifted relative to the spindle (usually due to shock or temperature).")  },
0157         { 221,  i18nc("SMART attr name", "G-Sense Error Rate"), i18nc("SMART attr description", "The number of errors resulting from externally-induced shock and vibration.")  },
0158         { 222,  i18nc("SMART attr name", "Loaded Hours"), i18nc("SMART attr description", "Time spent operating under data load.")  },
0159         { 223,  i18nc("SMART attr name", "Load/Unload Retry Count"), i18nc("SMART attr description", "Number of times head changes position.")  },
0160         { 224,  i18nc("SMART attr name", "Load Friction"), i18nc("SMART attr description", "Resistance caused by friction in mechanical parts while operating.")  },
0161         { 225,  i18nc("SMART attr name", "Load/Unload Cycle Count"), i18nc("SMART attr description", "Total number of load cycles.")  },
0162         { 226,  i18nc("SMART attr name", "Load-In Time"), i18nc("SMART attr description", "Total time of loading on the magnetic heads actuator (time not spent in parking area).")  },
0163         { 227,  i18nc("SMART attr name", "Torque Amplification Count"), i18nc("SMART attr description", "Number of attempts to compensate for platter speed variations.")  },
0164         { 228,  i18nc("SMART attr name", "Power-Off Retract Cycle"), i18nc("SMART attr description", "The number of times the magnetic armature was retracted automatically as a result of cutting power.")  },
0165         { 230,  i18nc("SMART attr name", "GMR Head Amplitude"), i18nc("SMART attr description", "Amplitude of &quot;thrashing&quot; (distance of repetitive forward/reverse head motion)")  },
0166         { 231,  i18nc("SMART attr name", "Temperature"), i18nc("SMART attr description", "Drive Temperature")  },
0167         { 232,  i18nc("SMART attr name", "Endurance Remaining"), i18nc("SMART attr description", "Count of physical erase cycles completed on the drive as a percentage of the maximum physical erase cycles the drive supports")  },
0168         { 233,  i18nc("SMART attr name", "Power-On Seconds"), i18nc("SMART attr description", "Time elapsed in the power-on state")  },
0169         { 234,  i18nc("SMART attr name", "Unrecoverable ECC Count"), i18nc("SMART attr description", "Count of unrecoverable ECC errors")  },
0170         { 235,  i18nc("SMART attr name", "Good Block Rate"), i18nc("SMART attr description", "Count of available reserved blocks as percentage of the total number of reserved blocks")  },
0171         { 240,  i18nc("SMART attr name", "Head Flying Hours<br/>or Transfer Error Rate (Fujitsu)"), i18nc("SMART attr description", "Time while head is positioning<br/>or counts the number of times the link is reset during a data transfer.")  },
0172         { 241,  i18nc("SMART attr name", "Total LBAs Written"), i18nc("SMART attr description", "Total LBAs Written")  },
0173         { 242,  i18nc("SMART attr name", "Total LBAs Read"), i18nc("SMART attr description", "Total LBAs Read")  },
0174         { 249,  i18nc("SMART attr name", "SSD NAND_Writes_1GiB"), i18nc("SMART attr description", "Number of writes to NAND in 1 GB increments")  },
0175         { 250,  i18nc("SMART attr name", "Read Error Retry Rate"), i18nc("SMART attr description", "Number of errors while reading from a disk")  },
0176         { 254,  i18nc("SMART attr name", "Free Fall Protection"), i18nc("SMART attr description", "Number of &quot;Free Fall Events&quot; detected") },
0177         { -1, QString(), QString() }
0178     };
0179 
0180     return details;
0181 }
0182 
0183 static QString getAttrName(qint32 id)
0184 {
0185     qint32 idx = 0;
0186 
0187     while (attrDetails()[idx].id != -1) {
0188         if (attrDetails()[idx].id == id)
0189             return attrDetails()[idx].name;
0190         idx++;
0191     }
0192 
0193     return QString();
0194 }
0195 
0196 static QString getAttrDescription(qint32 id)
0197 {
0198     qint32 idx = 0;
0199 
0200     while (attrDetails()[idx].id != -1) {
0201         if (attrDetails()[idx].id == id)
0202             return attrDetails()[idx].desc;
0203         idx++;
0204     }
0205 
0206     return QString();
0207 }
0208 
0209 static SmartAttribute::Assessment getAssessment(const SmartAttributeParsedData& a)
0210 {
0211     SmartAttribute::Assessment rval = SmartAttribute::Assessment::NotApplicable;
0212 
0213     bool failed = false;
0214     bool hasFailed = false;
0215 
0216     if (a.prefailure()) {
0217         if (a.goodNowValid() && !a.goodNow())
0218             failed = true;
0219 
0220         if (a.goodInThePastValid() && !a.goodInThePast())
0221             hasFailed = true;
0222     } else if (a.thresholdValid()) {
0223         if (a.currentValueValid() && a.currentValue() <= a.threshold())
0224             failed = true;
0225         else if (a.worstValueValid() && a.worstValue() <= a.threshold())
0226             hasFailed = true;
0227     }
0228 
0229     if (failed)
0230         rval = SmartAttribute::Assessment::Failing;
0231     else if (hasFailed)
0232         rval = SmartAttribute::Assessment::HasFailed;
0233     else if (a.warn())
0234         rval = SmartAttribute::Assessment::Warning;
0235     else if (a.goodNowValid())
0236         rval = SmartAttribute::Assessment::Good;
0237 
0238     return rval;
0239 }
0240 
0241 static QString getRaw(quint64 raw)
0242 {
0243     QString rval = QStringLiteral("0x");
0244     rval += QStringLiteral("%1").arg(raw, 12, 16, QLatin1Char('0'));
0245     return rval;
0246 }