Ticket #1079: scsiprint.cpp

File scsiprint.cpp, 86.9 KB (added by Rick Chen, 6 years ago)
Line 
1/*
2 * scsiprint.cpp
3 *
4 * Home page of code is: http://www.smartmontools.org
5 *
6 * Copyright (C) 2002-11 Bruce Allen
7 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
8 * Copyright (C) 2003-18 Douglas Gilbert <dgilbert@interlog.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13
14#include "config.h"
15#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
16
17#include <inttypes.h>
18#include <stdio.h>
19#include <string.h>
20#include <fcntl.h>
21#include <errno.h>
22
23#include "scsicmds.h"
24#include "atacmds.h" // smart_command_set
25#include "dev_interface.h"
26#include "scsiprint.h"
27#include "smartctl.h"
28#include "utility.h"
29#include "sg_unaligned.h"
30
31#define GBUF_SIZE 65532
32
33const char * scsiprint_c_cvsid = "$Id$"
34 SCSIPRINT_H_CVSID;
35
36
37uint8_t gBuf[GBUF_SIZE];
38#define LOG_RESP_LEN 252
39#define LOG_RESP_LONG_LEN ((62 * 256) + 252)
40#define LOG_RESP_TAPE_ALERT_LEN 0x144
41
42/* Log pages supported */
43static bool gSmartLPage = false; /* Informational Exceptions log page */
44static bool gTempLPage = false;
45static bool gSelfTestLPage = false;
46static bool gStartStopLPage = false;
47static bool gReadECounterLPage = false;
48static bool gWriteECounterLPage = false;
49static bool gVerifyECounterLPage = false;
50static bool gNonMediumELPage = false;
51static bool gLastNErrorEvLPage = false;
52static bool gBackgroundResultsLPage = false;
53static bool gProtocolSpecificLPage = false;
54static bool gTapeAlertsLPage = false;
55static bool gSSMediaLPage = false;
56static bool gFormatStatusLPage = false;
57static bool gEnviroReportingLPage = false;
58static bool gEnviroLimitsLPage = false;
59static bool gUtilizationLPage = false;
60static bool gPendDefectsLPage = false;
61static bool gBackgroundOpLPage = false;
62static bool gLPSMisalignLPage = false;
63
64/* Vendor specific log pages */
65static bool gSeagateCacheLPage = false;
66static bool gSeagateFactoryLPage = false;
67
68/* Mode pages supported */
69static bool gIecMPage = true; /* N.B. assume it until we know otherwise */
70
71/* Remember last successful mode sense/select command */
72static int modese_len = 0;
73
74/* Remember this value from the most recent INQUIRY */
75static int scsi_version;
76#define SCSI_VERSION_SPC_4 0x6
77#define SCSI_VERSION_SPC_5 0x7
78#define SCSI_VERSION_HIGHEST SCSI_VERSION_SPC_5
79
80/* T10 vendor identification. Should match entry in last Annex of SPC
81 * drafts and standards (e.g. SPC-4). */
82static char scsi_vendor[8+1];
83#define T10_VENDOR_SEAGATE "SEAGATE"
84#define T10_VENDOR_HITACHI_1 "HITACHI"
85#define T10_VENDOR_HITACHI_2 "HL-DT-ST"
86#define T10_VENDOR_HITACHI_3 "HGST"
87
88static const char * logSenStr = "Log Sense";
89static const char * logSenRspStr = "Log Sense response";
90
91
92static bool
93seagate_or_hitachi(void)
94{
95 return ((0 == memcmp(scsi_vendor, T10_VENDOR_SEAGATE,
96 strlen(T10_VENDOR_SEAGATE))) ||
97 (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_1,
98 strlen(T10_VENDOR_HITACHI_1))) ||
99 (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_2,
100 strlen(T10_VENDOR_HITACHI_2))) ||
101 (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_3,
102 strlen(T10_VENDOR_HITACHI_3))));
103}
104
105static bool
106all_ffs(const uint8_t * bp, int b_len)
107{
108 if ((NULL == bp) || (b_len <= 0))
109 return false;
110 for (--b_len; b_len >= 0; --b_len) {
111 if (0xff != bp[b_len])
112 return false;
113 }
114 return true;
115}
116
117static void
118scsiGetSupportedLogPages(scsi_device * device)
119{
120 bool got_subpages = false;
121 int k, bump, err, payload_len, num_unreported, num_unreported_spg;
122 const uint8_t * up;
123 uint8_t sup_lpgs[LOG_RESP_LEN];
124
125 memset(gBuf, 0, LOG_RESP_LEN);
126 if ((err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
127 LOG_RESP_LEN, 0))) {
128 if (scsi_debugmode > 0)
129 pout("%s for supported pages failed [%s]\n", logSenStr,
130 scsiErrString(err));
131 /* try one more time with defined length, workaround for the bug #678
132 found with ST8000NM0075/E001 */
133 err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
134 LOG_RESP_LEN, 68); /* 64 max pages + 4b header */
135 if (scsi_debugmode > 0)
136 pout("%s for supported pages failed (second attempt) [%s]\n",
137 logSenStr, scsiErrString(err));
138 if (err)
139 return;
140 memcpy(sup_lpgs, gBuf, LOG_RESP_LEN);
141 } else if ((scsi_version >= SCSI_VERSION_SPC_4) &&
142 (scsi_version <= SCSI_VERSION_HIGHEST)) {
143 /* unclear what code T10 will choose for SPC-6 */
144 memcpy(sup_lpgs, gBuf, LOG_RESP_LEN);
145 if ((err = scsiLogSense(device, SUPPORTED_LPAGES, SUPP_SPAGE_L_SPAGE,
146 gBuf, LOG_RESP_LONG_LEN,
147 -1 /* just single not double fetch */))) {
148 if (scsi_debugmode > 0)
149 pout("%s for supported pages and subpages failed [%s]\n",
150 logSenStr, scsiErrString(err));
151 } else {
152 if (0 == memcmp(gBuf, sup_lpgs, LOG_RESP_LEN)) {
153 if (scsi_debugmode > 0)
154 pout("%s: %s ignored subpage field, bad\n",
155 __func__, logSenRspStr);
156 } else if (! ((0x40 & gBuf[0]) &&
157 (SUPP_SPAGE_L_SPAGE == gBuf[1]))) {
158 if (scsi_debugmode > 0)
159 pout("%s supported subpages is bad SPF=%u SUBPG=%u\n",
160 logSenRspStr, !! (0x40 & gBuf[0]), gBuf[2]);
161 } else
162 got_subpages = true;
163 }
164 } else
165 memcpy(sup_lpgs, gBuf, LOG_RESP_LEN);
166
167 if (got_subpages) {
168 payload_len = sg_get_unaligned_be16(gBuf + 2);
169 bump = 2;
170 up = gBuf + LOGPAGEHDRSIZE;
171 } else {
172 payload_len = sup_lpgs[3];
173 bump = 1;
174 up = sup_lpgs + LOGPAGEHDRSIZE;
175 }
176
177 num_unreported_spg = 0;
178 for (num_unreported = 0, k = 0; k < payload_len; k += bump, up += bump) {
179 uint8_t pg_num = 0x3f & up[0];
180 uint8_t sub_pg_num = (0x40 & up[0]) ? up[1] : 0;
181
182 switch (pg_num)
183 {
184 case SUPPORTED_LPAGES:
185 if (! ((NO_SUBPAGE_L_SPAGE == sub_pg_num) ||
186 (SUPP_SPAGE_L_SPAGE == sub_pg_num))) {
187 if (scsi_debugmode > 1)
188 pout("%s: Strange Log page number: 0x0,0x%x\n",
189 __func__, sub_pg_num);
190 }
191 break;
192 case READ_ERROR_COUNTER_LPAGE:
193 gReadECounterLPage = true;
194 break;
195 case WRITE_ERROR_COUNTER_LPAGE:
196 gWriteECounterLPage = true;
197 break;
198 case VERIFY_ERROR_COUNTER_LPAGE:
199 gVerifyECounterLPage = true;
200 break;
201 case LAST_N_ERROR_EVENTS_LPAGE:
202 gLastNErrorEvLPage = true;
203 break;
204 case NON_MEDIUM_ERROR_LPAGE:
205 gNonMediumELPage = true;
206 break;
207 case TEMPERATURE_LPAGE:
208 if (NO_SUBPAGE_L_SPAGE == sub_pg_num)
209 gTempLPage = true;
210 else if (ENVIRO_REP_L_SPAGE == sub_pg_num)
211 gEnviroReportingLPage = true;
212 else if (ENVIRO_LIMITS_L_SPAGE == sub_pg_num)
213 gEnviroLimitsLPage = true;
214 else {
215 ++num_unreported;
216 ++num_unreported_spg;
217 }
218 break;
219 case STARTSTOP_CYCLE_COUNTER_LPAGE:
220 if (NO_SUBPAGE_L_SPAGE == sub_pg_num)
221 gStartStopLPage = true;
222 else if (UTILIZATION_L_SPAGE == sub_pg_num)
223 gUtilizationLPage = true;
224 else {
225 ++num_unreported;
226 ++num_unreported_spg;
227 }
228 break;
229 case SELFTEST_RESULTS_LPAGE:
230 gSelfTestLPage = true;
231 break;
232 case IE_LPAGE:
233 gSmartLPage = true;
234 break;
235 case BACKGROUND_RESULTS_LPAGE:
236 if (NO_SUBPAGE_L_SPAGE == sub_pg_num)
237 gBackgroundResultsLPage = true;
238 else if (PEND_DEFECTS_L_SPAGE == sub_pg_num)
239 gPendDefectsLPage = true;
240 else if (BACKGROUND_OP_L_SPAGE == sub_pg_num)
241 gBackgroundOpLPage = true;
242 else if (LPS_MISALIGN_L_SPAGE == sub_pg_num)
243 gLPSMisalignLPage = true;
244 else {
245 ++num_unreported;
246 ++num_unreported_spg;
247 }
248 break;
249 case PROTOCOL_SPECIFIC_LPAGE:
250 gProtocolSpecificLPage = true;
251 break;
252 case TAPE_ALERTS_LPAGE:
253 gTapeAlertsLPage = true;
254 break;
255 case SS_MEDIA_LPAGE:
256 gSSMediaLPage = true;
257 break;
258 case FORMAT_STATUS_LPAGE:
259 gFormatStatusLPage = true;
260 break;
261 case SEAGATE_CACHE_LPAGE:
262 if (failuretest_permissive) {
263 gSeagateCacheLPage = true;
264 break;
265 }
266 if (seagate_or_hitachi())
267 gSeagateCacheLPage = true;
268 break;
269 case SEAGATE_FACTORY_LPAGE:
270 if (failuretest_permissive) {
271 gSeagateFactoryLPage = true;
272 break;
273 }
274 if (seagate_or_hitachi())
275 gSeagateFactoryLPage = true;
276 break;
277 default:
278 if (pg_num < 0x30) { /* don't count VS pages */
279 ++num_unreported;
280 if (sub_pg_num > 0)
281 ++num_unreported_spg;
282 }
283 break;
284 }
285 }
286 if (scsi_debugmode > 1)
287 pout("%s: number of unreported (standard) log pages: %d (sub-pages: "
288 "%d)\n", __func__, num_unreported, num_unreported_spg);
289}
290
291/* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
292 (or at least something to report). */
293static int
294scsiGetSmartData(scsi_device * device, bool attribs)
295{
296 uint8_t asc;
297 uint8_t ascq;
298 uint8_t currenttemp = 255;
299 uint8_t triptemp = 255;
300 const char * cp;
301 int err = 0;
302 print_on();
303 if (scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, &ascq,
304 &currenttemp, &triptemp)) {
305 /* error message already announced */
306 print_off();
307 return -1;
308 }
309 print_off();
310 cp = scsiGetIEString(asc, ascq);
311 if (cp) {
312 err = -2;
313 print_on();
314 jout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq);
315 print_off();
316 jglb["smart_status"]["passed"] = false;
317 jglb["smart_status"]["scsi"]["asc"] = asc;
318 jglb["smart_status"]["scsi"]["ascq"] = ascq;
319 jglb["smart_status"]["scsi"]["ie_string"] = cp;
320 }
321 else if (gIecMPage) {
322 jout("SMART Health Status: OK\n");
323 jglb["smart_status"]["passed"] = true;
324 }
325
326 if (attribs && !gTempLPage) {
327 if (255 == currenttemp)
328 pout("Current Drive Temperature: <not available>\n");
329 else {
330 jout("Current Drive Temperature: %d C\n", currenttemp);
331 jglb["temperature"]["current"] = currenttemp;
332 }
333 if (255 == triptemp)
334 pout("Drive Trip Temperature: <not available>\n");
335 else
336 {
337 pout("Drive Trip Temperature: %d C\n", triptemp);
338 jglb["temperature"]["drive_trip"] = triptemp;
339 }
340 }
341 pout("\n");
342 return err;
343}
344
345
346// Returns number of logged errors or zero if none or -1 if fetching
347// TapeAlerts fails
348static const char * const severities = "CWI";
349
350static int
351scsiGetTapeAlertsData(scsi_device * device, int peripheral_type)
352{
353 unsigned short pagelength;
354 unsigned short parametercode;
355 int i, err;
356 const char *s;
357 const char *ts;
358 int failures = 0;
359
360 print_on();
361 if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf,
362 LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) {
363 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
364 print_off();
365 return -1;
366 }
367 if (gBuf[0] != 0x2e) {
368 pout("TapeAlerts %s Failed\n", logSenStr);
369 print_off();
370 return -1;
371 }
372 pagelength = sg_get_unaligned_be16(gBuf + 2);
373
374 for (s=severities; *s; s++) {
375 for (i = 4; i < pagelength; i += 5) {
376 parametercode = sg_get_unaligned_be16(gBuf + i);
377
378 if (gBuf[i + 4]) {
379 ts = SCSI_PT_MEDIUM_CHANGER == peripheral_type ?
380 scsiTapeAlertsChangerDevice(parametercode) :
381 scsiTapeAlertsTapeDevice(parametercode);
382 if (*ts == *s) {
383 if (!failures)
384 pout("TapeAlert Errors (C=Critical, W=Warning, "
385 "I=Informational):\n");
386 pout("[0x%02x] %s\n", parametercode, ts);
387 failures += 1;
388 }
389 }
390 }
391 }
392 print_off();
393
394 if (! failures)
395 pout("TapeAlert: OK\n");
396
397 return failures;
398}
399
400static void
401scsiGetStartStopData(scsi_device * device)
402{
403 int err, len, k, extra;
404 unsigned char * ucp;
405
406 if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf,
407 LOG_RESP_LEN, 0))) {
408 print_on();
409 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
410 print_off();
411 return;
412 }
413 if ((gBuf[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE) {
414 print_on();
415 pout("StartStop %s Failed, page mismatch\n", logSenStr);
416 print_off();
417 return;
418 }
419 len = sg_get_unaligned_be16(gBuf + 2);
420 ucp = gBuf + 4;
421 for (k = len; k > 0; k -= extra, ucp += extra) {
422 if (k < 3) {
423 print_on();
424 pout("StartStop %s: short\n", logSenRspStr);
425 print_off();
426 return;
427 }
428 extra = ucp[3] + 4;
429 int pc = sg_get_unaligned_be16(ucp + 0);
430 uint32_t u = (extra > 7) ? sg_get_unaligned_be32(ucp + 4) : 0;
431 bool is_all_ffs = (extra > 7) ? all_ffs(ucp + 4, 4) : false;
432 switch (pc) {
433 case 1:
434 if (10 == extra)
435 pout("Manufactured in week %.2s of year %.4s\n", ucp + 8,
436 ucp + 4);
437 break;
438 case 2:
439 /* ignore Accounting date */
440 break;
441 case 3:
442 if ((extra > 7) && (! is_all_ffs))
443 pout("Specified cycle count over device lifetime: %u\n", u);
444 break;
445 case 4:
446 if ((extra > 7) && (! is_all_ffs))
447 pout("Accumulated start-stop cycles: %u\n", u);
448 break;
449 case 5:
450 if ((extra > 7) && (! is_all_ffs))
451 pout("Specified load-unload count over device lifetime: "
452 "%u\n", u);
453 break;
454 case 6:
455 if ((extra > 7) && (! is_all_ffs))
456 pout("Accumulated load-unload cycles: %u\n", u);
457 break;
458 default:
459 /* ignore */
460 break;
461 }
462 }
463}
464/* PENDING_DEFECTS_SUBPG [0x15,0x1] introduced: SBC-4 */
465static void
466scsiPrintPendingDefectsLPage(scsi_device * device)
467{
468 int num, pl, pc, err;
469 uint32_t count;
470 const uint8_t * bp;
471 static const char * pDefStr = "Pending Defects";
472 static const char * jname = "pending_defects";
473
474 if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE,
475 PEND_DEFECTS_L_SPAGE, gBuf, LOG_RESP_LONG_LEN,
476 0))) {
477 print_on();
478 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
479 print_off();
480 return;
481 }
482 if (((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) &&
483 (gBuf[1] != PEND_DEFECTS_L_SPAGE)) {
484 print_on();
485 pout("%s %s, page mismatch\n", pDefStr, logSenRspStr);
486 print_off();
487 return;
488 }
489 num = sg_get_unaligned_be16(gBuf + 2);
490 if (num > LOG_RESP_LONG_LEN) {
491 print_on();
492 pout("%s %s too long\n", pDefStr, logSenRspStr);
493 print_off();
494 return;
495 }
496 bp = gBuf + 4;
497 while (num > 3) {
498 pc = sg_get_unaligned_be16(bp + 0);
499 pl = bp[3] + 4;
500 switch (pc) {
501 case 0x0:
502 printf(" Pending defect count:");
503 if ((pl < 8) || (num < 8)) {
504 print_on();
505 pout("%s truncated descriptor\n", pDefStr);
506 print_off();
507 return;
508 }
509 count = sg_get_unaligned_be32(bp + 4);
510 jglb[jname]["count"] = count;
511 if (0 == count)
512 jout("0 %s\n", pDefStr);
513 else if (1 == count)
514 jout("1 Pending Defect, LBA and accumulated_power_on_hours "
515 "follow\n");
516 else
517 jout("%u %s: index, LBA and accumulated_power_on_hours "
518 "follow\n", count, pDefStr);
519 break;
520 default:
521 if ((pl < 16) || (num < 16)) {
522 print_on();
523 pout("%s truncated descriptor\n", pDefStr);
524 print_off();
525 return;
526 }
527 jout(" %4d: 0x%-16" PRIx64 ", %5u\n", pc,
528 sg_get_unaligned_be64(bp + 8), sg_get_unaligned_be32(bp + 4));
529 jglb[jname][pc]["LBA"] = sg_get_unaligned_be64(bp + 8);
530 jglb[jname][pc]["accum_power_on_hours"] =
531 sg_get_unaligned_be32(bp + 4);
532 break;
533 }
534 num -= pl;
535 bp += pl;
536 }
537}
538
539static void
540scsiPrintGrownDefectListLen(scsi_device * device)
541{
542 bool got_rd12;
543 int err, dl_format;
544 unsigned int dl_len, div;
545 static const char * hname = "Read defect list";
546
547 memset(gBuf, 0, 8);
548 if ((err = scsiReadDefect12(device, 0 /* req_plist */, 1 /* req_glist */,
549 4 /* format: bytes from index */,
550 0 /* addr desc index */, gBuf, 8))) {
551 if (2 == err) { /* command not supported */
552 err = scsiReadDefect10(device, 0 /* req_plist */,
553 1 /* req_glist */,
554 4 /* format: bytes from index */, gBuf, 4);
555 if (err) {
556 if (scsi_debugmode > 0) {
557 print_on();
558 pout("%s (10) Failed: %s\n", hname, scsiErrString(err));
559 print_off();
560 }
561 return;
562 } else
563 got_rd12 = 0;
564 } else if (101 == err) /* Defect list not found, leave quietly */
565 return;
566 else {
567 if (scsi_debugmode > 0) {
568 print_on();
569 pout("%s (12) Failed: %s\n", hname, scsiErrString(err));
570 print_off();
571 }
572 return;
573 }
574 } else
575 got_rd12 = true;
576
577 if (got_rd12) {
578 int generation = sg_get_unaligned_be16(gBuf + 2);
579 if ((generation > 1) && (scsi_debugmode > 0)) {
580 print_on();
581 pout("%s (12): generation=%d\n", hname, generation);
582 print_off();
583 }
584 dl_len = sg_get_unaligned_be32(gBuf + 4);
585 } else
586 dl_len = sg_get_unaligned_be16(gBuf + 2);
587 if (0x8 != (gBuf[1] & 0x18)) {
588 print_on();
589 pout("%s: asked for grown list but didn't get it\n", hname);
590 print_off();
591 return;
592 }
593 div = 0;
594 dl_format = (gBuf[1] & 0x7);
595 switch (dl_format) {
596 case 0: /* short block */
597 div = 4;
598 break;
599 case 1: /* extended bytes from index */
600 case 2: /* extended physical sector */
601 /* extended = 1; # might use in future */
602 div = 8;
603 break;
604 case 3: /* long block */
605 case 4: /* bytes from index */
606 case 5: /* physical sector */
607 div = 8;
608 break;
609 default:
610 print_on();
611 pout("defect list format %d unknown\n", dl_format);
612 print_off();
613 break;
614 }
615 if (0 == dl_len)
616 {
617 pout("Elements in grown defect list: 0\n\n");
618 jglb["elements_grown_list"] = 0;
619 }
620 else {
621 if (0 == div)
622 pout("Grown defect list length=%u bytes [unknown "
623 "number of elements]\n\n", dl_len);
624 else
625 {
626 pout("Elements in grown defect list: %u\n\n", dl_len / div);
627 jglb["elements_grown_list"] = dl_len;
628 }
629 }
630}
631
632static void
633scsiPrintSeagateCacheLPage(scsi_device * device)
634{
635 int num, pl, pc, err, len;
636 unsigned char * ucp;
637 uint64_t ull;
638 static const char * seaCacStr = "Seagate Cache";
639
640 if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf,
641 LOG_RESP_LEN, 0))) {
642 if (scsi_debugmode > 0) {
643 print_on();
644 pout("%s %s Failed: %s\n", seaCacStr, logSenStr,
645 scsiErrString(err));
646 print_off();
647 }
648 return;
649 }
650 if ((gBuf[0] & 0x3f) != SEAGATE_CACHE_LPAGE) {
651 if (scsi_debugmode > 0) {
652 print_on();
653 pout("%s %s, page mismatch\n", seaCacStr, logSenRspStr);
654 print_off();
655 }
656 return;
657 }
658 len = sg_get_unaligned_be16(gBuf + 2) + 4;
659 num = len - 4;
660 ucp = &gBuf[0] + 4;
661 while (num > 3) {
662 pc = sg_get_unaligned_be16(ucp + 0);
663 pl = ucp[3] + 4;
664 switch (pc) {
665 case 0: case 1: case 2: case 3: case 4:
666 break;
667 default:
668 if (scsi_debugmode > 0) {
669 print_on();
670 pout("Vendor (%s) lpage has unexpected parameter, skip\n",
671 seaCacStr);
672 print_off();
673 }
674 return;
675 }
676 num -= pl;
677 ucp += pl;
678 }
679 pout("Vendor (%s) information\n", seaCacStr);
680 num = len - 4;
681 ucp = &gBuf[0] + 4;
682 while (num > 3) {
683 pc = sg_get_unaligned_be16(ucp + 0);
684 pl = ucp[3] + 4;
685 switch (pc) {
686 case 0: pout(" Blocks sent to initiator"); break;
687 case 1: pout(" Blocks received from initiator"); break;
688 case 2: pout(" Blocks read from cache and sent to initiator"); break;
689 case 3: pout(" Number of read and write commands whose size "
690 "<= segment size"); break;
691 case 4: pout(" Number of read and write commands whose size "
692 "> segment size"); break;
693 default: pout(" Unknown Seagate parameter code [0x%x]", pc); break;
694 }
695 int k = pl - 4;
696 const int sz_ull = (int)sizeof(ull);
697 unsigned char * xp = ucp + 4;
698 if (k > sz_ull) {
699 xp += (k - sz_ull);
700 k = sz_ull;
701 }
702 ull = sg_get_unaligned_be(k, xp + 0);
703 pout(" = %" PRIu64 "\n", ull);
704 num -= pl;
705 ucp += pl;
706 }
707 pout("\n");
708}
709
710static void
711scsiPrintSeagateFactoryLPage(scsi_device * device)
712{
713 int num, pl, pc, len, err, good, bad;
714 unsigned char * ucp;
715 uint64_t ull;
716 static const char * jname = "format_status";
717
718 if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf,
719 LOG_RESP_LEN, 0))) {
720 if (scsi_debugmode > 0) {
721 print_on();
722 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
723 print_off();
724 }
725 return;
726 }
727 if ((gBuf[0] & 0x3f) != SEAGATE_FACTORY_LPAGE) {
728 if (scsi_debugmode > 0) {
729 print_on();
730 pout("Seagate/Hitachi Factory %s, page mismatch\n", logSenRspStr);
731 print_off();
732 }
733 return;
734 }
735 len = sg_get_unaligned_be16(gBuf + 2) + 4;
736 num = len - 4;
737 ucp = &gBuf[0] + 4;
738 good = 0;
739 bad = 0;
740 while (num > 3) {
741 pc = sg_get_unaligned_be16(ucp + 0);
742 pl = ucp[3] + 4;
743 switch (pc) {
744 case 0: case 8:
745 ++good;
746 break;
747 default:
748 ++bad;
749 break;
750 }
751 num -= pl;
752 ucp += pl;
753 }
754 if ((good < 2) || (bad > 4)) { /* heuristic */
755 if (scsi_debugmode > 0) {
756 print_on();
757 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
758 "unexpected parameters, skip\n");
759 print_off();
760 }
761 return;
762 }
763 pout("Vendor (Seagate/Hitachi) factory information\n");
764 num = len - 4;
765 ucp = &gBuf[0] + 4;
766 while (num > 3) {
767 pc = sg_get_unaligned_be16(ucp + 0);
768 pl = ucp[3] + 4;
769 good = 0;
770 switch (pc) {
771 case 0: pout(" number of hours powered up");
772 jname = "hours_powered_up";
773 good = 1;
774 break;
775 case 8: pout(" number of minutes until next internal SMART test");
776 jname = "minutes_next_smart_test";
777 good = 1;
778 break;
779 default:
780 if (scsi_debugmode > 0) {
781 print_on();
782 pout("Vendor (Seagate/Hitachi) factory lpage: "
783 "unknown parameter code [0x%x]\n", pc);
784 print_off();
785 }
786 break;
787 }
788 if (good) {
789 int k = pl - 4;
790 unsigned char * xp = ucp + 4;
791 if (k > (int)sizeof(ull)) {
792 xp += (k - (int)sizeof(ull));
793 k = (int)sizeof(ull);
794 }
795 ull = sg_get_unaligned_be(k, xp + 0);
796 if (0 == pc)
797 {
798 pout(" = %.2f\n", ull / 60.0 );
799 jglb[jname] = strprintf("%.2f", ull / 60.0);
800 }
801 else
802 {
803 pout(" = %" PRIu64 "\n", ull);
804 jglb[jname] = ull;
805 }
806 }
807 num -= pl;
808 ucp += pl;
809 }
810 pout("\n");
811}
812
813static void
814scsiPrintErrorCounterLog(scsi_device * device)
815{
816 struct scsiErrorCounter errCounterArr[3];
817 struct scsiErrorCounter * ecp;
818 int found[3] = {0, 0, 0};
819
820 if (gReadECounterLPage && (0 == scsiLogSense(device,
821 READ_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
822 scsiDecodeErrCounterPage(gBuf, &errCounterArr[0]);
823 found[0] = 1;
824 }
825 if (gWriteECounterLPage && (0 == scsiLogSense(device,
826 WRITE_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
827 scsiDecodeErrCounterPage(gBuf, &errCounterArr[1]);
828 found[1] = 1;
829 }
830 if (gVerifyECounterLPage && (0 == scsiLogSense(device,
831 VERIFY_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
832 scsiDecodeErrCounterPage(gBuf, &errCounterArr[2]);
833 ecp = &errCounterArr[2];
834 for (int k = 0; k < 7; ++k) {
835 if (ecp->gotPC[k] && ecp->counter[k]) {
836 found[2] = 1;
837 break;
838 }
839 }
840 }
841 if (found[0] || found[1] || found[2]) {
842 pout("Error counter log:\n");
843 pout(" Errors Corrected by Total "
844 "Correction Gigabytes Total\n");
845 pout(" ECC rereads/ errors "
846 "algorithm processed uncorrected\n");
847 pout(" fast | delayed rewrites corrected "
848 "invocations [10^9 bytes] errors\n");
849
850 for (int k = 0; k < 3; ++k) {
851 if (! found[k])
852 continue;
853 ecp = &errCounterArr[k];
854 static const char * const pageNames[3] =
855 {"read: ", "write: ", "verify: "};
856 static const char * jpageNames[3] =
857 {"read", "write", "verify"};
858 pout("%s%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64
859 " %8" PRIu64, pageNames[k], ecp->counter[0],
860 ecp->counter[1], ecp->counter[2], ecp->counter[3],
861 ecp->counter[4]);
862 double processed_gb = ecp->counter[5] / 1000000000.0;
863 pout(" %12.3f %8" PRIu64 "\n", processed_gb,
864 ecp->counter[6]);
865 // Error counter log info
866 jglb["error_counter_log"][jpageNames[k]]["errors_corrected_by_eccfast"] = ecp->counter[0];
867 jglb["error_counter_log"][jpageNames[k]]["errors_corrected_by_eccdelayed"] = ecp->counter[1];
868 jglb["error_counter_log"][jpageNames[k]]["errors_corrected_by_rereads_rewrites"] = ecp->counter[2];
869 jglb["error_counter_log"][jpageNames[k]]["total_errors_corrected"] = ecp->counter[3];
870 jglb["error_counter_log"][jpageNames[k]]["correction_algorithm_invocations"] = ecp->counter[4];
871 jglb["error_counter_log"][jpageNames[k]]["gigabytes_processed"] = strprintf("%.3f", processed_gb);
872 jglb["error_counter_log"][jpageNames[k]]["total_uncorrected_errors"] = ecp->counter[6];
873 }
874 }
875 else
876 pout("Error Counter logging not supported\n");
877 if (gNonMediumELPage && (0 == scsiLogSense(device,
878 NON_MEDIUM_ERROR_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
879 struct scsiNonMediumError nme;
880 scsiDecodeNonMediumErrPage(gBuf, &nme);
881 if (nme.gotPC0)
882 pout("\nNon-medium error count: %8" PRIu64 "\n", nme.counterPC0);
883 if (nme.gotTFE_H)
884 pout("Track following error count [Hitachi]: %8" PRIu64 "\n",
885 nme.counterTFE_H);
886 if (nme.gotPE_H)
887 pout("Positioning error count [Hitachi]: %8" PRIu64 "\n",
888 nme.counterPE_H);
889 }
890 if (gLastNErrorEvLPage &&
891 (0 == scsiLogSense(device, LAST_N_ERROR_EVENTS_LPAGE, 0, gBuf,
892 LOG_RESP_LONG_LEN, 0))) {
893 int num = sg_get_unaligned_be16(gBuf + 2) + 4;
894 int truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
895 if (truncated)
896 num = LOG_RESP_LONG_LEN;
897 unsigned char * ucp = gBuf + 4;
898 num -= 4;
899 if (num < 4)
900 pout("\nNo error events logged\n");
901 else {
902 pout("\nLast n error events log page\n");
903 for (int k = num, pl; k > 0; k -= pl, ucp += pl) {
904 if (k < 3) {
905 pout(" <<short Last n error events log page>>\n");
906 break;
907 }
908 pl = ucp[3] + 4;
909 int pc = sg_get_unaligned_be16(ucp + 0);
910 if (pl > 4) {
911 if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) {
912 pout(" Error event %d:\n", pc);
913 pout(" [binary]:\n");
914 dStrHex((const uint8_t *)ucp + 4, pl - 4, 1);
915 } else if (ucp[2] & 0x1) {
916 pout(" Error event %d:\n", pc);
917 pout(" %.*s\n", pl - 4, (const char *)(ucp + 4));
918 } else {
919 if (scsi_debugmode > 0) {
920 pout(" Error event %d:\n", pc);
921 pout(" [data counter??]:\n");
922 dStrHex((const uint8_t *)ucp + 4, pl - 4, 1);
923 }
924 }
925 }
926 }
927 if (truncated)
928 pout(" >>>> log truncated, fetched %d of %d available "
929 "bytes\n", LOG_RESP_LONG_LEN, truncated);
930 }
931 }
932 pout("\n");
933}
934
935static const char * self_test_code[] = {
936 "Default ",
937 "Background short",
938 "Background long ",
939 "Reserved(3) ",
940 "Abort background",
941 "Foreground short",
942 "Foreground long ",
943 "Reserved(7) "
944};
945
946static const char * self_test_result[] = {
947 "Completed ",
948 "Aborted (by user command)",
949 "Aborted (device reset ?) ",
950 "Unknown error, incomplete",
951 "Completed, segment failed",
952 "Failed in first segment ",
953 "Failed in second segment ",
954 "Failed in segment --> ",
955 "Reserved(8) ",
956 "Reserved(9) ",
957 "Reserved(10) ",
958 "Reserved(11) ",
959 "Reserved(12) ",
960 "Reserved(13) ",
961 "Reserved(14) ",
962 "Self test in progress ..."
963};
964
965// See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
966// Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
967// 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
968// FAILSMART is returned.
969static int
970scsiPrintSelfTest(scsi_device * device)
971{
972 int num, k, err, durationSec;
973 int noheader = 1;
974 int retval = 0;
975 uint8_t * ucp;
976 uint64_t ull;
977 struct scsi_sense_disect sense_info;
978 static const char * hname = "Self-test";
979
980 // check if test is running
981 if (!scsiRequestSense(device, &sense_info) &&
982 (sense_info.asc == 0x04 && sense_info.ascq == 0x09 &&
983 sense_info.progress != -1)) {
984 pout("%s execution status:\t\t%d%% of test remaining\n", hname,
985 100 - ((sense_info.progress * 100) / 65535));
986 }
987
988 if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf,
989 LOG_RESP_SELF_TEST_LEN, 0))) {
990 print_on();
991 pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
992 print_off();
993 return FAILSMART;
994 }
995 if ((gBuf[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
996 print_on();
997 pout("%s %s, page mismatch\n", hname, logSenRspStr);
998 print_off();
999 return FAILSMART;
1000 }
1001 // compute page length
1002 num = sg_get_unaligned_be16(gBuf + 2);
1003 // Log sense page length 0x190 bytes
1004 if (num != 0x190) {
1005 print_on();
1006 pout("%s %s length is 0x%x not 0x190 bytes\n", hname, logSenStr, num);
1007 print_off();
1008 return FAILSMART;
1009 }
1010 // loop through the twenty possible entries
1011 for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) {
1012 // timestamp in power-on hours (or zero if test in progress)
1013 int n = sg_get_unaligned_be16(ucp + 6);
1014
1015 // The spec says "all 20 bytes will be zero if no test" but
1016 // DG has found otherwise. So this is a heuristic.
1017 if ((0 == n) && (0 == ucp[4]))
1018 break;
1019
1020 // only print header if needed
1021 if (noheader) {
1022 pout("SMART %s log\n", hname);
1023 pout("Num Test Status segment "
1024 "LifeTime LBA_first_err [SK ASC ASQ]\n");
1025 pout(" Description number "
1026 "(hours)\n");
1027 noheader=0;
1028 }
1029
1030 // print parameter code (test number) & self-test code text
1031 pout("#%2d %s", sg_get_unaligned_be16(ucp + 0),
1032 self_test_code[(ucp[4] >> 5) & 0x7]);
1033
1034 // check the self-test result nibble, using the self-test results
1035 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
1036 int res;
1037 switch ((res = ucp[4] & 0xf)) {
1038 case 0x3:
1039 // an unknown error occurred while the device server
1040 // was processing the self-test and the device server
1041 // was unable to complete the self-test
1042 retval|=FAILSMART;
1043 break;
1044 case 0x4:
1045 // the self-test completed with a failure in a test
1046 // segment, and the test segment that failed is not
1047 // known
1048 retval|=FAILLOG;
1049 break;
1050 case 0x5:
1051 // the first segment of the self-test failed
1052 retval|=FAILLOG;
1053 break;
1054 case 0x6:
1055 // the second segment of the self-test failed
1056 retval|=FAILLOG;
1057 break;
1058 case 0x7:
1059 // another segment of the self-test failed and which
1060 // test is indicated by the contents of the SELF-TEST
1061 // NUMBER field
1062 retval|=FAILLOG;
1063 break;
1064 default:
1065 break;
1066 }
1067 pout(" %s", self_test_result[res]);
1068
1069 // self-test number identifies test that failed and consists
1070 // of either the number of the segment that failed during
1071 // the test, or the number of the test that failed and the
1072 // number of the segment in which the test was run, using a
1073 // vendor-specific method of putting both numbers into a
1074 // single byte.
1075 if (ucp[5])
1076 pout(" %3d", (int)ucp[5]);
1077 else
1078 pout(" -");
1079
1080 // print time that the self-test was completed
1081 if (n==0 && res==0xf)
1082 // self-test in progress
1083 pout(" NOW");
1084 else
1085 pout(" %5d", n);
1086
1087 // construct 8-byte integer address of first failure
1088 ull = sg_get_unaligned_be64(ucp + 8);
1089 bool is_all_ffs = all_ffs(ucp + 8, 8);
1090 // print Address of First Failure, if sensible
1091 if ((! is_all_ffs) && (res > 0) && (res < 0xf)) {
1092 char buff[32];
1093
1094 // was hex but change to decimal to conform with ATA
1095 snprintf(buff, sizeof(buff), "%" PRIu64, ull);
1096 // snprintf(buff, sizeof(buff), "0x%" PRIx64, ull);
1097 pout("%18s", buff);
1098 } else
1099 pout(" -");
1100
1101 // if sense key nonzero, then print it, along with
1102 // additional sense code and additional sense code qualifier
1103 if (ucp[16] & 0xf)
1104 pout(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]);
1105 else
1106 pout(" [- - -]\n");
1107 }
1108
1109 // if header never printed, then there was no output
1110 if (noheader)
1111 pout("No %ss have been logged\n", hname);
1112 else
1113 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
1114 modese_len)) && (durationSec > 0)) {
1115 pout("\nLong (extended) %s duration: %d seconds "
1116 "[%.1f minutes]\n", hname, durationSec, durationSec / 60.0);
1117 }
1118 pout("\n");
1119 return retval;
1120}
1121
1122static const char * bms_status[] = {
1123 "no scans active",
1124 "scan is active",
1125 "pre-scan is active",
1126 "halted due to fatal error",
1127 "halted due to a vendor specific pattern of error",
1128 "halted due to medium formatted without P-List",
1129 "halted - vendor specific cause",
1130 "halted due to temperature out of range",
1131 "waiting until BMS interval timer expires", /* 8 */
1132};
1133
1134static const char * reassign_status[] = {
1135 "Reserved [0x0]",
1136 "Require Write or Reassign Blocks command",
1137 "Successfully reassigned",
1138 "Reserved [0x3]",
1139 "Reassignment by disk failed",
1140 "Recovered via rewrite in-place",
1141 "Reassigned by app, has valid data",
1142 "Reassigned by app, has no valid data",
1143 "Unsuccessfully reassigned by app", /* 8 */
1144};
1145
1146// See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
1147// Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1148// and up to 2048 events (although would hope to have less). May set
1149// FAILLOG if serious errors detected (in the future).
1150static int
1151scsiPrintBackgroundResults(scsi_device * device)
1152{
1153 int num, j, m, err, truncated;
1154 int noheader = 1;
1155 int firstresult = 1;
1156 int retval = 0;
1157 uint8_t * ucp;
1158 static const char * hname = "Background scan results";
1159
1160 if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf,
1161 LOG_RESP_LONG_LEN, 0))) {
1162 print_on();
1163 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
1164 print_off();
1165 return FAILSMART;
1166 }
1167 if ((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) {
1168 print_on();
1169 pout("%s %s, page mismatch\n", hname, logSenRspStr);
1170 print_off();
1171 return FAILSMART;
1172 }
1173 // compute page length
1174 num = sg_get_unaligned_be16(gBuf + 2) + 4;
1175 if (num < 20) {
1176 print_on();
1177 pout("%s %s length is %d, no scan status\n", hname, logSenStr, num);
1178 print_off();
1179 return FAILSMART;
1180 }
1181 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1182 if (truncated)
1183 num = LOG_RESP_LONG_LEN;
1184 ucp = gBuf + 4;
1185 num -= 4;
1186 while (num > 3) {
1187 int pc = sg_get_unaligned_be16(ucp + 0);
1188 // pcb = ucp[2];
1189 int pl = ucp[3] + 4;
1190 switch (pc) {
1191 case 0:
1192 if (noheader) {
1193 noheader = 0;
1194 pout("%s log\n", hname);
1195 }
1196 pout(" Status: ");
1197 if ((pl < 16) || (num < 16)) {
1198 pout("\n");
1199 break;
1200 }
1201 j = ucp[9];
1202 if (j < (int)(sizeof(bms_status) / sizeof(bms_status[0])))
1203 pout("%s\n", bms_status[j]);
1204 else
1205 pout("unknown [0x%x] background scan status value\n", j);
1206 j = sg_get_unaligned_be32(ucp + 4);
1207 pout(" Accumulated power on time, hours:minutes %d:%02d "
1208 "[%d minutes]\n", (j / 60), (j % 60), j);
1209 jglb["accumulated_power_on_time_minutes"] = j;
1210 pout(" Number of background scans performed: %d, ",
1211 sg_get_unaligned_be16(ucp + 10));
1212 jglb["number_sacns_performed"] = sg_get_unaligned_be16(ucp + 10);
1213 pout("scan progress: %.2f%%\n",
1214 (double)sg_get_unaligned_be16(ucp + 12) * 100.0 / 65536.0);
1215 pout(" Number of background medium scans performed: %d\n",
1216 sg_get_unaligned_be16(ucp + 14));
1217 jglb["number_medium_scans_performed"] = sg_get_unaligned_be16(ucp + 14);
1218 break;
1219 default:
1220 if (noheader) {
1221 noheader = 0;
1222 pout("\n%s log\n", hname);
1223 }
1224 if (firstresult) {
1225 firstresult = 0;
1226 pout("\n # when lba(hex) [sk,asc,ascq] "
1227 "reassign_status\n");
1228 }
1229 pout(" %3d ", pc);
1230 if ((pl < 24) || (num < 24)) {
1231 if (pl < 24)
1232 pout("parameter length >= 24 expected, got %d\n", pl);
1233 break;
1234 }
1235 j = sg_get_unaligned_be32(ucp + 4);
1236 pout("%4d:%02d ", (j / 60), (j % 60));
1237 for (m = 0; m < 8; ++m)
1238 pout("%02x", ucp[16 + m]);
1239 pout(" [%x,%x,%x] ", ucp[8] & 0xf, ucp[9], ucp[10]);
1240 j = (ucp[8] >> 4) & 0xf;
1241 if (j <
1242 (int)(sizeof(reassign_status) / sizeof(reassign_status[0])))
1243 pout("%s\n", reassign_status[j]);
1244 else
1245 pout("Reassign status: reserved [0x%x]\n", j);
1246 break;
1247 }
1248 num -= pl;
1249 ucp += pl;
1250 }
1251 if (truncated)
1252 pout(" >>>> log truncated, fetched %d of %d available "
1253 "bytes\n", LOG_RESP_LONG_LEN, truncated);
1254 pout("\n");
1255 return retval;
1256}
1257
1258// See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1259// Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1260// and up to 2048 events (although would hope to have less). May set
1261// FAILLOG if serious errors detected (in the future).
1262static int
1263scsiPrintSSMedia(scsi_device * device)
1264{
1265 int num, err, truncated;
1266 int retval = 0;
1267 uint8_t * ucp;
1268 static const char * hname = "Solid state media";
1269
1270 if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf,
1271 LOG_RESP_LONG_LEN, 0))) {
1272 print_on();
1273 pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
1274 print_off();
1275 return FAILSMART;
1276 }
1277 if ((gBuf[0] & 0x3f) != SS_MEDIA_LPAGE) {
1278 print_on();
1279 pout("%s %s, page mismatch\n", hname, logSenStr);
1280 print_off();
1281 return FAILSMART;
1282 }
1283 // compute page length
1284 num = sg_get_unaligned_be16(gBuf + 2) + 4;
1285 if (num < 12) {
1286 print_on();
1287 pout("%s %s length is %d, too short\n", hname, logSenStr, num);
1288 print_off();
1289 return FAILSMART;
1290 }
1291 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1292 if (truncated)
1293 num = LOG_RESP_LONG_LEN;
1294 ucp = gBuf + 4;
1295 num -= 4;
1296 while (num > 3) {
1297 int pc = sg_get_unaligned_be16(ucp + 0);
1298 // pcb = ucp[2];
1299 int pl = ucp[3] + 4;
1300 switch (pc) {
1301 case 1:
1302 if (pl < 8) {
1303 print_on();
1304 pout("%s Percentage used endurance indicator parameter "
1305 "too short (pl=%d)\n", hname, pl);
1306 print_off();
1307 return FAILSMART;
1308 }
1309 pout("Percentage used endurance indicator: %d%%\n", ucp[7]);
1310 jglb["percentage_used_endurance_indicator"] = ucp[7];
1311 default: /* ignore other parameter codes */
1312 break;
1313 }
1314 num -= pl;
1315 ucp += pl;
1316 }
1317 return retval;
1318}
1319
1320static int
1321scsiPrintFormatStatus(scsi_device * device)
1322{
1323 bool is_count;
1324 int k, num, err, truncated;
1325 int retval = 0;
1326 uint64_t ull;
1327 uint8_t * ucp;
1328 uint8_t * xp;
1329 const char * jout_str;
1330 const char * jglb_str;
1331 static const char * hname = "Format Status";
1332 static const char * jname = "format_status";
1333
1334 if ((err = scsiLogSense(device, FORMAT_STATUS_LPAGE, 0, gBuf,
1335 LOG_RESP_LONG_LEN, 0))) {
1336 print_on();
1337 jout("%s: Failed [%s]\n", __func__, scsiErrString(err));
1338 print_off();
1339 return FAILSMART;
1340 }
1341 if ((gBuf[0] & 0x3f) != FORMAT_STATUS_LPAGE) {
1342 print_on();
1343 jout("%s %s, page mismatch\n", hname, logSenRspStr);
1344 print_off();
1345 return FAILSMART;
1346 }
1347 // compute page length
1348 num = sg_get_unaligned_be16(gBuf + 2) + 4;
1349 if (num < 12) {
1350 print_on();
1351 jout("%s %s length is %d, too short\n", hname, logSenStr, num);
1352 print_off();
1353 return FAILSMART;
1354 }
1355 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1356 if (truncated)
1357 num = LOG_RESP_LONG_LEN;
1358 ucp = gBuf + 4;
1359 num -= 4;
1360 while (num > 3) {
1361 int pc = sg_get_unaligned_be16(ucp + 0);
1362 // pcb = ucp[2];
1363 int pl = ucp[3] + 4;
1364
1365 is_count = true;
1366 jout_str = "";
1367 jglb_str = "x";
1368 switch (pc) {
1369 case 0:
1370 if (scsi_debugmode > 1) {
1371 if (pl < 5)
1372 jout("Format data out: <empty>\n");
1373 else {
1374 if (all_ffs(ucp + 4, pl - 4))
1375 jout("Format data out: <not available>\n");
1376 else {
1377 jout("Format data out:\n");
1378 dStrHex((const uint8_t *)ucp + 4, pl - 4, 0);
1379 }
1380 }
1381 }
1382 is_count = false;
1383 break;
1384 case 1:
1385 jout_str = "Grown defects during certification";
1386 jglb_str = "grown_defects_during_cert";
1387 break;
1388 case 2:
1389 jout_str = "Total blocks reassigned during format";
1390 jglb_str = "blocks_reassigned_during_format";
1391 break;
1392 case 3:
1393 jout_str = "Total new blocks reassigned";
1394 jglb_str = "total_new_block_since_format";
1395 break;
1396 case 4:
1397 jout_str = "Power on minutes since format";
1398 jglb_str = "power_on_minutes_since_format";
1399 break;
1400 default:
1401 if (scsi_debugmode > 3) {
1402 pout(" Unknown Format parameter code = 0x%x\n", pc);
1403 dStrHex((const uint8_t *)ucp, pl, 0);
1404 }
1405 is_count = false;
1406 break;
1407 }
1408 if (is_count) {
1409 k = pl - 4;
1410 xp = ucp + 4;
1411 if (all_ffs(xp, k)) {
1412 jout("%s <not available>\n", jout_str);
1413 jglb[jname][jglb_str] = "not_available";
1414 } else {
1415 if (k > (int)sizeof(ull)) {
1416 xp += (k - sizeof(ull));
1417 k = sizeof(ull);
1418 }
1419 ull = sg_get_unaligned_be(k, xp);
1420 jout("%s = %" PRIu64 "\n", jout_str, ull);
1421 jglb[jname][jglb_str] = ull;
1422 }
1423 } else
1424 num -= pl;
1425 ucp += pl;
1426 }
1427 return retval;
1428
1429}
1430
1431static void
1432show_sas_phy_event_info(int peis, unsigned int val, unsigned thresh_val)
1433{
1434 unsigned int u;
1435
1436 switch (peis) {
1437 case 0:
1438 pout(" No event\n");
1439 break;
1440 case 0x1:
1441 pout(" Invalid word count: %u\n", val);
1442 break;
1443 case 0x2:
1444 pout(" Running disparity error count: %u\n", val);
1445 break;
1446 case 0x3:
1447 pout(" Loss of dword synchronization count: %u\n", val);
1448 break;
1449 case 0x4:
1450 pout(" Phy reset problem count: %u\n", val);
1451 break;
1452 case 0x5:
1453 pout(" Elasticity buffer overflow count: %u\n", val);
1454 break;
1455 case 0x6:
1456 pout(" Received ERROR count: %u\n", val);
1457 break;
1458 case 0x20:
1459 pout(" Received address frame error count: %u\n", val);
1460 break;
1461 case 0x21:
1462 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val);
1463 break;
1464 case 0x22:
1465 pout(" Received abandon-class OPEN_REJECT count: %u\n", val);
1466 break;
1467 case 0x23:
1468 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val);
1469 break;
1470 case 0x24:
1471 pout(" Received retry-class OPEN_REJECT count: %u\n", val);
1472 break;
1473 case 0x25:
1474 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val);
1475 break;
1476 case 0x26:
1477 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val);
1478 break;
1479 case 0x27:
1480 pout(" Transmitted BREAK count: %u\n", val);
1481 break;
1482 case 0x28:
1483 pout(" Received BREAK count: %u\n", val);
1484 break;
1485 case 0x29:
1486 pout(" Break timeout count: %u\n", val);
1487 break;
1488 case 0x2a:
1489 pout(" Connection count: %u\n", val);
1490 break;
1491 case 0x2b:
1492 pout(" Peak transmitted pathway blocked count: %u\n",
1493 val & 0xff);
1494 pout(" Peak value detector threshold: %u\n",
1495 thresh_val & 0xff);
1496 break;
1497 case 0x2c:
1498 u = val & 0xffff;
1499 if (u < 0x8000)
1500 pout(" Peak transmitted arbitration wait time (us): "
1501 "%u\n", u);
1502 else
1503 pout(" Peak transmitted arbitration wait time (ms): "
1504 "%u\n", 33 + (u - 0x8000));
1505 u = thresh_val & 0xffff;
1506 if (u < 0x8000)
1507 pout(" Peak value detector threshold (us): %u\n",
1508 u);
1509 else
1510 pout(" Peak value detector threshold (ms): %u\n",
1511 33 + (u - 0x8000));
1512 break;
1513 case 0x2d:
1514 pout(" Peak arbitration time (us): %u\n", val);
1515 pout(" Peak value detector threshold: %u\n", thresh_val);
1516 break;
1517 case 0x2e:
1518 pout(" Peak connection time (us): %u\n", val);
1519 pout(" Peak value detector threshold: %u\n", thresh_val);
1520 break;
1521 case 0x40:
1522 pout(" Transmitted SSP frame count: %u\n", val);
1523 break;
1524 case 0x41:
1525 pout(" Received SSP frame count: %u\n", val);
1526 break;
1527 case 0x42:
1528 pout(" Transmitted SSP frame error count: %u\n", val);
1529 break;
1530 case 0x43:
1531 pout(" Received SSP frame error count: %u\n", val);
1532 break;
1533 case 0x44:
1534 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val);
1535 break;
1536 case 0x45:
1537 pout(" Received CREDIT_BLOCKED count: %u\n", val);
1538 break;
1539 case 0x50:
1540 pout(" Transmitted SATA frame count: %u\n", val);
1541 break;
1542 case 0x51:
1543 pout(" Received SATA frame count: %u\n", val);
1544 break;
1545 case 0x52:
1546 pout(" SATA flow control buffer overflow count: %u\n", val);
1547 break;
1548 case 0x60:
1549 pout(" Transmitted SMP frame count: %u\n", val);
1550 break;
1551 case 0x61:
1552 pout(" Received SMP frame count: %u\n", val);
1553 break;
1554 case 0x63:
1555 pout(" Received SMP frame error count: %u\n", val);
1556 break;
1557 default:
1558 break;
1559 }
1560}
1561
1562static void
1563show_sas_port_param(unsigned char * ucp, int param_len)
1564{
1565 int j, m, nphys, t, sz, spld_len;
1566 unsigned char * vcp;
1567 char s[64];
1568
1569 sz = sizeof(s);
1570 // pcb = ucp[2];
1571 t = sg_get_unaligned_be16(ucp + 0);
1572 pout("relative target port id = %d\n", t);
1573 pout(" generation code = %d\n", ucp[6]);
1574 nphys = ucp[7];
1575 pout(" number of phys = %d\n", nphys);
1576
1577 for (j = 0, vcp = ucp + 8; j < (param_len - 8);
1578 vcp += spld_len, j += spld_len) {
1579 pout(" phy identifier = %d\n", vcp[1]);
1580 spld_len = vcp[3];
1581 if (spld_len < 44)
1582 spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1583 else
1584 spld_len += 4;
1585 t = ((0x70 & vcp[4]) >> 4);
1586 switch (t) {
1587 case 0: snprintf(s, sz, "no device attached"); break;
1588 case 1: snprintf(s, sz, "SAS or SATA device"); break;
1589 case 2: snprintf(s, sz, "expander device"); break;
1590 case 3: snprintf(s, sz, "expander device (fanout)"); break;
1591 default: snprintf(s, sz, "reserved [%d]", t); break;
1592 }
1593 pout(" attached device type: %s\n", s);
1594 t = 0xf & vcp[4];
1595 switch (t) {
1596 case 0: snprintf(s, sz, "unknown"); break;
1597 case 1: snprintf(s, sz, "power on"); break;
1598 case 2: snprintf(s, sz, "hard reset"); break;
1599 case 3: snprintf(s, sz, "SMP phy control function"); break;
1600 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
1601 case 5: snprintf(s, sz, "mux mix up"); break;
1602 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
1603 break;
1604 case 7: snprintf(s, sz, "break timeout timer expired"); break;
1605 case 8: snprintf(s, sz, "phy test function stopped"); break;
1606 case 9: snprintf(s, sz, "expander device reduced functionality");
1607 break;
1608 default: snprintf(s, sz, "reserved [0x%x]", t); break;
1609 }
1610 pout(" attached reason: %s\n", s);
1611 t = (vcp[5] & 0xf0) >> 4;
1612 switch (t) {
1613 case 0: snprintf(s, sz, "unknown"); break;
1614 case 1: snprintf(s, sz, "power on"); break;
1615 case 2: snprintf(s, sz, "hard reset"); break;
1616 case 3: snprintf(s, sz, "SMP phy control function"); break;
1617 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
1618 case 5: snprintf(s, sz, "mux mix up"); break;
1619 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
1620 break;
1621 case 7: snprintf(s, sz, "break timeout timer expired"); break;
1622 case 8: snprintf(s, sz, "phy test function stopped"); break;
1623 case 9: snprintf(s, sz, "expander device reduced functionality");
1624 break;
1625 default: snprintf(s, sz, "reserved [0x%x]", t); break;
1626 }
1627 pout(" reason: %s\n", s);
1628 t = (0xf & vcp[5]);
1629 switch (t) {
1630 case 0: snprintf(s, sz, "phy enabled; unknown");
1631 break;
1632 case 1: snprintf(s, sz, "phy disabled"); break;
1633 case 2: snprintf(s, sz, "phy enabled; speed negotiation failed");
1634 break;
1635 case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state");
1636 break;
1637 case 4: snprintf(s, sz, "phy enabled; port selector");
1638 break;
1639 case 5: snprintf(s, sz, "phy enabled; reset in progress");
1640 break;
1641 case 6: snprintf(s, sz, "phy enabled; unsupported phy attached");
1642 break;
1643 case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
1644 case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
1645 case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
1646 case 0xb: snprintf(s, sz, "phy enabled; 12 Gbps"); break;
1647 default: snprintf(s, sz, "reserved [%d]", t); break;
1648 }
1649 pout(" negotiated logical link rate: %s\n", s);
1650 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1651 !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
1652 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1653 !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
1654 if (!dont_print_serial_number) {
1655 uint64_t ull = sg_get_unaligned_be64(vcp + 8);
1656
1657 pout(" SAS address = 0x%" PRIx64 "\n", ull);
1658 ull = sg_get_unaligned_be64(vcp + 16);
1659 pout(" attached SAS address = 0x%" PRIx64 "\n", ull);
1660 }
1661 pout(" attached phy identifier = %d\n", vcp[24]);
1662 unsigned int ui = sg_get_unaligned_be32(vcp + 32);
1663
1664 pout(" Invalid DWORD count = %u\n", ui);
1665 ui = sg_get_unaligned_be32(vcp + 36);
1666 pout(" Running disparity error count = %u\n", ui);
1667 ui = sg_get_unaligned_be32(vcp + 40);
1668 pout(" Loss of DWORD synchronization = %u\n", ui);
1669 ui = sg_get_unaligned_be32(vcp + 44);
1670 pout(" Phy reset problem = %u\n", ui);
1671 if (spld_len > 51) {
1672 int num_ped;
1673 unsigned char * xcp;
1674
1675 num_ped = vcp[51];
1676 if (num_ped > 0)
1677 pout(" Phy event descriptors:\n");
1678 xcp = vcp + 52;
1679 for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
1680 int peis;
1681 unsigned int pvdt;
1682 peis = xcp[3];
1683 ui = sg_get_unaligned_be32(xcp + 4);
1684 pvdt = sg_get_unaligned_be32(xcp + 8);
1685 show_sas_phy_event_info(peis, ui, pvdt);
1686 }
1687 }
1688 }
1689}
1690
1691// Returns 1 if okay, 0 if non SAS descriptors
1692static int
1693show_protocol_specific_page(unsigned char * resp, int len)
1694{
1695 int k, num;
1696 unsigned char * ucp;
1697
1698 num = len - 4;
1699 for (k = 0, ucp = resp + 4; k < num; ) {
1700 int param_len = ucp[3] + 4;
1701 if (SCSI_TPROTO_SAS != (0xf & ucp[4]))
1702 return 0; /* only decode SAS log page */
1703 if (0 == k)
1704 pout("Protocol Specific port log page for SAS SSP\n");
1705 show_sas_port_param(ucp, param_len);
1706 k += param_len;
1707 ucp += param_len;
1708 }
1709 pout("\n");
1710 return 1;
1711}
1712
1713
1714// See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1715// log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1716static int
1717scsiPrintSasPhy(scsi_device * device, int reset)
1718{
1719 int num, err;
1720 static const char * hname = "Protocol specific port";
1721
1722 if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
1723 LOG_RESP_LONG_LEN, 0))) {
1724 print_on();
1725 pout("%s %s Failed [%s]\n\n", __func__, logSenStr,
1726 scsiErrString(err));
1727 print_off();
1728 return FAILSMART;
1729 }
1730 if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
1731 print_on();
1732 pout("%s %s, page mismatch\n\n", hname, logSenRspStr);
1733 print_off();
1734 return FAILSMART;
1735 }
1736 // compute page length
1737 num = sg_get_unaligned_be16(gBuf + 2);
1738 if (1 != show_protocol_specific_page(gBuf, num + 4)) {
1739 print_on();
1740 pout("Only support %s log page on SAS devices\n\n", hname);
1741 print_off();
1742 return FAILSMART;
1743 }
1744 if (reset) {
1745 if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1746 PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) {
1747 print_on();
1748 pout("%s Log Select (reset) Failed [%s]\n\n", __func__,
1749 scsiErrString(err));
1750 print_off();
1751 return FAILSMART;
1752 }
1753 }
1754 return 0;
1755}
1756
1757
1758static const char * peripheral_dt_arr[32] = {
1759 "disk",
1760 "tape",
1761 "printer",
1762 "processor",
1763 "optical disk(4)",
1764 "CD/DVD",
1765 "scanner",
1766 "optical disk(7)",
1767 "medium changer",
1768 "communications",
1769 "graphics(10)",
1770 "graphics(11)",
1771 "storage array",
1772 "enclosure",
1773 "simplified disk",
1774 "optical card reader",
1775 "reserved [0x10]",
1776 "object based storage",
1777 "automation/driver interface",
1778 "security manager device",
1779 "host managed zoned block device",
1780 "reserved [0x15]",
1781 "reserved [0x16]",
1782 "reserved [0x17]",
1783 "reserved [0x18]",
1784 "reserved [0x19]",
1785 "reserved [0x1a]",
1786 "reserved [0x1b]",
1787 "reserved [0x1c]",
1788 "reserved [0x1d]",
1789 "well known logical unit",
1790 "unknown or no device type",
1791};
1792
1793/* Symbolic indexes to this array SCSI_TPROTO_* in scscmds.h */
1794static const char * transport_proto_arr[] = {
1795 "Fibre channel (FCP-2)",
1796 "Parallel SCSI (SPI-4)",
1797 "SSA",
1798 "IEEE 1394 (SBP-2)",
1799 "RDMA (SRP)",
1800 "iSCSI",
1801 "SAS (SPL-3)",
1802 "ADT",
1803 "ATA (ACS-2)",
1804 "UAS",
1805 "SOP",
1806 "PCIe",
1807 "0xc",
1808 "0xd",
1809 "0xe",
1810 "None given [0xf]"
1811};
1812
1813/* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1814static int
1815scsiGetDriveInfo(scsi_device * device, uint8_t * peripheral_type, bool all)
1816{
1817 struct scsi_iec_mode_page iec;
1818 int err, iec_err, len, req_len, avail_len;
1819 bool is_tape = false;
1820 int peri_dt = 0;
1821 int transport = -1;
1822 int form_factor = 0;
1823 int haw_zbc = 0;
1824 int protect = 0;
1825
1826 memset(gBuf, 0, 96);
1827 req_len = 36;
1828 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
1829 print_on();
1830 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
1831 pout("Retrying with a 64 byte Standard Inquiry\n");
1832 print_off();
1833 /* Marvell controllers fail with 36 byte StdInquiry, but 64 is ok */
1834 req_len = 64;
1835 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
1836 print_on();
1837 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1838 scsiErrString(err));
1839 print_off();
1840 return 1;
1841 }
1842 }
1843 avail_len = gBuf[4] + 5;
1844 len = (avail_len < req_len) ? avail_len : req_len;
1845 peri_dt = gBuf[0] & 0x1f;
1846 *peripheral_type = peri_dt;
1847 if ((SCSI_PT_SEQUENTIAL_ACCESS == peri_dt) ||
1848 (SCSI_PT_MEDIUM_CHANGER == peri_dt))
1849 is_tape = true;
1850
1851 if (len < 36) {
1852 print_on();
1853 pout("Short INQUIRY response, skip product id\n");
1854 print_off();
1855 return 1;
1856 }
1857 // Upper bits of version bytes were used in older standards
1858 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
1859 scsi_version = gBuf[2] & 0x7;
1860
1861 if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) {
1862 char product[16+1], revision[4+1];
1863 scsi_format_id_string(scsi_vendor, &gBuf[8], 8);
1864 scsi_format_id_string(product, &gBuf[16], 16);
1865 scsi_format_id_string(revision, &gBuf[32], 4);
1866
1867 pout("=== START OF INFORMATION SECTION ===\n");
1868 jout("Vendor: %.8s\n", scsi_vendor);
1869 jglb["vendor"] = scsi_vendor;
1870 jout("Product: %.16s\n", product);
1871 jglb["product"] = product;
1872 jglb["model_name"] = strprintf("%s%s%s",
1873 scsi_vendor, (*scsi_vendor && *product ? " " : ""), product);
1874 if (gBuf[32] >= ' ') {
1875 jout("Revision: %.4s\n", revision);
1876 // jglb["firmware_version"] = revision;
1877 jglb["revision"] = revision; /* could be a hardware rev */
1878 }
1879 if ((scsi_version > 0x3) && (scsi_version < 0x8)) {
1880 char sv_arr[8];
1881
1882 snprintf(sv_arr, sizeof(sv_arr), "SPC-%d", scsi_version - 2);
1883 jout("Compliance: %s\n", sv_arr);
1884 jglb["scsi_version"] = sv_arr;
1885 }
1886 }
1887
1888 if (!*device->get_req_type()/*no type requested*/ &&
1889 (0 == strncmp((char *)&gBuf[8], "ATA", 3))) {
1890 pout("\nProbable ATA device behind a SAT layer\n"
1891 "Try an additional '-d ata' or '-d sat' argument.\n");
1892 return 2;
1893 }
1894 if (! all)
1895 return 0;
1896
1897 protect = gBuf[5] & 0x1; /* from and including SPC-3 */
1898
1899 if (! is_tape) { /* assume disk if not tape drive (or tape changer) */
1900 struct scsi_readcap_resp srr;
1901 int lbpme = -1;
1902 int lbprz = -1;
1903 unsigned char lb_prov_resp[8];
1904 uint64_t capacity = scsiGetSize(device, false /*avoid_rcap16 */,
1905 &srr);
1906
1907 if (capacity) {
1908 char cap_str[64], si_str[64];
1909 format_with_thousands_sep(cap_str, sizeof(cap_str), capacity);
1910 format_capacity(si_str, sizeof(si_str), capacity);
1911 jout("User Capacity: %s bytes [%s]\n", cap_str, si_str);
1912 if (srr.lb_size)
1913 jglb["user_capacity"]["blocks"].set_unsafe_uint64(capacity /
1914 srr.lb_size);
1915 jglb["user_capacity"]["bytes"].set_unsafe_uint64(capacity);
1916 jout("Logical block size: %u bytes\n", srr.lb_size);
1917 jglb["logical_block_size"] = srr.lb_size;
1918 if (protect || srr.lb_p_pb_exp) {
1919 if (srr.lb_p_pb_exp > 0) {
1920 unsigned pb_size = srr.lb_size * (1 << srr.lb_p_pb_exp);
1921 jout("Physical block size: %u bytes\n", pb_size);
1922 jglb["physical_block_size"] = pb_size;
1923 if (srr.l_a_lba > 0) // not common so cut the clutter
1924 pout("Lowest aligned LBA: %u\n", srr.l_a_lba);
1925 }
1926 if (srr.prot_type > 0) {
1927 switch (srr.prot_type) {
1928 case 1 :
1929 pout("Formatted with type 1 protection\n");
1930 break;
1931 case 2 :
1932 pout("Formatted with type 2 protection\n");
1933 break;
1934 case 3 :
1935 pout("Formatted with type 3 protection\n");
1936 break;
1937 default:
1938 pout("Formatted with unknown protection type [%d]\n",
1939 srr.prot_type);
1940 break;
1941 }
1942 unsigned p_i_per_lb = (1 << srr.p_i_exp);
1943 const unsigned pi_sz = 8; /* ref-tag(4 bytes),
1944 app-tag(2), tag-mask(2) */
1945
1946 if (p_i_per_lb > 1)
1947 pout("%d protection information intervals per "
1948 "logical block\n", p_i_per_lb);
1949 pout("%d bytes of protection information per logical "
1950 "block\n", pi_sz * p_i_per_lb);
1951 }
1952 /* Pick up some LB provisioning info since its available */
1953 lbpme = (int)srr.lbpme;
1954 lbprz = (int)srr.lbprz;
1955 }
1956 }
1957 /* Thin Provisioning VPD page renamed Logical Block Provisioning VPD
1958 * page in sbc3r25; some fields changed their meaning so that the
1959 * new page covered both thin and resource provisioned LUs. */
1960 if (0 == scsiInquiryVpd(device, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING,
1961 lb_prov_resp, sizeof(lb_prov_resp))) {
1962 int prov_type = lb_prov_resp[6] & 0x7; /* added sbc3r27 */
1963 int vpd_lbprz = ((lb_prov_resp[5] >> 2) & 0x7); /* sbc4r07 */
1964
1965 if (-1 == lbprz)
1966 lbprz = vpd_lbprz;
1967 else if ((0 == vpd_lbprz) && (1 == lbprz))
1968 ; /* vpd_lbprz introduced in sbc3r27, expanded in sbc4r07 */
1969 else
1970 lbprz = vpd_lbprz;
1971 switch (prov_type) {
1972 case 0:
1973 if (lbpme <= 0) {
1974 pout("LU is fully provisioned");
1975 if (lbprz)
1976 pout(" [LBPRZ=%d]\n", lbprz);
1977 else
1978 pout("\n");
1979 } else
1980 pout("LB provisioning type: not reported [LBPME=1, "
1981 "LBPRZ=%d]\n", lbprz);
1982 break;
1983 case 1:
1984 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz);
1985 break;
1986 case 2:
1987 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz);
1988 break;
1989 default:
1990 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1991 prov_type, lbprz);
1992 break;
1993 }
1994 } else if (1 == lbpme) {
1995 if (scsi_debugmode > 0)
1996 pout("rcap_16 sets LBPME but no LB provisioning VPD page\n");
1997 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz);
1998 }
1999
2000 int rpm = scsiGetRPM(device, modese_len, &form_factor, &haw_zbc);
2001 if (rpm >= 0) {
2002 if (0 == rpm)
2003 ; // Not reported
2004 else if (1 == rpm)
2005 jout("Rotation Rate: Solid State Device\n");
2006 else if ((rpm <= 0x400) || (0xffff == rpm))
2007 ; // Reserved
2008 else
2009 jout("Rotation Rate: %d rpm\n", rpm);
2010 jglb["rotation_rate"] = (rpm == 1 ? 0 : rpm);
2011 }
2012 if (form_factor > 0) {
2013 const char * cp = NULL;
2014
2015 switch (form_factor) {
2016 case 1:
2017 cp = "5.25";
2018 break;
2019 case 2:
2020 cp = "3.5";
2021 break;
2022 case 3:
2023 cp = "2.5";
2024 break;
2025 case 4:
2026 cp = "1.8";
2027 break;
2028 case 5:
2029 cp = "< 1.8";
2030 break;
2031 }
2032 jglb["form_factor"]["scsi_value"] = form_factor;
2033 if (cp) {
2034 jout("Form Factor: %s inches\n", cp);
2035 jglb["form_factor"]["name"] = strprintf("%s inches", cp);
2036 }
2037 }
2038 if (haw_zbc > 0)
2039 pout("Host aware zoned block capable\n");
2040 }
2041
2042 /* Do this here to try and detect badly conforming devices (some USB
2043 keys) that will lock up on a InquiryVpd or log sense or ... */
2044 if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) {
2045 if (SIMPLE_ERR_BAD_RESP == iec_err) {
2046 pout(">> Terminate command early due to bad response to IEC "
2047 "mode page\n");
2048 print_off();
2049 gIecMPage = 0;
2050 return 1;
2051 }
2052 } else
2053 modese_len = iec.modese_len;
2054
2055 if (! dont_print_serial_number) {
2056 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_DEVICE_IDENTIFICATION,
2057 gBuf, 252))) {
2058 char s[256];
2059
2060 len = gBuf[3];
2061 scsi_decode_lu_dev_id(gBuf + 4, len, s, sizeof(s), &transport);
2062 if (strlen(s) > 0)
2063 pout("Logical Unit id: %s\n", s);
2064 } else if (scsi_debugmode > 0) {
2065 print_on();
2066 if (SIMPLE_ERR_BAD_RESP == err)
2067 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
2068 else
2069 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
2070 print_off();
2071 }
2072 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_UNIT_SERIAL_NUMBER,
2073 gBuf, 252))) {
2074 char serial[256];
2075 len = gBuf[3];
2076
2077 gBuf[4 + len] = '\0';
2078 scsi_format_id_string(serial, &gBuf[4], len);
2079 jout("Serial number: %s\n", serial);
2080 jglb["serial_number"] = serial;
2081 } else if (scsi_debugmode > 0) {
2082 print_on();
2083 if (SIMPLE_ERR_BAD_RESP == err)
2084 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
2085 else
2086 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
2087 print_off();
2088 }
2089 }
2090
2091 // print SCSI peripheral device type
2092 jglb["device_type"]["scsi_value"] = peri_dt;
2093 if (peri_dt < (int)(sizeof(peripheral_dt_arr) /
2094 sizeof(peripheral_dt_arr[0]))) {
2095 jout("Device type: %s\n", peripheral_dt_arr[peri_dt]);
2096 jglb["device_type"]["name"] = peripheral_dt_arr[peri_dt];
2097 }
2098 else
2099 jout("Device type: <%d>\n", peri_dt);
2100
2101 // See if transport protocol is known
2102 if (transport < 0)
2103 transport = scsiFetchTransportProtocol(device, modese_len);
2104 if ((transport >= 0) && (transport <= 0xf))
2105 pout("Transport protocol: %s\n", transport_proto_arr[transport]);
2106
2107 // print current time and date and timezone
2108 time_t now = time(0);
2109 char timedatetz[DATEANDEPOCHLEN]; dateandtimezoneepoch(timedatetz, now);
2110 jout("Local Time is: %s\n", timedatetz);
2111 jglb["local_time"]["time_t"] = now;
2112 jglb["local_time"]["asctime"] = timedatetz;
2113
2114 // See if unit accepts SCSI commmands from us
2115 if ((err = scsiTestUnitReady(device))) {
2116 if (SIMPLE_ERR_NOT_READY == err) {
2117 print_on();
2118 if (!is_tape)
2119 pout("device is NOT READY (e.g. spun down, busy)\n");
2120 else
2121 pout("device is NOT READY (e.g. no tape)\n");
2122 print_off();
2123 } else if (SIMPLE_ERR_NO_MEDIUM == err) {
2124 print_on();
2125 if (is_tape)
2126 pout("NO tape present in drive\n");
2127 else
2128 pout("NO MEDIUM present in device\n");
2129 print_off();
2130 } else if (SIMPLE_ERR_BECOMING_READY == err) {
2131 print_on();
2132 pout("device becoming ready (wait)\n");
2133 print_off();
2134 } else {
2135 print_on();
2136 pout("device Test Unit Ready [%s]\n", scsiErrString(err));
2137 print_off();
2138 }
2139 if (! is_tape) {
2140 int returnval = 0; // TODO: exit with FAILID if failuretest returns
2141
2142 failuretest(MANDATORY_CMD, returnval|=FAILID);
2143 }
2144 }
2145
2146 if (iec_err) {
2147 if (!is_tape) {
2148 print_on();
2149 pout("SMART support is: Unavailable - device lacks SMART "
2150 "capability.\n");
2151 if (scsi_debugmode > 0)
2152 pout(" [%s]\n", scsiErrString(iec_err));
2153 print_off();
2154 }
2155 gIecMPage = 0;
2156 return 0;
2157 }
2158
2159 if (!is_tape)
2160 pout("SMART support is: Available - device has SMART capability.\n"
2161 "SMART support is: %s\n",
2162 (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled");
2163 pout("%s\n", (scsi_IsWarningEnabled(&iec)) ?
2164 "Temperature Warning: Enabled" :
2165 "Temperature Warning: Disabled or Not Supported");
2166 return 0;
2167}
2168
2169static int
2170scsiSmartEnable(scsi_device * device)
2171{
2172 struct scsi_iec_mode_page iec;
2173 int err;
2174
2175 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
2176 print_on();
2177 pout("unable to fetch IEC (SMART) mode page [%s]\n",
2178 scsiErrString(err));
2179 print_off();
2180 return 1;
2181 } else
2182 modese_len = iec.modese_len;
2183
2184 if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) {
2185 print_on();
2186 pout("unable to enable Exception control and warning [%s]\n",
2187 scsiErrString(err));
2188 print_off();
2189 return 1;
2190 }
2191 /* Need to refetch 'iec' since could be modified by previous call */
2192 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
2193 pout("unable to fetch IEC (SMART) mode page [%s]\n",
2194 scsiErrString(err));
2195 return 1;
2196 } else
2197 modese_len = iec.modese_len;
2198
2199 pout("Informational Exceptions (SMART) %s\n",
2200 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
2201 pout("Temperature warning %s\n",
2202 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
2203 return 0;
2204}
2205
2206static int
2207scsiSmartDisable(scsi_device * device)
2208{
2209 struct scsi_iec_mode_page iec;
2210 int err;
2211
2212 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
2213 print_on();
2214 pout("unable to fetch IEC (SMART) mode page [%s]\n",
2215 scsiErrString(err));
2216 print_off();
2217 return 1;
2218 } else
2219 modese_len = iec.modese_len;
2220
2221 if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) {
2222 print_on();
2223 pout("unable to disable Exception control and warning [%s]\n",
2224 scsiErrString(err));
2225 print_off();
2226 return 1;
2227 }
2228 /* Need to refetch 'iec' since could be modified by previous call */
2229 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
2230 pout("unable to fetch IEC (SMART) mode page [%s]\n",
2231 scsiErrString(err));
2232 return 1;
2233 } else
2234 modese_len = iec.modese_len;
2235
2236 pout("Informational Exceptions (SMART) %s\n",
2237 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
2238 pout("Temperature warning %s\n",
2239 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
2240 return 0;
2241}
2242
2243static void
2244scsiPrintTemp(scsi_device * device)
2245{
2246 uint8_t temp = 255;
2247 uint8_t trip = 255;
2248
2249 if (scsiGetTemp(device, &temp, &trip))
2250 return;
2251
2252 if (255 == temp)
2253 pout("Current Drive Temperature: <not available>\n");
2254 else {
2255 jout("Current Drive Temperature: %d C\n", temp);
2256 jglb["temperature"]["current"] = temp;
2257 }
2258 if (255 == trip)
2259 pout("Drive Trip Temperature: <not available>\n");
2260 else
2261 {
2262 pout("Drive Trip Temperature: %d C\n", trip);
2263 jglb["temperature"]["drive_trip"] = trip;
2264 }
2265 pout("\n");
2266}
2267
2268/* Main entry point used by smartctl command. Return 0 for success */
2269int
2270scsiPrintMain(scsi_device * device, const scsi_print_options & options)
2271{
2272 int checkedSupportedLogPages = 0;
2273 uint8_t peripheral_type = 0;
2274 int returnval = 0;
2275 int res, durationSec;
2276 struct scsi_sense_disect sense_info;
2277 bool is_disk;
2278 bool is_tape;
2279
2280 bool any_output = options.drive_info;
2281
2282 if (supported_vpd_pages_p) {
2283 delete supported_vpd_pages_p;
2284 supported_vpd_pages_p = NULL;
2285 }
2286 supported_vpd_pages_p = new supported_vpd_pages(device);
2287
2288 res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info);
2289 if (res) {
2290 if (2 == res)
2291 return 0;
2292 else
2293 failuretest(MANDATORY_CMD, returnval |= FAILID);
2294 any_output = true;
2295 }
2296 is_disk = ((SCSI_PT_DIRECT_ACCESS == peripheral_type) ||
2297 (SCSI_PT_HOST_MANAGED == peripheral_type));
2298 is_tape = ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
2299 (SCSI_PT_MEDIUM_CHANGER == peripheral_type));
2300
2301 short int wce = -1, rcd = -1;
2302 // Print read look-ahead status for disks
2303 if (options.get_rcd || options.get_wce) {
2304 if (is_disk) {
2305 res = scsiGetSetCache(device, modese_len, &wce, &rcd);
2306 if (options.get_rcd)
2307 pout("Read Cache is: %s\n",
2308 res ? "Unavailable" : // error
2309 rcd ? "Disabled" : "Enabled");
2310 if (options.get_wce)
2311 pout("Writeback Cache is: %s\n",
2312 res ? "Unavailable" : // error
2313 !wce ? "Disabled" : "Enabled");
2314 }
2315 } else
2316 any_output = true;
2317
2318 if (options.drive_info)
2319 pout("\n");
2320
2321 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
2322 if (options.smart_disable || options.smart_enable ||
2323 options.smart_auto_save_disable || options.smart_auto_save_enable)
2324 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
2325
2326 if (options.smart_enable) {
2327 if (scsiSmartEnable(device))
2328 failuretest(MANDATORY_CMD, returnval |= FAILSMART);
2329 any_output = true;
2330 }
2331
2332 if (options.smart_disable) {
2333 if (scsiSmartDisable(device))
2334 failuretest(MANDATORY_CMD,returnval |= FAILSMART);
2335 any_output = true;
2336 }
2337
2338 if (options.smart_auto_save_enable) {
2339 if (scsiSetControlGLTSD(device, 0, modese_len)) {
2340 pout("Enable autosave (clear GLTSD bit) failed\n");
2341 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
2342 } else
2343 pout("Autosave enabled (GLTSD bit cleared).\n");
2344 any_output = true;
2345 }
2346
2347 // Enable/Disable write cache
2348 if (options.set_wce && is_disk) {
2349 short int enable = wce = (options.set_wce > 0);
2350
2351 rcd = -1;
2352 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
2353 pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"),
2354 device->get_errmsg());
2355 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
2356 } else
2357 pout("Write cache %sabled\n", (enable ? "en" : "dis"));
2358 any_output = true;
2359 }
2360
2361 // Enable/Disable read cache
2362 if (options.set_rcd && is_disk) {
2363 short int enable = (options.set_rcd > 0);
2364
2365 rcd = !enable;
2366 wce = -1;
2367 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
2368 pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"),
2369 device->get_errmsg());
2370 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
2371 } else
2372 pout("Read cache %sabled\n", (enable ? "en" : "dis"));
2373 any_output = true;
2374 }
2375
2376 if (options.smart_auto_save_disable) {
2377 if (scsiSetControlGLTSD(device, 1, modese_len)) {
2378 pout("Disable autosave (set GLTSD bit) failed\n");
2379 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
2380 } else
2381 pout("Autosave disabled (GLTSD bit set).\n");
2382 any_output = true;
2383 }
2384 if (options.smart_disable || options.smart_enable ||
2385 options.smart_auto_save_disable || options.smart_auto_save_enable)
2386 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
2387
2388 // START OF READ-ONLY OPTIONS APART FROM -V and -i
2389 if (options.smart_check_status || options.smart_ss_media_log ||
2390 options.smart_vendor_attrib || options.smart_error_log ||
2391 options.smart_selftest_log || options.smart_background_log ||
2392 options.sasphy)
2393 pout("=== START OF READ SMART DATA SECTION ===\n");
2394
2395 if (options.smart_check_status) {
2396 scsiGetSupportedLogPages(device);
2397 checkedSupportedLogPages = 1;
2398 if (is_tape) {
2399 if (gTapeAlertsLPage) {
2400 if (options.drive_info)
2401 pout("TapeAlert Supported\n");
2402 if (-1 == scsiGetTapeAlertsData(device, peripheral_type))
2403 failuretest(OPTIONAL_CMD, returnval |= FAILSMART);
2404 }
2405 else
2406 pout("TapeAlert Not Supported\n");
2407 } else { /* disk, cd/dvd, enclosure, etc */
2408 if ((res = scsiGetSmartData(device,
2409 options.smart_vendor_attrib))) {
2410 if (-2 == res)
2411 returnval |= FAILSTATUS;
2412 else
2413 returnval |= FAILSMART;
2414 }
2415 }
2416 any_output = true;
2417 }
2418
2419 if (is_disk && options.smart_ss_media_log) {
2420 if (! checkedSupportedLogPages)
2421 scsiGetSupportedLogPages(device);
2422 res = 0;
2423 if (gSSMediaLPage)
2424 res = scsiPrintSSMedia(device);
2425 if (0 != res)
2426 failuretest(OPTIONAL_CMD, returnval|=res);
2427 if (gFormatStatusLPage)
2428 res = scsiPrintFormatStatus(device);
2429 if (0 != res)
2430 failuretest(OPTIONAL_CMD, returnval|=res);
2431 any_output = true;
2432 }
2433 if (options.smart_vendor_attrib) {
2434 if (! checkedSupportedLogPages)
2435 scsiGetSupportedLogPages(device);
2436 if (gTempLPage)
2437 scsiPrintTemp(device);
2438 if (gStartStopLPage)
2439 scsiGetStartStopData(device);
2440 if (is_disk) {
2441 scsiPrintGrownDefectListLen(device);
2442 if (gSeagateCacheLPage)
2443 scsiPrintSeagateCacheLPage(device);
2444 if (gSeagateFactoryLPage)
2445 scsiPrintSeagateFactoryLPage(device);
2446 }
2447 any_output = true;
2448 }
2449 if (options.smart_error_log) {
2450 if (! checkedSupportedLogPages)
2451 scsiGetSupportedLogPages(device);
2452 scsiPrintErrorCounterLog(device);
2453 if (gPendDefectsLPage)
2454 scsiPrintPendingDefectsLPage(device);
2455 if (1 == scsiFetchControlGLTSD(device, modese_len, 1))
2456 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2457 "Enable Save with '-S on']\n");
2458 any_output = true;
2459 }
2460 if (options.smart_selftest_log) {
2461 if (! checkedSupportedLogPages)
2462 scsiGetSupportedLogPages(device);
2463 res = 0;
2464 if (gSelfTestLPage)
2465 res = scsiPrintSelfTest(device);
2466 else {
2467 pout("Device does not support Self Test logging\n");
2468 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
2469 }
2470 if (0 != res)
2471 failuretest(OPTIONAL_CMD, returnval|=res);
2472 any_output = true;
2473 }
2474 if (options.smart_background_log && is_disk) {
2475 if (! checkedSupportedLogPages)
2476 scsiGetSupportedLogPages(device);
2477 res = 0;
2478 if (gBackgroundResultsLPage)
2479 res = scsiPrintBackgroundResults(device);
2480 else {
2481 pout("Device does not support Background scan results logging\n");
2482 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
2483 }
2484 if (0 != res)
2485 failuretest(OPTIONAL_CMD, returnval|=res);
2486 any_output = true;
2487 }
2488 if (options.smart_default_selftest) {
2489 if (scsiSmartDefaultSelfTest(device))
2490 return returnval | FAILSMART;
2491 pout("Default Self Test Successful\n");
2492 any_output = true;
2493 }
2494 if (options.smart_short_cap_selftest) {
2495 if (scsiSmartShortCapSelfTest(device))
2496 return returnval | FAILSMART;
2497 pout("Short Foreground Self Test Successful\n");
2498 any_output = true;
2499 }
2500 // check if another test is running
2501 if (options.smart_short_selftest || options.smart_extend_selftest) {
2502 if (!scsiRequestSense(device, &sense_info) &&
2503 (sense_info.asc == 0x04 && sense_info.ascq == 0x09)) {
2504 if (!options.smart_selftest_force) {
2505 pout("Can't start self-test without aborting current test");
2506 if (sense_info.progress != -1)
2507 pout(" (%d%% remaining)",
2508 100 - sense_info.progress * 100 / 65535);
2509 pout(",\nadd '-t force' option to override, or run "
2510 "'smartctl -X' to abort test.\n");
2511 return -1;
2512 } else
2513 scsiSmartSelfTestAbort(device);
2514 }
2515 }
2516 if (options.smart_short_selftest) {
2517 if (scsiSmartShortSelfTest(device))
2518 return returnval | FAILSMART;
2519 pout("Short Background Self Test has begun\n");
2520 pout("Use smartctl -X to abort test\n");
2521 any_output = true;
2522 }
2523 if (options.smart_extend_selftest) {
2524 if (scsiSmartExtendSelfTest(device))
2525 return returnval | FAILSMART;
2526 pout("Extended Background Self Test has begun\n");
2527 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
2528 modese_len)) && (durationSec > 0)) {
2529 time_t t = time(NULL);
2530
2531 t += durationSec;
2532 pout("Please wait %d minutes for test to complete.\n",
2533 durationSec / 60);
2534 pout("Estimated completion time: %s\n", ctime(&t));
2535 }
2536 pout("Use smartctl -X to abort test\n");
2537 any_output = true;
2538 }
2539 if (options.smart_extend_cap_selftest) {
2540 if (scsiSmartExtendCapSelfTest(device))
2541 return returnval | FAILSMART;
2542 pout("Extended Foreground Self Test Successful\n");
2543 }
2544 if (options.smart_selftest_abort) {
2545 if (scsiSmartSelfTestAbort(device))
2546 return returnval | FAILSMART;
2547 pout("Self Test returned without error\n");
2548 any_output = true;
2549 }
2550 if (options.sasphy && gProtocolSpecificLPage) {
2551 if (scsiPrintSasPhy(device, options.sasphy_reset))
2552 return returnval | FAILSMART;
2553 any_output = true;
2554 }
2555
2556 if (!any_output)
2557 pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
2558 "to print SMART (and more) information\n\n");
2559
2560 return returnval;
2561}