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