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