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