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