~ubuntu-branches/ubuntu/trusty/libatasmart/trusty

« back to all changes in this revision

Viewing changes to atasmart.strpool.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-08-07 10:13:42 UTC
  • mfrom: (1.2.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090807101342-kl1ri5w9q8niz61d
Tags: 0.14-1
* New upstream version.
* Update *.install, *.symbols, and debian/control for 0 → 4 library soname
  change.
* Add myself to uploaders.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Saved 96 relocations, saved 2 strings (19 b) due to suffix compression. */
 
1
/* Saved 109 relocations, saved 2 strings (19 b) due to suffix compression. */
2
2
static const char _strpool_[] =
3
3
        "16 Byte SCSI ATA SAT Passthru\0"
4
4
        "12 Byte SCSI ATA SAT Passthru\0"
5
 
        "Native Linux ATA\0"
 
5
        "Native Linux IDE\0"
6
6
        "Sunplus SCSI ATA Passthru\0"
7
7
        "JMicron SCSI ATA Passthru\0"
8
8
        "Blob\0"
9
 
        "Unknown\0"
 
9
        "Automatic\0"
 
10
        "None\0"
 
11
        "sat16\0"
 
12
        "sat12\0"
 
13
        "linux-ide\0"
 
14
        "sunplus\0"
 
15
        "jmicron\0"
 
16
        "none\0"
 
17
        "auto\0"
10
18
        "Off-line data collection activity was never started.\0"
11
19
        "Off-line data collection activity was completed without error.\0"
12
20
        "Off-line activity in progress.\0"
82
90
        "194_UNKNOWN\0"
83
91
        "200_WRITEERRORCOUNT\0"
84
92
        "201_DETECTEDTACOUNT\0"
 
93
        "5_UNKNOWN\0"
85
94
        "9_UNKNOWN\0"
 
95
        "197_UNKNOWN\0"
 
96
        "198_UNKNOWN\0"
86
97
        "power-on-minutes\0"
87
98
        "power-on-seconds\0"
88
99
        "power-on-half-minutes\0"
96
107
        "sectors\0"
97
108
        "mK\0"
98
109
        "GOOD\0"
99
 
        "BAD_STATUS\0"
100
 
        "BAD_ATTRIBUTE\0"
101
 
        "BAD_SECTOR\0";
 
110
        "BAD_ATTRIBUTE_IN_THE_PAST\0"
 
111
        "BAD_SECTOR\0"
 
112
        "BAD_ATTRIBUTE_NOW\0"
 
113
        "BAD_SECTOR_MANY\0"
 
114
        "BAD_STATUS\0";
102
115
#ifndef STRPOOL
103
116
#define STRPOOL
104
117
#endif
173
186
        /* These three will be autotested for: */
174
187
        SK_DISK_TYPE_ATA_PASSTHROUGH_12, /* ATA passthrough over SCSI transport, 12-byte version */
175
188
        SK_DISK_TYPE_ATA_PASSTHROUGH_16, /* ATA passthrough over SCSI transport, 16-byte version */
176
 
        SK_DISK_TYPE_ATA,                /* Classic Linux /dev/hda ioctls */
 
189
        SK_DISK_TYPE_LINUX_IDE,          /* Classic Linux /dev/hda ioctls */
177
190
 
178
191
        /* These three will not be autotested for */
179
192
        SK_DISK_TYPE_SUNPLUS,            /* SunPlus USB/ATA bridges */
180
193
        SK_DISK_TYPE_JMICRON,            /* JMicron USB/ATA bridges */
181
 
        SK_DISK_TYPE_BLOB,
182
 
        SK_DISK_TYPE_UNKNOWN,
 
194
        SK_DISK_TYPE_BLOB,               /* From a file */
 
195
        SK_DISK_TYPE_NONE,               /* No access method */
 
196
        SK_DISK_TYPE_AUTO,               /* We don't know yet */
183
197
        _SK_DISK_TYPE_MAX,
184
198
        _SK_DISK_TYPE_TEST_MAX = SK_DISK_TYPE_SUNPLUS /* only auto test until here */
185
199
} SkDiskType;
223
237
        SkBool blob_smart_status:1;
224
238
        SkBool blob_smart_status_valid:1;
225
239
 
 
240
        SkBool attribute_verification_bad:1;
 
241
 
226
242
        SkIdentifyParsedData identify_parsed_data;
227
243
        SkSmartParsedData smart_parsed_data;
228
244
 
247
263
        SK_SMART_COMMAND_RETURN_STATUS = 0xDA
248
264
} SkSmartCommand;
249
265
 
250
 
static const char *disk_type_to_string(SkDiskType type) {
 
266
/* Hmm, if the data we parse is out of a certain range just consider it misparsed */
 
267
#define SK_MKELVIN_VALID_MIN ((uint64_t) ((-15LL*1000LL) + 273150LL))
 
268
#define SK_MKELVIN_VALID_MAX ((uint64_t) ((100LL*1000LL) + 273150LL))
 
269
 
 
270
#define SK_MSECOND_VALID_MIN 1ULL
 
271
#define SK_MSECOND_VALID_SHORT_MAX (60ULL * 60ULL * 1000ULL)
 
272
#define SK_MSECOND_VALID_LONG_MAX (30ULL * 365ULL * 24ULL * 60ULL * 60ULL * 1000ULL)
 
273
 
 
274
static const char *disk_type_to_human_string(SkDiskType type) {
251
275
 
252
276
        /* %STRINGPOOLSTART% */
253
277
        static const char* const map[_SK_DISK_TYPE_MAX] = {
254
278
                [SK_DISK_TYPE_ATA_PASSTHROUGH_16] = ((const char*) 1),
255
279
                [SK_DISK_TYPE_ATA_PASSTHROUGH_12] = ((const char*) 31),
256
 
                [SK_DISK_TYPE_ATA] = ((const char*) 61),
 
280
                [SK_DISK_TYPE_LINUX_IDE] = ((const char*) 61),
257
281
                [SK_DISK_TYPE_SUNPLUS] = ((const char*) 78),
258
282
                [SK_DISK_TYPE_JMICRON] = ((const char*) 104),
259
283
                [SK_DISK_TYPE_BLOB] = ((const char*) 130),
260
 
                [SK_DISK_TYPE_UNKNOWN] = ((const char*) 135)
261
 
        };
262
 
        /* %STRINGPOOLSTOP% */
263
 
 
264
 
        if (type >= _SK_DISK_TYPE_MAX)
265
 
                return NULL;
266
 
 
267
 
        return _P(map[type]);
 
284
                [SK_DISK_TYPE_AUTO] = ((const char*) 135),
 
285
                [SK_DISK_TYPE_NONE] = ((const char*) 145)
 
286
        };
 
287
        /* %STRINGPOOLSTOP% */
 
288
 
 
289
        if (type >= _SK_DISK_TYPE_MAX)
 
290
                return NULL;
 
291
 
 
292
        return _P(map[type]);
 
293
}
 
294
 
 
295
static const char *disk_type_to_prefix_string(SkDiskType type) {
 
296
 
 
297
        /* %STRINGPOOLSTART% */
 
298
        static const char* const map[_SK_DISK_TYPE_MAX] = {
 
299
                [SK_DISK_TYPE_ATA_PASSTHROUGH_16] = ((const char*) 150),
 
300
                [SK_DISK_TYPE_ATA_PASSTHROUGH_12] = ((const char*) 156),
 
301
                [SK_DISK_TYPE_LINUX_IDE] = ((const char*) 162),
 
302
                [SK_DISK_TYPE_SUNPLUS] = ((const char*) 172),
 
303
                [SK_DISK_TYPE_JMICRON] = ((const char*) 180),
 
304
                [SK_DISK_TYPE_NONE] = ((const char*) 188),
 
305
                [SK_DISK_TYPE_AUTO] = ((const char*) 193),
 
306
        };
 
307
        /* %STRINGPOOLSTOP% */
 
308
 
 
309
        if (type >= _SK_DISK_TYPE_MAX)
 
310
                return NULL;
 
311
 
 
312
        return _P(map[type]);
 
313
}
 
314
 
 
315
static const char *disk_type_from_string(const char *s, SkDiskType *type) {
 
316
        unsigned u;
 
317
 
 
318
        assert(s);
 
319
        assert(type);
 
320
 
 
321
        for (u = 0; u < _SK_DISK_TYPE_MAX; u++) {
 
322
                const char *t;
 
323
                size_t l;
 
324
 
 
325
                if (!(t = disk_type_to_prefix_string(u)))
 
326
                        continue;
 
327
 
 
328
                l = strlen(t);
 
329
 
 
330
                if (strncmp(s, t, l))
 
331
                        continue;
 
332
 
 
333
                if (s[l] != ':')
 
334
                        continue;
 
335
 
 
336
                *type = u;
 
337
 
 
338
                return s + l + 1;
 
339
        }
 
340
 
 
341
        return NULL;
268
342
}
269
343
 
270
344
static SkBool disk_smart_is_available(SkDisk *d) {
298
372
        return !!(d->smart_data[367] & 41);
299
373
}
300
374
 
301
 
static int disk_ata_command(SkDisk *d, SkAtaCommand command, SkDirection direction, void* cmd_data, void* data, size_t *len) {
 
375
static int disk_linux_ide_command(SkDisk *d, SkAtaCommand command, SkDirection direction, void* cmd_data, void* data, size_t *len) {
302
376
        uint8_t *bytes = cmd_data;
303
377
        int ret;
304
378
 
305
 
        assert(d->type == SK_DISK_TYPE_ATA);
 
379
        assert(d->type == SK_DISK_TYPE_LINUX_IDE);
306
380
 
307
381
        switch (direction) {
308
382
 
743
817
static int disk_command(SkDisk *d, SkAtaCommand command, SkDirection direction, void* cmd_data, void* data, size_t *len) {
744
818
 
745
819
        static int (* const disk_command_table[_SK_DISK_TYPE_MAX]) (SkDisk *d, SkAtaCommand command, SkDirection direction, void* cmd_data, void* data, size_t *len) = {
746
 
                [SK_DISK_TYPE_ATA] = disk_ata_command,
 
820
                [SK_DISK_TYPE_LINUX_IDE] = disk_linux_ide_command,
747
821
                [SK_DISK_TYPE_ATA_PASSTHROUGH_12] = disk_passthrough_12_command,
748
822
                [SK_DISK_TYPE_ATA_PASSTHROUGH_16] = disk_passthrough_16_command,
749
823
                [SK_DISK_TYPE_SUNPLUS] = disk_sunplus_command,
750
824
                [SK_DISK_TYPE_JMICRON] = disk_jmicron_command,
751
825
                [SK_DISK_TYPE_BLOB] = NULL,
752
 
                [SK_DISK_TYPE_UNKNOWN] = NULL
 
826
                [SK_DISK_TYPE_AUTO] = NULL,
 
827
                [SK_DISK_TYPE_NONE] = NULL
753
828
        };
754
829
 
755
830
        assert(d);
1111
1186
 
1112
1187
        /* %STRINGPOOLSTART% */
1113
1188
        static const char* const map[] = {
1114
 
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_NEVER] = ((const char*) 143),
1115
 
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS] = ((const char*) 196),
1116
 
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS] = ((const char*) 259),
1117
 
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED] = ((const char*) 290),
1118
 
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_ABORTED] = ((const char*) 376),
1119
 
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_FATAL] = ((const char*) 460),
1120
 
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN] = ((const char*) 540)
 
1189
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_NEVER] = ((const char*) 198),
 
1190
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS] = ((const char*) 251),
 
1191
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS] = ((const char*) 314),
 
1192
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED] = ((const char*) 345),
 
1193
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_ABORTED] = ((const char*) 431),
 
1194
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_FATAL] = ((const char*) 515),
 
1195
                [SK_SMART_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN] = ((const char*) 595)
1121
1196
        };
1122
1197
        /* %STRINGPOOLSTOP% */
1123
1198
 
1131
1206
 
1132
1207
        /* %STRINGPOOLSTART% */
1133
1208
        static const char* const map[] = {
1134
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER] = ((const char*) 555),
1135
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED] = ((const char*) 645),
1136
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED] = ((const char*) 692),
1137
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_FATAL] = ((const char*) 777),
1138
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN] = ((const char*) 936),
1139
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL] = ((const char*) 1037),
1140
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO] = ((const char*) 1120),
1141
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ] = ((const char*) 1217),
1142
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING] = ((const char*) 1294),
1143
 
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS] = ((const char*) 1416)
 
1209
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER] = ((const char*) 610),
 
1210
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED] = ((const char*) 700),
 
1211
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED] = ((const char*) 747),
 
1212
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_FATAL] = ((const char*) 832),
 
1213
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN] = ((const char*) 991),
 
1214
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL] = ((const char*) 1092),
 
1215
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO] = ((const char*) 1175),
 
1216
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ] = ((const char*) 1272),
 
1217
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING] = ((const char*) 1349),
 
1218
                [SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS] = ((const char*) 1471)
1144
1219
        };
1145
1220
        /* %STRINGPOOLSTOP% */
1146
1221
 
1229
1304
        else if (!strcmp(a->name, "temperature-centi-celsius"))
1230
1305
                a->pretty_value = (fourtyeight & 0xFFFF)*100 + 273150;
1231
1306
        else if (!strcmp(a->name, "power-on-minutes"))
1232
 
                a->pretty_value = (((uint64_t) a->raw[0]) | (uint64_t) a->raw[1]) * 60 * 1000;
 
1307
                a->pretty_value = fourtyeight * 60 * 1000;
1233
1308
        else if (!strcmp(a->name, "power-on-seconds"))
1234
1309
                a->pretty_value = fourtyeight * 1000;
1235
1310
        else if (!strcmp(a->name, "power-on-half-minutes"))
1237
1312
        else if (!strcmp(a->name, "power-on-hours") ||
1238
1313
                 !strcmp(a->name, "loaded-hours") ||
1239
1314
                 !strcmp(a->name, "head-flying-hours"))
1240
 
                a->pretty_value = fourtyeight * 60 * 60 * 1000;
1241
 
        else if (!strcmp(a->name, "reallocated-sector-count"))
 
1315
                a->pretty_value = (fourtyeight & 0xFFFFFFFFU) * 60 * 60 * 1000;
 
1316
        else if (!strcmp(a->name, "reallocated-sector-count") ||
 
1317
                 !strcmp(a->name, "current-pending-sector"))
1242
1318
                a->pretty_value = fourtyeight & 0xFFFFFFFFU;
1243
1319
        else
1244
1320
                a->pretty_value = fourtyeight;
1245
1321
}
1246
1322
 
 
1323
typedef void (*SkSmartAttributeVerify)(SkDisk *d, SkSmartAttributeParsedData *a);
 
1324
 
1247
1325
typedef struct SkSmartAttributeInfo {
1248
1326
        const char *name;
1249
1327
        SkSmartAttributeUnit unit;
 
1328
        SkSmartAttributeVerify verify;
1250
1329
} SkSmartAttributeInfo;
1251
1330
 
 
1331
static void verify_temperature(SkDisk *d, SkSmartAttributeParsedData *a) {
 
1332
        assert(a);
 
1333
        assert(a->pretty_unit == SK_SMART_ATTRIBUTE_UNIT_MKELVIN);
 
1334
 
 
1335
        if (a->pretty_value < SK_MKELVIN_VALID_MIN ||
 
1336
            a->pretty_value > SK_MKELVIN_VALID_MAX) {
 
1337
                a->pretty_unit = SK_SMART_ATTRIBUTE_UNIT_UNKNOWN;
 
1338
                d->attribute_verification_bad = TRUE;
 
1339
        }
 
1340
}
 
1341
 
 
1342
static void verify_short_time(SkDisk *d, SkSmartAttributeParsedData *a) {
 
1343
        assert(a);
 
1344
        assert(a->pretty_unit == SK_SMART_ATTRIBUTE_UNIT_MSECONDS);
 
1345
 
 
1346
        if (a->pretty_value < SK_MSECOND_VALID_MIN ||
 
1347
            a->pretty_value > SK_MSECOND_VALID_SHORT_MAX) {
 
1348
                a->pretty_unit = SK_SMART_ATTRIBUTE_UNIT_UNKNOWN;
 
1349
                d->attribute_verification_bad = TRUE;
 
1350
        }
 
1351
}
 
1352
 
 
1353
static void verify_long_time(SkDisk *d, SkSmartAttributeParsedData *a) {
 
1354
        assert(a);
 
1355
        assert(a->pretty_unit == SK_SMART_ATTRIBUTE_UNIT_MSECONDS);
 
1356
 
 
1357
        if (a->pretty_value < SK_MSECOND_VALID_MIN ||
 
1358
            a->pretty_value > SK_MSECOND_VALID_LONG_MAX) {
 
1359
                a->pretty_unit = SK_SMART_ATTRIBUTE_UNIT_UNKNOWN;
 
1360
                d->attribute_verification_bad = TRUE;
 
1361
        }
 
1362
}
 
1363
 
 
1364
static void verify_sectors(SkDisk *d, SkSmartAttributeParsedData *a) {
 
1365
        uint64_t max_sectors;
 
1366
 
 
1367
        assert(d);
 
1368
        assert(a);
 
1369
        assert(a->pretty_unit == SK_SMART_ATTRIBUTE_UNIT_SECTORS);
 
1370
 
 
1371
        max_sectors = d->size / 512ULL;
 
1372
 
 
1373
        if (max_sectors > 0 && a->pretty_value > max_sectors) {
 
1374
                a->pretty_value = SK_SMART_ATTRIBUTE_UNIT_UNKNOWN;
 
1375
                d->attribute_verification_bad = TRUE;
 
1376
        } else {
 
1377
                if ((!strcmp(a->name, "reallocated-sector-count") ||
 
1378
                     !strcmp(a->name, "current-pending-sector")) &&
 
1379
                    a->pretty_value > 0)
 
1380
                        a->warn = TRUE;
 
1381
        }
 
1382
}
 
1383
 
1252
1384
/* This data is stolen from smartmontools */
1253
1385
 
1254
1386
/* %STRINGPOOLSTART% */
1255
1387
static const SkSmartAttributeInfo const attribute_info[256] = {
1256
 
        [1]   = { ((const char*) 1446),         SK_SMART_ATTRIBUTE_UNIT_NONE },
1257
 
        [2]   = { ((const char*) 1466),      SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1258
 
        [3]   = { ((const char*) 1489),                SK_SMART_ATTRIBUTE_UNIT_MSECONDS },
1259
 
        [4]   = { ((const char*) 1502),            SK_SMART_ATTRIBUTE_UNIT_NONE },
1260
 
        [5]   = { ((const char*) 1519),    SK_SMART_ATTRIBUTE_UNIT_SECTORS },
1261
 
        [6]   = { ((const char*) 1544),         SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1262
 
        [7]   = { ((const char*) 1564),             SK_SMART_ATTRIBUTE_UNIT_NONE },
1263
 
        [8]   = { ((const char*) 1580),       SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1264
 
        [9]   = { ((const char*) 1602),              SK_SMART_ATTRIBUTE_UNIT_MSECONDS },
1265
 
        [10]  = { ((const char*) 1617),            SK_SMART_ATTRIBUTE_UNIT_NONE },
1266
 
        [11]  = { ((const char*) 1634),     SK_SMART_ATTRIBUTE_UNIT_NONE },
1267
 
        [12]  = { ((const char*) 1658),           SK_SMART_ATTRIBUTE_UNIT_NONE },
1268
 
        [13]  = { ((const char*) 1676),        SK_SMART_ATTRIBUTE_UNIT_NONE },
1269
 
        [187] = { ((const char*) 1697),          SK_SMART_ATTRIBUTE_UNIT_SECTORS },
1270
 
        [189] = { ((const char*) 1716),             SK_SMART_ATTRIBUTE_UNIT_NONE },
1271
 
        [190] = { ((const char*) 1732), SK_SMART_ATTRIBUTE_UNIT_MKELVIN },
1272
 
        [191] = { ((const char*) 1760),          SK_SMART_ATTRIBUTE_UNIT_NONE },
1273
 
        [192] = { ((const char*) 1779),     SK_SMART_ATTRIBUTE_UNIT_NONE },
1274
 
        [193] = { ((const char*) 1803),            SK_SMART_ATTRIBUTE_UNIT_NONE },
1275
 
        [194] = { ((const char*) 1820),       SK_SMART_ATTRIBUTE_UNIT_MKELVIN },
1276
 
        [195] = { ((const char*) 1842),      SK_SMART_ATTRIBUTE_UNIT_NONE },
1277
 
        [196] = { ((const char*) 1865),     SK_SMART_ATTRIBUTE_UNIT_NONE },
1278
 
        [197] = { ((const char*) 1889),      SK_SMART_ATTRIBUTE_UNIT_SECTORS },
1279
 
        [198] = { ((const char*) 1912),       SK_SMART_ATTRIBUTE_UNIT_SECTORS },
1280
 
        [199] = { ((const char*) 1934),        SK_SMART_ATTRIBUTE_UNIT_NONE },
1281
 
        [200] = { ((const char*) 1955),       SK_SMART_ATTRIBUTE_UNIT_NONE },
1282
 
        [201] = { ((const char*) 1977),        SK_SMART_ATTRIBUTE_UNIT_NONE },
1283
 
        [202] = { ((const char*) 1998),           SK_SMART_ATTRIBUTE_UNIT_NONE },
1284
 
        [203] = { ((const char*) 2016),              SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1285
 
        [204] = { ((const char*) 2031),      SK_SMART_ATTRIBUTE_UNIT_NONE },
1286
 
        [205] = { ((const char*) 2054),       SK_SMART_ATTRIBUTE_UNIT_NONE },
1287
 
        [206] = { ((const char*) 2076),               SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1288
 
        [207] = { ((const char*) 2090),           SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1289
 
        [208] = { ((const char*) 2108),                   SK_SMART_ATTRIBUTE_UNIT_UNKNOWN},
1290
 
        [209] = { ((const char*) 2118),    SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1291
 
        [220] = { ((const char*) 2143),                  SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1292
 
        [221] = { ((const char*) 2154),        SK_SMART_ATTRIBUTE_UNIT_NONE },
1293
 
        [222] = { ((const char*) 2175),                SK_SMART_ATTRIBUTE_UNIT_MSECONDS },
1294
 
        [223] = { ((const char*) 2188),            SK_SMART_ATTRIBUTE_UNIT_NONE },
1295
 
        [224] = { ((const char*) 2205),               SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1296
 
        [225] = { ((const char*) 2219),          SK_SMART_ATTRIBUTE_UNIT_NONE },
1297
 
        [226] = { ((const char*) 2238),                SK_SMART_ATTRIBUTE_UNIT_MSECONDS },
1298
 
        [227] = { ((const char*) 2251),              SK_SMART_ATTRIBUTE_UNIT_NONE },
1299
 
        [228] = { ((const char*) 2266),   SK_SMART_ATTRIBUTE_UNIT_NONE },
1300
 
        [230] = { ((const char*) 2292),              SK_SMART_ATTRIBUTE_UNIT_UNKNOWN },
1301
 
        [231] = { ((const char*) 1740),         SK_SMART_ATTRIBUTE_UNIT_MKELVIN },
1302
 
        [240] = { ((const char*) 2307),           SK_SMART_ATTRIBUTE_UNIT_MSECONDS },
1303
 
        [250] = { ((const char*) 2325),       SK_SMART_ATTRIBUTE_UNIT_NONE }
 
1388
        [1]   = { ((const char*) 1501),         SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1389
        [2]   = { ((const char*) 1521),      SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1390
        [3]   = { ((const char*) 1544),                SK_SMART_ATTRIBUTE_UNIT_MSECONDS, verify_short_time },
 
1391
        [4]   = { ((const char*) 1557),            SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1392
        [5]   = { ((const char*) 1574),    SK_SMART_ATTRIBUTE_UNIT_SECTORS,  verify_sectors },
 
1393
        [6]   = { ((const char*) 1599),         SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1394
        [7]   = { ((const char*) 1619),             SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1395
        [8]   = { ((const char*) 1635),       SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1396
        [9]   = { ((const char*) 1657),              SK_SMART_ATTRIBUTE_UNIT_MSECONDS, verify_long_time },
 
1397
        [10]  = { ((const char*) 1672),            SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1398
        [11]  = { ((const char*) 1689),     SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1399
        [12]  = { ((const char*) 1713),           SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1400
        [13]  = { ((const char*) 1731),        SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1401
        [187] = { ((const char*) 1752),          SK_SMART_ATTRIBUTE_UNIT_SECTORS,  verify_sectors },
 
1402
        [189] = { ((const char*) 1771),             SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1403
        [190] = { ((const char*) 1787), SK_SMART_ATTRIBUTE_UNIT_MKELVIN,  verify_temperature },
 
1404
        [191] = { ((const char*) 1815),          SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1405
        [192] = { ((const char*) 1834),     SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1406
        [193] = { ((const char*) 1858),            SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1407
        [194] = { ((const char*) 1875),       SK_SMART_ATTRIBUTE_UNIT_MKELVIN,  verify_temperature },
 
1408
        [195] = { ((const char*) 1897),      SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1409
        [196] = { ((const char*) 1920),     SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1410
        [197] = { ((const char*) 1944),      SK_SMART_ATTRIBUTE_UNIT_SECTORS,  verify_sectors },
 
1411
        [198] = { ((const char*) 1967),       SK_SMART_ATTRIBUTE_UNIT_SECTORS,  verify_sectors },
 
1412
        [199] = { ((const char*) 1989),        SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1413
        [200] = { ((const char*) 2010),       SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1414
        [201] = { ((const char*) 2032),        SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1415
        [202] = { ((const char*) 2053),           SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1416
        [203] = { ((const char*) 2071),              SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1417
        [204] = { ((const char*) 2086),      SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1418
        [205] = { ((const char*) 2109),       SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1419
        [206] = { ((const char*) 2131),               SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1420
        [207] = { ((const char*) 2145),           SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1421
        [208] = { ((const char*) 2163),                   SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1422
        [209] = { ((const char*) 2173),    SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1423
        [220] = { ((const char*) 2198),                  SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1424
        [221] = { ((const char*) 2209),        SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1425
        [222] = { ((const char*) 2230),                SK_SMART_ATTRIBUTE_UNIT_MSECONDS, verify_long_time },
 
1426
        [223] = { ((const char*) 2243),            SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1427
        [224] = { ((const char*) 2260),               SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1428
        [225] = { ((const char*) 2274),          SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1429
        [226] = { ((const char*) 2293),                SK_SMART_ATTRIBUTE_UNIT_MSECONDS, verify_short_time },
 
1430
        [227] = { ((const char*) 2306),              SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1431
        [228] = { ((const char*) 2321),   SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL },
 
1432
        [230] = { ((const char*) 2347),              SK_SMART_ATTRIBUTE_UNIT_UNKNOWN,  NULL },
 
1433
        [231] = { ((const char*) 1795),         SK_SMART_ATTRIBUTE_UNIT_MKELVIN,  verify_temperature },
 
1434
        [240] = { ((const char*) 2362),           SK_SMART_ATTRIBUTE_UNIT_MSECONDS, verify_long_time },
 
1435
        [250] = { ((const char*) 2380),       SK_SMART_ATTRIBUTE_UNIT_NONE,     NULL }
1304
1436
};
1305
1437
/* %STRINGPOOLSTOP% */
1306
1438
 
1307
1439
typedef enum SkSmartQuirk {
1308
 
        SK_SMART_QUIRK_9_POWERONMINUTES = 1,
1309
 
        SK_SMART_QUIRK_9_POWERONSECONDS = 2,
1310
 
        SK_SMART_QUIRK_9_POWERONHALFMINUTES = 4,
1311
 
        SK_SMART_QUIRK_192_EMERGENCYRETRACTCYCLECT = 8,
1312
 
        SK_SMART_QUIRK_193_LOADUNLOAD = 16,
1313
 
        SK_SMART_QUIRK_194_10XCELSIUS = 32,
1314
 
        SK_SMART_QUIRK_194_UNKNOWN = 64,
1315
 
        SK_SMART_QUIRK_200_WRITEERRORCOUNT = 128,
1316
 
        SK_SMART_QUIRK_201_DETECTEDTACOUNT = 256,
1317
 
        SK_SMART_QUIRK_9_UNKNOWN = 512
 
1440
        SK_SMART_QUIRK_9_POWERONMINUTES            = 0x0001,
 
1441
        SK_SMART_QUIRK_9_POWERONSECONDS            = 0x0002,
 
1442
        SK_SMART_QUIRK_9_POWERONHALFMINUTES        = 0x0004,
 
1443
        SK_SMART_QUIRK_192_EMERGENCYRETRACTCYCLECT = 0x0008,
 
1444
        SK_SMART_QUIRK_193_LOADUNLOAD              = 0x0010,
 
1445
        SK_SMART_QUIRK_194_10XCELSIUS              = 0x0020,
 
1446
        SK_SMART_QUIRK_194_UNKNOWN                 = 0x0040,
 
1447
        SK_SMART_QUIRK_200_WRITEERRORCOUNT         = 0x0080,
 
1448
        SK_SMART_QUIRK_201_DETECTEDTACOUNT         = 0x0100,
 
1449
        SK_SMART_QUIRK_5_UNKNOWN                   = 0x0200,
 
1450
        SK_SMART_QUIRK_9_UNKNOWN                   = 0x0400,
 
1451
        SK_SMART_QUIRK_197_UNKNOWN                 = 0x0800,
 
1452
        SK_SMART_QUIRK_198_UNKNOWN                 = 0x1000,
1318
1453
} SkSmartQuirk;
1319
1454
 
1320
1455
/* %STRINGPOOLSTART% */
1321
1456
static const char *quirk_name[] = {
1322
 
        ((const char*) 2347),
1323
 
        ((const char*) 2364),
1324
 
        ((const char*) 2381),
1325
1457
        ((const char*) 2402),
1326
 
        ((const char*) 2430),
1327
 
        ((const char*) 2445),
1328
 
        ((const char*) 2460),
1329
 
        ((const char*) 2472),
1330
 
        ((const char*) 2492),
1331
 
        ((const char*) 2512),
 
1458
        ((const char*) 2419),
 
1459
        ((const char*) 2436),
 
1460
        ((const char*) 2457),
 
1461
        ((const char*) 2485),
 
1462
        ((const char*) 2500),
 
1463
        ((const char*) 2515),
 
1464
        ((const char*) 2527),
 
1465
        ((const char*) 2547),
 
1466
        ((const char*) 2567),
 
1467
        ((const char*) 2577),
 
1468
        ((const char*) 2587),
 
1469
        ((const char*) 2599),
1332
1470
        NULL
1333
1471
};
1334
1472
/* %STRINGPOOLSTOP% */
1341
1479
 
1342
1480
static const SkSmartQuirkDatabase quirk_database[] = { {
1343
1481
 
1344
 
        /*** Seagate */
1345
 
                "^ST9160821AS$",
1346
 
                NULL,
1347
 
                SK_SMART_QUIRK_9_UNKNOWN
1348
 
        }, {
1349
 
 
1350
1482
        /*** Fujitsu */
 
1483
                "^("
 
1484
                "FUJITSU MHY2120BH|"
 
1485
                "FUJITSU MHY2250BH"
 
1486
                ")$",
 
1487
                "^0085000B$", /* seems to be specific to this firmware */
 
1488
                SK_SMART_QUIRK_9_POWERONMINUTES|
 
1489
                SK_SMART_QUIRK_197_UNKNOWN|
 
1490
                SK_SMART_QUIRK_198_UNKNOWN
 
1491
        }, {
1351
1492
                "^FUJITSU MHR2040AT$",
1352
1493
                NULL,
1353
1494
                SK_SMART_QUIRK_9_POWERONSECONDS|
1466
1607
                SK_SMART_QUIRK_9_POWERONMINUTES|
1467
1608
                SK_SMART_QUIRK_193_LOADUNLOAD
1468
1609
        }, {
1469
 
 
 
1610
                "^HTS541010G9SA00$",
 
1611
                "^MBZOC60P$",
 
1612
                SK_SMART_QUIRK_5_UNKNOWN
 
1613
        }, {
1470
1614
                NULL,
1471
1615
                NULL,
1472
1616
                0
1549
1693
        if (quirk) {
1550
1694
                switch (id) {
1551
1695
 
 
1696
                        case 5:
 
1697
                                if (quirk & SK_SMART_QUIRK_5_UNKNOWN)
 
1698
                                        return NULL;
 
1699
 
 
1700
                                break;
 
1701
 
1552
1702
                        case 9:
1553
1703
                                /* %STRINGPOOLSTART% */
1554
1704
                                if (quirk & SK_SMART_QUIRK_9_POWERONMINUTES) {
1555
1705
                                        static const SkSmartAttributeInfo a = {
1556
 
                                                ((const char*) 2522), SK_SMART_ATTRIBUTE_UNIT_MSECONDS
 
1706
                                                ((const char*) 2611), SK_SMART_ATTRIBUTE_UNIT_MSECONDS, verify_long_time
1557
1707
                                        };
1558
1708
                                        return &a;
1559
1709
 
1560
1710
                                } else if (quirk & SK_SMART_QUIRK_9_POWERONSECONDS) {
1561
1711
                                        static const SkSmartAttributeInfo a = {
1562
 
                                                ((const char*) 2539), SK_SMART_ATTRIBUTE_UNIT_MSECONDS
 
1712
                                                ((const char*) 2628), SK_SMART_ATTRIBUTE_UNIT_MSECONDS, verify_long_time
1563
1713
                                        };
1564
1714
                                        return &a;
1565
1715
 
1566
1716
                                } else if (quirk & SK_SMART_QUIRK_9_POWERONHALFMINUTES) {
1567
1717
                                        static const SkSmartAttributeInfo a = {
1568
 
                                                ((const char*) 2556), SK_SMART_ATTRIBUTE_UNIT_MSECONDS
 
1718
                                                ((const char*) 2645), SK_SMART_ATTRIBUTE_UNIT_MSECONDS, verify_long_time
1569
1719
                                        };
1570
1720
                                        return &a;
1571
1721
                                } else if (quirk & SK_SMART_QUIRK_9_UNKNOWN)
1578
1728
                                /* %STRINGPOOLSTART% */
1579
1729
                                if (quirk & SK_SMART_QUIRK_192_EMERGENCYRETRACTCYCLECT) {
1580
1730
                                        static const SkSmartAttributeInfo a = {
1581
 
                                                ((const char*) 2578), SK_SMART_ATTRIBUTE_UNIT_NONE
 
1731
                                                ((const char*) 2667), SK_SMART_ATTRIBUTE_UNIT_NONE, NULL
1582
1732
                                        };
1583
1733
                                        return &a;
1584
1734
                                }
1590
1740
                                /* %STRINGPOOLSTART% */
1591
1741
                                if (quirk & SK_SMART_QUIRK_194_10XCELSIUS) {
1592
1742
                                        static const SkSmartAttributeInfo a = {
1593
 
                                                ((const char*) 2608), SK_SMART_ATTRIBUTE_UNIT_MKELVIN
 
1743
                                                ((const char*) 2697), SK_SMART_ATTRIBUTE_UNIT_MKELVIN, verify_temperature
1594
1744
                                        };
1595
1745
                                        return &a;
1596
1746
                                } else if (quirk & SK_SMART_QUIRK_194_UNKNOWN)
1599
1749
 
1600
1750
                                break;
1601
1751
 
 
1752
                        case 197:
 
1753
                                if (quirk & SK_SMART_QUIRK_197_UNKNOWN)
 
1754
                                        return NULL;
 
1755
 
 
1756
                                break;
 
1757
 
 
1758
                        case 198:
 
1759
                                if (quirk & SK_SMART_QUIRK_198_UNKNOWN)
 
1760
                                        return NULL;
 
1761
 
 
1762
                                break;
 
1763
 
1602
1764
                        case 200:
1603
1765
                                /* %STRINGPOOLSTART% */
1604
1766
                                if (quirk & SK_SMART_QUIRK_200_WRITEERRORCOUNT) {
1605
1767
                                        static const SkSmartAttributeInfo a = {
1606
 
                                                ((const char*) 2634), SK_SMART_ATTRIBUTE_UNIT_NONE
 
1768
                                                ((const char*) 2723), SK_SMART_ATTRIBUTE_UNIT_NONE, NULL
1607
1769
                                        };
1608
1770
                                        return &a;
1609
1771
                                }
1615
1777
                                /* %STRINGPOOLSTART% */
1616
1778
                                if (quirk & SK_SMART_QUIRK_201_DETECTEDTACOUNT) {
1617
1779
                                        static const SkSmartAttributeInfo a = {
1618
 
                                                ((const char*) 2652), SK_SMART_ATTRIBUTE_UNIT_NONE
 
1780
                                                ((const char*) 2741), SK_SMART_ATTRIBUTE_UNIT_NONE, NULL
1619
1781
                                        };
1620
1782
                                        return &a;
1621
1783
                                }
1697
1859
        uint8_t *p;
1698
1860
        unsigned n;
1699
1861
 
1700
 
        if (!d->smart_thresholds_valid) {
1701
 
                a->threshold_valid = FALSE;
1702
 
                return;
1703
 
        }
 
1862
        if (!d->smart_thresholds_valid)
 
1863
                goto fail;
1704
1864
 
1705
1865
        for (n = 0, p = d->smart_thresholds+2; n < 30; n++, p+=12)
1706
1866
                if (p[0] == a->id)
1707
1867
                        break;
1708
1868
 
1709
 
        if (n >= 30) {
1710
 
                a->threshold_valid = FALSE;
1711
 
                a->good_valid = FALSE;
1712
 
                return;
1713
 
        }
 
1869
        if (n >= 30)
 
1870
                goto fail;
1714
1871
 
1715
1872
        a->threshold = p[1];
1716
1873
        a->threshold_valid = p[1] != 0xFE;
1717
1874
 
1718
 
        a->good_valid = FALSE;
1719
 
        a->good = TRUE;
 
1875
        a->good_now_valid = FALSE;
 
1876
        a->good_now = TRUE;
 
1877
        a->good_in_the_past_valid = FALSE;
 
1878
        a->good_in_the_past = TRUE;
1720
1879
 
1721
1880
        /* Always-Fail and Always-Passing thresholds are not relevant
1722
1881
         * for our assessment. */
1723
1882
        if (p[1] >= 1 && p[1] <= 0xFD) {
1724
1883
 
1725
1884
                if (a->worst_value_valid) {
1726
 
                        a->good = a->good && (a->worst_value > a->threshold);
1727
 
                        a->good_valid = TRUE;
 
1885
                        a->good_in_the_past = a->good_in_the_past && (a->worst_value > a->threshold);
 
1886
                        a->good_in_the_past_valid = TRUE;
1728
1887
                }
1729
1888
 
1730
1889
                if (a->current_value_valid) {
1731
 
                        a->good = a->good && (a->current_value > a->threshold);
1732
 
                        a->good_valid = TRUE;
 
1890
                        a->good_now = a->good_now && (a->current_value > a->threshold);
 
1891
                        a->good_now_valid = TRUE;
1733
1892
                }
1734
1893
        }
 
1894
 
 
1895
        a->warn =
 
1896
                (a->good_now_valid && !a->good_now) ||
 
1897
                (a->good_in_the_past_valid && !a->good_in_the_past);
 
1898
 
 
1899
        return;
 
1900
 
 
1901
fail:
 
1902
        a->threshold_valid = FALSE;
 
1903
        a->good_now_valid = FALSE;
 
1904
        a->good_in_the_past_valid = FALSE;
 
1905
        a->warn = FALSE;
1735
1906
}
1736
1907
 
1737
1908
int sk_disk_smart_parse_attributes(SkDisk *d, SkSmartAttributeParseCallback cb, void* userdata) {
1781
1952
 
1782
1953
                find_threshold(d, &a);
1783
1954
 
1784
 
                /* Handle a few fields specially */
1785
 
                if ((!strcmp(a.name, "reallocated-sector-count") ||
1786
 
                     !strcmp(a.name, "current-pending-sector")) &&
1787
 
                    a.pretty_unit == SK_SMART_ATTRIBUTE_UNIT_SECTORS &&
1788
 
                    a.pretty_value > 0) {
1789
 
                        a.good = FALSE;
1790
 
                        a.good_valid = TRUE;
1791
 
                }
 
1955
                if (i && i->verify)
 
1956
                        i->verify(d, &a);
1792
1957
 
1793
1958
                cb(d, &a, userdata);
1794
1959
                free(an);
1807
1972
        const char * const map[] = {
1808
1973
                [SK_SMART_ATTRIBUTE_UNIT_UNKNOWN] = NULL,
1809
1974
                [SK_SMART_ATTRIBUTE_UNIT_NONE] = ((const char*) 30),
1810
 
                [SK_SMART_ATTRIBUTE_UNIT_MSECONDS] = ((const char*) 2670),
1811
 
                [SK_SMART_ATTRIBUTE_UNIT_SECTORS] = ((const char*) 2673),
1812
 
                [SK_SMART_ATTRIBUTE_UNIT_MKELVIN] = ((const char*) 2681)
 
1975
                [SK_SMART_ATTRIBUTE_UNIT_MSECONDS] = ((const char*) 2759),
 
1976
                [SK_SMART_ATTRIBUTE_UNIT_SECTORS] = ((const char*) 2762),
 
1977
                [SK_SMART_ATTRIBUTE_UNIT_MKELVIN] = ((const char*) 2770)
1813
1978
        };
1814
1979
        /* %STRINGPOOLSTOP% */
1815
1980
 
1998
2163
 
1999
2164
        /* %STRINGPOOLSTART% */
2000
2165
        const char * const map[] = {
2001
 
                [SK_SMART_OVERALL_GOOD] = ((const char*) 2684),
2002
 
                [SK_SMART_OVERALL_BAD_STATUS] = ((const char*) 2689),
2003
 
                [SK_SMART_OVERALL_BAD_ATTRIBUTE] = ((const char*) 2700),
2004
 
                [SK_SMART_OVERALL_BAD_SECTOR] = ((const char*) 2714)
 
2166
                [SK_SMART_OVERALL_GOOD] = ((const char*) 2773),
 
2167
                [SK_SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST] = ((const char*) 2778),
 
2168
                [SK_SMART_OVERALL_BAD_SECTOR] = ((const char*) 2804),
 
2169
                [SK_SMART_OVERALL_BAD_ATTRIBUTE_NOW] = ((const char*) 2815),
 
2170
                [SK_SMART_OVERALL_BAD_SECTOR_MANY] = ((const char*) 2833),
 
2171
                [SK_SMART_OVERALL_BAD_STATUS] = ((const char*) 2849),
2005
2172
        };
2006
2173
        /* %STRINGPOOLSTOP% */
2007
2174
 
2011
2178
        return _P(map[overall]);
2012
2179
}
2013
2180
 
2014
 
static void bad_attribute_cb(SkDisk *d, const SkSmartAttributeParsedData *a, SkBool *good) {
2015
 
        if (a->prefailure && a->good_valid && !a->good)
2016
 
                *good = FALSE;
 
2181
static void bad_attribute_now_cb(SkDisk *d, const SkSmartAttributeParsedData *a, SkBool *good) {
 
2182
        if (a->prefailure && a->good_now_valid && !a->good_now)
 
2183
                *good = FALSE;
 
2184
}
 
2185
 
 
2186
static void bad_attribute_in_the_past_cb(SkDisk *d, const SkSmartAttributeParsedData *a, SkBool *good) {
 
2187
        if (a->prefailure && a->good_in_the_past_valid && !a->good_in_the_past)
 
2188
                *good = FALSE;
 
2189
}
 
2190
 
 
2191
static uint64_t u64log2(uint64_t n) {
 
2192
        unsigned r;
 
2193
 
 
2194
        if (n <= 1)
 
2195
                return 0;
 
2196
 
 
2197
        r = 0;
 
2198
        for (;;) {
 
2199
                n = n >> 1;
 
2200
                if (!n)
 
2201
                        return r;
 
2202
                r++;
 
2203
        }
2017
2204
}
2018
2205
 
2019
2206
int sk_disk_smart_get_overall(SkDisk *d, SkSmartOverall *overall) {
2020
2207
        SkBool good;
2021
 
        uint64_t sectors;
 
2208
        uint64_t sectors, sector_threshold;
2022
2209
 
2023
2210
        assert(d);
2024
2211
        assert(overall);
2025
2212
 
 
2213
        /* First, check SMART self-assesment */
2026
2214
        if (sk_disk_smart_status(d, &good) < 0)
2027
2215
                return -1;
2028
2216
 
2031
2219
                return 0;
2032
2220
        }
2033
2221
 
 
2222
        /* Second, check if the number of bad sectors is greater than
 
2223
         * a certain threshold */
2034
2224
        if (sk_disk_smart_get_bad(d, &sectors) < 0) {
2035
2225
                if (errno != ENOENT)
2036
2226
                        return -1;
2037
 
        } else if (sectors > 0) {
 
2227
                sectors = 0;
 
2228
        } else {
 
2229
 
 
2230
                /* We use log2(n_sectors) as a threshold here. We had to pick
 
2231
                 * something, and this makes a bit of sense, or doesn't it? */
 
2232
                sector_threshold = u64log2(d->size/512);
 
2233
 
 
2234
                if (sectors >= sector_threshold) {
 
2235
                        *overall = SK_SMART_OVERALL_BAD_SECTOR_MANY;
 
2236
                        return 0;
 
2237
                }
 
2238
        }
 
2239
 
 
2240
        /* Third, check if any of the SMART attributes is bad */
 
2241
        good = TRUE;
 
2242
        if (sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) bad_attribute_now_cb, &good) < 0)
 
2243
                return -1;
 
2244
 
 
2245
        if (!good) {
 
2246
                *overall = SK_SMART_OVERALL_BAD_ATTRIBUTE_NOW;
 
2247
                return 0;
 
2248
        }
 
2249
 
 
2250
        /* Fourth, check if there are any bad sectors at all */
 
2251
        if (sectors > 0) {
2038
2252
                *overall = SK_SMART_OVERALL_BAD_SECTOR;
2039
2253
                return 0;
2040
2254
        }
2041
2255
 
 
2256
        /* Fifth, check if any of the SMART attributes ever was bad */
2042
2257
        good = TRUE;
2043
 
        if (sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) bad_attribute_cb, &good) < 0)
 
2258
        if (sk_disk_smart_parse_attributes(d, (SkSmartAttributeParseCallback) bad_attribute_in_the_past_cb, &good) < 0)
2044
2259
                return -1;
2045
2260
 
2046
2261
        if (!good) {
2047
 
                *overall = SK_SMART_OVERALL_BAD_ATTRIBUTE;
 
2262
                *overall = SK_SMART_OVERALL_BAD_ATTRIBUTE_IN_THE_PAST;
2048
2263
                return 0;
2049
2264
        }
2050
2265
 
 
2266
        /* Sixth, there's really nothing to complain about, so give it a pass */
2051
2267
        *overall = SK_SMART_OVERALL_GOOD;
2052
2268
        return 0;
2053
2269
}
2127
2343
        snprintf(tc, sizeof(tc), "%3u", a->current_value);
2128
2344
        tc[sizeof(tc)-1] = 0;
2129
2345
 
2130
 
        highlight = a->good_valid && !a->good && isatty(1);
 
2346
        highlight = a->warn && isatty(1);
2131
2347
 
2132
2348
        if (highlight)
2133
2349
                fprintf(stderr, HIGHLIGHT);
2134
2350
 
2135
 
        printf("%3u %-27s %-3s   %-3s   %-3s   %-11s 0x%02x%02x%02x%02x%02x%02x %-7s %-7s %-3s\n",
 
2351
        printf("%3u %-27s %-3s   %-3s   %-3s   %-11s 0x%02x%02x%02x%02x%02x%02x %-7s %-7s %-4s %-4s\n",
2136
2352
               a->id,
2137
2353
               print_name(name, sizeof(name), a->id, a->name),
2138
2354
               a->current_value_valid ? tc : "n/a",
2142
2358
               a->raw[0], a->raw[1], a->raw[2], a->raw[3], a->raw[4], a->raw[5],
2143
2359
               a->prefailure ? "prefail" : "old-age",
2144
2360
               a->online ? "online" : "offline",
2145
 
               a->good_valid ? yes_no(a->good) : "n/a");
 
2361
               a->good_now_valid ? yes_no(a->good_now) : "n/a",
 
2362
               a->good_in_the_past_valid ? yes_no(a->good_in_the_past) : "n/a");
2146
2363
 
2147
2364
        if (highlight)
2148
2365
                fprintf(stderr, ENDHIGHLIGHT);
2155
2372
 
2156
2373
        assert(d);
2157
2374
 
2158
 
        printf("Device: %s\n"
 
2375
        printf("Device: %s%s%s\n"
2159
2376
               "Type: %s\n",
 
2377
               d->name ? disk_type_to_prefix_string(d->type) : "",
 
2378
               d->name ? ":" : "",
2160
2379
               d->name ? d->name : "n/a",
2161
 
               disk_type_to_string(d->type));
 
2380
               disk_type_to_human_string(d->type));
2162
2381
 
2163
2382
        ret = sk_disk_get_size(d, &size);
2164
2383
        if (ret >= 0)
2193
2412
                                printf(" %s", _P(quirk_name[i]));
2194
2413
 
2195
2414
                printf("\n");
2196
 
 
2197
2415
        }
2198
2416
 
2199
2417
        ret = sk_disk_check_sleep_mode(d, &awake);
2208
2426
                uint64_t value, power_on;
2209
2427
 
2210
2428
                ret = sk_disk_smart_status(d, &good);
2211
 
                printf("SMART Disk Health Good: %s\n",
2212
 
                       ret >= 0 ? yes_no(good) : strerror(errno));
2213
 
 
 
2429
                printf("%sSMART Disk Health Good: %s%s\n",
 
2430
                       ret >= 0 && !good ? HIGHLIGHT : "",
 
2431
                       ret >= 0 ? yes_no(good) : strerror(errno),
 
2432
                       ret >= 0 && !good ? ENDHIGHLIGHT : "");
2214
2433
                if ((ret = sk_disk_smart_read_data(d)) < 0)
2215
2434
                        return ret;
2216
2435
 
2268
2487
                else
2269
2488
                        printf("Temperature: %s\n", print_value(pretty, sizeof(pretty), value, SK_SMART_ATTRIBUTE_UNIT_MKELVIN));
2270
2489
 
 
2490
                printf("Attribute Parsing Verification: %s\n",
 
2491
                       d->attribute_verification_bad ? "Bad" : "Good");
 
2492
 
2271
2493
                if (sk_disk_smart_get_overall(d, &overall) < 0)
2272
2494
                        printf("Overall Status: %s\n", strerror(errno));
2273
2495
                else
2276
2498
                               sk_smart_overall_to_string(overall),
2277
2499
                               overall != SK_SMART_OVERALL_GOOD ? ENDHIGHLIGHT : "");
2278
2500
 
2279
 
                printf("%3s %-27s %5s %5s %5s %-11s %-14s %-7s %-7s %-3s\n",
 
2501
                printf("%3s %-27s %5s %5s %5s %-11s %-14s %-7s %-7s %-4s %-4s\n",
2280
2502
                       "ID#",
2281
2503
                       "Name",
2282
2504
                       "Value",
2286
2508
                       "Raw",
2287
2509
                       "Type",
2288
2510
                       "Updates",
2289
 
                       "Good");
 
2511
                       "Good",
 
2512
                       "Good/Past");
2290
2513
 
2291
2514
                if ((ret = sk_disk_smart_parse_attributes(d, disk_dump_attributes, NULL)) < 0)
2292
2515
                        return ret;
2313
2536
        struct udev *udev;
2314
2537
        struct udev_device *dev = NULL, *usb;
2315
2538
        int r = -1;
 
2539
        const char *a;
2316
2540
 
2317
2541
        assert(d);
2318
2542
 
2326
2550
                goto finish;
2327
2551
        }
2328
2552
 
 
2553
        if ((a = udev_device_get_property_value(dev, "ID_ATA_SMART_ACCESS"))) {
 
2554
                unsigned u;
 
2555
 
 
2556
                for (u = 0; u < _SK_DISK_TYPE_MAX; u++) {
 
2557
                        const char *t;
 
2558
 
 
2559
                        if (!(t = disk_type_to_prefix_string(u)))
 
2560
                                continue;
 
2561
 
 
2562
                        if (!strcmp(a, t)) {
 
2563
                                d->type = u;
 
2564
                                r = 0;
 
2565
                                goto finish;
 
2566
                        }
 
2567
                }
 
2568
 
 
2569
                d->type = SK_DISK_TYPE_NONE;
 
2570
                r = 0;
 
2571
                goto finish;
 
2572
        }
 
2573
 
2329
2574
        if ((usb = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"))) {
2330
2575
                const char *product, *vendor;
2331
2576
                uint32_t pid, vid;
2343
2588
                }
2344
2589
 
2345
2590
                if ((vid == 0x0c0b && pid == 0xb159) ||
2346
 
                    (vid == 0x04fc && pid == 0x0c25))
 
2591
                    (vid == 0x04fc && pid == 0x0c25) ||
 
2592
                    (vid == 0x04fc && pid == 0x0c15))
2347
2593
                        d->type = SK_DISK_TYPE_SUNPLUS;
2348
 
                if ((vid == 0x152d && pid == 0x2329) ||
 
2594
                else if ((vid == 0x152d && pid == 0x2329) ||
2349
2595
                    (vid == 0x152d && pid == 0x2336) ||
2350
2596
                    (vid == 0x152d && pid == 0x2338) ||
2351
2597
                    (vid == 0x152d && pid == 0x2339))
2354
2600
                        d->type = SK_DISK_TYPE_ATA_PASSTHROUGH_12;
2355
2601
 
2356
2602
        } else if (udev_device_get_parent_with_subsystem_devtype(dev, "ide", NULL))
2357
 
                d->type = SK_DISK_TYPE_ATA;
 
2603
                d->type = SK_DISK_TYPE_LINUX_IDE;
2358
2604
        else if (udev_device_get_parent_with_subsystem_devtype(dev, "scsi", NULL))
2359
2605
                d->type = SK_DISK_TYPE_ATA_PASSTHROUGH_16;
2360
2606
        else
2361
 
                d->type = SK_DISK_TYPE_UNKNOWN;
 
2607
                d->type = SK_DISK_TYPE_AUTO;
2362
2608
 
2363
2609
        r = 0;
2364
2610
 
2384
2630
                goto fail;
2385
2631
        }
2386
2632
 
2387
 
        if (!name) {
2388
 
                d->fd = -1;
 
2633
        d->fd = -1;
 
2634
        d->size = (uint64_t) -1;
 
2635
 
 
2636
        if (!name)
2389
2637
                d->type = SK_DISK_TYPE_BLOB;
2390
 
                d->size = (uint64_t) -1;
2391
 
        } else {
2392
 
 
2393
 
                if (!(d->name = strdup(name))) {
 
2638
        else {
 
2639
                const char *dn;
 
2640
 
 
2641
                d->type = SK_DISK_TYPE_AUTO;
 
2642
 
 
2643
                if (!(dn = disk_type_from_string(name, &d->type)))
 
2644
                        dn = name;
 
2645
 
 
2646
                if (!(d->name = strdup(dn))) {
2394
2647
                        errno = ENOMEM;
2395
2648
                        goto fail;
2396
2649
                }
2397
2650
 
2398
 
                if ((d->fd = open(name,
 
2651
                if ((d->fd = open(d->name,
2399
2652
                                  O_RDONLY|O_NOCTTY|O_NONBLOCK
2400
2653
#ifdef O_CLOEXEC
2401
2654
                                  |O_CLOEXEC
2426
2679
                }
2427
2680
 
2428
2681
                /* OK, it's a real block device with a size. Now let's find the suitable API */
2429
 
                if ((ret = disk_find_type(d, st.st_rdev)) < 0)
2430
 
                        goto fail;
 
2682
                if (d->type == SK_DISK_TYPE_AUTO)
 
2683
                        if ((ret = disk_find_type(d, st.st_rdev)) < 0)
 
2684
                                goto fail;
2431
2685
 
2432
 
                if (d->type == SK_DISK_TYPE_UNKNOWN) {
 
2686
                if (d->type == SK_DISK_TYPE_AUTO) {
2433
2687
                        /* We have no clue, so let's autotest for a working API */
2434
2688
                        for (d->type = 0; d->type < _SK_DISK_TYPE_TEST_MAX; d->type++)
2435
2689
                                if (disk_identify_device(d) >= 0)
2436
2690
                                        break;
2437
2691
                        if (d->type >= _SK_DISK_TYPE_TEST_MAX)
2438
 
                                d->type = SK_DISK_TYPE_UNKNOWN;
 
2692
                                d->type = SK_DISK_TYPE_NONE;
2439
2693
                } else
2440
2694
                        disk_identify_device(d);
2441
2695