smartmontools SVN Rev 5554
Utility to control and monitor storage systems with "S.M.A.R.T."
scsiprint.cpp
Go to the documentation of this file.
1/*
2 * scsiprint.cpp
3 *
4 * Home page of code is: https://www.smartmontools.org
5 *
6 * Copyright (C) 2002-11 Bruce Allen
7 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
8 * Copyright (C) 2003-23 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" // dont_print_serial_number
25#include "dev_interface.h"
26#include "scsiprint.h"
27#include "smartctl.h"
28#include "utility.h"
29#include "sg_unaligned.h"
30
31#include "farmcmds.h"
32#include "farmprint.h"
33
34#define GBUF_SIZE 65532
35
36const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 5495 2023-07-10 13:17:30Z chrfranke $"
38
39#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
40
41uint8_t gBuf[GBUF_SIZE];
42#define LOG_RESP_LEN 252
43#define LOG_RESP_LONG_LEN ((62 * 256) + 252)
44#define LOG_RESP_TAPE_ALERT_LEN 0x144
45
46/* Supported log pages + Supported log pages and subpages maximum count */
47#define SCSI_SUPP_LOG_PAGES_MAX_COUNT (252 + (62 * 128) + 126)
48
49/* Log pages supported */
50static bool gSmartLPage = false; /* Informational Exceptions log page */
51static bool gTempLPage = false;
52static bool gSelfTestLPage = false;
53static bool gStartStopLPage = false;
54static bool gReadECounterLPage = false;
55static bool gWriteECounterLPage = false;
56static bool gVerifyECounterLPage = false;
57static bool gNonMediumELPage = false;
58static bool gLastNErrorEvLPage = false;
59static bool gBackgroundResultsLPage = false;
60static bool gProtocolSpecificLPage = false;
61static bool gTapeAlertsLPage = false;
62static bool gSSMediaLPage = false;
63static bool gFormatStatusLPage = false;
64static bool gEnviroReportingLPage = false;
65static bool gEnviroLimitsLPage = false;
66static bool gUtilizationLPage = false;
67static bool gPendDefectsLPage = false;
68static bool gBackgroundOpLPage = false;
69static bool gLPSMisalignLPage = false;
70static bool gTapeDeviceStatsLPage = false;
71static bool gZBDeviceStatsLPage = false;
72static bool gGenStatsAndPerfLPage = false;
73
74/* Vendor specific log pages */
75static bool gSeagateCacheLPage = false;
76static bool gSeagateFactoryLPage = false;
77static bool gSeagateFarmLPage = false;
78
79/* Mode pages supported */
80static bool gIecMPage = true; /* N.B. assume it until we know otherwise */
81
82/* Remember last successful mode sense/select command */
83static int modese_len = 0;
84
85/* Remember this value from the most recent INQUIRY */
86static int scsi_version;
87#define SCSI_VERSION_SPC_4 0x6
88#define SCSI_VERSION_SPC_5 0x7
89#define SCSI_VERSION_SPC_6 0xd /* T10/BSR INCITS 566, proposed in 23-015r0 */
90#define SCSI_VERSION_HIGHEST SCSI_VERSION_SPC_6
91
92/* T10 vendor identification. Should match entry in last Annex of SPC
93 * drafts and standards (e.g. SPC-4). */
94static char scsi_vendor[8+1];
95#define T10_VENDOR_SEAGATE "SEAGATE"
96#define T10_VENDOR_HITACHI_1 "HITACHI"
97#define T10_VENDOR_HITACHI_2 "HL-DT-ST"
98#define T10_VENDOR_HITACHI_3 "HGST"
99
100static const char * logSenStr = "Log Sense";
101static const char * logSenRspStr = "Log Sense response";
102static const char * gsap_s = "General statistics and performance";
103static const char * ssm_s = "Solid state media";
104static const char * zbds_s = "Zoned block device statistics";
105static const char * lp_s = "log page";
106
107
108static bool
110{
111 return ((0 == memcmp(scsi_vendor, T10_VENDOR_SEAGATE,
112 strlen(T10_VENDOR_SEAGATE))) ||
113 (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_1,
114 strlen(T10_VENDOR_HITACHI_1))) ||
115 (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_2,
116 strlen(T10_VENDOR_HITACHI_2))) ||
117 (0 == memcmp(scsi_vendor, T10_VENDOR_HITACHI_3,
118 strlen(T10_VENDOR_HITACHI_3))));
119}
120
121static bool
122all_ffs(const uint8_t * bp, int b_len)
123{
124 if ((nullptr == bp) || (b_len <= 0))
125 return false;
126 for (--b_len; b_len >= 0; --b_len) {
127 if (0xff != bp[b_len])
128 return false;
129 }
130 return true;
131}
132
133// trim from right. By default trims whitespace.
134static std::string rtrim(const std::string& s, const char* t = " \t\n\r\f\v")
135{
136 std::string r(s);
137
138 r.erase(r.find_last_not_of(t) + 1);
139 return r;
140}
141
142static void
144{
145 bool got_subpages = false;
146 int k, err, resp_len, num_unreported, num_unreported_spg;
147 int supp_lpg_and_spg_count = 0;
148
149 const uint8_t * up;
150 uint8_t sup_lpgs[LOG_RESP_LEN];
151 struct scsi_supp_log_pages supp_lpg_and_spg[SCSI_SUPP_LOG_PAGES_MAX_COUNT];
152
153 memset(gBuf, 0, LOG_RESP_LEN);
154 memset(supp_lpg_and_spg, 0, sizeof(supp_lpg_and_spg));
155
156 if (SC_NO_SUPPORT == device->cmd_support_level(LOG_SENSE, false, 0)) {
157 if (scsi_debugmode > 0)
158 pout("%s: RSOC says %s not supported\n", __func__, logSenStr);
159 return;
160 }
161 /* Get supported log pages */
162 if ((err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
163 LOG_RESP_LEN, 0 /* do double fetch */))) {
164 if (scsi_debugmode > 0)
165 pout("%s for supported pages failed [%s]\n", logSenStr,
166 scsiErrString(err));
167 /* try one more time with defined length, workaround for the bug #678
168 found with ST8000NM0075/E001 */
169 err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
170 LOG_RESP_LEN, 68); /* 64 max pages + 4b header */
171 if (scsi_debugmode > 0)
172 pout("%s for supported pages failed (second attempt) [%s]\n",
174 if (err)
175 return;
176 }
177
178 memcpy(sup_lpgs, gBuf, LOG_RESP_LEN);
179 resp_len = gBuf[3];
180 up = gBuf + LOGPAGEHDRSIZE;
181
182 for (k = 0; k < resp_len; k += 1) {
183 uint8_t page_code = 0x3f & up[k];
184 supp_lpg_and_spg[supp_lpg_and_spg_count++] = {page_code, 0};
185 }
186
187 if (SC_NO_SUPPORT ==
188 device->cmd_support_level(LOG_SENSE, false, 0,
189 true /* does it support subpages ? */))
190 goto skip_subpages;
191
192 /* Get supported log pages and subpages. Most drives seems to include the
193 supported log pages here as well, but some drives such as the Samsung
194 PM1643a will only report the additional log pages with subpages here */
197 /* unclear what code T10 will choose for SPC-6 */
200 -1 /* just single not double fetch */))) {
201 if (scsi_debugmode > 0)
202 pout("%s for supported pages and subpages failed [%s]\n",
204 } else {
205 /* Ensure we didn't get the same answer than without the subpages */
206 if (0 == memcmp(gBuf, sup_lpgs, LOG_RESP_LEN)) {
207 if (scsi_debugmode > 0)
208 pout("%s: %s ignored subpage field, bad\n",
209 __func__, logSenRspStr);
210 } else if (! ((0x40 & gBuf[0]) &&
211 (SUPP_SPAGE_L_SPAGE == gBuf[1]))) {
212 if (scsi_debugmode > 0)
213 pout("%s supported subpages is bad SPF=%u SUBPG=%u\n",
214 logSenRspStr, !! (0x40 & gBuf[0]), gBuf[2]);
215 } else {
216 got_subpages = true;
217 }
218 }
219 }
220
221 if (got_subpages) {
222 resp_len = sg_get_unaligned_be16(gBuf + 2);
223 up = gBuf + LOGPAGEHDRSIZE;
224 for (k = 0; k < resp_len; k += 2) {
225 uint8_t page_code = 0x3f & up[k];
226 uint8_t subpage_code = up[k+1];
227 supp_lpg_and_spg[supp_lpg_and_spg_count++] = {page_code, subpage_code};
228 }
229 }
230
231skip_subpages:
232 num_unreported = 0;
233 num_unreported_spg = 0;
234 for (k = 0; k < supp_lpg_and_spg_count; k += 1) {
235 struct scsi_supp_log_pages supp_lpg = supp_lpg_and_spg[k];
236
237 switch (supp_lpg.page_code)
238 {
239 case SUPPORTED_LPAGES:
240 if (! ((NO_SUBPAGE_L_SPAGE == supp_lpg.subpage_code) ||
241 (SUPP_SPAGE_L_SPAGE == supp_lpg.subpage_code))) {
242 if (scsi_debugmode > 1)
243 pout("%s: Strange Log page number: 0x0,0x%x\n",
244 __func__, supp_lpg.subpage_code);
245 }
246 break;
248 gReadECounterLPage = true;
249 break;
251 gWriteECounterLPage = true;
252 break;
255 break;
257 gLastNErrorEvLPage = true;
258 break;
260 gNonMediumELPage = true;
261 break;
263 if (NO_SUBPAGE_L_SPAGE == supp_lpg.subpage_code)
264 gTempLPage = true;
265 else if (ENVIRO_REP_L_SPAGE == supp_lpg.subpage_code)
267 else if (ENVIRO_LIMITS_L_SPAGE == supp_lpg.subpage_code)
268 gEnviroLimitsLPage = true;
269 else if (SUPP_SPAGE_L_SPAGE != supp_lpg.subpage_code) {
270 ++num_unreported;
271 ++num_unreported_spg;
272 }
273 /* WDC/HGST report <lpage>,0xff tuples for all supported
274 lpages; Seagate doesn't. T10 does not exclude the
275 reporting of <lpage>,0xff so it is not an error. */
276 break;
278 if (NO_SUBPAGE_L_SPAGE == supp_lpg.subpage_code)
279 gStartStopLPage = true;
280 else if (UTILIZATION_L_SPAGE == supp_lpg.subpage_code)
281 gUtilizationLPage = true;
282 else if (SUPP_SPAGE_L_SPAGE != supp_lpg.subpage_code) {
283 ++num_unreported;
284 ++num_unreported_spg;
285 }
286 break;
288 gSelfTestLPage = true;
289 break;
290 case IE_LPAGE:
291 gSmartLPage = true;
292 break;
294 if (NO_SUBPAGE_L_SPAGE == supp_lpg.subpage_code)
296 else if (ZB_DEV_STATS_L_SPAGE == supp_lpg.subpage_code)
297 gZBDeviceStatsLPage = true;
298 break;
300 if (NO_SUBPAGE_L_SPAGE == supp_lpg.subpage_code)
302 else if (PEND_DEFECTS_L_SPAGE == supp_lpg.subpage_code)
303 gPendDefectsLPage = true;
304 else if (BACKGROUND_OP_L_SPAGE == supp_lpg.subpage_code)
305 gBackgroundOpLPage = true;
306 else if (LPS_MISALIGN_L_SPAGE == supp_lpg.subpage_code)
307 gLPSMisalignLPage = true;
308 else if (SUPP_SPAGE_L_SPAGE != supp_lpg.subpage_code) {
309 ++num_unreported;
310 ++num_unreported_spg;
311 }
312 break;
315 break;
318 break;
320 gTapeAlertsLPage = true;
321 break;
322 case SS_MEDIA_LPAGE:
323 gSSMediaLPage = true;
324 break;
326 gFormatStatusLPage = true;
327 break;
330 gSeagateCacheLPage = true;
331 break;
332 }
333 if (seagate_or_hitachi())
334 gSeagateCacheLPage = true;
335 break;
339 break;
340 }
341 if (seagate_or_hitachi())
343 break;
347 gSeagateFarmLPage = true;
348 } else if (SUPP_SPAGE_L_SPAGE != supp_lpg.subpage_code) {
349 ++num_unreported;
350 ++num_unreported_spg;
351 }
352 }
353 break;
354 default:
355 if (supp_lpg.page_code < 0x30) { /* don't count VS pages */
356 ++num_unreported;
357 if ((supp_lpg.subpage_code > 0) &&
358 (SUPP_SPAGE_L_SPAGE != supp_lpg.subpage_code))
359 ++num_unreported_spg;
360 }
361 break;
362 }
363 }
364 if (scsi_debugmode > 1)
365 pout("%s: number of unreported (standard) %ss: %d (sub-pages: %d)\n",
366 __func__, lp_s, num_unreported, num_unreported_spg);
367}
368
369/* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
370 (or at least something to report). */
371static int
372scsiGetSmartData(scsi_device * device, bool attribs)
373{
374 uint8_t asc;
375 uint8_t ascq;
376 uint8_t currenttemp = 255;
377 uint8_t triptemp = 255;
378 const char * cp;
379 int err = 0;
380 char b[128];
381
382 print_on();
383 if (scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, &ascq,
384 &currenttemp, &triptemp)) {
385 /* error message already announced */
386 print_off();
387 return -1;
388 }
389 print_off();
390 cp = scsiGetIEString(asc, ascq, b, sizeof(b));
391 if (cp) {
392 err = -2;
393 print_on();
394 jout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq);
395 print_off();
396 jglb["smart_status"]["passed"] = false;
397 jglb["smart_status"]["scsi"]["asc"] = asc;
398 jglb["smart_status"]["scsi"]["ascq"] = ascq;
399 jglb["smart_status"]["scsi"]["ie_string"] = cp;
400 }
401 else if (gIecMPage) {
402 jout("SMART Health Status: OK\n");
403 jglb["smart_status"]["passed"] = true;
404 }
405
406 if (attribs && !gTempLPage) {
407 if (255 == currenttemp)
408 pout("Current Drive Temperature: <not available>\n");
409 else {
410 jout("Current Drive Temperature: %d C\n", currenttemp);
411 jglb["temperature"]["current"] = currenttemp;
412 }
413 if (255 == triptemp)
414 pout("Drive Trip Temperature: <not available>\n");
415 else {
416 jout("Drive Trip Temperature: %d C\n", triptemp);
417 jglb["temperature"]["drive_trip"] = triptemp;
418 }
419 }
420 pout("\n");
421 return err;
422}
423
424
425// Returns number of logged errors or zero if none or -1 if fetching
426// TapeAlerts fails
427static const char * const severities = "CWI";
428
429static int
430scsiPrintActiveTapeAlerts(scsi_device * device, int peripheral_type,
431 bool from_health)
432{
433 unsigned short pagelength;
434 unsigned short parametercode;
435 int i, k, j, m, err;
436 const char *s;
437 const char *ts;
438 int failures = 0;
439 const char * pad = from_health ? "" : " ";
440 static const char * const tapealert_s = "scsi_tapealert";
441
442 jout("\nTapeAlert %s:\n", lp_s);
443 print_on();
444 if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf,
446 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
447 print_off();
448 return -1;
449 }
450 if (gBuf[0] != 0x2e) {
451 pout("%sTapeAlerts %s Failed\n", pad, logSenStr);
452 print_off();
453 return -1;
454 }
455 pagelength = sg_get_unaligned_be16(gBuf + 2);
456
457 json::ref jref = jglb[tapealert_s]["status"];
458 for (s=severities, k = 0, j = 0; *s; s++, ++k) {
459 for (i = 4, m = 0; i < pagelength; i += 5, ++k, ++m) {
460 parametercode = sg_get_unaligned_be16(gBuf + i);
461
462 if (gBuf[i + 4]) {
463 ts = SCSI_PT_MEDIUM_CHANGER == peripheral_type ?
464 scsiTapeAlertsChangerDevice(parametercode) :
465 scsiTapeAlertsTapeDevice(parametercode);
466 if (*ts == *s) {
467 if (!failures)
468 jout("%sTapeAlert Errors (C=Critical, W=Warning, "
469 "I=Informational):\n", pad);
470 jout("%s[0x%02x] %s\n", pad, parametercode, ts);
471 jref[j]["descriptor_idx"] = m + 1;
472 jref[j]["parameter_code"] = parametercode;
473 jref[j]["string"] = ts;
474 ++j;
475 failures += 1;
476 }
477 }
478 }
479 }
480 print_off();
481
482 if (! failures) {
483 jout("%sTapeAlert: OK\n", pad);
484 jglb[tapealert_s]["status"] = "Good";
485 }
486
487 return failures;
488}
489
490static void
492{
493 int err, len, k, extra;
494 unsigned char * ucp;
495 char b[32];
496 const char * q;
497 static const char * jname = "scsi_start_stop_cycle_counter";
498
499 if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf,
500 LOG_RESP_LEN, 0))) {
501 print_on();
502 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
503 print_off();
504 return;
505 }
506 if ((gBuf[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE) {
507 print_on();
508 pout("StartStop %s Failed, page mismatch\n", logSenStr);
509 print_off();
510 return;
511 }
512 len = sg_get_unaligned_be16(gBuf + 2);
513 ucp = gBuf + 4;
514 for (k = len; k > 0; k -= extra, ucp += extra) {
515 if (k < 3) {
516 print_on();
517 pout("StartStop %s: short\n", logSenRspStr);
518 print_off();
519 return;
520 }
521 extra = ucp[3] + 4;
522 int pc = sg_get_unaligned_be16(ucp + 0);
523 uint32_t u = (extra > 7) ? sg_get_unaligned_be32(ucp + 4) : 0;
524 bool is_all_ffs = (extra > 7) ? all_ffs(ucp + 4, 4) : false;
525 switch (pc) {
526 case 1:
527 if (10 == extra) {
528 jout("Manufactured in week %.2s of year %.4s\n", ucp + 8,
529 ucp + 4);
530 snprintf(b, sizeof(b), "%.4s", ucp + 4);
531 jglb[jname]["year_of_manufacture"] = b;
532 snprintf(b, sizeof(b), "%.2s", ucp + 8);
533 jglb[jname]["week_of_manufacture"] = b;
534 }
535 break;
536 case 2:
537 /* ignore Accounting date */
538 break;
539 case 3:
540 if ((extra > 7) && (! is_all_ffs)) {
541 q = "Specified cycle count over device lifetime";
542 jout("%s: %u\n", q, u);
543 jglb[jname][json::str2key(q)] = u;
544 }
545 break;
546 case 4:
547 if ((extra > 7) && (! is_all_ffs)) {
548 q = "Accumulated start-stop cycles";
549 jout("%s: %u\n", q, u);
550 jglb[jname][json::str2key(q)] = u;
551 }
552 break;
553 case 5:
554 if ((extra > 7) && (! is_all_ffs)) {
555 q = "Specified load-unload count over device lifetime";
556 jout("%s: %u\n", q, u);
557 jglb[jname][json::str2key(q)] = u;
558 }
559 break;
560 case 6:
561 if ((extra > 7) && (! is_all_ffs)) {
562 q = "Accumulated load-unload cycles";
563 jout("%s: %u\n", q, u);
564 jglb[jname][json::str2key(q)] = u;
565 }
566 break;
567 default:
568 /* ignore */
569 break;
570 }
571 }
572}
573/* PENDING_DEFECTS_SUBPG [0x15,0x1] introduced: SBC-4 */
574static void
576{
577 static const char * pDefStr = "Pending Defects";
578 static const char * jname = "scsi_pending_defects";
579
580 int err;
581 if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE,
583 0))) {
584 print_on();
585 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
586 print_off();
587 return;
588 }
589 if (((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) &&
590 (gBuf[1] != PEND_DEFECTS_L_SPAGE)) {
591 print_on();
592 pout("%s %s, page mismatch\n", pDefStr, logSenRspStr);
593 print_off();
594 return;
595 }
596 int num = sg_get_unaligned_be16(gBuf + 2);
597 if (num > LOG_RESP_LONG_LEN) {
598 print_on();
599 pout("%s %s too long\n", pDefStr, logSenRspStr);
600 print_off();
601 return;
602 }
603 const uint8_t * bp = gBuf + 4;
604 while (num > 3) {
605 int pc = sg_get_unaligned_be16(bp + 0);
606 int pl = bp[3] + 4;
607 uint32_t count, poh;
608 uint64_t lba;
609
610 switch (pc) {
611 case 0x0:
612 jout(" Pending defect count:");
613 if ((pl < 8) || (num < 8)) {
614 print_on();
615 pout("%s truncated descriptor\n", pDefStr);
616 print_off();
617 return;
618 }
620 jglb[jname]["count"] = count;
621 if (0 == count)
622 jout("0 %s\n", pDefStr);
623 else if (1 == count)
624 jout("1 Pending Defect, LBA and accumulated_power_on_hours "
625 "follow\n");
626 else
627 jout("%u %s: index, LBA and accumulated_power_on_hours "
628 "follow\n", count, pDefStr);
629 break;
630 default:
631 if ((pl < 16) || (num < 16)) {
632 print_on();
633 pout("%s truncated descriptor\n", pDefStr);
634 print_off();
635 return;
636 }
637 poh = sg_get_unaligned_be32(bp + 4);
638 lba = sg_get_unaligned_be64(bp + 8);
639 jout(" %4d: 0x%-16" PRIx64 ", %5u\n", pc, lba, poh);
640 {
641 json::ref jref = jglb[jname]["table"][pc];
642
643 jref["lba"] = lba;
644 jref["accum_power_on_hours"] = poh;
645 }
646 break;
647 }
648 num -= pl;
649 bp += pl;
650 }
651}
652
653static void
655{
656 bool got_rd12;
657 int err, dl_format;
658 unsigned int dl_len, div;
659 static const char * hname = "Read defect list";
660
661 memset(gBuf, 0, 8);
662 if (prefer12) {
663 err = scsiReadDefect12(device, 0 /* req_plist */, 1 /* req_glist */,
664 4 /* format: bytes from index */,
665 0 /* addr desc index */, gBuf, 8);
666 got_rd12 = (0 == err);
667 if (err) {
668 if (scsi_debugmode > 0) {
669 print_on();
670 pout("%s (12) Failed: %s\n", hname, scsiErrString(err));
671 print_off();
672 }
673 }
674 } else { /* still try Read Defect(12) first, if not found try RD(10) */
675 err = scsiReadDefect12(device, 0 /* req_plist */, 1 /* req_glist */,
676 4 /* format: bytes from index */,
677 0 /* addr desc index */, gBuf, 8);
678 if (2 == err) { /* command not supported */
679 err = scsiReadDefect10(device, 0 /* req_plist */,
680 1 /* req_glist */,
681 4 /* format: bytes from index */, gBuf, 4);
682 if (2 == err) { /* command not supported */
683 if (scsi_debugmode > 0) {
684 print_on();
685 pout("%s (10) Failed: %s\n", hname, scsiErrString(err));
686 print_off();
687 }
688 return;
689 } else if (101 == err) /* Defect list not found, leave quietly */
690 return;
691 else {
692 if (scsi_debugmode > 0) {
693 print_on();
694 pout("%s (12) Failed: %s\n", hname, scsiErrString(err));
695 print_off();
696 }
697 return;
698 }
699 } else
700 got_rd12 = true;
701 }
702
703 if (got_rd12) {
704 int generation = sg_get_unaligned_be16(gBuf + 2);
705 if ((generation > 1) && (scsi_debugmode > 0)) {
706 print_on();
707 pout("%s (12): generation=%d\n", hname, generation);
708 print_off();
709 }
710 dl_len = sg_get_unaligned_be32(gBuf + 4);
711 } else
712 dl_len = sg_get_unaligned_be16(gBuf + 2);
713 if (0x8 != (gBuf[1] & 0x18)) {
714 print_on();
715 pout("%s: asked for grown list but didn't get it\n", hname);
716 print_off();
717 return;
718 }
719 div = 0;
720 dl_format = (gBuf[1] & 0x7);
721 switch (dl_format) {
722 case 0: /* short block */
723 div = 4;
724 break;
725 case 1: /* extended bytes from index */
726 case 2: /* extended physical sector */
727 /* extended = 1; # might use in future */
728 div = 8;
729 break;
730 case 3: /* long block */
731 case 4: /* bytes from index */
732 case 5: /* physical sector */
733 div = 8;
734 break;
735 case 6: /* vendor specific */
736 break;
737 default:
738 print_on();
739 pout("defect list format %d unknown\n", dl_format);
740 print_off();
741 break;
742 }
743 if (0 == dl_len) {
744 jout("Elements in grown defect list: 0\n\n");
745 jglb["scsi_grown_defect_list"] = 0;
746 }
747 else {
748 if (0 == div)
749 pout("Grown defect list length=%u bytes [unknown "
750 "number of elements]\n\n", dl_len);
751 else {
752 jout("Elements in grown defect list: %u\n\n", dl_len / div);
753 jglb["scsi_grown_defect_list"] = dl_len / div;
754 }
755 }
756}
757
758static uint64_t
759variableLengthIntegerParam(const unsigned char * ucp)
760{
761 static const size_t sz_u64 = (int)sizeof(uint64_t);
762 unsigned int u = ucp[3];
763 const unsigned char * xp = ucp + 4;
764
765 if (u > sz_u64) {
766 xp += (u - sz_u64);
767 u = sz_u64;
768 }
769 return sg_get_unaligned_be(u, xp + 0);
770}
771
772static void
774{
775 int num, pl, pc, err, len;
776 unsigned char * ucp;
777 static const char * seaCacStr = "Seagate Cache";
778
779 if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf,
780 LOG_RESP_LEN, 0))) {
781 if (scsi_debugmode > 0) {
782 print_on();
783 pout("%s %s Failed: %s\n", seaCacStr, logSenStr,
784 scsiErrString(err));
785 print_off();
786 }
787 return;
788 }
789 if ((gBuf[0] & 0x3f) != SEAGATE_CACHE_LPAGE) {
790 if (scsi_debugmode > 0) {
791 print_on();
792 pout("%s %s, page mismatch\n", seaCacStr, logSenRspStr);
793 print_off();
794 }
795 return;
796 }
797 len = sg_get_unaligned_be16(gBuf + 2) + 4;
798 num = len - 4;
799 ucp = &gBuf[0] + 4;
800 while (num > 3) {
801 pc = sg_get_unaligned_be16(ucp + 0);
802 pl = ucp[3] + 4;
803 switch (pc) {
804 case 0: case 1: case 2: case 3: case 4:
805 break;
806 default:
807 if (scsi_debugmode > 0) {
808 print_on();
809 pout("Vendor (%s) lpage has unexpected parameter, skip\n",
810 seaCacStr);
811 print_off();
812 }
813 return;
814 }
815 num -= pl;
816 ucp += pl;
817 }
818 pout("Vendor (%s) information\n", seaCacStr);
819 num = len - 4;
820 ucp = &gBuf[0] + 4;
821 while (num > 3) {
822 pc = sg_get_unaligned_be16(ucp + 0);
823 pl = ucp[3] + 4;
824 switch (pc) {
825 case 0: pout(" Blocks sent to initiator"); break;
826 case 1: pout(" Blocks received from initiator"); break;
827 case 2: pout(" Blocks read from cache and sent to initiator"); break;
828 case 3: pout(" Number of read and write commands whose size "
829 "<= segment size"); break;
830 case 4: pout(" Number of read and write commands whose size "
831 "> segment size"); break;
832 default: pout(" Unknown Seagate parameter code [0x%x]", pc); break;
833 }
834 pout(" = %" PRIu64 "\n", variableLengthIntegerParam(ucp));
835 num -= pl;
836 ucp += pl;
837 }
838 pout("\n");
839}
840
841static void
843{
844 int num, pl, pc, len, err, good, bad;
845 unsigned char * ucp;
846 uint64_t ull;
847
848 if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf,
849 LOG_RESP_LEN, 0))) {
850 if (scsi_debugmode > 0) {
851 print_on();
852 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
853 print_off();
854 }
855 return;
856 }
857 if ((gBuf[0] & 0x3f) != SEAGATE_FACTORY_LPAGE) {
858 if (scsi_debugmode > 0) {
859 print_on();
860 pout("Seagate/Hitachi Factory %s, page mismatch\n", logSenRspStr);
861 print_off();
862 }
863 return;
864 }
865 len = sg_get_unaligned_be16(gBuf + 2) + 4;
866 num = len - 4;
867 ucp = &gBuf[0] + 4;
868 good = 0;
869 bad = 0;
870 while (num > 3) {
871 pc = sg_get_unaligned_be16(ucp + 0);
872 pl = ucp[3] + 4;
873 switch (pc) {
874 case 0: case 8:
875 ++good;
876 break;
877 default:
878 ++bad;
879 break;
880 }
881 num -= pl;
882 ucp += pl;
883 }
884 if ((good < 2) || (bad > 4)) { /* heuristic */
885 if (scsi_debugmode > 0) {
886 print_on();
887 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
888 "unexpected parameters, skip\n");
889 print_off();
890 }
891 return;
892 }
893 pout("Vendor (Seagate/Hitachi) factory information\n");
894 num = len - 4;
895 ucp = &gBuf[0] + 4;
896 while (num > 3) {
897 pc = sg_get_unaligned_be16(ucp + 0);
898 pl = ucp[3] + 4;
899 good = 0;
900 switch (pc) {
901 case 0: jout(" number of hours powered up");
902 good = 1;
903 break;
904 case 8: pout(" number of minutes until next internal SMART test");
905 good = 1;
906 break;
907 default:
908 if (scsi_debugmode > 0) {
909 print_on();
910 pout("Vendor (Seagate/Hitachi) factory lpage: "
911 "unknown parameter code [0x%x]\n", pc);
912 print_off();
913 }
914 break;
915 }
916 if (good) {
918 if (0 == pc) {
919 jout(" = %.2f\n", ull / 60.0 );
920 jglb["power_on_time"]["hours"] = ull / 60;
921 jglb["power_on_time"]["minutes"] = ull % 60;
922 }
923 else
924 pout(" = %" PRIu64 "\n", ull);
925 }
926 num -= pl;
927 ucp += pl;
928 }
929 pout("\n");
930}
931
932static void
934{
935 struct scsiErrorCounter errCounterArr[3];
936 struct scsiErrorCounter * ecp;
937 int found[3] = {0, 0, 0};
938
939 if (gReadECounterLPage && (0 == scsiLogSense(device,
941 scsiDecodeErrCounterPage(gBuf, &errCounterArr[0], LOG_RESP_LEN);
942 found[0] = 1;
943 }
944 if (gWriteECounterLPage && (0 == scsiLogSense(device,
946 scsiDecodeErrCounterPage(gBuf, &errCounterArr[1], LOG_RESP_LEN);
947 found[1] = 1;
948 }
949 if (gVerifyECounterLPage && (0 == scsiLogSense(device,
951 scsiDecodeErrCounterPage(gBuf, &errCounterArr[2], LOG_RESP_LEN);
952 ecp = &errCounterArr[2];
953 for (int k = 0; k < 7; ++k) {
954 if (ecp->gotPC[k] && ecp->counter[k]) {
955 found[2] = 1;
956 break;
957 }
958 }
959 }
960 if (found[0] || found[1] || found[2]) {
961 pout("Error counter log:\n");
962 pout(" Errors Corrected by Total "
963 "Correction Gigabytes Total\n");
964 pout(" ECC rereads/ errors "
965 "algorithm processed uncorrected\n");
966 pout(" fast | delayed rewrites corrected "
967 "invocations [10^9 bytes] errors\n");
968
969 json::ref jref = jglb["scsi_error_counter_log"];
970 for (int k = 0; k < 3; ++k) {
971 if (! found[k])
972 continue;
973 ecp = &errCounterArr[k];
974 static const char * const pageNames[3] =
975 {"read: ", "write: ", "verify: "};
976 static const char * jpageNames[3] =
977 {"read", "write", "verify"};
978 jout("%s%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64
979 " %8" PRIu64, pageNames[k], ecp->counter[0],
980 ecp->counter[1], ecp->counter[2], ecp->counter[3],
981 ecp->counter[4]);
982 double processed_gb = ecp->counter[5] / 1000000000.0;
983 jout(" %12.3f %8" PRIu64 "\n", processed_gb,
984 ecp->counter[6]);
985 // Error counter log info
986 jref[jpageNames[k]]["errors_corrected_by_eccfast"] = ecp->counter[0];
987 jref[jpageNames[k]]["errors_corrected_by_eccdelayed"] = ecp->counter[1];
988 jref[jpageNames[k]]["errors_corrected_by_rereads_rewrites"] = ecp->counter[2];
989 jref[jpageNames[k]]["total_errors_corrected"] = ecp->counter[3];
990 jref[jpageNames[k]]["correction_algorithm_invocations"] = ecp->counter[4];
991 jref[jpageNames[k]]["gigabytes_processed"] = strprintf("%.3f", processed_gb);
992 jref[jpageNames[k]]["total_uncorrected_errors"] = ecp->counter[6];
993 }
994 }
995 else
996 pout("Error Counter logging not supported\n");
997 if (gNonMediumELPage && (0 == scsiLogSense(device,
999 struct scsiNonMediumError nme;
1001 if (nme.gotPC0)
1002 pout("\nNon-medium error count: %8" PRIu64 "\n", nme.counterPC0);
1003 if (nme.gotTFE_H)
1004 pout("Track following error count [Hitachi]: %8" PRIu64 "\n",
1005 nme.counterTFE_H);
1006 if (nme.gotPE_H)
1007 pout("Positioning error count [Hitachi]: %8" PRIu64 "\n",
1008 nme.counterPE_H);
1009 }
1010 if (gLastNErrorEvLPage &&
1012 LOG_RESP_LONG_LEN, 0))) {
1013 int num = sg_get_unaligned_be16(gBuf + 2) + 4;
1014 int truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1015 if (truncated)
1016 num = LOG_RESP_LONG_LEN;
1017 unsigned char * ucp = gBuf + 4;
1018 num -= 4;
1019 if (num < 4)
1020 pout("\nNo error events logged\n");
1021 else {
1022 pout("\nLast n error events %s\n", lp_s);
1023 for (int k = num, pl; k > 0; k -= pl, ucp += pl) {
1024 if (k < 3) {
1025 pout(" <<short Last n error events %s>>\n", lp_s);
1026 break;
1027 }
1028 pl = ucp[3] + 4;
1029 int pc = sg_get_unaligned_be16(ucp + 0);
1030 if (pl > 4) {
1031 if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) {
1032 pout(" Error event %d:\n", pc);
1033 pout(" [binary]:\n");
1034 dStrHex((const uint8_t *)ucp + 4, pl - 4, 1);
1035 } else if (ucp[2] & 0x1) {
1036 pout(" Error event %d:\n", pc);
1037 pout(" %.*s\n", pl - 4, (const char *)(ucp + 4));
1038 } else {
1039 if (scsi_debugmode > 0) {
1040 pout(" Error event %d:\n", pc);
1041 pout(" [data counter??]:\n");
1042 dStrHex((const uint8_t *)ucp + 4, pl - 4, 1);
1043 }
1044 }
1045 }
1046 }
1047 if (truncated)
1048 pout(" >>>> log truncated, fetched %d of %d available "
1049 "bytes\n", LOG_RESP_LONG_LEN, truncated);
1050 }
1051 }
1052 pout("\n");
1053}
1054
1055static const char * self_test_code[] = {
1056 "Default ",
1057 "Background short",
1058 "Background long ",
1059 "Reserved(3) ",
1060 "Abort background",
1061 "Foreground short",
1062 "Foreground long ",
1063 "Reserved(7) "
1064};
1065
1066static const char * self_test_result[] = {
1067 "Completed ",
1068 "Aborted (by user command)",
1069 "Aborted (device reset ?) ",
1070 "Unknown error, incomplete",
1071 "Completed, segment failed",
1072 "Failed in first segment ",
1073 "Failed in second segment ",
1074 "Failed in segment", /* special handling for result 7 */
1075 "Reserved(8) ",
1076 "Reserved(9) ",
1077 "Reserved(10) ",
1078 "Reserved(11) ",
1079 "Reserved(12) ",
1080 "Reserved(13) ",
1081 "Reserved(14) ",
1082 "Self test in progress ..."
1083};
1084
1085// See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
1086// Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
1087// 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
1088// FAILSMART is returned.
1089static int
1091{
1092 bool noheader = true;
1093 int num, k, err, durationSec;
1094 int retval = 0;
1095 uint8_t * ucp;
1096 struct scsi_sense_disect sense_info;
1097 static const char * hname = "Self-test";
1098 static const char * fixup_stres7 = " --> "; /* only for non-json */
1099
1100 // check if test is running
1101 if (!scsiRequestSense(device, &sense_info) &&
1102 (sense_info.asc == 0x04 && sense_info.ascq == 0x09 &&
1103 sense_info.progress != -1)) {
1104 pout("%s execution status:\t\t%d%% of test remaining\n", hname,
1105 100 - ((sense_info.progress * 100) / 65535));
1106 }
1107
1108 if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf,
1110 print_on();
1111 pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
1112 print_off();
1113 return FAILSMART;
1114 }
1115 if ((gBuf[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
1116 print_on();
1117 pout("%s %s, page mismatch\n", hname, logSenRspStr);
1118 print_off();
1119 return FAILSMART;
1120 }
1121 // compute page length
1122 num = sg_get_unaligned_be16(gBuf + 2);
1123 // Log sense page length 0x190 bytes
1124 if (num != 0x190) {
1125 print_on();
1126 pout("%s %s length is 0x%x not 0x190 bytes\n", hname, logSenStr, num);
1127 print_off();
1128 return FAILSMART;
1129 }
1130 // loop through the twenty possible entries
1131 for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) {
1132 // timestamp in power-on hours (or zero if test in progress)
1133 unsigned int poh = sg_get_unaligned_be16(ucp + 6);
1134 unsigned int u, tr;
1135 char st[32];
1136
1137 snprintf(st, sizeof(st), "scsi_self_test_%d", k);
1138 // The spec says "all 20 bytes will be zero if no test" but
1139 // DG has found otherwise. So this is a heuristic.
1140 if ((0 == poh) && (0 == ucp[4]))
1141 break;
1142
1143 // only print header if needed
1144 if (noheader) {
1145 jout("SMART %s log\n", hname);
1146 jout("Num Test Status segment "
1147 "LifeTime LBA_first_err [SK ASC ASQ]\n");
1148 jout(" Description number "
1149 "(hours)\n");
1150 noheader = false;
1151 }
1152
1153 // print parameter code (test number) & self-test code text
1154 u = (ucp[4] >> 5) & 0x7;
1155 jout("#%2d %s", sg_get_unaligned_be16(ucp + 0), self_test_code[u]);
1156 jglb[st]["code"]["value"] = u;
1157 jglb[st]["code"]["string"] = rtrim(self_test_code[u]);
1158
1159 // check the self-test result nibble, using the self-test results
1160 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
1161 tr = ucp[4] & 0xf;
1162 switch (tr) {
1163 case 0x3:
1164 // an unknown error occurred while the device server
1165 // was processing the self-test and the device server
1166 // was unable to complete the self-test
1167 retval|=FAILSMART;
1168 break;
1169 case 0x4:
1170 // the self-test completed with a failure in a test
1171 // segment, and the test segment that failed is not
1172 // known
1173 retval|=FAILLOG;
1174 break;
1175 case 0x5:
1176 // the first segment of the self-test failed
1177 retval|=FAILLOG;
1178 break;
1179 case 0x6:
1180 // the second segment of the self-test failed
1181 retval|=FAILLOG;
1182 break;
1183 case 0x7:
1184 // another segment of the self-test failed and which
1185 // test is indicated by the contents of the SELF-TEST
1186 // NUMBER field
1187 retval|=FAILLOG;
1188 break;
1189 default:
1190 break;
1191 }
1192 jout(" %s%s", self_test_result[tr], (tr == 7 ? fixup_stres7 : ""));
1193 jglb[st]["result"]["value"] = tr;
1194 jglb[st]["result"]["string"] = rtrim(self_test_result[tr]);
1195
1196 // self-test number identifies test that failed and consists
1197 // of either the number of the segment that failed during
1198 // the test, or the number of the test that failed and the
1199 // number of the segment in which the test was run, using a
1200 // vendor-specific method of putting both numbers into a
1201 // single byte.
1202 u = ucp[5];
1203 if (u > 0) {
1204 jout(" %3u", u);
1205 jglb[st]["failed_segment"]["value"] = u;
1206 jglb[st]["failed_segment"]["aka"] = "self_test_number";
1207 } else
1208 jout(" -");
1209
1210 // print time that the self-test was completed
1211 if (poh==0 && tr==0xf) {
1212 // self-test in progress
1213 jout(" NOW");
1214 jglb[st]["self_test_in_progress"] = true;
1215 } else {
1216 jout(" %5d", poh);
1217 jglb[st]["power_on_time"]["hours"] = poh;
1218 jglb[st]["power_on_time"]["aka"] = "accumulated_power_on_hours";
1219 }
1220
1221 // construct 8-byte integer address of first failure
1222 uint64_t ull = sg_get_unaligned_be64(ucp + 8);
1223 bool is_all_ffs = all_ffs(ucp + 8, 8);
1224 // print Address of First Failure, if sensible
1225 if ((! is_all_ffs) && (tr > 0) && (tr < 0xf)) {
1226 char buff[32];
1227
1228 // was hex but change to decimal to conform with ATA
1229 snprintf(buff, sizeof(buff), "%" PRIu64, ull);
1230 // snprintf(buff, sizeof(buff), "0x%" PRIx64, ull);
1231 jout("%18s", buff);
1232 jglb[st]["lba_first_failure"]["value"] = ull;
1233 jglb[st]["lba_first_failure"]["aka"] = "address_of_first_failure";
1234 } else
1235 jout(" -");
1236
1237 // if sense key nonzero, then print it, along with
1238 // additional sense code and additional sense code qualifier
1239 if (ucp[16] & 0xf) {
1240 char b[48];
1241
1242 jout(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]);
1243 u = ucp[16] & 0xf;
1244 jglb[st]["sense_key"]["value"] = u;
1245 jglb[st]["sense_key"]["string"] =
1246 scsi_get_sense_key_str(u, sizeof(b), b);
1247 jglb[st]["asc"] = ucp[17];
1248 jglb[st]["ascq"] = ucp[18];
1249 jglb[st]["vendor_specific"] = ucp[19];
1250 } else
1251 pout(" [- - -]\n");
1252 }
1253
1254 // if header never printed, then there was no output
1255 if (noheader)
1256 jout("No %ss have been logged\n", hname);
1257 else if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
1258 modese_len)) && (durationSec > 0)) {
1259 if (durationSec > 14400)
1260 jout("\nLong (extended) %s duration: %d seconds "
1261 "[%.1f hours]\n", hname, durationSec, durationSec / 3600.0);
1262 else
1263 jout("\nLong (extended) %s duration: %d seconds "
1264 "[%.1f minutes]\n", hname, durationSec, durationSec / 60.0);
1265 jglb["scsi_extended_self_test_seconds"] = durationSec;
1266 }
1267 jout("\n");
1268 return retval;
1269}
1270
1271static const char * bms_status[] = {
1272 "no scans active",
1273 "scan is active",
1274 "pre-scan is active",
1275 "halted due to fatal error",
1276 "halted due to a vendor specific pattern of error",
1277 "halted due to medium formatted without P-List",
1278 "halted - vendor specific cause",
1279 "halted due to temperature out of range",
1280 "waiting until BMS interval timer expires", /* 8 */
1281};
1282
1283static const char * reassign_status[] = {
1284 "Reserved [0x0]",
1285 "Require Write or Reassign Blocks command",
1286 "Successfully reassigned",
1287 "Reserved [0x3]",
1288 "Reassignment by disk failed",
1289 "Recovered via rewrite in-place",
1290 "Reassigned by app, has valid data",
1291 "Reassigned by app, has no valid data",
1292 "Unsuccessfully reassigned by app", /* 8 */
1293};
1294
1295// See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
1296// Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1297// and up to 2048 events (although would hope to have less). May set
1298// FAILLOG if serious errors detected (in the future).
1299// When only_pow_time is true only print "Accumulated power on time"
1300// data, if available.
1301static int
1302scsiPrintBackgroundResults(scsi_device * device, bool only_pow_time)
1303{
1304 bool noheader = true;
1305 bool firstresult = true;
1306 int num, j, m, err, truncated;
1307 int retval = 0;
1308 unsigned int u;
1309 uint64_t lba;
1310 uint8_t * ucp;
1311 char b[48];
1312 char res_s[32];
1313 static const char * hname = "Background scan results";
1314 static const char * jname = "scsi_background_scan";
1315
1316 if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf,
1317 LOG_RESP_LONG_LEN, 0))) {
1318 print_on();
1319 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
1320 print_off();
1321 return FAILSMART;
1322 }
1323 if ((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) {
1324 print_on();
1325 pout("%s %s, page mismatch\n", hname, logSenRspStr);
1326 print_off();
1327 return FAILSMART;
1328 }
1329 // compute page length
1330 num = sg_get_unaligned_be16(gBuf + 2) + 4;
1331 if (num < 20) {
1332 if (! only_pow_time) {
1333 print_on();
1334 pout("%s %s length is %d, no scan status\n", hname, logSenStr,
1335 num);
1336 print_off();
1337 }
1338 return FAILSMART;
1339 }
1340 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1341 if (truncated)
1342 num = LOG_RESP_LONG_LEN;
1343 ucp = gBuf + 4;
1344 num -= 4;
1345 while (num > 3) {
1346 int pc = sg_get_unaligned_be16(ucp + 0);
1347 // pcb = ucp[2];
1348 int pl = ucp[3] + 4;
1349 switch (pc) {
1350 case 0:
1351 if (noheader) {
1352 noheader = false;
1353 if (! only_pow_time)
1354 jout("%s log\n", hname);
1355 }
1356 if (! only_pow_time)
1357 jout(" Status: ");
1358 if ((pl < 16) || (num < 16)) {
1359 if (! only_pow_time)
1360 jout("\n");
1361 break;
1362 }
1363 j = ucp[9];
1364 if (! only_pow_time) {
1365 if (j < (int)ARRAY_SIZE(bms_status)) {
1366 jout("%s\n", bms_status[j]);
1367 jglb[jname]["status"]["value"] = j;
1368 jglb[jname]["status"]["string"] = bms_status[j];
1369 } else {
1370 jout("unknown [0x%x] background scan status value\n", j);
1371 jglb[jname]["status"]["value"] = j;
1372 }
1373 }
1374 j = sg_get_unaligned_be32(ucp + 4);
1375 jout("%sAccumulated power on time, hours:minutes %d:%02d",
1376 (only_pow_time ? "" : " "), (j / 60), (j % 60));
1377 if (only_pow_time)
1378 jout("\n");
1379 else
1380 jout(" [%d minutes]\n", j);
1381 jglb["power_on_time"]["hours"] = j / 60;
1382 jglb["power_on_time"]["minutes"] = j % 60;
1383 if (only_pow_time)
1384 break;
1385 u = sg_get_unaligned_be16(ucp + 10);
1386 jout(" Number of background scans performed: %u, ", u);
1387 jglb[jname]["status"]["number_scans_performed"] = u;
1388 u = sg_get_unaligned_be16(ucp + 12);
1389 snprintf(b, sizeof(b), "%.2f%%", (double)u * 100.0 / 65536.0);
1390 jout("scan progress: %s\n", b);
1391 jglb[jname]["status"]["scan_progress"] = b;
1392 u = sg_get_unaligned_be16(ucp + 14);
1393 jout(" Number of background medium scans performed: %d\n", u);
1394 jglb[jname]["status"]["number_medium_scans_performed"] = u;
1395 break;
1396 default:
1397 if (noheader) {
1398 noheader = false;
1399 if (! only_pow_time)
1400 jout("\n%s log\n", hname);
1401 }
1402 if (only_pow_time)
1403 break;
1404 if (firstresult) {
1405 firstresult = 0;
1406 jout("\n # when lba(hex) [sk,asc,ascq] "
1407 "reassign_status\n");
1408 }
1409 snprintf(res_s, sizeof(res_s), "result_%d", pc);
1410 jout(" %3d ", pc);
1411 jglb[jname][res_s]["parameter_code"] = pc;
1412 if ((pl < 24) || (num < 24)) {
1413 if (pl < 24)
1414 jout("parameter length >= 24 expected, got %d\n", pl);
1415 break;
1416 }
1417 u = sg_get_unaligned_be32(ucp + 4);
1418 jout("%4u:%02u ", (u / 60), (u % 60));
1419 jglb[jname][res_s]["accumulated_power_on"]["minutes"] = u;
1420 for (m = 0; m < 8; ++m)
1421 jout("%02x", ucp[16 + m]);
1422 lba = sg_get_unaligned_be64(ucp + 16);
1423 jglb[jname][res_s]["lba"] = lba;
1424 u = ucp[8] & 0xf;
1425 jout(" [%x,%x,%x] ", u, ucp[9], ucp[10]);
1426 jglb[jname][res_s]["sense_key"]["value"] = u;
1427 jglb[jname][res_s]["sense_key"]["string"] =
1428 scsi_get_sense_key_str(u, sizeof(b), b);
1429 jglb[jname][res_s]["asc"] = ucp[9];
1430 jglb[jname][res_s]["ascq"] = ucp[10];
1431 u = (ucp[8] >> 4) & 0xf;
1432 if (u < ARRAY_SIZE(reassign_status)) {
1433 jout("%s\n", reassign_status[u]);
1434 jglb[jname][res_s]["reassign_status"]["value"] = u;
1435 jglb[jname][res_s]["reassign_status"]["string"] =
1436 reassign_status[u];
1437 } else {
1438 jout("Reassign status: reserved [0x%x]\n", u);
1439 jglb[jname][res_s]["reassign_status"]["value"] = u;
1440 }
1441 break;
1442 }
1443 num -= pl;
1444 ucp += pl;
1445 }
1446 if (truncated && (! only_pow_time))
1447 jout(" >>>> log truncated, fetched %d of %d available "
1448 "bytes\n", LOG_RESP_LONG_LEN, truncated);
1449#if 0
1450 if (! only_pow_time)
1451 jout("\n");
1452#endif
1453 return retval;
1454}
1455
1456static int64_t
1457scsiGetTimeUnitInNano(const uint8_t * ucp, int num, uint16_t ti_pc)
1458{
1459 uint16_t loop_pc, pl;
1460 uint32_t a_exp, a_int, casc;
1461 int64_t res = -1;
1462
1463 while (num > 3) {
1464 loop_pc = sg_get_unaligned_be16(ucp + 0);
1465 pl = ucp[3] + 4;
1466
1467 if (loop_pc == ti_pc) {
1468 /* assume this pc corresponds to Time Interval param */
1469 if (pl < 12) {
1470 print_on();
1471 pout("%s Time interval log parameter too short (pl=%d)\n",
1472 __func__, pl);
1473 print_off();
1474 return res;
1475 }
1476 a_exp = sg_get_unaligned_be32(ucp + 4);
1477 a_int = sg_get_unaligned_be32(ucp + 8);
1478 if (0 == a_int)
1479 return 0;
1480 else
1481 res = a_int;
1482 if (a_exp > 10)
1483 return -2;
1484 if (10 == a_exp) {
1485 if (a_int < 10)
1486 return -2;
1487 return a_int / 10;
1488 }
1489 casc = 9 - a_exp;
1490 while (casc > 0) {
1491 res *= 10;
1492 --casc;
1493 }
1494 return res;
1495 }
1496 num -= pl;
1497 ucp += pl;
1498 }
1499 return res;
1500}
1501
1502static void
1503scsiPrintTimeUnitInNano(int leadin_spaces, uint64_t intervals,
1504 int64_t timeUnitInNS)
1505{
1506 if ((intervals > 0) && (timeUnitInNS > 0)) {
1507 intervals *= timeUnitInNS;
1508 intervals /= 1000000; /* now in milliseconds */
1509 jout("%*cin seconds: %" PRIu64 ".%03" PRIu64 "\n",
1510 leadin_spaces, ' ', intervals / 1000, intervals % 1000);
1511 if (intervals > 3600000) {
1512 intervals /= 3600; /* now in 3.6 second units */
1513 jout("%*cin hours: %" PRIu64 ".%03" PRIu64 "\n",
1514 leadin_spaces, ' ', intervals / 1000, intervals % 1000);
1515 }
1516 }
1517}
1518
1519// See SCSI Primary Commands - 6 (SPC-6) General Statistics and Performance
1520// log page [lp: 0x19,0x0]
1521static int
1523{
1524 int num, err, truncated;
1525 int retval = 0;
1526 int64_t timeUnitInNS;
1527 uint64_t ull;
1528 const char * ccp;
1529 uint8_t * ucp;
1530 // const char * q;
1531 json::ref jref = jglb["scsi_general_statistics_and_performance_log"];
1532 json::ref jref1 = jref["general_access"];
1533 json::ref jref2 = jref["idle_time"];
1534 json::ref jref3 = jref["time_interval"];
1535 json::ref jref4 = jref["fua_stats"];
1536 static const char * p1name = "General access statistics and performance";
1537 static const char * p2name = "Idle time";
1538 static const char * p3name = "Time interval";
1539 static const char * p4name = "Force Unit Access statistics and "
1540 "performance";
1541
1542 jout("\n%s %s:\n", gsap_s, lp_s);
1543 if ((err = scsiLogSense(device, GEN_STATS_PERF_LPAGE, 0, gBuf,
1544 LOG_RESP_LONG_LEN, 0))) {
1545 print_on();
1546 pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
1547 print_off();
1548 return FAILSMART;
1549 }
1550 if ((gBuf[0] & 0x3f) != GEN_STATS_PERF_LPAGE) {
1551 print_on();
1552 pout("%s %s, page mismatch\n", gsap_s, logSenStr);
1553 print_off();
1554 return FAILSMART;
1555 }
1556 // compute page length
1557 num = sg_get_unaligned_be16(gBuf + 2) + 4;
1558 if (num < 12) {
1559 print_on();
1560 pout("%s %s length is %d, too short\n", gsap_s, logSenStr, num);
1561 print_off();
1562 return FAILSMART;
1563 }
1564 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1565 if (truncated)
1566 num = LOG_RESP_LONG_LEN;
1567 ucp = gBuf + 4;
1568 num -= 4;
1569 timeUnitInNS = scsiGetTimeUnitInNano(ucp, num, 0x3 /* Time Interval */);
1570 if (timeUnitInNS < 0) {
1571 if (scsi_debugmode > 1) {
1572 print_on();
1573 pout("%s unable to decode time unit [%d]\n", gsap_s,
1574 (int)timeUnitInNS);
1575 print_off();
1576 }
1577 timeUnitInNS = 0;
1578 }
1579
1580 while (num > 3) {
1581 int pc = sg_get_unaligned_be16(ucp + 0);
1582 // pcb = ucp[2];
1583 int pl = ucp[3] + 4;
1584
1585 switch (pc) {
1586 case 1: /* General access statistics and performance log parameter */
1587 if (pl < 0x40 + 4) {
1588 print_on();
1589 pout("%s %s log parameter too short (pl=%d)\n", gsap_s,
1590 p1name, pl);
1591 print_off();
1592 return FAILSMART;
1593 }
1594 jout(" %s:\n", p1name);
1595 ccp = "Number of read commands";
1596 ull = sg_get_unaligned_be64(ucp + 4);
1597 jout(" %s: %" PRIu64 "\n", ccp, ull);
1598 jref1[ccp] = ull;
1599 ccp = "Number of write commands";
1600 ull = sg_get_unaligned_be64(ucp + 12);
1601 jout(" %s: %" PRIu64 "\n", ccp, ull);
1602 jref1[ccp] = ull;
1603 ccp = "number of logical blocks received";
1604 ull = sg_get_unaligned_be64(ucp + 20);
1605 jout(" %s: %" PRIu64 "\n", ccp, ull);
1606 jref1[ccp] = ull;
1607 ccp = "number of logical blocks transmitted";
1608 ull = sg_get_unaligned_be64(ucp + 28);
1609 jout(" %s: %" PRIu64 "\n", ccp, ull);
1610 jref1[ccp] = ull;
1611 ccp = "read command processing intervals";
1612 ull = sg_get_unaligned_be64(ucp + 36);
1613 jout(" %s: %" PRIu64 "\n", ccp, ull);
1614 scsiPrintTimeUnitInNano(6, ull, timeUnitInNS);
1615 jref1[ccp] = ull;
1616 ccp = "write command processing intervals";
1617 ull = sg_get_unaligned_be64(ucp + 44);
1618 jout(" %s: %" PRIu64 "\n", ccp, ull);
1619 scsiPrintTimeUnitInNano(6, ull, timeUnitInNS);
1620 jref1[ccp] = ull;
1621 ccp = "weighted number of read commands plus write commands";
1622 ull = sg_get_unaligned_be64(ucp + 52);
1623 jout(" %s: %" PRIu64 "\n", ccp, ull);
1624 jref1[ccp] = ull;
1625 ccp = "weighted read command processing plus write command "
1626 "processing";
1627 ull = sg_get_unaligned_be64(ucp + 60);
1628 scsiPrintTimeUnitInNano(6, ull, timeUnitInNS);
1629 jout(" %s: %" PRIu64 "\n", ccp, ull);
1630 jref1[ccp] = ull;
1631 break;
1632 case 2: /* Idle time log parameter */
1633 if (pl < 0x8 + 4) {
1634 print_on();
1635 pout("%s %s log parameter too short (pl=%d)\n", gsap_s,
1636 p2name, pl);
1637 print_off();
1638 return FAILSMART;
1639 }
1640 jout(" %s:\n", p2name);
1641 ccp = "Idle time intervals";
1642 ull = sg_get_unaligned_be64(ucp + 4);
1643 jout(" %s: %" PRIu64 "\n", ccp, ull);
1644 scsiPrintTimeUnitInNano(6, ull, timeUnitInNS);
1645 jref2[ccp] = ull;
1646 break;
1647 case 3: /* Time interval log parameter (shared with other lpages */
1648 /* only produce JSON for this parameter */
1649 if (pl < 0x8 + 4) {
1650 print_on();
1651 pout("%s %s log parameter too short (pl=%d)\n", gsap_s,
1652 p3name, pl);
1653 print_off();
1654 return FAILSMART;
1655 }
1656 ccp = "Exponent";
1657 ull = sg_get_unaligned_be32(ucp + 4);
1658 jref3[ccp] = ull;
1659 ccp = "Integer";
1660 ull = sg_get_unaligned_be32(ucp + 8);
1661 jref3[ccp] = ull;
1662 break;
1663 case 4: /* FUA statistics and performance log parameter */
1664 if (pl < 0x40 + 4) {
1665 print_on();
1666 pout("%s %s log parameter too short (pl=%d)\n", gsap_s,
1667 p4name, pl);
1668 print_off();
1669 return FAILSMART;
1670 }
1671 jout(" %s:\n", p4name);
1672 ccp = "Number of read FUA commands";
1673 ull = sg_get_unaligned_be64(ucp + 4);
1674 jout(" %s: %" PRIu64 "\n", ccp, ull);
1675 jref4[ccp] = ull;
1676 ccp = "Number of write FUA commands";
1677 ull = sg_get_unaligned_be64(ucp + 12);
1678 jout(" %s: %" PRIu64 "\n", ccp, ull);
1679 jref4[ccp] = ull;
1680 ccp = "Number of read FUA_NV commands";
1681 ull = sg_get_unaligned_be64(ucp + 20);
1682 jout(" %s: %" PRIu64 "\n", ccp, ull);
1683 jref4[ccp] = ull;
1684 ccp = "Number of write FUA_NV commands";
1685 ull = sg_get_unaligned_be64(ucp + 28);
1686 jout(" %s: %" PRIu64 "\n", ccp, ull);
1687 jref4[ccp] = ull;
1688 ccp = "Number of read FUA intervals";
1689 ull = sg_get_unaligned_be64(ucp + 36);
1690 jout(" %s: %" PRIu64 "\n", ccp, ull);
1691 scsiPrintTimeUnitInNano(6, ull, timeUnitInNS);
1692 jref4[ccp] = ull;
1693 ccp = "Number of write FUA intervals";
1694 ull = sg_get_unaligned_be64(ucp + 44);
1695 jout(" %s: %" PRIu64 "\n", ccp, ull);
1696 jref4[ccp] = ull;
1697 ccp = "Number of read FUA_NV intervals";
1698 ull = sg_get_unaligned_be64(ucp + 52);
1699 jout(" %s: %" PRIu64 "\n", ccp, ull);
1700 scsiPrintTimeUnitInNano(6, ull, timeUnitInNS);
1701 jref4[ccp] = ull;
1702 ccp = "Number of write FUA_NV intervals";
1703 ull = sg_get_unaligned_be64(ucp + 60);
1704 jout(" %s: %" PRIu64 "\n", ccp, ull);
1705 scsiPrintTimeUnitInNano(6, ull, timeUnitInNS);
1706 jref4[ccp] = ull;
1707 break;
1708 default: /* ignore other parameter codes */
1709 break;
1710 }
1711 num -= pl;
1712 ucp += pl;
1713 } /* end of long for loop */
1714 return retval;
1715}
1716
1717// Print Solid state media log page.
1718// See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1719// Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1720// and up to 2048 events (although would hope to have less). May set
1721// FAILLOG if serious errors detected (in the future).
1722static int
1724{
1725 int num, err, truncated;
1726 int retval = 0;
1727 uint8_t * ucp;
1728 const char * q;
1729
1730 if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf,
1731 LOG_RESP_LONG_LEN, 0))) {
1732 print_on();
1733 pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
1734 print_off();
1735 return FAILSMART;
1736 }
1737 if ((gBuf[0] & 0x3f) != SS_MEDIA_LPAGE) {
1738 print_on();
1739 pout("%s %s, page mismatch\n", ssm_s, logSenStr);
1740 print_off();
1741 return FAILSMART;
1742 }
1743 // compute page length
1744 num = sg_get_unaligned_be16(gBuf + 2) + 4;
1745 if (num < 12) {
1746 print_on();
1747 pout("%s %s length is %d, too short\n", ssm_s, logSenStr, num);
1748 print_off();
1749 return FAILSMART;
1750 }
1751 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1752 if (truncated)
1753 num = LOG_RESP_LONG_LEN;
1754 ucp = gBuf + 4;
1755 num -= 4;
1756 while (num > 3) {
1757 int pc = sg_get_unaligned_be16(ucp + 0);
1758 // pcb = ucp[2];
1759 int pl = ucp[3] + 4;
1760 switch (pc) {
1761 case 1:
1762 if (pl < 8) {
1763 print_on();
1764 pout("%s Percentage used endurance indicator parameter "
1765 "too short (pl=%d)\n", ssm_s, pl);
1766 print_off();
1767 return FAILSMART;
1768 }
1769 q = "Percentage used endurance indicator";
1770 jout("%s: %d%%\n", q, ucp[7]);
1771 jglb[std::string("scsi_") + json::str2key(q)] = ucp[7];
1772 default: /* ignore other parameter codes */
1773 break;
1774 }
1775 num -= pl;
1776 ucp += pl;
1777 }
1778 return retval;
1779}
1780
1781static int
1783{
1784 int num, err, truncated;
1785 int retval = 0;
1786 uint32_t u;
1787 uint8_t * ucp;
1788 const char * q;
1789 static const char * jname = "scsi_zoned_block_device_statistics";
1790
1791 jout("\n%s %s:\n", zbds_s, lp_s);
1793 gBuf, LOG_RESP_LONG_LEN, 0))) {
1794 print_on();
1795 pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
1796 print_off();
1797 return FAILSMART;
1798 }
1799 if (((gBuf[0] & 0x3f) != DEVICE_STATS_LPAGE) &&
1800 (gBuf[1] == ZB_DEV_STATS_L_SPAGE)) {
1801 print_on();
1802 pout("%s %s, page mismatch\n", zbds_s, logSenStr);
1803 print_off();
1804 return FAILSMART;
1805 }
1806 // compute page length
1807 num = sg_get_unaligned_be16(gBuf + 2) + 4;
1808 if (num < 12) {
1809 print_on();
1810 pout("%s %s length is %d, too short\n", zbds_s, logSenStr, num);
1811 print_off();
1812 return FAILSMART;
1813 }
1814 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1815 if (truncated)
1816 num = LOG_RESP_LONG_LEN;
1817 ucp = gBuf + 4;
1818 num -= 4;
1819 while (num > 3) {
1820 int pc = sg_get_unaligned_be16(ucp + 0);
1821 // pcb = ucp[2];
1822 int pl = ucp[3] + 4;
1823
1824 if (pl < 12)
1825 goto skip; /* DC HC650 has non-compliant 4 byte parameters */
1826 switch (pc) {
1827 case 0:
1828 q = "Maximum open zones";
1829 u = sg_get_unaligned_be32(ucp + 8);
1830 jout(" %s: %u\n", q, u);
1831 jglb[jname][json::str2key(q)] = u;
1832 break;
1833 case 1:
1834 q = "Maximum explicitly open zones";
1835 u = sg_get_unaligned_be32(ucp + 8);
1836 jout(" %s: %u\n", q, u);
1837 jglb[jname][json::str2key(q)] = u;
1838 break;
1839 case 2:
1840 q = "Maximum implicitly open zones";
1841 u = sg_get_unaligned_be32(ucp + 8);
1842 jout(" %s: %u\n", q, u);
1843 jglb[jname][json::str2key(q)] = u;
1844 break;
1845 case 3:
1846 q = "Minimum empty zones";
1847 u = sg_get_unaligned_be32(ucp + 8);
1848 jout(" %s: %u\n", q, u);
1849 jglb[jname][json::str2key(q)] = u;
1850 break;
1851 case 4:
1852 q = "Maximum nonseq zones";
1853 u = sg_get_unaligned_be32(ucp + 8);
1854 jout(" %s: %u\n", q, u);
1855 jglb[jname][json::str2key(q)] = u;
1856 break;
1857 case 5:
1858 q = "Zones emptied";
1859 u = sg_get_unaligned_be32(ucp + 8);
1860 jout(" %s: %u\n", q, u);
1861 jglb[jname][json::str2key(q)] = u;
1862 break;
1863 case 6:
1864 q = "Suboptimal write commands";
1865 u = sg_get_unaligned_be32(ucp + 8);
1866 jout(" %s: %u\n", q, u);
1867 jglb[jname][json::str2key(q)] = u;
1868 break;
1869 case 7:
1870 q = "Commands exceeding optinmal limit";
1871 u = sg_get_unaligned_be32(ucp + 8);
1872 jout(" %s: %u\n", q, u);
1873 jglb[jname][json::str2key(q)] = u;
1874 break;
1875 case 8:
1876 q = "Failed explicit opens";
1877 u = sg_get_unaligned_be32(ucp + 8);
1878 jout(" %s: %u\n", q, u);
1879 jglb[jname][json::str2key(q)] = u;
1880 break;
1881 case 9:
1882 q = "Read rule violations";
1883 u = sg_get_unaligned_be32(ucp + 8);
1884 jout(" %s: %u\n", q, u);
1885 jglb[jname][json::str2key(q)] = u;
1886 break;
1887 case 0xa:
1888 q = "Write rule violations";
1889 u = sg_get_unaligned_be32(ucp + 8);
1890 jout(" %s: %u\n", q, u);
1891 jglb[jname][json::str2key(q)] = u;
1892 break;
1893 case 0xb:
1894 q = "Maximum implicitly open sequential or before required zones";
1895 u = sg_get_unaligned_be32(ucp + 8);
1896 jout(" %s: %u\n", q, u);
1897 jglb[jname][json::str2key(q)] = u;
1898 break;
1899 default: /* ignore other parameter codes */
1900 break;
1901 }
1902skip:
1903 num -= pl;
1904 ucp += pl;
1905 }
1906 return retval;
1907}
1908
1909static int
1911{
1912 int num, err, truncated;
1913 int retval = 0;
1914 uint32_t k, n, u;
1915 uint64_t ull;
1916 uint8_t * ucp;
1917 const char * q;
1918 static const char * hname = "Device statistics (SSC, tape)";
1919 static const char * jname = "scsi_device_statistics";
1920
1921 jout("\n%s %s:\n", hname, lp_s);
1922 if ((err = scsiLogSense(device, DEVICE_STATS_LPAGE, 0,
1923 gBuf, LOG_RESP_LONG_LEN, 0))) {
1924 print_on();
1925 pout("%s: Failed [%s]\n", __func__, scsiErrString(err));
1926 print_off();
1927 return FAILSMART;
1928 }
1929 if (((gBuf[0] & 0x3f) != DEVICE_STATS_LPAGE) &&
1930 (gBuf[1] != 0)) {
1931 print_on();
1932 pout("%s %s, page mismatch\n", hname, logSenStr);
1933 print_off();
1934 return FAILSMART;
1935 }
1936 // compute page length
1937 num = sg_get_unaligned_be16(gBuf + 2) + 4;
1938 if (num < 12) {
1939 print_on();
1940 pout("%s %s length is %d, too short\n", hname, logSenStr, num);
1941 print_off();
1942 return FAILSMART;
1943 }
1944 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1945 if (truncated)
1946 num = LOG_RESP_LONG_LEN;
1947 ucp = gBuf + 4;
1948 num -= 4;
1949 while (num > 3) {
1950 int pc = sg_get_unaligned_be16(ucp + 0);
1951 // pcb = ucp[2];
1952 int pl = ucp[3] + 4;
1953 std::string s;
1954
1955 switch (pc) {
1956 case 0:
1957 q = "Lifetime volume loads";
1958 ull = variableLengthIntegerParam(ucp);
1959 jout(" %s: %" PRIu64 "\n", q, ull);
1960 jglb[jname][json::str2key(q)] = ull;
1961 break;
1962 case 1:
1963 q = "Lifetime cleaning operations";
1964 ull = variableLengthIntegerParam(ucp);
1965 jout(" %s: %" PRIu64 "\n", q, ull);
1966 jglb[jname][json::str2key(q)] = ull;
1967 break;
1968 case 2:
1969 q = "Lifetime power on hours";
1970 ull = variableLengthIntegerParam(ucp);
1971 jout(" %s: %" PRIu64 "\n", q, ull);
1972 jglb[jname][json::str2key(q)] = ull;
1973 break;
1974 case 3:
1975 q = "Lifetime medium motion hours";
1976 ull = variableLengthIntegerParam(ucp);
1977 jout(" %s: %" PRIu64 "\n", q, ull);
1978 jglb[jname][json::str2key(q)] = ull;
1979 break;
1980 case 4:
1981 q = "Lifetime meters of tape processed";
1982 ull = variableLengthIntegerParam(ucp);
1983 jout(" %s: %" PRIu64 "\n", q, ull);
1984 jglb[jname][json::str2key(q)] = ull;
1985 break;
1986 case 5:
1987 q = "Lifetime medium motion hours at last incompatible volume "
1988 "load";
1989 ull = variableLengthIntegerParam(ucp);
1990 jout(" %s: %" PRIu64 "\n", q, ull);
1991 jglb[jname][json::str2key(q)] = ull;
1992 break;
1993 case 6:
1994 q = "Lifetime power on hours at last temperature condition "
1995 "occurrence";
1996 ull = variableLengthIntegerParam(ucp);
1997 jout(" %s: %" PRIu64 "\n", q, ull);
1998 jglb[jname][json::str2key(q)] = ull;
1999 break;
2000 case 7:
2001 q = "Lifetime power on hours at last power consumption condition "
2002 "occurrence";
2003 ull = variableLengthIntegerParam(ucp);
2004 jout(" %s: %" PRIu64 "\n", q, ull);
2005 jglb[jname][json::str2key(q)] = ull;
2006 break;
2007 case 8:
2008 q = "Medium motion hours since last successful cleaning "
2009 "operation";
2010 ull = variableLengthIntegerParam(ucp);
2011 jout(" %s: %" PRIu64 "\n", q, ull);
2012 jglb[jname][json::str2key(q)] = ull;
2013 break;
2014 case 9:
2015 q = "Medium motion hours since second to last successful "
2016 "cleaning operation";
2017 ull = variableLengthIntegerParam(ucp);
2018 jout(" %s: %" PRIu64 "\n", q, ull);
2019 jglb[jname][json::str2key(q)] = ull;
2020 break;
2021 case 0xa:
2022 q = "Medium motion hours since third to last successful "
2023 "cleaning operation";
2024 ull = variableLengthIntegerParam(ucp);
2025 jout(" %s: %" PRIu64 "\n", q, ull);
2026 jglb[jname][json::str2key(q)] = ull;
2027 break;
2028 case 0xb:
2029 q = "Lifetime power on hours at last operator initiated forced "
2030 "reset and/or emergency eject occurrence";
2031 ull = variableLengthIntegerParam(ucp);
2032 jout(" %s: %" PRIu64 "\n", q, ull);
2033 jglb[jname][json::str2key(q)] = ull;
2034 break;
2035 case 0xc:
2036 q = "Lifetime power cycles";
2037 ull = variableLengthIntegerParam(ucp);
2038 jout(" %s: %" PRIu64 "\n", q, ull);
2039 jglb[jname][json::str2key(q)] = ull;
2040 break;
2041 case 0xd:
2042 q = "Volume loads since last parameter reset";
2043 ull = variableLengthIntegerParam(ucp);
2044 jout(" %s: %" PRIu64 "\n", q, ull);
2045 jglb[jname][json::str2key(q)] = ull;
2046 break;
2047 case 0xe:
2048 q = "Hard write errors";
2049 ull = variableLengthIntegerParam(ucp);
2050 jout(" %s: %" PRIu64 "\n", q, ull);
2051 jglb[jname][json::str2key(q)] = ull;
2052 break;
2053 case 0xf:
2054 q = "Hard read errors";
2055 ull = variableLengthIntegerParam(ucp);
2056 jout(" %s: %" PRIu64 "\n", q, ull);
2057 jglb[jname][json::str2key(q)] = ull;
2058 break;
2059 case 0x10:
2060 q = "Duty cycle sample time";
2061 ull = variableLengthIntegerParam(ucp);
2062 jout(" %s: %" PRIu64 "\n", q, ull);
2063 jglb[jname][json::str2key(q)] = ull;
2064 break;
2065 case 0x11:
2066 q = "Read duty cycle";
2067 ull = variableLengthIntegerParam(ucp);
2068 jout(" %s: %" PRIu64 "\n", q, ull);
2069 jglb[jname][json::str2key(q)] = ull;
2070 break;
2071 case 0x12:
2072 q = "Write duty cycle";
2073 ull = variableLengthIntegerParam(ucp);
2074 jout(" %s: %" PRIu64 "\n", q, ull);
2075 jglb[jname][json::str2key(q)] = ull;
2076 break;
2077 case 0x13:
2078 q = "Activity duty cycle";
2079 ull = variableLengthIntegerParam(ucp);
2080 jout(" %s: %" PRIu64 "\n", q, ull);
2081 jglb[jname][json::str2key(q)] = ull;
2082 break;
2083 case 0x14:
2084 q = "Volume not present duty cycle";
2085 ull = variableLengthIntegerParam(ucp);
2086 jout(" %s: %" PRIu64 "\n", q, ull);
2087 jglb[jname][json::str2key(q)] = ull;
2088 break;
2089 case 0x15:
2090 q = "Ready duty cycle";
2091 ull = variableLengthIntegerParam(ucp);
2092 jout(" %s: %" PRIu64 "\n", q, ull);
2093 jglb[jname][json::str2key(q)] = ull;
2094 break;
2095 case 0x16:
2096 q = "Megabytes transferred from application client in duty cycle"
2097 "sample time";
2098 ull = variableLengthIntegerParam(ucp);
2099 jout(" %s: %" PRIu64 "\n", q, ull);
2100 jglb[jname][json::str2key(q)] = ull;
2101 break;
2102 case 0x17:
2103 q = "Megabytes transferred to application client in duty cycle"
2104 "sample time";
2105 ull = variableLengthIntegerParam(ucp);
2106 jout(" %s: %" PRIu64 "\n", q, ull);
2107 jglb[jname][json::str2key(q)] = ull;
2108 break;
2109 case 0x40:
2110 {
2111 std::string v((const char *)(ucp + 4), ucp[3]);
2112 q = "Drive manufacturer's serial number";
2113 jout(" %s: %s\n", q, v.c_str());
2114 jglb[jname][json::str2key(q)] = v;
2115 }
2116 break;
2117 case 0x41:
2118 {
2119 std::string v((const char *)(ucp + 4), ucp[3]);
2120 q = "Drive serial number";
2121 jout(" %s: %s\n", q, v.c_str());
2122 jglb[jname][json::str2key(q)] = v;
2123 }
2124 break;
2125 case 0x42:
2126 {
2127 std::string v((const char *)(ucp + 4), ucp[3]);
2128 q = "Manufacturing date year,month,day";
2129 jout(" %s: %s\n", q, v.c_str());
2130 jglb[jname][json::str2key(q)] = v;
2131 }
2132 break;
2133 case 0x43:
2134 {
2135 std::string v((const char *)(ucp + 4), ucp[3]);
2136 q = "Manufacturing date year,week";
2137 jout(" %s: %s\n", q, v.c_str());
2138 jglb[jname][json::str2key(q)] = v;
2139 }
2140 break;
2141 case 0x44:
2142 {
2143 std::string v((const char *)(ucp + 4), ucp[3]);
2144 q = "Manufacturing date year,week";
2145 jout(" %s: %s\n", q, v.c_str());
2146 jglb[jname][json::str2key(q)] = v;
2147 }
2148 break;
2149 case 0x80:
2150 q = "Medium removal prevented";
2151 ull = variableLengthIntegerParam(ucp);
2152 jout(" %s: %" PRIu64 "\n", q, ull);
2153 jglb[jname][json::str2key(q)] = ull;
2154 break;
2155 case 0x81:
2156 q = "Maximum recommended mechanism temperature exceeded";
2157 ull = variableLengthIntegerParam(ucp);
2158 jout(" %s: %" PRIu64 "\n", q, ull);
2159 jglb[jname][json::str2key(q)] = ull;
2160 break;
2161 case 0x1000:
2162 q = "Medium motion hours for each medium type";
2163 s = json::str2key(q);
2164 n = ucp[3] / 8;
2165 jout(" %s, number of element: %u\n", q, n);
2166 for (k = 0; k < n; ++k, ucp += 8) {
2167 u = sg_get_unaligned_be32(ucp + 8);
2168 jout(" [%d] density code: %u, density code: %u, hours: "
2169 "%u\n", k + 1, ucp[6], ucp[7], u);
2170 jglb[jname][s][k]["density_code"] = ucp[6];
2171 jglb[jname][s][k]["medium_type"] = ucp[7];
2172 jglb[jname][s][k]["medium_motion_hours"] = u;
2173 }
2174 break;
2175 default: /* ignore other parameter codes */
2176 break;
2177 }
2178 num -= pl;
2179 ucp += pl;
2180 }
2181 return retval;
2182}
2183
2184static int
2186{
2187 int num, err, truncated;
2188 int retval = 0;
2189 uint64_t ull;
2190 uint8_t * ucp;
2191 static const char * hname = "Format Status";
2192 static const char * jname = "scsi_format_status";
2193
2194 if ((err = scsiLogSense(device, FORMAT_STATUS_LPAGE, 0, gBuf,
2195 LOG_RESP_LONG_LEN, 0))) {
2196 print_on();
2197 jout("%s: Failed [%s]\n", __func__, scsiErrString(err));
2198 print_off();
2199 return FAILSMART;
2200 }
2201 if ((gBuf[0] & 0x3f) != FORMAT_STATUS_LPAGE) {
2202 print_on();
2203 jout("%s %s, page mismatch\n", hname, logSenRspStr);
2204 print_off();
2205 return FAILSMART;
2206 }
2207 // compute page length
2208 num = sg_get_unaligned_be16(gBuf + 2) + 4;
2209 if (num < 12) {
2210 print_on();
2211 jout("%s %s length is %d, too short\n", hname, logSenStr, num);
2212 print_off();
2213 return FAILSMART;
2214 }
2215 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
2216 if (truncated)
2217 num = LOG_RESP_LONG_LEN;
2218 ucp = gBuf + 4;
2219 num -= 4;
2220 while (num > 3) {
2221 int pc = sg_get_unaligned_be16(ucp + 0);
2222 // pcb = ucp[2];
2223 int pl = ucp[3] + 4;
2224
2225 bool is_count = true;
2226 const char * jout_str = "";
2227 const char * jglb_str = "x";
2228 switch (pc) {
2229 case 0:
2230 if (scsi_debugmode > 1) {
2231 if (pl < 5)
2232 jout("Format data out: <empty>\n");
2233 else {
2234 if (all_ffs(ucp + 4, pl - 4))
2235 jout("Format data out: <not available>\n");
2236 else {
2237 jout("Format data out:\n");
2238 dStrHex((const uint8_t *)ucp + 4, pl - 4, 0);
2239 }
2240 }
2241 }
2242 is_count = false;
2243 break;
2244 case 1:
2245 jout_str = "Grown defects during certification";
2246 jglb_str = "grown_defects_during_cert";
2247 break;
2248 case 2:
2249 jout_str = "Total blocks reassigned during format";
2250 jglb_str = "blocks_reassigned_during_format";
2251 break;
2252 case 3:
2253 jout_str = "Total new blocks reassigned";
2254 jglb_str = "total_new_block_since_format";
2255 break;
2256 case 4:
2257 jout_str = "Power on minutes since format";
2258 jglb_str = "power_on_minutes_since_format";
2259 break;
2260 default:
2261 if (scsi_debugmode > 3) {
2262 pout(" Unknown Format parameter code = 0x%x\n", pc);
2263 dStrHex((const uint8_t *)ucp, pl, 0);
2264 }
2265 is_count = false;
2266 break;
2267 }
2268 if (is_count) {
2269 if (all_ffs(ucp + 4, ucp[3])) {
2270 pout("%s <not available>\n", jout_str);
2271 } else {
2272 ull = variableLengthIntegerParam(ucp);
2273 jout("%s = %" PRIu64 "\n", jout_str, ull);
2274 jglb[jname][jglb_str] = ull;
2275 }
2276 } else
2277 num -= pl;
2278 ucp += pl;
2279 }
2280 return retval;
2281
2282}
2283
2284static void
2285show_sas_phy_event_info(const json::ref & jref, int peis, unsigned int val,
2286 unsigned thresh_val)
2287{
2288 unsigned int u;
2289 const char * q;
2290 static const char * pvd_th = "Peak value detector threshold";
2291 static const char * pvd_th_j = "pvd_threshold";
2292
2293 switch (peis) {
2294 case 0:
2295 jout(" No event\n");
2296 break;
2297 case 0x1: /* 0x1 to 0x4 will be duplicates so append "_2" to name */
2298 q = "Invalid dword count";
2299 jout(" %s: %u\n", q, val);
2300 jref[std::string(q) + "_2"] = val;
2301 break;
2302 case 0x2:
2303 q = "Running disparity error count";
2304 jout(" %s: %u\n", q, val);
2305 jref[std::string(q) + "_2"] = val;
2306 break;
2307 case 0x3:
2308 q = "Loss of dword synchronization count";
2309 jout(" %s: %u\n", q, val);
2310 jref[std::string(q) + "_2"] = val;
2311 break;
2312 case 0x4:
2313 q = "Phy reset problem count";
2314 jout(" %s: %u\n", q, val);
2315 jref[std::string(q) + "_2"] = val;
2316 break;
2317 case 0x5:
2318 q = "Elasticity buffer overflow count";
2319 jout(" %s: %u\n", q, val);
2320 jref[q] = val;
2321 break;
2322 case 0x6:
2323 q = "Received ERROR count";
2324 jout(" %s: %u\n", q, val);
2325 jref[q] = val;
2326 break;
2327 case 0x20:
2328 q = "Received address frame error count";
2329 jout(" %s: %u\n", q, val);
2330 jref[q] = val;
2331 break;
2332 case 0x21:
2333 q = "Transmitted abandon-class OPEN_REJECT count";
2334 jout(" %s: %u\n", q, val);
2335 jref[q] = val;
2336 break;
2337 case 0x22:
2338 q = "Received abandon-class OPEN_REJECT count";
2339 jout(" %s: %u\n", q, val);
2340 jref[q] = val;
2341 break;
2342 case 0x23:
2343 q = "Transmitted retry-class OPEN_REJECT count";
2344 jout(" %s: %u\n", q, val);
2345 jref[q] = val;
2346 break;
2347 case 0x24:
2348 q = "Received retry-class OPEN_REJECT count";
2349 jout(" %s: %u\n", q, val);
2350 jref[q] = val;
2351 break;
2352 case 0x25:
2353 q = "Received AIP (WAITING ON PARTIAL) count";
2354 jout(" %s: %u\n", q, val);
2355 jref[q] = val;
2356 break;
2357 case 0x26:
2358 q = "Received AIP (WAITING ON CONNECTION) count";
2359 jout(" %s: %u\n", q, val);
2360 jref[q] = val;
2361 break;
2362 case 0x27:
2363 q = "Transmitted BREAK count";
2364 jout(" %s: %u\n", q, val);
2365 jref[q] = val;
2366 break;
2367 case 0x28:
2368 q = "Received BREAK count";
2369 jout(" %s: %u\n", q, val);
2370 jref[q] = val;
2371 break;
2372 case 0x29:
2373 q = "Break timeout count";
2374 jout(" %s: %u\n", q, val);
2375 jref[q] = val;
2376 break;
2377 case 0x2a:
2378 q = "Connection count";
2379 jout(" %s: %u\n", q, val);
2380 jref[q] = val;
2381 break;
2382 case 0x2b:
2383 q = "Peak transmitted pathway blocked";
2384 jout(" %s count: %u\n", q, val & 0xff);
2385 jout(" %s: %u\n", pvd_th, thresh_val & 0xff);
2386 jref[q]["count"] = val & 0xff;
2387 jref[q][pvd_th_j] = thresh_val & 0xff;
2388 break;
2389 case 0x2c:
2390 q = "Peak transmitted arbitration wait time";
2391 u = val & 0xffff;
2392 if (u < 0x8000) {
2393 jout(" %s (us): %u\n", q, u);
2394 jref[std::string(q) + "_us"]["event"] = u;
2395 } else {
2396 jout(" %s (ms): %u\n", q, 33 + (u - 0x8000));
2397 jref[std::string(q) + "_ms"]["event"] = 33 + (u - 0x8000);
2398 }
2399 u = thresh_val & 0xffff;
2400 if (u < 0x8000) {
2401 jout(" %s (us): %u\n", pvd_th, u);
2402 jref[std::string(q) + "_us"][pvd_th_j] = u;
2403 } else {
2404 jout(" %s (ms): %u\n", pvd_th, 33 + (u - 0x8000));
2405 jref[std::string(q) + "_ms"][pvd_th_j] = 33 + (u - 0x8000);
2406 }
2407 break;
2408 case 0x2d:
2409 q = "Peak arbitration time";
2410 jout(" %s (us): %u\n", q, val);
2411 jref[std::string(q) + "_us"]["event"] = val;
2412 jout(" %s: %u\n", pvd_th, thresh_val);
2413 jref[std::string(q) + "_us"][pvd_th_j] = thresh_val;
2414 break;
2415 case 0x2e:
2416 q = "Peak connection time";
2417 jout(" %s (us): %u\n", q, val);
2418 jref[std::string(q) + "_us"]["event"] = val;
2419 jout(" %s: %u\n", pvd_th, thresh_val);
2420 jref[std::string(q) + "_us"][pvd_th_j] = thresh_val;
2421 break;
2422 case 0x40:
2423 q = "Transmitted SSP frame count";
2424 jout(" %s: %u\n", q, val);
2425 jref[q] = val;
2426 break;
2427 case 0x41:
2428 q = "Received SSP frame count";
2429 jout(" %s: %u\n", q, val);
2430 jref[q] = val;
2431 break;
2432 case 0x42:
2433 q = "Transmitted SSP frame error count";
2434 jout(" %s: %u\n", q, val);
2435 jref[q] = val;
2436 break;
2437 case 0x43:
2438 q = "Received SSP frame error count";
2439 jout(" %s: %u\n", q, val);
2440 jref[q] = val;
2441 break;
2442 case 0x44:
2443 q = "Transmitted CREDIT_BLOCKED count";
2444 jout(" %s: %u\n", q, val);
2445 jref[q] = val;
2446 break;
2447 case 0x45:
2448 q = "Received CREDIT_BLOCKED count";
2449 jout(" %s: %u\n", q, val);
2450 jref[q] = val;
2451 break;
2452 case 0x50:
2453 q = "Transmitted SATA frame count";
2454 jout(" %s: %u\n", q, val);
2455 jref[q] = val;
2456 break;
2457 case 0x51:
2458 q = "Received SATA frame count";
2459 jout(" %s: %u\n", q, val);
2460 jref[q] = val;
2461 break;
2462 case 0x52:
2463 q = "SATA flow control buffer overflow count";
2464 jout(" %s: %u\n", q, val);
2465 jref[q] = val;
2466 break;
2467 case 0x60:
2468 q = "Transmitted SMP frame count";
2469 jout(" %s: %u\n", q, val);
2470 jref[q] = val;
2471 break;
2472 case 0x61:
2473 q = "Received SMP frame count";
2474 jout(" %s: %u\n", q, val);
2475 jref[q] = val;
2476 break;
2477 case 0x63:
2478 q = "Received SMP frame error count";
2479 jout(" %s: %u\n", q, val);
2480 jref[q] = val;
2481 break;
2482 default:
2483 break;
2484 }
2485}
2486
2487static void
2488show_sas_port_param(int port_num, unsigned char * ucp, int param_len)
2489{
2490 int k, j, m, nphys, t, sz, spld_len;
2491 char pn[32];
2492 unsigned char * vcp;
2493 char s[64];
2494 const char * q;
2495
2496 snprintf(pn, sizeof(pn), "scsi_sas_port_%d", port_num);
2497 sz = sizeof(s);
2498 // pcb = ucp[2];
2499 t = sg_get_unaligned_be16(ucp + 0);
2500 jout("relative target port id = %d\n", t);
2501 jglb[pn]["relative_target_port_id"] = t;
2502 jout(" generation code = %d\n", ucp[6]);
2503 jglb[pn]["generation_code"] = ucp[6];
2504 nphys = ucp[7];
2505 jout(" number of phys = %d\n", nphys);
2506 jglb[pn]["number_of_phys"] = nphys;
2507
2508 for (j = 0, k = 0, vcp = ucp + 8; j < (param_len - 8);
2509 vcp += spld_len, j += spld_len, ++k) {
2510 char yn[32];
2511
2512 snprintf(yn, sizeof(yn), "phy_%d", k);
2513 json::ref jref = jglb[pn][yn];
2514 jout(" phy identifier = %d\n", vcp[1]);
2515 jref["identifier"] = vcp[1];
2516 spld_len = vcp[3];
2517 if (spld_len < 44)
2518 spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
2519 else
2520 spld_len += 4;
2521 t = ((0x70 & vcp[4]) >> 4);
2522 switch (t) {
2523 case 0: snprintf(s, sz, "no device attached"); break;
2524 case 1: snprintf(s, sz, "SAS or SATA device"); break;
2525 case 2: snprintf(s, sz, "expander device"); break;
2526 case 3: snprintf(s, sz, "expander device (fanout)"); break;
2527 default: snprintf(s, sz, "reserved [%d]", t); break;
2528 }
2529 q = "attached device type";
2530 jout(" %s: %s\n", q, s);
2531 jref[q] = s;
2532 t = 0xf & vcp[4];
2533 switch (t) {
2534 case 0: snprintf(s, sz, "unknown"); break;
2535 case 1: snprintf(s, sz, "power on"); break;
2536 case 2: snprintf(s, sz, "hard reset"); break;
2537 case 3: snprintf(s, sz, "SMP phy control function"); break;
2538 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
2539 case 5: snprintf(s, sz, "mux mix up"); break;
2540 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
2541 break;
2542 case 7: snprintf(s, sz, "break timeout timer expired"); break;
2543 case 8: snprintf(s, sz, "phy test function stopped"); break;
2544 case 9: snprintf(s, sz, "expander device reduced functionality");
2545 break;
2546 default: snprintf(s, sz, "reserved [0x%x]", t); break;
2547 }
2548 q = "attached reason";
2549 jout(" %s: %s\n", q, s);
2550 jref[q] = s;
2551 t = (vcp[5] & 0xf0) >> 4;
2552 switch (t) {
2553 case 0: snprintf(s, sz, "unknown"); break;
2554 case 1: snprintf(s, sz, "power on"); break;
2555 case 2: snprintf(s, sz, "hard reset"); break;
2556 case 3: snprintf(s, sz, "SMP phy control function"); break;
2557 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
2558 case 5: snprintf(s, sz, "mux mix up"); break;
2559 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
2560 break;
2561 case 7: snprintf(s, sz, "break timeout timer expired"); break;
2562 case 8: snprintf(s, sz, "phy test function stopped"); break;
2563 case 9: snprintf(s, sz, "expander device reduced functionality");
2564 break;
2565 default: snprintf(s, sz, "reserved [0x%x]", t); break;
2566 }
2567 q = "reason";
2568 jout(" %s: %s\n", q, s);
2569 jref[q] = s;
2570 t = (0xf & vcp[5]);
2571 switch (t) {
2572 case 0: snprintf(s, sz, "phy enabled; unknown");
2573 break;
2574 case 1: snprintf(s, sz, "phy disabled"); break;
2575 case 2: snprintf(s, sz, "phy enabled; speed negotiation failed");
2576 break;
2577 case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state");
2578 break;
2579 case 4: snprintf(s, sz, "phy enabled; port selector");
2580 break;
2581 case 5: snprintf(s, sz, "phy enabled; reset in progress");
2582 break;
2583 case 6: snprintf(s, sz, "phy enabled; unsupported phy attached");
2584 break;
2585 case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
2586 case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
2587 case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
2588 case 0xb: snprintf(s, sz, "phy enabled; 12 Gbps"); break;
2589 default: snprintf(s, sz, "reserved [%d]", t); break;
2590 }
2591 q = "negotiated logical link rate";
2592 jout(" %s: %s\n", q, s);
2593 jref[q] = s;
2594 q = "attached initiator port";
2595 jout(" %s: ssp=%d stp=%d smp=%d\n", q,
2596 !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
2597 snprintf(s, sz, "%03d", ((vcp[6] & 8) ? 100 : 0) +
2598 ((vcp[6] & 4) ? 10 : 0) + ((vcp[6] & 2) ? 1 : 0));
2599 jref[q]["ssp_stp_smp"] = s;
2600 q = "attached target port";
2601 jout(" %s: ssp=%d stp=%d smp=%d\n", q,
2602 !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
2603 snprintf(s, sz, "%03d", ((vcp[7] & 8) ? 100 : 0) +
2604 ((vcp[7] & 4) ? 10 : 0) + ((vcp[7] & 2) ? 1 : 0));
2605 jref[q]["ssp_stp_smp"] = s;
2607 uint64_t ull = sg_get_unaligned_be64(vcp + 8);
2608 char b[32];
2609
2610 snprintf(b, sizeof(b), "0x%" PRIx64, ull);
2611 q = "SAS address";
2612 jout(" %s = %s\n", q, b);
2613 jref[q] = b;
2614 ull = sg_get_unaligned_be64(vcp + 16);
2615 snprintf(b, sizeof(b), "0x%" PRIx64, ull);
2616 q = "attached SAS address";
2617 jout(" %s = %s\n", q, b);
2618 jref[q] = b;
2619 }
2620 q = "attached phy identifier";
2621 jout(" %s = %d\n", q, vcp[24]);
2622 jref[q] = vcp[24];
2623 unsigned int ui = sg_get_unaligned_be32(vcp + 32);
2624
2625 q = "Invalid DWORD count";
2626 jout(" %s = %u\n", q, ui);
2627 jref[q] = ui;
2628 ui = sg_get_unaligned_be32(vcp + 36);
2629 q = "Running disparity error count";
2630 jout(" %s = %u\n", q, ui);
2631 jref[q] = ui;
2632 ui = sg_get_unaligned_be32(vcp + 40);
2633 q = "Loss of DWORD synchronization count";
2634 jout(" %s = %u\n", q, ui);
2635 jref[q] = ui;
2636 ui = sg_get_unaligned_be32(vcp + 44);
2637 q = "Phy reset problem count";
2638 jout(" %s = %u\n", q, ui);
2639 jref[q] = ui;
2640 if (spld_len > 51) {
2641 bool header_given = false;
2642 bool allow_dupl = (scsi_debugmode > 0);
2643 int num_ped;
2644 unsigned char * xcp;
2645
2646 num_ped = vcp[51];
2647 xcp = vcp + 52;
2648 for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
2649 int peis;
2650 unsigned int pvdt;
2651
2652 peis = xcp[3];
2653 ui = sg_get_unaligned_be32(xcp + 4);
2654 pvdt = sg_get_unaligned_be32(xcp + 8);
2655 if (allow_dupl || (peis > 0x4)) {
2656 if (! header_given) {
2657 header_given = true;
2658 jout(" Phy event descriptors:\n");
2659 }
2660 show_sas_phy_event_info(jref, peis, ui, pvdt);
2661 }
2662 }
2663 }
2664 }
2665}
2666
2667// Returns 1 if okay, 0 if non SAS descriptors
2668static int
2669show_protocol_specific_port_page(unsigned char * resp, int len)
2670{
2671 int k, j, num;
2672 unsigned char * ucp;
2673
2674 num = len - 4;
2675 for (k = 0, j = 0, ucp = resp + 4; k < num; ++j) {
2676 int param_len = ucp[3] + 4;
2677 if (SCSI_TPROTO_SAS != (0xf & ucp[4]))
2678 return 0; /* only decode SAS log page */
2679 if (0 == k)
2680 jout("\nProtocol Specific port %s for SAS SSP\n", lp_s);
2681 show_sas_port_param(j, ucp, param_len);
2682 k += param_len;
2683 ucp += param_len;
2684 }
2685 pout("\n");
2686 return 1;
2687}
2688
2689
2690// See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
2691// log page [0x18]. Returns 0 if ok else FAIL* bitmask.
2692static int
2693scsiPrintSasPhy(scsi_device * device, int reset)
2694{
2695 int num, err;
2696 static const char * hname = "Protocol specific port";
2697
2698 if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
2699 LOG_RESP_LONG_LEN, 0))) {
2700 print_on();
2701 pout("%s %s Failed [%s]\n\n", __func__, logSenStr,
2702 scsiErrString(err));
2703 print_off();
2704 return FAILSMART;
2705 }
2706 if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
2707 print_on();
2708 pout("%s %s, page mismatch\n\n", hname, logSenRspStr);
2709 print_off();
2710 return FAILSMART;
2711 }
2712 // compute page length
2713 num = sg_get_unaligned_be16(gBuf + 2);
2714 if (1 != show_protocol_specific_port_page(gBuf, num + 4)) {
2715 print_on();
2716 pout("Only support %s %s on SAS devices\n\n", hname, lp_s);
2717 print_off();
2718 return FAILSMART;
2719 }
2720 if (reset) {
2721 if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
2722 PROTOCOL_SPECIFIC_LPAGE, 0, nullptr, 0))) {
2723 print_on();
2724 pout("%s Log Select (reset) Failed [%s]\n\n", __func__,
2725 scsiErrString(err));
2726 print_off();
2727 return FAILSMART;
2728 }
2729 }
2730 return 0;
2731}
2732
2733
2734static const char * peripheral_dt_arr[32] = {
2735 "disk",
2736 "tape",
2737 "printer",
2738 "processor",
2739 "optical disk(4)",
2740 "CD/DVD",
2741 "scanner",
2742 "optical disk(7)",
2743 "medium changer",
2744 "communications",
2745 "graphics(10)",
2746 "graphics(11)",
2747 "storage array",
2748 "enclosure",
2749 "simplified disk",
2750 "optical card reader",
2751 "reserved [0x10]",
2752 "object based storage",
2753 "automation/driver interface",
2754 "security manager device",
2755 "host managed zoned block device",
2756 "reserved [0x15]",
2757 "reserved [0x16]",
2758 "reserved [0x17]",
2759 "reserved [0x18]",
2760 "reserved [0x19]",
2761 "reserved [0x1a]",
2762 "reserved [0x1b]",
2763 "reserved [0x1c]",
2764 "reserved [0x1d]",
2765 "well known logical unit",
2766 "unknown or no device type",
2767};
2768
2769/* Symbolic indexes to this array SCSI_TPROTO_* in scscmds.h */
2770static const char * transport_proto_arr[] = {
2771 "Fibre channel (FCP-4)",
2772 "Parallel SCSI (SPI-4)", /* obsolete */
2773 "SSA",
2774 "IEEE 1394 (SBP-3)",
2775 "RDMA (SRP)",
2776 "iSCSI",
2777 "SAS (SPL-4)",
2778 "ADT",
2779 "ATA (ACS-2)",
2780 "UAS",
2781 "SOP",
2782 "PCIe",
2783 "0xc",
2784 "0xd",
2785 "0xe",
2786 "None given [0xf]"
2787};
2788
2789/* Returns 0 on success, 1 on general error and 2 for early, clean exit */
2790static int
2791scsiGetDriveInfo(scsi_device * device, uint8_t * peripheral_type,
2792 bool & have_zbc, bool all)
2793{
2794 bool ok;
2795 bool is_tape = false;
2796 int err, iec_err, len, req_len, avail_len;
2797 int peri_dt = 0;
2798 int transport = -1;
2799 int form_factor = 0;
2800 int haw_zbc = 0;
2801 int protect = 0;
2802 const char * q;
2803 struct scsi_iec_mode_page iec;
2804
2805 memset(gBuf, 0, 96);
2806 have_zbc = false;
2807 req_len = 36;
2808 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
2809 print_on();
2810 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
2811 pout("Retrying with a 64 byte Standard Inquiry\n");
2812 print_off();
2813 /* Marvell controllers fail with 36 byte StdInquiry, but 64 is ok */
2814 req_len = 64;
2815 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
2816 print_on();
2817 pout("Standard Inquiry (64 bytes) failed [%s]\n",
2818 scsiErrString(err));
2819 print_off();
2820 return 1;
2821 }
2822 }
2823 avail_len = gBuf[4] + 5;
2824 len = (avail_len < req_len) ? avail_len : req_len;
2825 peri_dt = gBuf[0] & 0x1f;
2826 *peripheral_type = peri_dt;
2827 if (SCSI_PT_HOST_MANAGED == peri_dt)
2828 have_zbc = true;
2829 if ((SCSI_PT_SEQUENTIAL_ACCESS == peri_dt) ||
2830 (SCSI_PT_MEDIUM_CHANGER == peri_dt))
2831 is_tape = true;
2832
2833 if (len < 36) {
2834 print_on();
2835 pout("Short INQUIRY response, skip product id\n");
2836 print_off();
2837 return 1;
2838 }
2839 // Upper bits of version bytes were used in older standards
2840 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
2841 scsi_version = gBuf[2] & 0x7;
2842
2843 if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) {
2844 char product[16+1], revision[4+1];
2846 scsi_format_id_string(product, &gBuf[16], 16);
2847 scsi_format_id_string(revision, &gBuf[32], 4);
2848
2849 pout("=== START OF INFORMATION SECTION ===\n");
2850 jout("Vendor: %.8s\n", scsi_vendor);
2851 jglb["scsi_vendor"] = scsi_vendor;
2852 jout("Product: %.16s\n", product);
2853 jglb["scsi_product"] = product;
2854 jglb["scsi_model_name"] = strprintf("%s%s%s",
2855 scsi_vendor, (*scsi_vendor && *product ? " " : ""), product);
2856 if (gBuf[32] >= ' ') {
2857 jout("Revision: %.4s\n", revision);
2858 // jglb["firmware_version"] = revision;
2859 jglb["scsi_revision"] = revision;
2860 }
2861 if ((scsi_version > 0x3) && (scsi_version < 0x8)) {
2862 char sv_arr[8];
2863
2864 snprintf(sv_arr, sizeof(sv_arr), "SPC-%d", scsi_version - 2);
2865 jout("Compliance: %s\n", sv_arr);
2866 jglb["scsi_version"] = sv_arr;
2867 }
2868 }
2869
2870 if (!*device->get_req_type()/*no type requested*/ &&
2871 (0 == strncmp((char *)&gBuf[8], "ATA", 3))) {
2872 pout("\nProbable ATA device behind a SAT layer\n"
2873 "Try an additional '-d ata' or '-d sat' argument.\n");
2874 return 2;
2875 }
2876 if (! all)
2877 return 0;
2878
2879 protect = gBuf[5] & 0x1; /* from and including SPC-3 */
2880
2881 if (! is_tape) { /* assume disk if not tape drive (or tape changer) */
2882 struct scsi_readcap_resp srr;
2883 int lbpme = -1;
2884 int lbprz = -1;
2885 unsigned char lb_prov_resp[8];
2886 uint64_t capacity = scsiGetSize(device, false /*avoid_rcap16 */,
2887 &srr);
2888 static const char * lb_prov_j = "scsi_lb_provisioning";
2889
2890 if (capacity) {
2891 char cap_str[64], si_str[64];
2892 format_with_thousands_sep(cap_str, sizeof(cap_str), capacity);
2893 format_capacity(si_str, sizeof(si_str), capacity);
2894 jout("User Capacity: %s bytes [%s]\n", cap_str, si_str);
2895 if (srr.lb_size)
2896 jglb["user_capacity"]["blocks"].set_unsafe_uint64(capacity /
2897 srr.lb_size);
2898 jglb["user_capacity"]["bytes"].set_unsafe_uint64(capacity);
2899 jout("Logical block size: %u bytes\n", srr.lb_size);
2900 jglb["logical_block_size"] = srr.lb_size;
2901 if (protect || srr.lb_p_pb_exp) {
2902 if (srr.lb_p_pb_exp > 0) {
2903 unsigned pb_size = srr.lb_size * (1 << srr.lb_p_pb_exp);
2904 jout("Physical block size: %u bytes\n", pb_size);
2905 jglb["physical_block_size"] = pb_size;
2906 if (srr.l_a_lba > 0) // not common so cut the clutter
2907 pout("Lowest aligned LBA: %u\n", srr.l_a_lba);
2908 }
2909 if (srr.prot_type > 0) {
2910 switch (srr.prot_type) {
2911 case 1 :
2912 pout("Formatted with type 1 protection\n");
2913 break;
2914 case 2 :
2915 pout("Formatted with type 2 protection\n");
2916 break;
2917 case 3 :
2918 pout("Formatted with type 3 protection\n");
2919 break;
2920 default:
2921 pout("Formatted with unknown protection type [%d]\n",
2922 srr.prot_type);
2923 break;
2924 }
2925 jglb["scsi_protection_type"] = srr.prot_type;
2926 unsigned p_i_per_lb = (1 << srr.p_i_exp);
2927 const unsigned pi_sz = 8; /* ref-tag(4 bytes),
2928 app-tag(2), tag-mask(2) */
2929
2930 if (p_i_per_lb > 1) {
2931 jout("%d protection information intervals per "
2932 "logical block\n", p_i_per_lb);
2933 jglb["scsi_protection_intervals_per_lb"] = srr.prot_type;
2934 }
2935 jout("%d bytes of protection information per logical "
2936 "block\n", pi_sz * p_i_per_lb);
2937 jglb["scsi_protection_interval_bytes_per_lb"] =
2938 pi_sz * p_i_per_lb;
2939 }
2940 /* Pick up some LB provisioning info since its available */
2941 lbpme = (int)srr.lbpme;
2942 lbprz = (int)srr.lbprz;
2943 }
2944 }
2945 /* Thin Provisioning VPD page renamed Logical Block Provisioning VPD
2946 * page in sbc3r25; some fields changed their meaning so that the
2947 * new page covered both thin and resource provisioned LUs. */
2949 lb_prov_resp, sizeof(lb_prov_resp))) {
2950 int prov_type = lb_prov_resp[6] & 0x7; /* added sbc3r27 */
2951 int vpd_lbprz = ((lb_prov_resp[5] >> 2) & 0x7); /* sbc4r07 */
2952
2953 if (-1 == lbprz)
2954 lbprz = vpd_lbprz;
2955 else if ((0 == vpd_lbprz) && (1 == lbprz))
2956 ; /* vpd_lbprz introduced in sbc3r27, expanded in sbc4r07 */
2957 else
2958 lbprz = vpd_lbprz;
2959 switch (prov_type) {
2960 case 0:
2961 if (lbpme <= 0) {
2962 jout("LU is fully provisioned");
2963 jglb[lb_prov_j]["name"] = "fully provisioned";
2964 if (lbprz)
2965 jout(" [LBPRZ=%d]\n", lbprz);
2966 else
2967 jout("\n");
2968 } else {
2969 jout("LB provisioning type: not reported [LBPME=1, "
2970 "LBPRZ=%d]\n", lbprz);
2971 jglb[lb_prov_j]["name"] = "not reported";
2972 }
2973 break;
2974 case 1:
2975 jout("LU is resource provisioned, LBPRZ=%d\n", lbprz);
2976 jglb[lb_prov_j]["name"] = "resource provisioned";
2977 break;
2978 case 2:
2979 jout("LU is thin provisioned, LBPRZ=%d\n", lbprz);
2980 jglb[lb_prov_j]["name"] = "thin provisioned";
2981 break;
2982 default:
2983 jout("LU provisioning type reserved [%d], LBPRZ=%d\n",
2984 prov_type, lbprz);
2985 jglb[lb_prov_j]["name"] = "reserved";
2986 break;
2987 }
2988 jglb[lb_prov_j]["value"] = prov_type;
2989 jglb[lb_prov_j]["management_enabled"]["name"] = "LBPME";
2990 jglb[lb_prov_j]["management_enabled"]["value"] = lbpme;
2991 jglb[lb_prov_j]["read_zeros"]["name"] = "LBPRZ";
2992 jglb[lb_prov_j]["read_zeros"]["value"] = lbprz;
2993 } else if (1 == lbpme) {
2994 if (scsi_debugmode > 0)
2995 jout("rcap_16 sets LBPME but no LB provisioning VPD page\n");
2996 jout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz);
2997 }
2998
2999 int rpm = scsiGetRPM(device, modese_len, &form_factor, &haw_zbc);
3000 if (rpm >= 0) {
3001 if (0 == rpm)
3002 ; // Not reported
3003 else if (1 == rpm)
3004 jout("Rotation Rate: Solid State Device\n");
3005 else if ((rpm <= 0x400) || (0xffff == rpm))
3006 ; // Reserved
3007 else
3008 jout("Rotation Rate: %d rpm\n", rpm);
3009 jglb["rotation_rate"] = (rpm == 1 ? 0 : rpm);
3010 }
3011 if (form_factor > 0) {
3012 const char * cp = nullptr;
3013
3014 switch (form_factor) {
3015 case 1:
3016 cp = "5.25";
3017 break;
3018 case 2:
3019 cp = "3.5";
3020 break;
3021 case 3:
3022 cp = "2.5";
3023 break;
3024 case 4:
3025 cp = "1.8";
3026 break;
3027 case 5:
3028 cp = "< 1.8";
3029 break;
3030 }
3031 jglb["form_factor"]["scsi_value"] = form_factor;
3032 if (cp) {
3033 jout("Form Factor: %s inches\n", cp);
3034 jglb["form_factor"]["name"] = strprintf("%s inches", cp);
3035 }
3036 }
3037 if (haw_zbc == 1) {
3038 have_zbc = true;
3039 q = "Host aware zoned block capable";
3040 jout("%s\n", q);
3041 jglb[std::string("scsi_") + json::str2key(q)] = true;
3042 } else if (haw_zbc == 2) {
3043 have_zbc = true;
3044 q = "Device managed zoned block capable";
3045 jout("%s\n", q);
3046 jglb[std::string("scsi_") + json::str2key(q)] = true;
3047 } else {
3049
3050 if (s_vpd_pp &&
3052 // TODO: need to read that VPD page and look at the
3053 // 'Zoned block device extension' field
3054
3055 }
3056 }
3057 }
3058
3059 /* Do this here to try and detect badly conforming devices (some USB
3060 keys) that will lock up on a InquiryVpd or log sense or ... */
3061 if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) {
3062 if (SIMPLE_ERR_BAD_RESP == iec_err) {
3063 pout(">> Terminate command early due to bad response to IEC "
3064 "mode page\n");
3065 print_off();
3066 gIecMPage = 0;
3067 return 1;
3068 }
3069 } else
3070 modese_len = iec.modese_len;
3071
3073 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_DEVICE_IDENTIFICATION,
3074 gBuf, 252))) {
3075 char s[256];
3076
3077 len = gBuf[3];
3078 scsi_decode_lu_dev_id(gBuf + 4, len, s, sizeof(s), &transport);
3079 if (strlen(s) > 0) {
3080 jout("Logical Unit id: %s\n", s);
3081 jglb["logical_unit_id"] = s;
3082 }
3083 } else if (scsi_debugmode > 0) {
3084 print_on();
3085 if (SIMPLE_ERR_BAD_RESP == err)
3086 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
3087 else
3088 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
3089 print_off();
3090 }
3091 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_UNIT_SERIAL_NUMBER,
3092 gBuf, 252))) {
3093 char serial[256];
3094 len = gBuf[3];
3095
3096 gBuf[4 + len] = '\0';
3097 scsi_format_id_string(serial, &gBuf[4], len);
3098 jout("Serial number: %s\n", serial);
3099 jglb["serial_number"] = serial;
3100 } else if (scsi_debugmode > 0) {
3101 print_on();
3102 if (SIMPLE_ERR_BAD_RESP == err)
3103 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
3104 else
3105 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
3106 print_off();
3107 }
3108 }
3109
3110 // print SCSI peripheral device type
3111 jglb["device_type"]["scsi_terminology"] = "Peripheral Device Type [PDT]";
3112 jglb["device_type"]["scsi_value"] = peri_dt;
3113 if (peri_dt < (int)(ARRAY_SIZE(peripheral_dt_arr))) {
3114 jout("Device type: %s\n", peripheral_dt_arr[peri_dt]);
3115 jglb["device_type"]["name"] = peripheral_dt_arr[peri_dt];
3116 }
3117 else
3118 jout("Device type: <%d>\n", peri_dt);
3119
3120 // See if transport protocol is known
3121 if (transport < 0)
3122 transport = scsiFetchTransportProtocol(device, modese_len);
3123 if ((transport >= 0) && (transport <= 0xf)) {
3124 jout("Transport protocol: %s\n", transport_proto_arr[transport]);
3125 jglb["scsi_transport_protocol"]["name"] = transport_proto_arr[transport];
3126 jglb["scsi_transport_protocol"]["value"] = transport;
3127 }
3128
3129 jout_startup_datetime("Local Time is: ");
3130
3131 // See if unit accepts SCSI commands from us
3132 if ((err = scsiTestUnitReady(device))) {
3133 if (SIMPLE_ERR_NOT_READY == err) {
3134 print_on();
3135 if (!is_tape)
3136 pout("device is NOT READY (e.g. spun down, busy)\n");
3137 else
3138 pout("device is NOT READY (e.g. no tape)\n");
3139 print_off();
3140 } else if (SIMPLE_ERR_NO_MEDIUM == err) {
3141 print_on();
3142 if (is_tape)
3143 pout("NO tape present in drive\n");
3144 else
3145 pout("NO MEDIUM present in device\n");
3146 print_off();
3147 } else if (SIMPLE_ERR_BECOMING_READY == err) {
3148 print_on();
3149 pout("device becoming ready (wait)\n");
3150 print_off();
3151 } else {
3152 print_on();
3153 pout("device Test Unit Ready [%s]\n", scsiErrString(err));
3154 print_off();
3155 }
3156 if (! is_tape) {
3157 // TODO: exit with FAILID if failuretest returns
3159 }
3160 }
3161
3162 if (iec_err) {
3163 if (!is_tape) {
3164 print_on();
3165 jout("SMART support is: Unavailable - device lacks SMART "
3166 "capability.\n");
3167 jglb["smart_support"]["available"] = false;
3168 if (scsi_debugmode > 0)
3169 pout(" [%s]\n", scsiErrString(iec_err));
3170 print_off();
3171 }
3172 gIecMPage = 0;
3173 return 0;
3174 }
3175
3176 if (!is_tape) {
3178 jout("SMART support is: Available - device has SMART capability.\n"
3179 "SMART support is: %s\n", ok ? "Enabled" : "Disabled");
3180 jglb["smart_support"]["available"] = true;
3181 jglb["smart_support"]["enabled"] = ok;
3182 }
3183 ok = scsi_IsWarningEnabled(&iec);
3184 jout("Temperature Warning: %s\n",
3185 ok ? "Enabled" : "Disabled or Not Supported");
3186 jglb["temperature_warning"]["enabled"] = ok;
3187 return 0;
3188}
3189
3190static int
3192{
3193 struct scsi_iec_mode_page iec;
3194 int err;
3195
3196 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
3197 print_on();
3198 pout("unable to fetch IEC (SMART) mode page [%s]\n",
3199 scsiErrString(err));
3200 print_off();
3201 return 1;
3202 } else
3203 modese_len = iec.modese_len;
3204
3205 if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) {
3206 print_on();
3207 pout("unable to enable Exception control and warning [%s]\n",
3208 scsiErrString(err));
3209 print_off();
3210 return 1;
3211 }
3212 /* Need to refetch 'iec' since could be modified by previous call */
3213 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
3214 pout("unable to fetch IEC (SMART) mode page [%s]\n",
3215 scsiErrString(err));
3216 return 1;
3217 } else
3218 modese_len = iec.modese_len;
3219
3220 pout("Informational Exceptions (SMART) %s\n",
3221 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
3222 pout("Temperature warning %s\n",
3223 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
3224 return 0;
3225}
3226
3227static int
3229{
3230 struct scsi_iec_mode_page iec;
3231 int err;
3232
3233 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
3234 print_on();
3235 pout("unable to fetch IEC (SMART) mode page [%s]\n",
3236 scsiErrString(err));
3237 print_off();
3238 return 1;
3239 } else
3240 modese_len = iec.modese_len;
3241
3242 if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) {
3243 print_on();
3244 pout("unable to disable Exception control and warning [%s]\n",
3245 scsiErrString(err));
3246 print_off();
3247 return 1;
3248 }
3249 /* Need to refetch 'iec' since could be modified by previous call */
3250 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
3251 pout("unable to fetch IEC (SMART) mode page [%s]\n",
3252 scsiErrString(err));
3253 return 1;
3254 } else
3255 modese_len = iec.modese_len;
3256
3257 pout("Informational Exceptions (SMART) %s\n",
3258 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
3259 pout("Temperature warning %s\n",
3260 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
3261 return 0;
3262}
3263
3264static void
3266{
3267 uint8_t temp = 255;
3268 uint8_t trip = 255;
3269
3270 if (scsiGetTemp(device, &temp, &trip))
3271 return;
3272
3273 if (255 == temp)
3274 pout("Current Drive Temperature: <not available>\n");
3275 else {
3276 jout("Current Drive Temperature: %d C\n", temp);
3277 jglb["temperature"]["current"] = temp;
3278 }
3279 if (255 == trip)
3280 pout("Drive Trip Temperature: <not available>\n");
3281 else {
3282 jout("Drive Trip Temperature: %d C\n", trip);
3283 jglb["temperature"]["drive_trip"] = trip;
3284 }
3285 pout("\n");
3286}
3287
3288static void
3290{
3291 int len, num, err;
3292 int temp_num = 0;
3293 int humid_num = 0;
3294 unsigned char * ucp;
3295 const char * q;
3296 static const char * hname = "Environmental Reports";
3297 static const char * jname = "scsi_environmental_reports";
3298 static const char * rh_n = "relative humidity";
3299 static const char * temp_n = "temperature";
3300 static const char * sop_n = "since power on";
3301 static const char * unkn_n = "unknown";
3302
3304 gBuf, LOG_RESP_LEN, -1 /* single fetch */))) {
3305 print_on();
3306 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
3307 print_off();
3308 return;
3309 }
3310 if (((gBuf[0] & 0x3f) != TEMPERATURE_LPAGE) ||
3311 (gBuf[1] != ENVIRO_REP_L_SPAGE)) {
3312 print_on();
3313 pout("%s %s Failed, page mismatch\n", hname, logSenStr);
3314 print_off();
3315 return;
3316 }
3317 if (! (gBuf[0] & 0x40)) {
3318 if (scsi_debugmode > 0) {
3319 print_on();
3320 pout("Another flaky device that doesn't set the SPF bit\n");
3321 print_off();
3322 }
3323 }
3324 len = sg_get_unaligned_be16(gBuf + 2);
3325 num = len - 4;
3326 ucp = &gBuf[0] + 4;
3327
3328 while (num > 3) {
3329 int pc = sg_get_unaligned_be16(ucp + 0);
3330 int pl = ucp[3] + 4;
3331 char pc_s[32];
3332 std::string s;
3333
3334 if ((pc < 0x100) && (pl == 12)) {
3335 snprintf(pc_s, sizeof(pc_s), "temperature_%d", ++temp_num);
3336 /* temperature is two's complement 8 bit in centigrade */
3337 int temp = (int)(int8_t)ucp[5];
3338
3339 jglb[jname][pc_s]["parameter_code"] = pc;
3340 q = "Current";
3341 s = json::str2key(q);
3342 if (ucp[5] == 0x80) {
3343 jout("%s %s = %s\n", q, temp_n, unkn_n);
3344 jglb[jname][pc_s][s] = unkn_n;
3345 } else {
3346 jout("%s %s = %d\n", q, temp_n, temp);
3347 jglb[jname][pc_s][s] = temp;
3348 }
3349 temp = (int)(int8_t)ucp[6];
3350 q = "Lifetime maximum";
3351 s = json::str2key(q);
3352 if (ucp[6] == 0x80) {
3353 jout("%s %s = %s\n", q, temp_n, unkn_n);
3354 jglb[jname][pc_s][s] = unkn_n;
3355 } else {
3356 jout("%s %s = %d\n", q, temp_n, temp);
3357 jglb[jname][pc_s][s] = temp;
3358 }
3359 temp = (int)(int8_t)ucp[7];
3360 q = "Lifetime minimum";
3361 s = json::str2key(q);
3362 if (ucp[7] == 0x80) {
3363 jout("%s %s = %s\n", q, temp_n, unkn_n);
3364 jglb[jname][pc_s][s] = unkn_n;
3365 } else {
3366 jout("%s %s = %d\n", q, temp_n, temp);
3367 jglb[jname][pc_s][s] = temp;
3368 }
3369 temp = (int)(int8_t)ucp[8];
3370 q = "Maximum since power on";
3371 s = json::str2key(q);
3372 if (ucp[8] == 0x80) {
3373 jout("Maximum %s %s = %s\n", temp_n, sop_n, unkn_n);
3374 jglb[jname][pc_s][s] = unkn_n;
3375 } else {
3376 jout("Maximum %s %s = %d\n", temp_n, sop_n, temp);
3377 jglb[jname][pc_s][s] = temp;
3378 }
3379 temp = (int)(int8_t)ucp[9];
3380 q = "Minimum since power on";
3381 s = json::str2key(q);
3382 if (ucp[9] == 0x80) {
3383 jout("Minimum %s %s = %s\n", temp_n, sop_n, unkn_n);
3384 jglb[jname][pc_s][s] = unkn_n;
3385 } else {
3386 jout("Minimum %s %s = %d\n", temp_n, sop_n, temp);
3387 jglb[jname][pc_s][s] = temp;
3388 }
3389 if ((ucp[4] & 0x3) == 1) { /* OTV field set to 1 */
3390 temp = (int)(int8_t)ucp[10];
3391 q = "Maximum other";
3392 s = json::str2key(q);
3393 if (ucp[10] == 0x80) {
3394 jout("%s %s = %s\n", q, temp_n, unkn_n);
3395 jglb[jname][pc_s][s] = unkn_n;
3396 } else {
3397 jout("%s %s = %d\n", q, temp_n, temp);
3398 jglb[jname][pc_s][s] = temp;
3399 }
3400 temp = (int)(int8_t)ucp[11];
3401 q = "Minimum other";
3402 s = json::str2key(q);
3403 if (ucp[11] == 0x80) {
3404 jout("%s %s = %s\n", q, temp_n, unkn_n);
3405 jglb[jname][pc_s][s] = unkn_n;
3406 } else {
3407 jout("%s %s = %d\n", q, temp_n, temp);
3408 jglb[jname][pc_s][s] = temp;
3409 }
3410 }
3411 } else if ((pc < 0x200) && (pl == 12)) {
3412 snprintf(pc_s, sizeof(pc_s), "relative_humidity_%d", ++humid_num);
3413 jglb[jname][pc_s]["parameter_code"] = pc;
3414 jout("Relative humidity = %u\n", ucp[5]);
3415 jglb[jname][pc_s]["current"] = ucp[5];
3416 q = "Lifetime maximum";
3417 s = json::str2key(q);
3418 jout("%s %s = %d\n", q, rh_n, ucp[6]);
3419 jglb[jname][pc_s][s] = ucp[6];
3420 q = "Lifetime minimum";
3421 s = json::str2key(q);
3422 jout("%s %s = %d\n", q, rh_n, ucp[7]);
3423 jglb[jname][pc_s][s] = ucp[7];
3424 jout("Maximum %s %s = %d\n", rh_n, sop_n, ucp[8]);
3425 jglb[jname][pc_s]["maximum_since_power_on"] = ucp[8];
3426 jout("Minimum %s %s = %d\n", rh_n, sop_n, ucp[9]);
3427 jglb[jname][pc_s]["minimum_since_power_on"] = ucp[9];
3428 if ((ucp[4] & 0x3) == 1) { /* ORHV field set to 1 */
3429 q = "Maximum other";
3430 s = json::str2key(q);
3431 jout("%s %s = %d\n", q, rh_n, ucp[10]);
3432 jglb[jname][pc_s][s] = ucp[10];
3433 q = "Minimum other";
3434 s = json::str2key(q);
3435 jout("%s %s = %d\n", q, rh_n, ucp[11]);
3436 jglb[jname][pc_s][s] = ucp[11];
3437 }
3438 } else {
3439 if (scsi_debugmode > 0) {
3440 print_on();
3441 if ((pc < 0x200) && (pl != 12))
3442 pout("%s sub-lpage unexpected parameter length [%d], skip\n",
3443 hname, pl);
3444 else
3445 pout("%s sub-lpage has unexpected parameter [0x%x], skip\n",
3446 hname, pc);
3447 print_off();
3448 }
3449 return;
3450 }
3451 num -= pl;
3452 ucp += pl;
3453 }
3454}
3455
3456
3457/* Main entry point used by smartctl command. Return 0 for success */
3458int
3460{
3461 bool envRepDone = false;
3462 uint8_t peripheral_type = 0;
3463 int returnval = 0;
3464 int res, durationSec;
3465 struct scsi_sense_disect sense_info;
3466 bool is_disk;
3467 bool is_zbc;
3468 bool is_tape;
3469 bool any_output = options.drive_info;
3470
3471// Enable -n option for SCSI Drives
3472 const char * powername = nullptr;
3473 bool powerchg = false;
3474
3475 if (options.powermode) {
3476 scsiRequestSense(device, &sense_info) ;
3477 if (sense_info.asc == 0x5E) {
3478 unsigned char powerlimit = 0xff;
3479 int powermode = sense_info.ascq ;
3480
3481 // 5Eh/00h DZTPRO A K LOW POWER CONDITION ON
3482 // 5Eh/01h DZTPRO A K IDLE CONDITION ACTIVATED BY TIMER
3483 // 5Eh/02h DZTPRO A K STANDBY CONDITION ACTIVATED BY TIMER
3484 // 5Eh/03h DZTPRO A K IDLE CONDITION ACTIVATED BY COMMAND
3485 // 5Eh/04h DZTPRO A K STANDBY CONDITION ACTIVATED BY COMMAND
3486 // 5Eh/05h DZTPRO A K IDLE_B CONDITION ACTIVATED BY TIMER
3487 // 5Eh/06h DZTPRO A K IDLE_B CONDITION ACTIVATED BY COMMAND
3488 // 5Eh/07h DZTPRO A K IDLE_C CONDITION ACTIVATED BY TIMER
3489 // 5Eh/08h DZTPRO A K IDLE_C CONDITION ACTIVATED BY COMMAND
3490 // 5Eh/09h DZTPRO A K STANDBY_Y CONDITION ACTIVATED BY TIMER
3491 // 5Eh/0Ah DZTPRO A K STANDBY_Y CONDITION ACTIVATED BY COMMAND
3492 // 5Eh/41h B POWER STATE CHANGE TO ACTIVE
3493 // 5Eh/42h B POWER STATE CHANGE TO IDLE
3494 // 5Eh/43h B POWER STATE CHANGE TO STANDBY
3495 // 5Eh/45h B POWER STATE CHANGE TO SLEEP
3496 // 5Eh/47h BK POWER STATE CHANGE TO DEVICE CONTROL
3497
3498 switch (powermode) {
3499 case -1:
3500 if (device->is_syscall_unsup()) {
3501 pout("CHECK POWER MODE not implemented, ignoring -n option\n"); break;
3502 }
3503 powername = "SLEEP"; powerlimit = 2;
3504 break;
3505
3506 case 0x00: // LOW POWER CONDITION ON
3507 powername = "LOW POWER"; powerlimit = 2; break;
3508 case 0x01: // IDLE CONDITION ACTIVATED BY TIMER
3509 powername = "IDLE BY TIMER"; powerlimit = 4; break;
3510 case 0x02: // STANDBY CONDITION ACTIVATED BY TIMER
3511 powername = "STANDBY BY TIMER"; powerlimit = 2; break;
3512 case 0x03: // IDLE CONDITION ACTIVATED BY COMMAND
3513 powername = "IDLE BY COMMAND"; powerlimit = 4; break;
3514 case 0x04: // STANDBY CONDITION ACTIVATED BY COMMAND
3515 powername = "STANDBY BY COMMAND"; powerlimit = 2; break;
3516 case 0x05: // IDLE_B CONDITION ACTIVATED BY TIMER
3517 powername = "IDLE BY TIMER"; powerlimit = 4; break;
3518 case 0x06: // IDLE_B CONDITION ACTIVATED BY COMMAND
3519 powername = "IDLE_ BY COMMAND"; powerlimit = 4; break;
3520 case 0x07: // IDLE_C CONDITION ACTIVATED BY TIMER
3521 powername = "IDLE_C BY TIMER"; powerlimit = 4; break;
3522 case 0x08: // IDLE_C CONDITION ACTIVATED BY COMMAND
3523 powername = "IDLE_C BY COMMAND"; powerlimit = 4; break;
3524 case 0x09: // STANDBY_Y CONDITION ACTIVATED BY TIMER
3525 powername = "STANDBY_Y BY TIMER"; powerlimit = 2; break;
3526 case 0x0A: // STANDBY_Y CONDITION ACTIVATED BY COMMAND
3527 powername = "STANDBY_Y BY COMMAND"; powerlimit = 2; break;
3528
3529 default:
3530 pout("CHECK POWER MODE returned unknown value 0x%02x, "
3531 "ignoring -n option\n", powermode);
3532 break;
3533 }
3534 if (powername) {
3535 if (options.powermode >= powerlimit) {
3536 jinf("Device is in %s mode, exit(%d)\n", powername, options.powerexit);
3537 return options.powerexit;
3538 }
3539 powerchg = (powermode != 0xff);
3540 }
3541 } else
3542 powername = "ACTIVE";
3543 }
3544
3545 delete supported_vpd_pages_p;
3547
3548 res = scsiGetDriveInfo(device, &peripheral_type, is_zbc,
3549 options.drive_info || options.farm_log);
3550 if (res) {
3551 if (2 == res)
3552 return 0;
3553 else
3554 failuretest(MANDATORY_CMD, returnval |= FAILID);
3555 any_output = true;
3556 }
3557 is_disk = ((SCSI_PT_DIRECT_ACCESS == peripheral_type) ||
3558 (SCSI_PT_HOST_MANAGED == peripheral_type));
3559 is_tape = ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
3560 (SCSI_PT_MEDIUM_CHANGER == peripheral_type));
3561 bool ge_spc4 = device->is_spc4_or_higher();
3562 if (ge_spc4 && (! device->checked_cmd_support())) {
3563 if (! device->query_cmd_support()) {
3564 if (scsi_debugmode)
3565 pout("%s: query_cmd_support() failed\n", __func__);
3566 }
3567 }
3568
3569 short int wce = -1, rcd = -1;
3570 // Print read look-ahead status for disks
3571 if (options.get_rcd || options.get_wce) {
3572 if (is_disk) {
3573 res = scsiGetSetCache(device, modese_len, &wce, &rcd);
3574 if (options.get_rcd)
3575 pout("Read Cache is: %s\n",
3576 res ? "Unavailable" : // error
3577 rcd ? "Disabled" : "Enabled");
3578 if (options.get_wce)
3579 pout("Writeback Cache is: %s\n",
3580 res ? "Unavailable" : // error
3581 !wce ? "Disabled" : "Enabled");
3582 }
3583 any_output = true;
3584 }
3585
3586 if (options.drive_info) {
3587 if (powername) // Print power condition if requested -n (nocheck)
3588 pout("Power mode %s %s\n", (powerchg?"was:":"is: "), powername);
3589 pout("\n");
3590 }
3591
3592 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
3593 if (options.smart_disable || options.smart_enable ||
3595 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
3596
3597 if (options.smart_enable) {
3598 if (scsiSmartEnable(device))
3599 failuretest(MANDATORY_CMD, returnval |= FAILSMART);
3600 any_output = true;
3601 }
3602
3603 if (options.smart_disable) {
3604 if (scsiSmartDisable(device))
3605 failuretest(MANDATORY_CMD,returnval |= FAILSMART);
3606 any_output = true;
3607 }
3608
3609 if (options.smart_auto_save_enable) {
3610 if (scsiSetControlGLTSD(device, 0, modese_len)) {
3611 pout("Enable autosave (clear GLTSD bit) failed\n");
3612 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
3613 } else
3614 pout("Autosave enabled (GLTSD bit cleared).\n");
3615 any_output = true;
3616 }
3617
3618 // Enable/Disable write cache
3619 if (options.set_wce && is_disk) {
3620 short int enable = wce = (options.set_wce > 0);
3621
3622 rcd = -1;
3623 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
3624 pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"),
3625 device->get_errmsg());
3626 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
3627 } else
3628 pout("Write cache %sabled\n", (enable ? "en" : "dis"));
3629 any_output = true;
3630 }
3631
3632 // Enable/Disable read cache
3633 if (options.set_rcd && is_disk) {
3634 short int enable = (options.set_rcd > 0);
3635
3636 rcd = !enable;
3637 wce = -1;
3638 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
3639 pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"),
3640 device->get_errmsg());
3641 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
3642 } else
3643 pout("Read cache %sabled\n", (enable ? "en" : "dis"));
3644 any_output = true;
3645 }
3646
3647 if (options.smart_auto_save_disable) {
3648 if (scsiSetControlGLTSD(device, 1, modese_len)) {
3649 pout("Disable autosave (set GLTSD bit) failed\n");
3650 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
3651 } else
3652 pout("Autosave disabled (GLTSD bit set).\n");
3653 any_output = true;
3654 }
3655 if (options.smart_disable || options.smart_enable ||
3657 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
3658
3659 // START OF READ-ONLY OPTIONS APART FROM -V and -i
3660 if (options.smart_check_status || options.smart_ss_media_log ||
3661 options.smart_vendor_attrib || options.smart_error_log ||
3662 options.smart_selftest_log || options.smart_background_log ||
3663 options.sasphy)
3664 pout("=== START OF READ SMART DATA SECTION ===\n");
3665
3666 // Most of the following need log page data. Check for the supported log
3667 // pages unless we have been told by RSOC that LOG SENSE is not supported
3668 if (SC_NO_SUPPORT != device->cmd_support_level(LOG_SENSE, false, 0))
3670
3671 if (options.smart_check_status) {
3672 if (is_tape) {
3673 if (gTapeAlertsLPage) {
3674 if (options.drive_info) {
3675 jout("TapeAlert Supported\n");
3676 jglb["tapealert"]["supported"] = true;
3677 }
3678 if (options.health_opt_count > 1) {
3679 if (-1 == scsiPrintActiveTapeAlerts(device, peripheral_type, true))
3680 failuretest(OPTIONAL_CMD, returnval |= FAILSMART);
3681 }
3682 } else {
3683 jout("TapeAlert Not Supported\n");
3684 jglb["tapealert"]["supported"] = false;
3685 }
3686 } else { /* disk, cd/dvd, enclosure, etc */
3687 if ((res = scsiGetSmartData(device,
3688 options.smart_vendor_attrib))) {
3689 if (-2 == res)
3690 returnval |= FAILSTATUS;
3691 else
3692 returnval |= FAILSMART;
3693 }
3694 }
3695 any_output = true;
3696 }
3697
3698 if (is_disk && options.smart_ss_media_log) {
3699 res = 0;
3700 if (gSSMediaLPage)
3701 res = scsiPrintSSMedia(device);
3702 if (0 != res)
3703 failuretest(OPTIONAL_CMD, returnval|=res);
3705 res = scsiPrintFormatStatus(device);
3706 if (0 != res)
3707 failuretest(OPTIONAL_CMD, returnval|=res);
3708 any_output = true;
3709 }
3710 if (options.smart_vendor_attrib) {
3711 if (gEnviroReportingLPage && options.smart_env_rep) {
3713 envRepDone = true;
3714 } else if (gTempLPage)
3715 scsiPrintTemp(device);
3716 // in the 'smartctl -A' case only want: "Accumulated power on time"
3717 if ((! options.smart_background_log) && is_disk) {
3718 res = 0;
3720 res = scsiPrintBackgroundResults(device, true);
3721 (void)res; // not yet used below, suppress warning
3722 }
3723 if (gStartStopLPage)
3724 scsiGetStartStopData(device);
3725 if (is_disk) {
3726 enum scsi_cmd_support rdefect10 =
3727 device->cmd_support_level(READ_DEFECT_10, false, 0);
3728 enum scsi_cmd_support rdefect12 =
3729 device->cmd_support_level(READ_DEFECT_12, false, 0);
3730
3731 if ((SC_NO_SUPPORT == rdefect10) && (SC_NO_SUPPORT == rdefect12))
3732 ;
3733 else if (SC_SUPPORT == rdefect12)
3734 scsiPrintGrownDefectListLen(device, true);
3735 else
3736 scsiPrintGrownDefectListLen(device, false);
3737
3742 }
3743 any_output = true;
3744 }
3745 // Print SCSI FARM log for Seagate SCSI drive
3746 if (options.farm_log || options.farm_log_suggest) {
3747 bool farm_supported = true;
3748 // Check if drive is a Seagate drive that supports FARM
3749 if (gSeagateFarmLPage) {
3750 // If -x/-xall or -a/-all is run without explicit -l farm, suggests FARM log
3751 if (options.farm_log_suggest && !options.farm_log) {
3752 jout("Seagate FARM log supported [try: -l farm]\n\n");
3753 // Otherwise, actually pull the FARM log
3754 } else {
3755 scsiFarmLog farmLog;
3756 if (!scsiReadFarmLog(device, farmLog)) {
3757 pout("\nRead FARM log (SCSI Log page 0x3d, sub-page 0x3) failed\n\n");
3758 farm_supported = false;
3759 } else {
3760 scsiPrintFarmLog(farmLog);
3761 }
3762 }
3763 } else {
3764 if (options.farm_log) {
3765 jout("\nFARM log (SCSI Log page 0x3d, sub-page 0x3) not supported\n\n");
3766 }
3767 farm_supported = false;
3768 }
3769 jglb["seagate_farm_log"]["supported"] = farm_supported;
3770 }
3771 if (options.smart_error_log || options.scsi_pending_defects) {
3772 if (options.smart_error_log) {
3774 any_output = true;
3775 }
3776 if (gPendDefectsLPage) {
3778 any_output = true;
3779 }
3780 if (options.smart_error_log) {
3781 if (1 == scsiFetchControlGLTSD(device, modese_len, 1)) {
3782 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
3783 "Enable Save with '-S on']\n");
3784 any_output = true;
3785 }
3786 }
3787 }
3788 if (options.smart_selftest_log) {
3789 res = 0;
3790 if (gSelfTestLPage)
3791 res = scsiPrintSelfTest(device);
3792 else {
3793 pout("Device does not support Self Test logging\n");
3794 if (! is_tape)
3795 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
3796 }
3797 if (0 != res)
3798 failuretest(OPTIONAL_CMD, returnval|=res);
3799 any_output = true;
3800 }
3801 if (options.smart_background_log && is_disk) {
3802 res = 0;
3804 res = scsiPrintBackgroundResults(device, false);
3805 else {
3806 pout("Device does not support Background scan results logging\n");
3807 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
3808 }
3809 if (0 != res)
3810 failuretest(OPTIONAL_CMD, returnval|=res);
3811 any_output = true;
3812 }
3813 if (options.zoned_device_stats && is_zbc) {
3814 res = 0;
3816 res = scsiPrintZBDeviceStats(device);
3817 else {
3818 pout("Device does not support %s logging\n", zbds_s);
3819 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
3820 }
3821 if (0 != res)
3822 failuretest(OPTIONAL_CMD, returnval|=res);
3823 any_output = true;
3824 }
3825 if (options.general_stats_and_perf) {
3826 res = 0;
3828 res = scsiPrintGStatsPerf(device);
3829 else {
3830 pout("Device does not support %s logging\n", gsap_s);
3831 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
3832 }
3833 if (0 != res)
3834 failuretest(OPTIONAL_CMD, returnval|=res);
3835 any_output = true;
3836
3837 }
3838 if (is_tape) {
3839 if (options.tape_device_stats) {
3840 res = 0;
3842 res = scsiPrintTapeDeviceStats(device);
3843 } else {
3844 pout("Device does not support (tape) device characteristics "
3845 "(SSC) logging\n");
3846 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
3847 }
3848 if (0 != res)
3849 failuretest(OPTIONAL_CMD, returnval|=res);
3850 any_output = true;
3851 }
3852 if (options.tape_alert) {
3853 res = 0;
3854 if (gTapeAlertsLPage) {
3855 res = scsiPrintActiveTapeAlerts(device, peripheral_type, false);
3856 } else {
3857 pout("Device does not support TapeAlert logging\n");
3858 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
3859 }
3860 if (res < 0)
3861 failuretest(OPTIONAL_CMD, returnval|=res);
3862 if ((scsi_debugmode > 0) && (res == 0))
3863 pout("TapeAlerts only printed if active, so none printed is good\n");
3864 any_output = true;
3865 }
3866 }
3867 if (options.smart_default_selftest) {
3868 if (scsiSmartDefaultSelfTest(device))
3869 return returnval | FAILSMART;
3870 pout("Default Self Test Successful\n");
3871 any_output = true;
3872 }
3873 if (options.smart_short_cap_selftest) {
3874 if (scsiSmartShortCapSelfTest(device))
3875 return returnval | FAILSMART;
3876 pout("Short Foreground Self Test Successful\n");
3877 any_output = true;
3878 }
3879 // check if another test is running
3880 if (options.smart_short_selftest || options.smart_extend_selftest) {
3881 if (!scsiRequestSense(device, &sense_info) &&
3882 (sense_info.asc == 0x04 && sense_info.ascq == 0x09)) {
3883 if (!options.smart_selftest_force) {
3884 pout("Can't start self-test without aborting current test");
3885 if (sense_info.progress != -1)
3886 pout(" (%d%% remaining)",
3887 100 - sense_info.progress * 100 / 65535);
3888 pout(",\nadd '-t force' option to override, or run "
3889 "'smartctl -X' to abort test.\n");
3890 return -1;
3891 } else
3892 scsiSmartSelfTestAbort(device);
3893 }
3894 }
3895 if (options.smart_short_selftest) {
3896 if (scsiSmartShortSelfTest(device))
3897 return returnval | FAILSMART;
3898 pout("Short Background Self Test has begun\n");
3899 pout("Use smartctl -X to abort test\n");
3900 any_output = true;
3901 }
3902 if (options.smart_extend_selftest) {
3903 if (scsiSmartExtendSelfTest(device))
3904 return returnval | FAILSMART;
3905 pout("Extended Background Self Test has begun\n");
3906 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
3907 modese_len)) && (durationSec > 0)) {
3908 time_t t = time(nullptr);
3909
3910 t += durationSec;
3911 pout("Please wait %d minutes for test to complete.\n",
3912 durationSec / 60);
3913 char comptime[DATEANDEPOCHLEN];
3914 dateandtimezoneepoch(comptime, t);
3915 pout("Estimated completion time: %s\n", comptime);
3916 }
3917 pout("Use smartctl -X to abort test\n");
3918 any_output = true;
3919 }
3920 if (options.smart_extend_cap_selftest) {
3921 if (scsiSmartExtendCapSelfTest(device))
3922 return returnval | FAILSMART;
3923 pout("Extended Foreground Self Test Successful\n");
3924 }
3925 if (options.smart_selftest_abort) {
3926 if (scsiSmartSelfTestAbort(device))
3927 return returnval | FAILSMART;
3928 pout("Self Test returned without error\n");
3929 any_output = true;
3930 }
3931 if (options.sasphy) {
3933 if (scsiPrintSasPhy(device, options.sasphy_reset))
3934 return returnval | FAILSMART;
3935 any_output = true;
3936 }
3937 }
3938 if (options.smart_env_rep && ! envRepDone) {
3941 any_output = true;
3942 }
3943 }
3944
3945 if (options.set_standby == 1) {
3947 pout("SCSI SSU(ACTIVE) command failed: %s\n",
3948 device->get_errmsg());
3949 returnval |= FAILSMART;
3950 } else
3951 pout("Device placed in ACTIVE mode\n");
3952 } else if (options.set_standby > 1) {
3953 pout("SCSI SSU(STANDBY) with timeout not supported yet\n");
3954 returnval |= FAILSMART;
3955 } else if (options.set_standby_now) {
3957 pout("SCSI STANDBY command failed: %s\n", device->get_errmsg());
3958 returnval |= FAILSMART;
3959 } else
3960 pout("Device placed in STANDBY mode\n");
3961 }
3962
3963 if (!any_output && powername) // Output power mode if -n (nocheck)
3964 pout("Device is in %s mode\n", powername);
3965
3966 if (!any_output)
3967 pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
3968 "to print SMART (and more) information\n\n");
3969
3970 return returnval;
3971}
bool dont_print_serial_number
Definition: atacmds.cpp:37
Reference to a JSON element.
Definition: json.h:105
static std::string str2key(const char *str)
Replace space and non-alphanumerics with '_', upper to lower case.
Definition: json.cpp:41
SCSI device access.
bool is_spc4_or_higher() const
bool checked_cmd_support() const
bool query_cmd_support()
Definition: scsicmds.cpp:80
enum scsi_cmd_support cmd_support_level(uint8_t opcode, bool sa_valid, uint16_t sa, bool for_lsense_spc=false) const
Definition: scsicmds.cpp:172
const char * get_req_type() const
Get type requested by user, empty if none.
const char * get_errmsg() const
Get last error message.
virtual bool is_syscall_unsup() const
Return true if last error indicates an unsupported system call.
bool is_supported(int vpd_page_num) const
Definition: scsicmds.cpp:216
scsi_cmd_support
@ SC_SUPPORT
@ SC_NO_SUPPORT
bool scsiReadFarmLog(scsi_device *device, scsiFarmLog &farmLog)
Definition: farmcmds.cpp:162
bool scsiIsSeagate(char *scsi_vendor)
Definition: farmcmds.cpp:149
void scsiPrintFarmLog(const scsiFarmLog &farmLog)
Definition: farmprint.cpp:508
u32 count
Definition: megaraid.h:1
u8 b[12]
Definition: megaraid.h:17
u16 s[6]
Definition: megaraid.h:18
unsigned char failuretest_permissive
Definition: smartctl.cpp:1456
int scsiSetPowerCondition(scsi_device *device, int power_cond, int pcond_modifier)
Definition: scsicmds.cpp:1361
int scsiReadDefect12(scsi_device *device, int req_plist, int req_glist, int dl_format, int addrDescIndex, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1506
int scsiFetchExtendedSelfTestTime(scsi_device *device, int *durationSec, int modese_len)
Definition: scsicmds.cpp:2555
void scsiDecodeErrCounterPage(unsigned char *resp, struct scsiErrorCounter *ecp, int allocLen)
Definition: scsicmds.cpp:2607
int scsiSetExceptionControlAndWarning(scsi_device *device, int enabled, const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1928
int scsiSmartExtendCapSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2530
int scsiFetchIECmpage(scsi_device *device, struct scsi_iec_mode_page *iecp, int modese_len)
Definition: scsicmds.cpp:1838
int scsiGetTemp(scsi_device *device, uint8_t *currenttemp, uint8_t *triptemp)
Definition: scsicmds.cpp:1998
int scsiSmartShortCapSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2519
int scsiSmartSelfTestAbort(scsi_device *device)
Definition: scsicmds.cpp:2542
char * scsi_get_sense_key_str(int sense_key, int buff_len, char *buff)
Definition: scsicmds.cpp:695
const char * scsiTapeAlertsTapeDevice(unsigned short code)
Definition: scsicmds.cpp:2327
int scsiFetchTransportProtocol(scsi_device *device, int modese_len)
Definition: scsicmds.cpp:3055
int scsi_decode_lu_dev_id(const unsigned char *b, int blen, char *s, int slen, int *transport)
Definition: scsicmds.cpp:747
int scsiTestUnitReady(scsi_device *device)
Definition: scsicmds.cpp:1456
int scsiInquiryVpd(scsi_device *device, int vpd_page, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1210
int scsiSmartExtendSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2507
void scsiDecodeNonMediumErrPage(unsigned char *resp, struct scsiNonMediumError *nmep, int allocLen)
Definition: scsicmds.cpp:2652
int scsiRequestSense(scsi_device *device, struct scsi_sense_disect *sense_info)
Definition: scsicmds.cpp:1268
int scsiCheckIE(scsi_device *device, int hasIELogPage, int hasTempLogPage, uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp, uint8_t *triptemp)
Definition: scsicmds.cpp:2026
uint64_t scsiGetSize(scsi_device *device, bool avoid_rcap16, struct scsi_readcap_resp *srrp)
Definition: scsicmds.cpp:1713
char * scsiGetIEString(uint8_t asc, uint8_t ascq, char *b, int blen)
Definition: scsicmds.cpp:3196
int scsiGetSetCache(scsi_device *device, int modese_len, short int *wcep, short int *rcdp)
Definition: scsicmds.cpp:2881
supported_vpd_pages * supported_vpd_pages_p
Definition: scsicmds.cpp:47
int scsiGetRPM(scsi_device *device, int modese_len, int *form_factorp, int *haw_zbcp)
Definition: scsicmds.cpp:2836
void scsi_format_id_string(char *out, const uint8_t *in, int n)
Definition: scsicmds.cpp:3115
int scsiStdInquiry(scsi_device *device, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1163
int scsiSmartDefaultSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2485
void dStrHex(const uint8_t *up, int len, int no_ascii)
Definition: scsicmds.cpp:368
const char * scsiErrString(int scsiErr)
Definition: scsicmds.cpp:630
const char * scsiTapeAlertsChangerDevice(unsigned short code)
Definition: scsicmds.cpp:2475
int scsiFetchControlGLTSD(scsi_device *device, int modese_len, int current)
Definition: scsicmds.cpp:2799
int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1899
int scsiSetControlGLTSD(scsi_device *device, int enabled, int modese_len)
Definition: scsicmds.cpp:2985
int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1885
int scsiSmartShortSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2496
int scsiLogSense(scsi_device *device, int pagenum, int subpagenum, uint8_t *pBuf, int bufLen, int known_resp_len)
Definition: scsicmds.cpp:873
unsigned char scsi_debugmode
Definition: scsicmds.cpp:45
int scsiLogSelect(scsi_device *device, int pcr, int sp, int pc, int pagenum, int subpagenum, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:962
int scsiReadDefect10(scsi_device *device, int req_plist, int req_glist, int dl_format, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1472
#define ENVIRO_LIMITS_L_SPAGE
Definition: scsicmds.h:248
#define SIMPLE_ERR_BECOMING_READY
Definition: scsicmds.h:354
#define LOGPAGEHDRSIZE
Definition: scsicmds.h:385
#define SCSI_TPROTO_SAS
Definition: scsicmds.h:208
#define SIMPLE_ERR_NOT_READY
Definition: scsicmds.h:348
#define LAST_N_ERROR_EVENTS_LPAGE
Definition: scsicmds.h:225
#define SCSI_VPD_DEVICE_IDENTIFICATION
Definition: scsicmds.h:309
#define READ_DEFECT_12
Definition: scsicmds.h:70
#define PEND_DEFECTS_L_SPAGE
Definition: scsicmds.h:251
#define LPS_MISALIGN_L_SPAGE
Definition: scsicmds.h:253
#define READ_DEFECT_10
Definition: scsicmds.h:67
#define SEAGATE_FARM_LPAGE
Definition: scsicmds.h:258
#define SCSI_VPD_LOGICAL_BLOCK_PROVISIONING
Definition: scsicmds.h:316
#define SCSI_VPD_ZONED_BLOCK_DEV_CHAR
Definition: scsicmds.h:317
#define TAPE_ALERTS_LPAGE
Definition: scsicmds.h:269
#define SIMPLE_ERR_NO_MEDIUM
Definition: scsicmds.h:353
#define SELFTEST_RESULTS_LPAGE
Definition: scsicmds.h:232
#define LOG_SENSE
Definition: scsicmds.h:40
#define SCSI_POW_COND_ACTIVE
Definition: scsicmds.h:373
#define SCSI_POW_COND_STANDBY
Definition: scsicmds.h:375
#define VERIFY_ERROR_COUNTER_LPAGE
Definition: scsicmds.h:223
#define SUPPORTED_LPAGES
Definition: scsicmds.h:218
#define SCSI_PT_MEDIUM_CHANGER
Definition: scsicmds.h:196
#define NON_MEDIUM_ERROR_LPAGE
Definition: scsicmds.h:224
#define SCSI_VPD_UNIT_SERIAL_NUMBER
Definition: scsicmds.h:308
#define UTILIZATION_L_SPAGE
Definition: scsicmds.h:249
#define SCSI_PT_SEQUENTIAL_ACCESS
Definition: scsicmds.h:192
#define ENVIRO_REP_L_SPAGE
Definition: scsicmds.h:247
#define SS_MEDIA_LPAGE
Definition: scsicmds.h:233
#define NO_SUBPAGE_L_SPAGE
Definition: scsicmds.h:244
#define SCSI_PT_HOST_MANAGED
Definition: scsicmds.h:199
#define ZB_DEV_STATS_L_SPAGE
Definition: scsicmds.h:250
#define FORMAT_STATUS_LPAGE
Definition: scsicmds.h:226
#define SUPP_SPAGE_L_SPAGE
Definition: scsicmds.h:254
#define LOG_RESP_SELF_TEST_LEN
Definition: scsicmds.h:265
#define BACKGROUND_RESULTS_LPAGE
Definition: scsicmds.h:235
#define PROTOCOL_SPECIFIC_LPAGE
Definition: scsicmds.h:238
#define TEMPERATURE_LPAGE
Definition: scsicmds.h:229
#define WRITE_ERROR_COUNTER_LPAGE
Definition: scsicmds.h:220
#define SIMPLE_ERR_BAD_RESP
Definition: scsicmds.h:352
#define SCSI_PT_DIRECT_ACCESS
Definition: scsicmds.h:191
#define READ_ERROR_COUNTER_LPAGE
Definition: scsicmds.h:221
#define SEAGATE_FACTORY_LPAGE
Definition: scsicmds.h:259
#define BACKGROUND_OP_L_SPAGE
Definition: scsicmds.h:252
#define IE_LPAGE
Definition: scsicmds.h:241
#define SEAGATE_FARM_CURRENT_L_SPAGE
Definition: scsicmds.h:262
#define GEN_STATS_PERF_LPAGE
Definition: scsicmds.h:239
#define DEVICE_STATS_LPAGE
Definition: scsicmds.h:234
#define STARTSTOP_CYCLE_COUNTER_LPAGE
Definition: scsicmds.h:230
#define SEAGATE_CACHE_LPAGE
Definition: scsicmds.h:257
static bool gSmartLPage
Definition: scsiprint.cpp:50
static bool gFormatStatusLPage
Definition: scsiprint.cpp:63
static bool gSeagateFactoryLPage
Definition: scsiprint.cpp:76
static bool gEnviroLimitsLPage
Definition: scsiprint.cpp:65
static void scsiPrintTemp(scsi_device *device)
Definition: scsiprint.cpp:3265
static int scsiPrintActiveTapeAlerts(scsi_device *device, int peripheral_type, bool from_health)
Definition: scsiprint.cpp:430
static void scsiPrintSeagateCacheLPage(scsi_device *device)
Definition: scsiprint.cpp:773
static void scsiGetSupportedLogPages(scsi_device *device)
Definition: scsiprint.cpp:143
static void show_sas_phy_event_info(const json::ref &jref, int peis, unsigned int val, unsigned thresh_val)
Definition: scsiprint.cpp:2285
static const char * lp_s
Definition: scsiprint.cpp:105
static std::string rtrim(const std::string &s, const char *t=" \t\n\r\f\v")
Definition: scsiprint.cpp:134
static int scsiGetDriveInfo(scsi_device *device, uint8_t *peripheral_type, bool &have_zbc, bool all)
Definition: scsiprint.cpp:2791
static bool gBackgroundResultsLPage
Definition: scsiprint.cpp:59
#define T10_VENDOR_HITACHI_2
Definition: scsiprint.cpp:97
static bool gPendDefectsLPage
Definition: scsiprint.cpp:67
static int scsiPrintBackgroundResults(scsi_device *device, bool only_pow_time)
Definition: scsiprint.cpp:1302
const char * scsiprint_c_cvsid
Definition: scsiprint.cpp:36
static const char * bms_status[]
Definition: scsiprint.cpp:1271
static const char * zbds_s
Definition: scsiprint.cpp:104
#define ARRAY_SIZE(arr)
Definition: scsiprint.cpp:39
#define SCSI_VERSION_HIGHEST
Definition: scsiprint.cpp:90
#define T10_VENDOR_HITACHI_3
Definition: scsiprint.cpp:98
static int scsiPrintSelfTest(scsi_device *device)
Definition: scsiprint.cpp:1090
static bool gLPSMisalignLPage
Definition: scsiprint.cpp:69
#define LOG_RESP_TAPE_ALERT_LEN
Definition: scsiprint.cpp:44
static char scsi_vendor[8+1]
Definition: scsiprint.cpp:94
#define T10_VENDOR_SEAGATE
Definition: scsiprint.cpp:95
static const char * self_test_result[]
Definition: scsiprint.cpp:1066
#define LOG_RESP_LONG_LEN
Definition: scsiprint.cpp:43
static bool gSSMediaLPage
Definition: scsiprint.cpp:62
static const char * reassign_status[]
Definition: scsiprint.cpp:1283
static int scsiPrintFormatStatus(scsi_device *device)
Definition: scsiprint.cpp:2185
static bool gTapeDeviceStatsLPage
Definition: scsiprint.cpp:70
static bool gGenStatsAndPerfLPage
Definition: scsiprint.cpp:72
static int show_protocol_specific_port_page(unsigned char *resp, int len)
Definition: scsiprint.cpp:2669
static bool gStartStopLPage
Definition: scsiprint.cpp:53
static void scsiPrintErrorCounterLog(scsi_device *device)
Definition: scsiprint.cpp:933
static const char * logSenRspStr
Definition: scsiprint.cpp:101
static void scsiPrintPendingDefectsLPage(scsi_device *device)
Definition: scsiprint.cpp:575
static bool gTempLPage
Definition: scsiprint.cpp:51
static bool gUtilizationLPage
Definition: scsiprint.cpp:66
static bool gSeagateCacheLPage
Definition: scsiprint.cpp:75
static bool gTapeAlertsLPage
Definition: scsiprint.cpp:61
static int modese_len
Definition: scsiprint.cpp:83
static int scsiPrintGStatsPerf(scsi_device *device)
Definition: scsiprint.cpp:1522
static bool gSelfTestLPage
Definition: scsiprint.cpp:52
static void scsiPrintGrownDefectListLen(scsi_device *device, bool prefer12)
Definition: scsiprint.cpp:654
static bool gSeagateFarmLPage
Definition: scsiprint.cpp:77
static uint64_t variableLengthIntegerParam(const unsigned char *ucp)
Definition: scsiprint.cpp:759
static int scsiGetSmartData(scsi_device *device, bool attribs)
Definition: scsiprint.cpp:372
static const char * peripheral_dt_arr[32]
Definition: scsiprint.cpp:2734
static bool gZBDeviceStatsLPage
Definition: scsiprint.cpp:71
static void show_sas_port_param(int port_num, unsigned char *ucp, int param_len)
Definition: scsiprint.cpp:2488
#define LOG_RESP_LEN
Definition: scsiprint.cpp:42
static int scsiSmartEnable(scsi_device *device)
Definition: scsiprint.cpp:3191
uint8_t gBuf[GBUF_SIZE]
Definition: scsiprint.cpp:41
static bool gReadECounterLPage
Definition: scsiprint.cpp:54
static const char * transport_proto_arr[]
Definition: scsiprint.cpp:2770
static void scsiPrintSeagateFactoryLPage(scsi_device *device)
Definition: scsiprint.cpp:842
static int scsi_version
Definition: scsiprint.cpp:86
static bool gEnviroReportingLPage
Definition: scsiprint.cpp:64
#define SCSI_VERSION_SPC_4
Definition: scsiprint.cpp:87
static const char *const severities
Definition: scsiprint.cpp:427
static void scsiPrintEnviroReporting(scsi_device *device)
Definition: scsiprint.cpp:3289
#define T10_VENDOR_HITACHI_1
Definition: scsiprint.cpp:96
static int scsiPrintTapeDeviceStats(scsi_device *device)
Definition: scsiprint.cpp:1910
static bool gProtocolSpecificLPage
Definition: scsiprint.cpp:60
#define SCSI_SUPP_LOG_PAGES_MAX_COUNT
Definition: scsiprint.cpp:47
static const char * logSenStr
Definition: scsiprint.cpp:100
static const char * ssm_s
Definition: scsiprint.cpp:103
static bool gBackgroundOpLPage
Definition: scsiprint.cpp:68
static const char * gsap_s
Definition: scsiprint.cpp:102
static int scsiPrintSSMedia(scsi_device *device)
Definition: scsiprint.cpp:1723
static int scsiPrintSasPhy(scsi_device *device, int reset)
Definition: scsiprint.cpp:2693
static bool gVerifyECounterLPage
Definition: scsiprint.cpp:56
static int64_t scsiGetTimeUnitInNano(const uint8_t *ucp, int num, uint16_t ti_pc)
Definition: scsiprint.cpp:1457
static const char * self_test_code[]
Definition: scsiprint.cpp:1055
static bool gNonMediumELPage
Definition: scsiprint.cpp:57
static int scsiSmartDisable(scsi_device *device)
Definition: scsiprint.cpp:3228
static bool all_ffs(const uint8_t *bp, int b_len)
Definition: scsiprint.cpp:122
static void scsiGetStartStopData(scsi_device *device)
Definition: scsiprint.cpp:491
static bool gLastNErrorEvLPage
Definition: scsiprint.cpp:58
static bool gWriteECounterLPage
Definition: scsiprint.cpp:55
#define GBUF_SIZE
Definition: scsiprint.cpp:34
int scsiPrintMain(scsi_device *device, const scsi_print_options &options)
Definition: scsiprint.cpp:3459
static bool seagate_or_hitachi(void)
Definition: scsiprint.cpp:109
static void scsiPrintTimeUnitInNano(int leadin_spaces, uint64_t intervals, int64_t timeUnitInNS)
Definition: scsiprint.cpp:1503
static int scsiPrintZBDeviceStats(scsi_device *device)
Definition: scsiprint.cpp:1782
static bool gIecMPage
Definition: scsiprint.cpp:80
#define SCSIPRINT_H_CVSID
Definition: scsiprint.h:19
static uint64_t sg_get_unaligned_be64(const void *p)
Definition: sg_unaligned.h:267
static uint64_t sg_get_unaligned_be(int num_bytes, const void *p)
Definition: sg_unaligned.h:350
static uint16_t sg_get_unaligned_be16(const void *p)
Definition: sg_unaligned.h:256
static uint32_t sg_get_unaligned_be32(const void *p)
Definition: sg_unaligned.h:261
void jout_startup_datetime(const char *prefix)
Definition: smartctl.cpp:1449
json jglb
Definition: smartctl.cpp:53
void failuretest(failure_type type, int returnvalue)
Definition: smartctl.cpp:1461
void void jinf(const char *fmt,...) __attribute_format_printf(1
#define FAILID
Definition: smartctl.h:30
#define FAILSTATUS
Definition: smartctl.h:36
void print_off()
Definition: smartctl.h:79
#define FAILSMART
Definition: smartctl.h:33
void jout(const char *fmt,...) __attribute_format_printf(1
@ OPTIONAL_CMD
Definition: smartctl.h:57
@ MANDATORY_CMD
Definition: smartctl.h:58
void print_on()
Definition: smartctl.h:74
#define FAILLOG
Definition: smartctl.h:49
void pout(const char *fmt,...)
Definition: smartd.cpp:1338
uint8_t gotPC[7]
Definition: scsicmds.h:156
uint64_t counter[8]
Definition: scsicmds.h:158
uint64_t counterTFE_H
Definition: scsicmds.h:167
uint64_t counterPE_H
Definition: scsicmds.h:169
uint8_t gotTFE_H
Definition: scsicmds.h:166
uint64_t counterPC0
Definition: scsicmds.h:165
uint8_t modese_len
Definition: scsicmds.h:149
short int set_rcd
Definition: scsiprint.h:53
bool smart_background_log
Definition: scsiprint.h:29
bool smart_selftest_abort
Definition: scsiprint.h:38
bool smart_auto_save_disable
Definition: scsiprint.h:33
bool smart_selftest_force
Definition: scsiprint.h:39
short int set_wce
Definition: scsiprint.h:53
unsigned char powerexit
Definition: scsiprint.h:56
bool smart_vendor_attrib
Definition: scsiprint.h:26
bool smart_default_selftest
Definition: scsiprint.h:35
bool smart_selftest_log
Definition: scsiprint.h:28
bool smart_short_cap_selftest
Definition: scsiprint.h:36
bool smart_check_status
Definition: scsiprint.h:25
bool smart_short_selftest
Definition: scsiprint.h:36
bool smart_extend_cap_selftest
Definition: scsiprint.h:37
bool smart_extend_selftest
Definition: scsiprint.h:37
bool tape_device_stats
Definition: scsiprint.h:47
bool smart_auto_save_enable
Definition: scsiprint.h:33
bool smart_ss_media_log
Definition: scsiprint.h:30
unsigned char powermode
Definition: scsiprint.h:55
bool scsi_pending_defects
Definition: scsiprint.h:40
bool general_stats_and_perf
Definition: scsiprint.h:41
bool zoned_device_stats
Definition: scsiprint.h:50
uint16_t l_a_lba
Definition: scsicmds.h:182
uint8_t lb_p_pb_exp
Definition: scsicmds.h:179
uint8_t prot_type
Definition: scsicmds.h:176
uint8_t p_i_exp
Definition: scsicmds.h:178
uint32_t lb_size
Definition: scsicmds.h:174
uint8_t subpage_code
Definition: scsicmds.h:187
void dateandtimezoneepoch(char(&buffer)[DATEANDEPOCHLEN], time_t tval)
Definition: utility.cpp:346
const char * format_capacity(char *str, int strsize, uint64_t val, const char *decimal_point)
Definition: utility.cpp:745
const char * format_with_thousands_sep(char *str, int strsize, uint64_t val, const char *thousands_sep)
Definition: utility.cpp:713
std::string strprintf(const char *fmt,...)
Definition: utility.cpp:796
#define DATEANDEPOCHLEN
Definition: utility.h:64