1 /*
2 SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com>
3 SPDX-FileCopyrightText: 2018-2020 Andrius Štikonas <andrius@stikonas.eu>
4
5 SPDX-License-Identifier: GPL-3.0-or-later
6 */
7
8 #include "core/smartdiskinformation.h"
9 #include "core/smartattributeparseddata.h"
10
11 #include <memory>
12 #include <utility>
13
14 static quint64 u64log2(quint64 n);
15
16 /** Creates a new SmartDiskInformationObject */
SmartDiskInformation()17 SmartDiskInformation::SmartDiskInformation() :
18 m_ModelName(QString()),
19 m_FirmwareVersion(QString()),
20 m_SerialNumber(QString()),
21 m_Sectors(0),
22 m_Temperature(0),
23 m_BadSectors(0),
24 m_PoweredOn(0),
25 m_PowerCycles(0),
26 m_SmartStatus(false),
27 m_BadAttributeNow(false),
28 m_BadAttributeInThePast(false),
29 m_SelfTestExecutionStatus(SmartStatus::SelfTestStatus::Success),
30 m_Overall(SmartStatus::Overall::Bad)
31 {
32 }
33
34 /** Update the number of bad sectors based on reallocated sector count and current pending sector attributes data */
updateBadSectors()35 void SmartDiskInformation::updateBadSectors()
36 {
37 std::unique_ptr<SmartAttributeParsedData> reallocatedSectorCt(findAttribute(5));
38 std::unique_ptr<SmartAttributeParsedData> currentPendingSector(findAttribute(197));
39
40 if (!reallocatedSectorCt && !currentPendingSector)
41 m_BadSectors = 0;
42 else if (reallocatedSectorCt && currentPendingSector)
43 m_BadSectors = reallocatedSectorCt->prettyValue() + currentPendingSector->prettyValue();
44 else if (reallocatedSectorCt)
45 m_BadSectors = reallocatedSectorCt->prettyValue();
46 else
47 m_BadSectors = currentPendingSector->prettyValue();
48 }
49
50 /** Update SMART overall data based on the quantity of bad sectors and the status of SMART attributes */
updateOverall()51 void SmartDiskInformation::updateOverall()
52 {
53 if (!smartStatus()) {
54 m_Overall = SmartStatus::Overall::Bad;
55 return;
56 }
57
58 quint64 sector_threshold = u64log2(sectors()) * 1024;
59
60 if (badSectors() >= sector_threshold) {
61 m_Overall = SmartStatus::Overall::BadSectorsMany;
62 return;
63 }
64
65 validateBadAttributes();
66
67 if (m_BadAttributeNow) {
68 m_Overall = SmartStatus::Overall::BadNow;
69 return;
70 }
71
72 if (badSectors() > 0) {
73 m_Overall = SmartStatus::Overall::BadSectors;
74 return;
75 }
76
77 if (m_BadAttributeInThePast) {
78 m_Overall = SmartStatus::Overall::BadPast;
79 return;
80 }
81
82 m_Overall = SmartStatus::Overall::Good;
83 }
84
85 /** Update the temperature value based on SMART attributes
86 @return a boolean representing the status of the operation
87 */
updateTemperature()88 bool SmartDiskInformation::updateTemperature()
89 {
90 std::unique_ptr<SmartAttributeParsedData> temperatureCelsius(findAttribute(231));
91 std::unique_ptr<SmartAttributeParsedData> temperatureCelsius2(findAttribute(194));
92 std::unique_ptr<SmartAttributeParsedData> airflowTemperatureCelsius(findAttribute(190));
93
94 if (temperatureCelsius != nullptr
95 && temperatureCelsius->prettyUnit() == SmartAttributeUnit::Milikelvin) {
96 m_Temperature = temperatureCelsius->prettyValue();
97 return true;
98 } else if (temperatureCelsius2 != nullptr
99 && temperatureCelsius2->prettyUnit() == SmartAttributeUnit::Milikelvin) {
100 m_Temperature = temperatureCelsius2->prettyValue();
101 return true;
102 } else if (airflowTemperatureCelsius != nullptr
103 && airflowTemperatureCelsius->prettyUnit() ==
104 SmartAttributeUnit::Milikelvin) {
105 m_Temperature = airflowTemperatureCelsius->prettyValue();
106 return true;
107 }
108 return false;
109 }
110
111 /** Update the powered on value based on SMART attributes
112 @return a boolean representing the status of the operation
113 */
updatePowerOn()114 bool SmartDiskInformation::updatePowerOn()
115 {
116 std::unique_ptr<SmartAttributeParsedData> powerOnHours(findAttribute(9));
117 std::unique_ptr<SmartAttributeParsedData> powerOnSeconds(findAttribute(233));
118
119 if (powerOnHours != nullptr
120 && powerOnHours->prettyUnit() == SmartAttributeUnit::Miliseconds) {
121 m_PoweredOn = powerOnHours->prettyValue();
122 return true;
123 } else if (powerOnSeconds != nullptr
124 && powerOnSeconds->prettyUnit() == SmartAttributeUnit::Miliseconds) {
125 m_PoweredOn = powerOnSeconds->prettyValue();
126 return true;
127 }
128 return false;
129 }
130
131 /** Update the power cycles value based on SMART attributes
132 @return a boolean representing the status of the operation
133 */
updatePowerCycle()134 bool SmartDiskInformation::updatePowerCycle()
135 {
136 std::unique_ptr<SmartAttributeParsedData> powerCycleCount(findAttribute(12));
137
138 if (powerCycleCount != nullptr
139 && powerCycleCount->prettyUnit() == SmartAttributeUnit::None) {
140 m_PowerCycles = powerCycleCount->prettyValue();
141 return true;
142 }
143 return false;
144 }
145
146 /** Validate disk attributes status */
validateBadAttributes()147 void SmartDiskInformation::validateBadAttributes()
148 {
149 for (const SmartAttributeParsedData &attribute : std::as_const(m_Attributes)) {
150 if (attribute.prefailure()) {
151 if (attribute.goodNowValid() && !attribute.goodNow())
152 m_BadAttributeNow = true;
153 if (attribute.goodInThePastValid() && !attribute.goodInThePast())
154 m_BadAttributeInThePast = true;
155 }
156 }
157 }
158
159 /** Search for a attribute based on its id number
160 @return a reference to the attribute
161 */
findAttribute(quint32 id)162 SmartAttributeParsedData *SmartDiskInformation::findAttribute(quint32 id)
163 {
164 SmartAttributeParsedData *attr = nullptr;
165 for (const SmartAttributeParsedData &attribute : std::as_const(m_Attributes)) {
166 if (id == attribute.id()) {
167 attr = new SmartAttributeParsedData(attribute);
168 break;
169 }
170 }
171 return attr;
172 }
173
u64log2(quint64 n)174 static quint64 u64log2(quint64 n)
175 {
176 quint64 r;
177
178 if (n <= 1)
179 return 0;
180
181 r = 0;
182 for (;;) {
183 n = n >> 1;
184 if (!n)
185 return r;
186 r++;
187 }
188 return 0;
189 }
190