4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2002-11 Bruce Allen
7 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
8 * Copyright (C) 2003-18 Douglas Gilbert <dgilbert@interlog.com>
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
24 #include "atacmds.h" // smart_command_set
25 #include "dev_interface.h"
26 #include "scsiprint.h"
29 #include "sg_unaligned.h"
31 #define GBUF_SIZE 65532
33 const char * scsiprint_c_cvsid
= "$Id: scsiprint.cpp 4870 2018-12-27 17:07:44Z chrfranke $"
37 uint8_t gBuf
[GBUF_SIZE
];
38 #define LOG_RESP_LEN 252
39 #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
40 #define LOG_RESP_TAPE_ALERT_LEN 0x144
42 /* Log pages supported */
43 static bool gSmartLPage
= false; /* Informational Exceptions log page */
44 static bool gTempLPage
= false;
45 static bool gSelfTestLPage
= false;
46 static bool gStartStopLPage
= false;
47 static bool gReadECounterLPage
= false;
48 static bool gWriteECounterLPage
= false;
49 static bool gVerifyECounterLPage
= false;
50 static bool gNonMediumELPage
= false;
51 static bool gLastNErrorEvLPage
= false;
52 static bool gBackgroundResultsLPage
= false;
53 static bool gProtocolSpecificLPage
= false;
54 static bool gTapeAlertsLPage
= false;
55 static bool gSSMediaLPage
= false;
56 static bool gFormatStatusLPage
= false;
57 static bool gEnviroReportingLPage
= false;
58 static bool gEnviroLimitsLPage
= false;
59 static bool gUtilizationLPage
= false;
60 static bool gPendDefectsLPage
= false;
61 static bool gBackgroundOpLPage
= false;
62 static bool gLPSMisalignLPage
= false;
64 /* Vendor specific log pages */
65 static bool gSeagateCacheLPage
= false;
66 static bool gSeagateFactoryLPage
= false;
68 /* Mode pages supported */
69 static bool gIecMPage
= true; /* N.B. assume it until we know otherwise */
71 /* Remember last successful mode sense/select command */
72 static int modese_len
= 0;
74 /* Remember this value from the most recent INQUIRY */
75 static int scsi_version
;
76 #define SCSI_VERSION_SPC_4 0x6
77 #define SCSI_VERSION_SPC_5 0x7
78 #define SCSI_VERSION_HIGHEST SCSI_VERSION_SPC_5
80 /* T10 vendor identification. Should match entry in last Annex of SPC
81 * drafts and standards (e.g. SPC-4). */
82 static char scsi_vendor
[8+1];
83 #define T10_VENDOR_SEAGATE "SEAGATE"
84 #define T10_VENDOR_HITACHI_1 "HITACHI"
85 #define T10_VENDOR_HITACHI_2 "HL-DT-ST"
86 #define T10_VENDOR_HITACHI_3 "HGST"
88 static const char * logSenStr
= "Log Sense";
89 static const char * logSenRspStr
= "Log Sense response";
93 seagate_or_hitachi(void)
95 return ((0 == memcmp(scsi_vendor
, T10_VENDOR_SEAGATE
,
96 strlen(T10_VENDOR_SEAGATE
))) ||
97 (0 == memcmp(scsi_vendor
, T10_VENDOR_HITACHI_1
,
98 strlen(T10_VENDOR_HITACHI_1
))) ||
99 (0 == memcmp(scsi_vendor
, T10_VENDOR_HITACHI_2
,
100 strlen(T10_VENDOR_HITACHI_2
))) ||
101 (0 == memcmp(scsi_vendor
, T10_VENDOR_HITACHI_3
,
102 strlen(T10_VENDOR_HITACHI_3
))));
106 all_ffs(const uint8_t * bp
, int b_len
)
108 if ((NULL
== bp
) || (b_len
<= 0))
110 for (--b_len
; b_len
>= 0; --b_len
) {
111 if (0xff != bp
[b_len
])
118 scsiGetSupportedLogPages(scsi_device
* device
)
120 bool got_subpages
= false;
121 int k
, bump
, err
, payload_len
, num_unreported
, num_unreported_spg
;
123 uint8_t sup_lpgs
[LOG_RESP_LEN
];
125 memset(gBuf
, 0, LOG_RESP_LEN
);
126 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
128 if (scsi_debugmode
> 0)
129 pout("%s for supported pages failed [%s]\n", logSenStr
,
131 /* try one more time with defined length, workaround for the bug #678
132 found with ST8000NM0075/E001 */
133 err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
134 LOG_RESP_LEN
, 68); /* 64 max pages + 4b header */
135 if (scsi_debugmode
> 0)
136 pout("%s for supported pages failed (second attempt) [%s]\n",
137 logSenStr
, scsiErrString(err
));
140 memcpy(sup_lpgs
, gBuf
, LOG_RESP_LEN
);
141 } else if ((scsi_version
>= SCSI_VERSION_SPC_4
) &&
142 (scsi_version
<= SCSI_VERSION_HIGHEST
)) {
143 /* unclear what code T10 will choose for SPC-6 */
144 memcpy(sup_lpgs
, gBuf
, LOG_RESP_LEN
);
145 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, SUPP_SPAGE_L_SPAGE
,
146 gBuf
, LOG_RESP_LONG_LEN
,
147 -1 /* just single not double fetch */))) {
148 if (scsi_debugmode
> 0)
149 pout("%s for supported pages and subpages failed [%s]\n",
150 logSenStr
, scsiErrString(err
));
152 if (0 == memcmp(gBuf
, sup_lpgs
, LOG_RESP_LEN
)) {
153 if (scsi_debugmode
> 0)
154 pout("%s: %s ignored subpage field, bad\n",
155 __func__
, logSenRspStr
);
156 } else if (! ((0x40 & gBuf
[0]) &&
157 (SUPP_SPAGE_L_SPAGE
== gBuf
[1]))) {
158 if (scsi_debugmode
> 0)
159 pout("%s supported subpages is bad SPF=%u SUBPG=%u\n",
160 logSenRspStr
, !! (0x40 & gBuf
[0]), gBuf
[2]);
165 memcpy(sup_lpgs
, gBuf
, LOG_RESP_LEN
);
168 payload_len
= sg_get_unaligned_be16(gBuf
+ 2);
170 up
= gBuf
+ LOGPAGEHDRSIZE
;
172 payload_len
= sup_lpgs
[3];
174 up
= sup_lpgs
+ LOGPAGEHDRSIZE
;
177 num_unreported_spg
= 0;
178 for (num_unreported
= 0, k
= 0; k
< payload_len
; k
+= bump
, up
+= bump
) {
179 uint8_t pg_num
= 0x3f & up
[0];
180 uint8_t sub_pg_num
= (0x40 & up
[0]) ? up
[1] : 0;
184 case SUPPORTED_LPAGES
:
185 if (! ((NO_SUBPAGE_L_SPAGE
== sub_pg_num
) ||
186 (SUPP_SPAGE_L_SPAGE
== sub_pg_num
))) {
187 if (scsi_debugmode
> 1)
188 pout("%s: Strange Log page number: 0x0,0x%x\n",
189 __func__
, sub_pg_num
);
192 case READ_ERROR_COUNTER_LPAGE
:
193 gReadECounterLPage
= true;
195 case WRITE_ERROR_COUNTER_LPAGE
:
196 gWriteECounterLPage
= true;
198 case VERIFY_ERROR_COUNTER_LPAGE
:
199 gVerifyECounterLPage
= true;
201 case LAST_N_ERROR_EVENTS_LPAGE
:
202 gLastNErrorEvLPage
= true;
204 case NON_MEDIUM_ERROR_LPAGE
:
205 gNonMediumELPage
= true;
207 case TEMPERATURE_LPAGE
:
208 if (NO_SUBPAGE_L_SPAGE
== sub_pg_num
)
210 else if (ENVIRO_REP_L_SPAGE
== sub_pg_num
)
211 gEnviroReportingLPage
= true;
212 else if (ENVIRO_LIMITS_L_SPAGE
== sub_pg_num
)
213 gEnviroLimitsLPage
= true;
216 ++num_unreported_spg
;
219 case STARTSTOP_CYCLE_COUNTER_LPAGE
:
220 if (NO_SUBPAGE_L_SPAGE
== sub_pg_num
)
221 gStartStopLPage
= true;
222 else if (UTILIZATION_L_SPAGE
== sub_pg_num
)
223 gUtilizationLPage
= true;
226 ++num_unreported_spg
;
229 case SELFTEST_RESULTS_LPAGE
:
230 gSelfTestLPage
= true;
235 case BACKGROUND_RESULTS_LPAGE
:
236 if (NO_SUBPAGE_L_SPAGE
== sub_pg_num
)
237 gBackgroundResultsLPage
= true;
238 else if (PEND_DEFECTS_L_SPAGE
== sub_pg_num
)
239 gPendDefectsLPage
= true;
240 else if (BACKGROUND_OP_L_SPAGE
== sub_pg_num
)
241 gBackgroundOpLPage
= true;
242 else if (LPS_MISALIGN_L_SPAGE
== sub_pg_num
)
243 gLPSMisalignLPage
= true;
246 ++num_unreported_spg
;
249 case PROTOCOL_SPECIFIC_LPAGE
:
250 gProtocolSpecificLPage
= true;
252 case TAPE_ALERTS_LPAGE
:
253 gTapeAlertsLPage
= true;
256 gSSMediaLPage
= true;
258 case FORMAT_STATUS_LPAGE
:
259 gFormatStatusLPage
= true;
261 case SEAGATE_CACHE_LPAGE
:
262 if (failuretest_permissive
) {
263 gSeagateCacheLPage
= true;
266 if (seagate_or_hitachi())
267 gSeagateCacheLPage
= true;
269 case SEAGATE_FACTORY_LPAGE
:
270 if (failuretest_permissive
) {
271 gSeagateFactoryLPage
= true;
274 if (seagate_or_hitachi())
275 gSeagateFactoryLPage
= true;
278 if (pg_num
< 0x30) { /* don't count VS pages */
281 ++num_unreported_spg
;
286 if (scsi_debugmode
> 1)
287 pout("%s: number of unreported (standard) log pages: %d (sub-pages: "
288 "%d)\n", __func__
, num_unreported
, num_unreported_spg
);
291 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
292 (or at least something to report). */
294 scsiGetSmartData(scsi_device
* device
, bool attribs
)
298 uint8_t currenttemp
= 255;
299 uint8_t triptemp
= 255;
303 if (scsiCheckIE(device
, gSmartLPage
, gTempLPage
, &asc
, &ascq
,
304 ¤ttemp
, &triptemp
)) {
305 /* error message already announced */
310 cp
= scsiGetIEString(asc
, ascq
);
314 jout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp
, asc
, ascq
);
316 jglb
["smart_status"]["passed"] = false;
317 jglb
["smart_status"]["scsi"]["asc"] = asc
;
318 jglb
["smart_status"]["scsi"]["ascq"] = ascq
;
319 jglb
["smart_status"]["scsi"]["ie_string"] = cp
;
321 else if (gIecMPage
) {
322 jout("SMART Health Status: OK\n");
323 jglb
["smart_status"]["passed"] = true;
326 if (attribs
&& !gTempLPage
) {
327 if (255 == currenttemp
)
328 pout("Current Drive Temperature: <not available>\n");
330 jout("Current Drive Temperature: %d C\n", currenttemp
);
331 jglb
["temperature"]["current"] = currenttemp
;
334 pout("Drive Trip Temperature: <not available>\n");
336 jout("Drive Trip Temperature: %d C\n", triptemp
);
337 jglb
["temperature"]["drive_trip"] = triptemp
;
345 // Returns number of logged errors or zero if none or -1 if fetching
347 static const char * const severities
= "CWI";
350 scsiGetTapeAlertsData(scsi_device
* device
, int peripheral_type
)
352 unsigned short pagelength
;
353 unsigned short parametercode
;
360 if ((err
= scsiLogSense(device
, TAPE_ALERTS_LPAGE
, 0, gBuf
,
361 LOG_RESP_TAPE_ALERT_LEN
, LOG_RESP_TAPE_ALERT_LEN
))) {
362 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
366 if (gBuf
[0] != 0x2e) {
367 pout("TapeAlerts %s Failed\n", logSenStr
);
371 pagelength
= sg_get_unaligned_be16(gBuf
+ 2);
373 for (s
=severities
; *s
; s
++) {
374 for (i
= 4; i
< pagelength
; i
+= 5) {
375 parametercode
= sg_get_unaligned_be16(gBuf
+ i
);
378 ts
= SCSI_PT_MEDIUM_CHANGER
== peripheral_type
?
379 scsiTapeAlertsChangerDevice(parametercode
) :
380 scsiTapeAlertsTapeDevice(parametercode
);
383 pout("TapeAlert Errors (C=Critical, W=Warning, "
384 "I=Informational):\n");
385 pout("[0x%02x] %s\n", parametercode
, ts
);
394 pout("TapeAlert: OK\n");
400 scsiGetStartStopData(scsi_device
* device
)
402 int err
, len
, k
, extra
;
405 if ((err
= scsiLogSense(device
, STARTSTOP_CYCLE_COUNTER_LPAGE
, 0, gBuf
,
408 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
412 if ((gBuf
[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE
) {
414 pout("StartStop %s Failed, page mismatch\n", logSenStr
);
418 len
= sg_get_unaligned_be16(gBuf
+ 2);
420 for (k
= len
; k
> 0; k
-= extra
, ucp
+= extra
) {
423 pout("StartStop %s: short\n", logSenRspStr
);
428 int pc
= sg_get_unaligned_be16(ucp
+ 0);
429 uint32_t u
= (extra
> 7) ? sg_get_unaligned_be32(ucp
+ 4) : 0;
430 bool is_all_ffs
= (extra
> 7) ? all_ffs(ucp
+ 4, 4) : false;
434 pout("Manufactured in week %.2s of year %.4s\n", ucp
+ 8,
438 /* ignore Accounting date */
441 if ((extra
> 7) && (! is_all_ffs
))
442 pout("Specified cycle count over device lifetime: %u\n", u
);
445 if ((extra
> 7) && (! is_all_ffs
))
446 pout("Accumulated start-stop cycles: %u\n", u
);
449 if ((extra
> 7) && (! is_all_ffs
))
450 pout("Specified load-unload count over device lifetime: "
454 if ((extra
> 7) && (! is_all_ffs
))
455 pout("Accumulated load-unload cycles: %u\n", u
);
463 /* PENDING_DEFECTS_SUBPG [0x15,0x1] introduced: SBC-4 */
465 scsiPrintPendingDefectsLPage(scsi_device
* device
)
467 int num
, pl
, pc
, err
;
470 static const char * pDefStr
= "Pending Defects";
471 static const char * jname
= "pending_defects";
473 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
,
474 PEND_DEFECTS_L_SPAGE
, gBuf
, LOG_RESP_LONG_LEN
,
477 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
481 if (((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) &&
482 (gBuf
[1] != PEND_DEFECTS_L_SPAGE
)) {
484 pout("%s %s, page mismatch\n", pDefStr
, logSenRspStr
);
488 num
= sg_get_unaligned_be16(gBuf
+ 2);
489 if (num
> LOG_RESP_LONG_LEN
) {
491 pout("%s %s too long\n", pDefStr
, logSenRspStr
);
497 pc
= sg_get_unaligned_be16(bp
+ 0);
501 printf(" Pending defect count:");
502 if ((pl
< 8) || (num
< 8)) {
504 pout("%s truncated descriptor\n", pDefStr
);
508 count
= sg_get_unaligned_be32(bp
+ 4);
509 jglb
[jname
]["count"] = count
;
511 jout("0 %s\n", pDefStr
);
513 jout("1 Pending Defect, LBA and accumulated_power_on_hours "
516 jout("%u %s: index, LBA and accumulated_power_on_hours "
517 "follow\n", count
, pDefStr
);
520 if ((pl
< 16) || (num
< 16)) {
522 pout("%s truncated descriptor\n", pDefStr
);
526 jout(" %4d: 0x%-16" PRIx64
", %5u\n", pc
,
527 sg_get_unaligned_be64(bp
+ 8), sg_get_unaligned_be32(bp
+ 4));
528 jglb
[jname
][pc
]["LBA"] = sg_get_unaligned_be64(bp
+ 8);
529 jglb
[jname
][pc
]["accum_power_on_hours"] =
530 sg_get_unaligned_be32(bp
+ 4);
539 scsiPrintGrownDefectListLen(scsi_device
* device
)
543 unsigned int dl_len
, div
;
544 static const char * hname
= "Read defect list";
547 if ((err
= scsiReadDefect12(device
, 0 /* req_plist */, 1 /* req_glist */,
548 4 /* format: bytes from index */,
549 0 /* addr desc index */, gBuf
, 8))) {
550 if (2 == err
) { /* command not supported */
551 err
= scsiReadDefect10(device
, 0 /* req_plist */,
553 4 /* format: bytes from index */, gBuf
, 4);
555 if (scsi_debugmode
> 0) {
557 pout("%s (10) Failed: %s\n", hname
, scsiErrString(err
));
563 } else if (101 == err
) /* Defect list not found, leave quietly */
566 if (scsi_debugmode
> 0) {
568 pout("%s (12) Failed: %s\n", hname
, scsiErrString(err
));
577 int generation
= sg_get_unaligned_be16(gBuf
+ 2);
578 if ((generation
> 1) && (scsi_debugmode
> 0)) {
580 pout("%s (12): generation=%d\n", hname
, generation
);
583 dl_len
= sg_get_unaligned_be32(gBuf
+ 4);
585 dl_len
= sg_get_unaligned_be16(gBuf
+ 2);
586 if (0x8 != (gBuf
[1] & 0x18)) {
588 pout("%s: asked for grown list but didn't get it\n", hname
);
593 dl_format
= (gBuf
[1] & 0x7);
595 case 0: /* short block */
598 case 1: /* extended bytes from index */
599 case 2: /* extended physical sector */
600 /* extended = 1; # might use in future */
603 case 3: /* long block */
604 case 4: /* bytes from index */
605 case 5: /* physical sector */
610 pout("defect list format %d unknown\n", dl_format
);
615 jout("Elements in grown defect list: 0\n\n");
616 jglb
["scsi_grown_defect_list"] = 0;
620 pout("Grown defect list length=%u bytes [unknown "
621 "number of elements]\n\n", dl_len
);
623 jout("Elements in grown defect list: %u\n\n", dl_len
/ div
);
624 jglb
["scsi_grown_defect_list"] = dl_len
;
630 scsiPrintSeagateCacheLPage(scsi_device
* device
)
632 int num
, pl
, pc
, err
, len
;
635 static const char * seaCacStr
= "Seagate Cache";
637 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
639 if (scsi_debugmode
> 0) {
641 pout("%s %s Failed: %s\n", seaCacStr
, logSenStr
,
647 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
648 if (scsi_debugmode
> 0) {
650 pout("%s %s, page mismatch\n", seaCacStr
, logSenRspStr
);
655 len
= sg_get_unaligned_be16(gBuf
+ 2) + 4;
659 pc
= sg_get_unaligned_be16(ucp
+ 0);
662 case 0: case 1: case 2: case 3: case 4:
665 if (scsi_debugmode
> 0) {
667 pout("Vendor (%s) lpage has unexpected parameter, skip\n",
676 pout("Vendor (%s) information\n", seaCacStr
);
680 pc
= sg_get_unaligned_be16(ucp
+ 0);
683 case 0: pout(" Blocks sent to initiator"); break;
684 case 1: pout(" Blocks received from initiator"); break;
685 case 2: pout(" Blocks read from cache and sent to initiator"); break;
686 case 3: pout(" Number of read and write commands whose size "
687 "<= segment size"); break;
688 case 4: pout(" Number of read and write commands whose size "
689 "> segment size"); break;
690 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
693 const int sz_ull
= (int)sizeof(ull
);
694 unsigned char * xp
= ucp
+ 4;
699 ull
= sg_get_unaligned_be(k
, xp
+ 0);
700 pout(" = %" PRIu64
"\n", ull
);
708 scsiPrintSeagateFactoryLPage(scsi_device
* device
)
710 int num
, pl
, pc
, len
, err
, good
, bad
;
714 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
716 if (scsi_debugmode
> 0) {
718 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
723 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
724 if (scsi_debugmode
> 0) {
726 pout("Seagate/Hitachi Factory %s, page mismatch\n", logSenRspStr
);
731 len
= sg_get_unaligned_be16(gBuf
+ 2) + 4;
737 pc
= sg_get_unaligned_be16(ucp
+ 0);
750 if ((good
< 2) || (bad
> 4)) { /* heuristic */
751 if (scsi_debugmode
> 0) {
753 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
754 "unexpected parameters, skip\n");
759 pout("Vendor (Seagate/Hitachi) factory information\n");
763 pc
= sg_get_unaligned_be16(ucp
+ 0);
767 case 0: pout(" number of hours powered up");
770 case 8: pout(" number of minutes until next internal SMART test");
774 if (scsi_debugmode
> 0) {
776 pout("Vendor (Seagate/Hitachi) factory lpage: "
777 "unknown parameter code [0x%x]\n", pc
);
784 unsigned char * xp
= ucp
+ 4;
785 if (k
> (int)sizeof(ull
)) {
786 xp
+= (k
- (int)sizeof(ull
));
787 k
= (int)sizeof(ull
);
789 ull
= sg_get_unaligned_be(k
, xp
+ 0);
791 pout(" = %.2f\n", ull
/ 60.0 );
792 jglb
["power_on_time"]["hours"] = ull
/ 60;
793 jglb
["power_on_time"]["minutes"] = ull
% 60;
796 pout(" = %" PRIu64
"\n", ull
);
805 scsiPrintErrorCounterLog(scsi_device
* device
)
807 struct scsiErrorCounter errCounterArr
[3];
808 struct scsiErrorCounter
* ecp
;
809 int found
[3] = {0, 0, 0};
811 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
812 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
813 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
816 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
817 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
818 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
821 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
822 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
823 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
824 ecp
= &errCounterArr
[2];
825 for (int k
= 0; k
< 7; ++k
) {
826 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
832 if (found
[0] || found
[1] || found
[2]) {
833 pout("Error counter log:\n");
834 pout(" Errors Corrected by Total "
835 "Correction Gigabytes Total\n");
836 pout(" ECC rereads/ errors "
837 "algorithm processed uncorrected\n");
838 pout(" fast | delayed rewrites corrected "
839 "invocations [10^9 bytes] errors\n");
841 json::ref jref
= jglb
["scsi_error_counter_log"];
842 for (int k
= 0; k
< 3; ++k
) {
845 ecp
= &errCounterArr
[k
];
846 static const char * const pageNames
[3] =
847 {"read: ", "write: ", "verify: "};
848 static const char * jpageNames
[3] =
849 {"read", "write", "verify"};
850 jout("%s%8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
851 " %8" PRIu64
, pageNames
[k
], ecp
->counter
[0],
852 ecp
->counter
[1], ecp
->counter
[2], ecp
->counter
[3],
854 double processed_gb
= ecp
->counter
[5] / 1000000000.0;
855 jout(" %12.3f %8" PRIu64
"\n", processed_gb
,
857 // Error counter log info
858 jref
[jpageNames
[k
]]["errors_corrected_by_eccfast"] = ecp
->counter
[0];
859 jref
[jpageNames
[k
]]["errors_corrected_by_eccdelayed"] = ecp
->counter
[1];
860 jref
[jpageNames
[k
]]["errors_corrected_by_rereads_rewrites"] = ecp
->counter
[2];
861 jref
[jpageNames
[k
]]["total_errors_corrected"] = ecp
->counter
[3];
862 jref
[jpageNames
[k
]]["correction_algorithm_invocations"] = ecp
->counter
[4];
863 jref
[jpageNames
[k
]]["gigabytes_processed"] = strprintf("%.3f", processed_gb
);
864 jref
[jpageNames
[k
]]["total_uncorrected_errors"] = ecp
->counter
[6];
868 pout("Error Counter logging not supported\n");
869 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
870 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
871 struct scsiNonMediumError nme
;
872 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
874 pout("\nNon-medium error count: %8" PRIu64
"\n", nme
.counterPC0
);
876 pout("Track following error count [Hitachi]: %8" PRIu64
"\n",
879 pout("Positioning error count [Hitachi]: %8" PRIu64
"\n",
882 if (gLastNErrorEvLPage
&&
883 (0 == scsiLogSense(device
, LAST_N_ERROR_EVENTS_LPAGE
, 0, gBuf
,
884 LOG_RESP_LONG_LEN
, 0))) {
885 int num
= sg_get_unaligned_be16(gBuf
+ 2) + 4;
886 int truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
888 num
= LOG_RESP_LONG_LEN
;
889 unsigned char * ucp
= gBuf
+ 4;
892 pout("\nNo error events logged\n");
894 pout("\nLast n error events log page\n");
895 for (int k
= num
, pl
; k
> 0; k
-= pl
, ucp
+= pl
) {
897 pout(" <<short Last n error events log page>>\n");
901 int pc
= sg_get_unaligned_be16(ucp
+ 0);
903 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
904 pout(" Error event %d:\n", pc
);
905 pout(" [binary]:\n");
906 dStrHex((const uint8_t *)ucp
+ 4, pl
- 4, 1);
907 } else if (ucp
[2] & 0x1) {
908 pout(" Error event %d:\n", pc
);
909 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
911 if (scsi_debugmode
> 0) {
912 pout(" Error event %d:\n", pc
);
913 pout(" [data counter??]:\n");
914 dStrHex((const uint8_t *)ucp
+ 4, pl
- 4, 1);
920 pout(" >>>> log truncated, fetched %d of %d available "
921 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
927 static const char * self_test_code
[] = {
938 static const char * self_test_result
[] = {
940 "Aborted (by user command)",
941 "Aborted (device reset ?) ",
942 "Unknown error, incomplete",
943 "Completed, segment failed",
944 "Failed in first segment ",
945 "Failed in second segment ",
946 "Failed in segment --> ",
954 "Self test in progress ..."
957 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
958 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
959 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
960 // FAILSMART is returned.
962 scsiPrintSelfTest(scsi_device
* device
)
964 int num
, k
, err
, durationSec
;
969 struct scsi_sense_disect sense_info
;
970 static const char * hname
= "Self-test";
972 // check if test is running
973 if (!scsiRequestSense(device
, &sense_info
) &&
974 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09 &&
975 sense_info
.progress
!= -1)) {
976 pout("%s execution status:\t\t%d%% of test remaining\n", hname
,
977 100 - ((sense_info
.progress
* 100) / 65535));
980 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
981 LOG_RESP_SELF_TEST_LEN
, 0))) {
983 pout("%s: Failed [%s]\n", __func__
, scsiErrString(err
));
987 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
989 pout("%s %s, page mismatch\n", hname
, logSenRspStr
);
993 // compute page length
994 num
= sg_get_unaligned_be16(gBuf
+ 2);
995 // Log sense page length 0x190 bytes
998 pout("%s %s length is 0x%x not 0x190 bytes\n", hname
, logSenStr
, num
);
1002 // loop through the twenty possible entries
1003 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
1004 // timestamp in power-on hours (or zero if test in progress)
1005 int n
= sg_get_unaligned_be16(ucp
+ 6);
1007 // The spec says "all 20 bytes will be zero if no test" but
1008 // DG has found otherwise. So this is a heuristic.
1009 if ((0 == n
) && (0 == ucp
[4]))
1012 // only print header if needed
1014 pout("SMART %s log\n", hname
);
1015 pout("Num Test Status segment "
1016 "LifeTime LBA_first_err [SK ASC ASQ]\n");
1017 pout(" Description number "
1022 // print parameter code (test number) & self-test code text
1023 pout("#%2d %s", sg_get_unaligned_be16(ucp
+ 0),
1024 self_test_code
[(ucp
[4] >> 5) & 0x7]);
1026 // check the self-test result nibble, using the self-test results
1027 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
1029 switch ((res
= ucp
[4] & 0xf)) {
1031 // an unknown error occurred while the device server
1032 // was processing the self-test and the device server
1033 // was unable to complete the self-test
1037 // the self-test completed with a failure in a test
1038 // segment, and the test segment that failed is not
1043 // the first segment of the self-test failed
1047 // the second segment of the self-test failed
1051 // another segment of the self-test failed and which
1052 // test is indicated by the contents of the SELF-TEST
1059 pout(" %s", self_test_result
[res
]);
1061 // self-test number identifies test that failed and consists
1062 // of either the number of the segment that failed during
1063 // the test, or the number of the test that failed and the
1064 // number of the segment in which the test was run, using a
1065 // vendor-specific method of putting both numbers into a
1068 pout(" %3d", (int)ucp
[5]);
1072 // print time that the self-test was completed
1073 if (n
==0 && res
==0xf)
1074 // self-test in progress
1079 // construct 8-byte integer address of first failure
1080 ull
= sg_get_unaligned_be64(ucp
+ 8);
1081 bool is_all_ffs
= all_ffs(ucp
+ 8, 8);
1082 // print Address of First Failure, if sensible
1083 if ((! is_all_ffs
) && (res
> 0) && (res
< 0xf)) {
1086 // was hex but change to decimal to conform with ATA
1087 snprintf(buff
, sizeof(buff
), "%" PRIu64
, ull
);
1088 // snprintf(buff, sizeof(buff), "0x%" PRIx64, ull);
1093 // if sense key nonzero, then print it, along with
1094 // additional sense code and additional sense code qualifier
1096 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
1101 // if header never printed, then there was no output
1103 pout("No %ss have been logged\n", hname
);
1105 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
1106 modese_len
)) && (durationSec
> 0)) {
1107 pout("\nLong (extended) %s duration: %d seconds "
1108 "[%.1f minutes]\n", hname
, durationSec
, durationSec
/ 60.0);
1114 static const char * bms_status
[] = {
1117 "pre-scan is active",
1118 "halted due to fatal error",
1119 "halted due to a vendor specific pattern of error",
1120 "halted due to medium formatted without P-List",
1121 "halted - vendor specific cause",
1122 "halted due to temperature out of range",
1123 "waiting until BMS interval timer expires", /* 8 */
1126 static const char * reassign_status
[] = {
1128 "Require Write or Reassign Blocks command",
1129 "Successfully reassigned",
1131 "Reassignment by disk failed",
1132 "Recovered via rewrite in-place",
1133 "Reassigned by app, has valid data",
1134 "Reassigned by app, has no valid data",
1135 "Unsuccessfully reassigned by app", /* 8 */
1138 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
1139 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1140 // and up to 2048 events (although would hope to have less). May set
1141 // FAILLOG if serious errors detected (in the future).
1143 scsiPrintBackgroundResults(scsi_device
* device
)
1145 int num
, j
, m
, err
, truncated
;
1147 int firstresult
= 1;
1150 static const char * hname
= "Background scan results";
1152 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
1153 LOG_RESP_LONG_LEN
, 0))) {
1155 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
1159 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
1161 pout("%s %s, page mismatch\n", hname
, logSenRspStr
);
1165 // compute page length
1166 num
= sg_get_unaligned_be16(gBuf
+ 2) + 4;
1169 pout("%s %s length is %d, no scan status\n", hname
, logSenStr
, num
);
1173 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
1175 num
= LOG_RESP_LONG_LEN
;
1179 int pc
= sg_get_unaligned_be16(ucp
+ 0);
1181 int pl
= ucp
[3] + 4;
1186 pout("%s log\n", hname
);
1189 if ((pl
< 16) || (num
< 16)) {
1194 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
1195 pout("%s\n", bms_status
[j
]);
1197 pout("unknown [0x%x] background scan status value\n", j
);
1198 j
= sg_get_unaligned_be32(ucp
+ 4);
1199 pout(" Accumulated power on time, hours:minutes %d:%02d "
1200 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
1201 jglb
["power_on_time"]["hours"] = j
/ 60;
1202 jglb
["power_on_time"]["minutes"] = j
% 60;
1203 pout(" Number of background scans performed: %d, ",
1204 sg_get_unaligned_be16(ucp
+ 10));
1205 pout("scan progress: %.2f%%\n",
1206 (double)sg_get_unaligned_be16(ucp
+ 12) * 100.0 / 65536.0);
1207 pout(" Number of background medium scans performed: %d\n",
1208 sg_get_unaligned_be16(ucp
+ 14));
1213 pout("\n%s log\n", hname
);
1217 pout("\n # when lba(hex) [sk,asc,ascq] "
1218 "reassign_status\n");
1221 if ((pl
< 24) || (num
< 24)) {
1223 pout("parameter length >= 24 expected, got %d\n", pl
);
1226 j
= sg_get_unaligned_be32(ucp
+ 4);
1227 pout("%4d:%02d ", (j
/ 60), (j
% 60));
1228 for (m
= 0; m
< 8; ++m
)
1229 pout("%02x", ucp
[16 + m
]);
1230 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
1231 j
= (ucp
[8] >> 4) & 0xf;
1233 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
1234 pout("%s\n", reassign_status
[j
]);
1236 pout("Reassign status: reserved [0x%x]\n", j
);
1243 pout(" >>>> log truncated, fetched %d of %d available "
1244 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
1249 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1250 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1251 // and up to 2048 events (although would hope to have less). May set
1252 // FAILLOG if serious errors detected (in the future).
1254 scsiPrintSSMedia(scsi_device
* device
)
1256 int num
, err
, truncated
;
1259 static const char * hname
= "Solid state media";
1261 if ((err
= scsiLogSense(device
, SS_MEDIA_LPAGE
, 0, gBuf
,
1262 LOG_RESP_LONG_LEN
, 0))) {
1264 pout("%s: Failed [%s]\n", __func__
, scsiErrString(err
));
1268 if ((gBuf
[0] & 0x3f) != SS_MEDIA_LPAGE
) {
1270 pout("%s %s, page mismatch\n", hname
, logSenStr
);
1274 // compute page length
1275 num
= sg_get_unaligned_be16(gBuf
+ 2) + 4;
1278 pout("%s %s length is %d, too short\n", hname
, logSenStr
, num
);
1282 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
1284 num
= LOG_RESP_LONG_LEN
;
1288 int pc
= sg_get_unaligned_be16(ucp
+ 0);
1290 int pl
= ucp
[3] + 4;
1295 pout("%s Percentage used endurance indicator parameter "
1296 "too short (pl=%d)\n", hname
, pl
);
1300 jout("Percentage used endurance indicator: %d%%\n", ucp
[7]);
1301 jglb
["scsi_percentage_used_endurance_indicator"] = ucp
[7];
1302 default: /* ignore other parameter codes */
1312 scsiPrintFormatStatus(scsi_device
* device
)
1315 int k
, num
, err
, truncated
;
1320 const char * jout_str
;
1321 const char * jglb_str
;
1322 static const char * hname
= "Format Status";
1323 static const char * jname
= "format_status";
1325 if ((err
= scsiLogSense(device
, FORMAT_STATUS_LPAGE
, 0, gBuf
,
1326 LOG_RESP_LONG_LEN
, 0))) {
1328 jout("%s: Failed [%s]\n", __func__
, scsiErrString(err
));
1332 if ((gBuf
[0] & 0x3f) != FORMAT_STATUS_LPAGE
) {
1334 jout("%s %s, page mismatch\n", hname
, logSenRspStr
);
1338 // compute page length
1339 num
= sg_get_unaligned_be16(gBuf
+ 2) + 4;
1342 jout("%s %s length is %d, too short\n", hname
, logSenStr
, num
);
1346 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
1348 num
= LOG_RESP_LONG_LEN
;
1352 int pc
= sg_get_unaligned_be16(ucp
+ 0);
1354 int pl
= ucp
[3] + 4;
1361 if (scsi_debugmode
> 1) {
1363 jout("Format data out: <empty>\n");
1365 if (all_ffs(ucp
+ 4, pl
- 4))
1366 jout("Format data out: <not available>\n");
1368 jout("Format data out:\n");
1369 dStrHex((const uint8_t *)ucp
+ 4, pl
- 4, 0);
1376 jout_str
= "Grown defects during certification";
1377 jglb_str
= "grown_defects_during_cert";
1380 jout_str
= "Total blocks reassigned during format";
1381 jglb_str
= "blocks_reassigned_during_format";
1384 jout_str
= "Total new blocks reassigned";
1385 jglb_str
= "total_new_block_since_format";
1388 jout_str
= "Power on minutes since format";
1389 jglb_str
= "power_on_minutes_since_format";
1392 if (scsi_debugmode
> 3) {
1393 pout(" Unknown Format parameter code = 0x%x\n", pc
);
1394 dStrHex((const uint8_t *)ucp
, pl
, 0);
1402 if (all_ffs(xp
, k
)) {
1403 pout("%s <not available>\n", jout_str
);
1405 if (k
> (int)sizeof(ull
)) {
1406 xp
+= (k
- sizeof(ull
));
1409 ull
= sg_get_unaligned_be(k
, xp
);
1410 jout("%s = %" PRIu64
"\n", jout_str
, ull
);
1411 jglb
[jname
][jglb_str
] = ull
;
1422 show_sas_phy_event_info(int peis
, unsigned int val
, unsigned thresh_val
)
1428 pout(" No event\n");
1431 pout(" Invalid word count: %u\n", val
);
1434 pout(" Running disparity error count: %u\n", val
);
1437 pout(" Loss of dword synchronization count: %u\n", val
);
1440 pout(" Phy reset problem count: %u\n", val
);
1443 pout(" Elasticity buffer overflow count: %u\n", val
);
1446 pout(" Received ERROR count: %u\n", val
);
1449 pout(" Received address frame error count: %u\n", val
);
1452 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
1455 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
1458 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
1461 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
1464 pout(" Received AIP (WAITING ON PARTIAL) count: %u\n", val
);
1467 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
1470 pout(" Transmitted BREAK count: %u\n", val
);
1473 pout(" Received BREAK count: %u\n", val
);
1476 pout(" Break timeout count: %u\n", val
);
1479 pout(" Connection count: %u\n", val
);
1482 pout(" Peak transmitted pathway blocked count: %u\n",
1484 pout(" Peak value detector threshold: %u\n",
1490 pout(" Peak transmitted arbitration wait time (us): "
1493 pout(" Peak transmitted arbitration wait time (ms): "
1494 "%u\n", 33 + (u
- 0x8000));
1495 u
= thresh_val
& 0xffff;
1497 pout(" Peak value detector threshold (us): %u\n",
1500 pout(" Peak value detector threshold (ms): %u\n",
1504 pout(" Peak arbitration time (us): %u\n", val
);
1505 pout(" Peak value detector threshold: %u\n", thresh_val
);
1508 pout(" Peak connection time (us): %u\n", val
);
1509 pout(" Peak value detector threshold: %u\n", thresh_val
);
1512 pout(" Transmitted SSP frame count: %u\n", val
);
1515 pout(" Received SSP frame count: %u\n", val
);
1518 pout(" Transmitted SSP frame error count: %u\n", val
);
1521 pout(" Received SSP frame error count: %u\n", val
);
1524 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1527 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1530 pout(" Transmitted SATA frame count: %u\n", val
);
1533 pout(" Received SATA frame count: %u\n", val
);
1536 pout(" SATA flow control buffer overflow count: %u\n", val
);
1539 pout(" Transmitted SMP frame count: %u\n", val
);
1542 pout(" Received SMP frame count: %u\n", val
);
1545 pout(" Received SMP frame error count: %u\n", val
);
1553 show_sas_port_param(unsigned char * ucp
, int param_len
)
1555 int j
, m
, nphys
, t
, sz
, spld_len
;
1556 unsigned char * vcp
;
1561 t
= sg_get_unaligned_be16(ucp
+ 0);
1562 pout("relative target port id = %d\n", t
);
1563 pout(" generation code = %d\n", ucp
[6]);
1565 pout(" number of phys = %d\n", nphys
);
1567 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1568 vcp
+= spld_len
, j
+= spld_len
) {
1569 pout(" phy identifier = %d\n", vcp
[1]);
1572 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1575 t
= ((0x70 & vcp
[4]) >> 4);
1577 case 0: snprintf(s
, sz
, "no device attached"); break;
1578 case 1: snprintf(s
, sz
, "SAS or SATA device"); break;
1579 case 2: snprintf(s
, sz
, "expander device"); break;
1580 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1581 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1583 pout(" attached device type: %s\n", s
);
1586 case 0: snprintf(s
, sz
, "unknown"); break;
1587 case 1: snprintf(s
, sz
, "power on"); break;
1588 case 2: snprintf(s
, sz
, "hard reset"); break;
1589 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1590 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1591 case 5: snprintf(s
, sz
, "mux mix up"); break;
1592 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1594 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1595 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1596 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1598 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1600 pout(" attached reason: %s\n", s
);
1601 t
= (vcp
[5] & 0xf0) >> 4;
1603 case 0: snprintf(s
, sz
, "unknown"); break;
1604 case 1: snprintf(s
, sz
, "power on"); break;
1605 case 2: snprintf(s
, sz
, "hard reset"); break;
1606 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1607 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1608 case 5: snprintf(s
, sz
, "mux mix up"); break;
1609 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1611 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1612 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1613 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1615 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1617 pout(" reason: %s\n", s
);
1620 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1622 case 1: snprintf(s
, sz
, "phy disabled"); break;
1623 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1625 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1627 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1629 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1631 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1633 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1634 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1635 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1636 case 0xb: snprintf(s
, sz
, "phy enabled; 12 Gbps"); break;
1637 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1639 pout(" negotiated logical link rate: %s\n", s
);
1640 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1641 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1642 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1643 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1644 if (!dont_print_serial_number
) {
1645 uint64_t ull
= sg_get_unaligned_be64(vcp
+ 8);
1647 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1648 ull
= sg_get_unaligned_be64(vcp
+ 16);
1649 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1651 pout(" attached phy identifier = %d\n", vcp
[24]);
1652 unsigned int ui
= sg_get_unaligned_be32(vcp
+ 32);
1654 pout(" Invalid DWORD count = %u\n", ui
);
1655 ui
= sg_get_unaligned_be32(vcp
+ 36);
1656 pout(" Running disparity error count = %u\n", ui
);
1657 ui
= sg_get_unaligned_be32(vcp
+ 40);
1658 pout(" Loss of DWORD synchronization = %u\n", ui
);
1659 ui
= sg_get_unaligned_be32(vcp
+ 44);
1660 pout(" Phy reset problem = %u\n", ui
);
1661 if (spld_len
> 51) {
1663 unsigned char * xcp
;
1667 pout(" Phy event descriptors:\n");
1669 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1673 ui
= sg_get_unaligned_be32(xcp
+ 4);
1674 pvdt
= sg_get_unaligned_be32(xcp
+ 8);
1675 show_sas_phy_event_info(peis
, ui
, pvdt
);
1681 // Returns 1 if okay, 0 if non SAS descriptors
1683 show_protocol_specific_page(unsigned char * resp
, int len
)
1686 unsigned char * ucp
;
1689 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1690 int param_len
= ucp
[3] + 4;
1691 if (SCSI_TPROTO_SAS
!= (0xf & ucp
[4]))
1692 return 0; /* only decode SAS log page */
1694 pout("Protocol Specific port log page for SAS SSP\n");
1695 show_sas_port_param(ucp
, param_len
);
1704 // See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1705 // log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1707 scsiPrintSasPhy(scsi_device
* device
, int reset
)
1710 static const char * hname
= "Protocol specific port";
1712 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1713 LOG_RESP_LONG_LEN
, 0))) {
1715 pout("%s %s Failed [%s]\n\n", __func__
, logSenStr
,
1716 scsiErrString(err
));
1720 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1722 pout("%s %s, page mismatch\n\n", hname
, logSenRspStr
);
1726 // compute page length
1727 num
= sg_get_unaligned_be16(gBuf
+ 2);
1728 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1730 pout("Only support %s log page on SAS devices\n\n", hname
);
1735 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1736 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1738 pout("%s Log Select (reset) Failed [%s]\n\n", __func__
,
1739 scsiErrString(err
));
1748 static const char * peripheral_dt_arr
[32] = {
1764 "optical card reader",
1766 "object based storage",
1767 "automation/driver interface",
1768 "security manager device",
1769 "host managed zoned block device",
1779 "well known logical unit",
1780 "unknown or no device type",
1783 /* Symbolic indexes to this array SCSI_TPROTO_* in scscmds.h */
1784 static const char * transport_proto_arr
[] = {
1785 "Fibre channel (FCP-2)",
1786 "Parallel SCSI (SPI-4)",
1788 "IEEE 1394 (SBP-2)",
1803 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1805 scsiGetDriveInfo(scsi_device
* device
, uint8_t * peripheral_type
, bool all
)
1807 struct scsi_iec_mode_page iec
;
1808 int err
, iec_err
, len
, req_len
, avail_len
;
1809 bool is_tape
= false;
1812 int form_factor
= 0;
1816 memset(gBuf
, 0, 96);
1818 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1820 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1821 pout("Retrying with a 64 byte Standard Inquiry\n");
1823 /* Marvell controllers fail with 36 byte StdInquiry, but 64 is ok */
1825 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1827 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1828 scsiErrString(err
));
1833 avail_len
= gBuf
[4] + 5;
1834 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1835 peri_dt
= gBuf
[0] & 0x1f;
1836 *peripheral_type
= peri_dt
;
1837 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peri_dt
) ||
1838 (SCSI_PT_MEDIUM_CHANGER
== peri_dt
))
1843 pout("Short INQUIRY response, skip product id\n");
1847 // Upper bits of version bytes were used in older standards
1848 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
1849 scsi_version
= gBuf
[2] & 0x7;
1851 if (all
&& (0 != strncmp((char *)&gBuf
[8], "ATA", 3))) {
1852 char product
[16+1], revision
[4+1];
1853 scsi_format_id_string(scsi_vendor
, &gBuf
[8], 8);
1854 scsi_format_id_string(product
, &gBuf
[16], 16);
1855 scsi_format_id_string(revision
, &gBuf
[32], 4);
1857 pout("=== START OF INFORMATION SECTION ===\n");
1858 jout("Vendor: %.8s\n", scsi_vendor
);
1859 jglb
["vendor"] = scsi_vendor
;
1860 jout("Product: %.16s\n", product
);
1861 jglb
["product"] = product
;
1862 jglb
["model_name"] = strprintf("%s%s%s",
1863 scsi_vendor
, (*scsi_vendor
&& *product
? " " : ""), product
);
1864 if (gBuf
[32] >= ' ') {
1865 jout("Revision: %.4s\n", revision
);
1866 // jglb["firmware_version"] = revision;
1867 jglb
["revision"] = revision
; /* could be a hardware rev */
1869 if ((scsi_version
> 0x3) && (scsi_version
< 0x8)) {
1872 snprintf(sv_arr
, sizeof(sv_arr
), "SPC-%d", scsi_version
- 2);
1873 jout("Compliance: %s\n", sv_arr
);
1874 jglb
["scsi_version"] = sv_arr
;
1878 if (!*device
->get_req_type()/*no type requested*/ &&
1879 (0 == strncmp((char *)&gBuf
[8], "ATA", 3))) {
1880 pout("\nProbable ATA device behind a SAT layer\n"
1881 "Try an additional '-d ata' or '-d sat' argument.\n");
1887 protect
= gBuf
[5] & 0x1; /* from and including SPC-3 */
1889 if (! is_tape
) { /* assume disk if not tape drive (or tape changer) */
1890 struct scsi_readcap_resp srr
;
1893 unsigned char lb_prov_resp
[8];
1894 uint64_t capacity
= scsiGetSize(device
, false /*avoid_rcap16 */,
1898 char cap_str
[64], si_str
[64];
1899 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1900 format_capacity(si_str
, sizeof(si_str
), capacity
);
1901 jout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1903 jglb
["user_capacity"]["blocks"].set_unsafe_uint64(capacity
/
1905 jglb
["user_capacity"]["bytes"].set_unsafe_uint64(capacity
);
1906 jout("Logical block size: %u bytes\n", srr
.lb_size
);
1907 jglb
["logical_block_size"] = srr
.lb_size
;
1908 if (protect
|| srr
.lb_p_pb_exp
) {
1909 if (srr
.lb_p_pb_exp
> 0) {
1910 unsigned pb_size
= srr
.lb_size
* (1 << srr
.lb_p_pb_exp
);
1911 jout("Physical block size: %u bytes\n", pb_size
);
1912 jglb
["physical_block_size"] = pb_size
;
1913 if (srr
.l_a_lba
> 0) // not common so cut the clutter
1914 pout("Lowest aligned LBA: %u\n", srr
.l_a_lba
);
1916 if (srr
.prot_type
> 0) {
1917 switch (srr
.prot_type
) {
1919 pout("Formatted with type 1 protection\n");
1922 pout("Formatted with type 2 protection\n");
1925 pout("Formatted with type 3 protection\n");
1928 pout("Formatted with unknown protection type [%d]\n",
1932 unsigned p_i_per_lb
= (1 << srr
.p_i_exp
);
1933 const unsigned pi_sz
= 8; /* ref-tag(4 bytes),
1934 app-tag(2), tag-mask(2) */
1937 pout("%d protection information intervals per "
1938 "logical block\n", p_i_per_lb
);
1939 pout("%d bytes of protection information per logical "
1940 "block\n", pi_sz
* p_i_per_lb
);
1942 /* Pick up some LB provisioning info since its available */
1943 lbpme
= (int)srr
.lbpme
;
1944 lbprz
= (int)srr
.lbprz
;
1947 /* Thin Provisioning VPD page renamed Logical Block Provisioning VPD
1948 * page in sbc3r25; some fields changed their meaning so that the
1949 * new page covered both thin and resource provisioned LUs. */
1950 if (0 == scsiInquiryVpd(device
, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING
,
1951 lb_prov_resp
, sizeof(lb_prov_resp
))) {
1952 int prov_type
= lb_prov_resp
[6] & 0x7; /* added sbc3r27 */
1953 int vpd_lbprz
= ((lb_prov_resp
[5] >> 2) & 0x7); /* sbc4r07 */
1957 else if ((0 == vpd_lbprz
) && (1 == lbprz
))
1958 ; /* vpd_lbprz introduced in sbc3r27, expanded in sbc4r07 */
1961 switch (prov_type
) {
1964 pout("LU is fully provisioned");
1966 pout(" [LBPRZ=%d]\n", lbprz
);
1970 pout("LB provisioning type: not reported [LBPME=1, "
1971 "LBPRZ=%d]\n", lbprz
);
1974 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz
);
1977 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz
);
1980 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1984 } else if (1 == lbpme
) {
1985 if (scsi_debugmode
> 0)
1986 pout("rcap_16 sets LBPME but no LB provisioning VPD page\n");
1987 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz
);
1990 int rpm
= scsiGetRPM(device
, modese_len
, &form_factor
, &haw_zbc
);
1995 jout("Rotation Rate: Solid State Device\n");
1996 else if ((rpm
<= 0x400) || (0xffff == rpm
))
1999 jout("Rotation Rate: %d rpm\n", rpm
);
2000 jglb
["rotation_rate"] = (rpm
== 1 ? 0 : rpm
);
2002 if (form_factor
> 0) {
2003 const char * cp
= NULL
;
2005 switch (form_factor
) {
2022 jglb
["form_factor"]["scsi_value"] = form_factor
;
2024 jout("Form Factor: %s inches\n", cp
);
2025 jglb
["form_factor"]["name"] = strprintf("%s inches", cp
);
2029 pout("Host aware zoned block capable\n");
2032 /* Do this here to try and detect badly conforming devices (some USB
2033 keys) that will lock up on a InquiryVpd or log sense or ... */
2034 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
2035 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
2036 pout(">> Terminate command early due to bad response to IEC "
2043 modese_len
= iec
.modese_len
;
2045 if (! dont_print_serial_number
) {
2046 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_DEVICE_IDENTIFICATION
,
2051 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
2053 pout("Logical Unit id: %s\n", s
);
2054 } else if (scsi_debugmode
> 0) {
2056 if (SIMPLE_ERR_BAD_RESP
== err
)
2057 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
2059 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
2062 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_UNIT_SERIAL_NUMBER
,
2067 gBuf
[4 + len
] = '\0';
2068 scsi_format_id_string(serial
, &gBuf
[4], len
);
2069 jout("Serial number: %s\n", serial
);
2070 jglb
["serial_number"] = serial
;
2071 } else if (scsi_debugmode
> 0) {
2073 if (SIMPLE_ERR_BAD_RESP
== err
)
2074 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
2076 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
2081 // print SCSI peripheral device type
2082 jglb
["device_type"]["scsi_value"] = peri_dt
;
2083 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
2084 sizeof(peripheral_dt_arr
[0]))) {
2085 jout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
2086 jglb
["device_type"]["name"] = peripheral_dt_arr
[peri_dt
];
2089 jout("Device type: <%d>\n", peri_dt
);
2091 // See if transport protocol is known
2093 transport
= scsiFetchTransportProtocol(device
, modese_len
);
2094 if ((transport
>= 0) && (transport
<= 0xf))
2095 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
2097 // print current time and date and timezone
2098 time_t now
= time(0);
2099 char timedatetz
[DATEANDEPOCHLEN
]; dateandtimezoneepoch(timedatetz
, now
);
2100 jout("Local Time is: %s\n", timedatetz
);
2101 jglb
["local_time"]["time_t"] = now
;
2102 jglb
["local_time"]["asctime"] = timedatetz
;
2104 // See if unit accepts SCSI commands from us
2105 if ((err
= scsiTestUnitReady(device
))) {
2106 if (SIMPLE_ERR_NOT_READY
== err
) {
2109 pout("device is NOT READY (e.g. spun down, busy)\n");
2111 pout("device is NOT READY (e.g. no tape)\n");
2113 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
2116 pout("NO tape present in drive\n");
2118 pout("NO MEDIUM present in device\n");
2120 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
2122 pout("device becoming ready (wait)\n");
2126 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
2130 int returnval
= 0; // TODO: exit with FAILID if failuretest returns
2132 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
2139 pout("SMART support is: Unavailable - device lacks SMART "
2141 if (scsi_debugmode
> 0)
2142 pout(" [%s]\n", scsiErrString(iec_err
));
2150 pout("SMART support is: Available - device has SMART capability.\n"
2151 "SMART support is: %s\n",
2152 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
2153 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
2154 "Temperature Warning: Enabled" :
2155 "Temperature Warning: Disabled or Not Supported");
2160 scsiSmartEnable(scsi_device
* device
)
2162 struct scsi_iec_mode_page iec
;
2165 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
2167 pout("unable to fetch IEC (SMART) mode page [%s]\n",
2168 scsiErrString(err
));
2172 modese_len
= iec
.modese_len
;
2174 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
2176 pout("unable to enable Exception control and warning [%s]\n",
2177 scsiErrString(err
));
2181 /* Need to refetch 'iec' since could be modified by previous call */
2182 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
2183 pout("unable to fetch IEC (SMART) mode page [%s]\n",
2184 scsiErrString(err
));
2187 modese_len
= iec
.modese_len
;
2189 pout("Informational Exceptions (SMART) %s\n",
2190 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
2191 pout("Temperature warning %s\n",
2192 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
2197 scsiSmartDisable(scsi_device
* device
)
2199 struct scsi_iec_mode_page iec
;
2202 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
2204 pout("unable to fetch IEC (SMART) mode page [%s]\n",
2205 scsiErrString(err
));
2209 modese_len
= iec
.modese_len
;
2211 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
2213 pout("unable to disable Exception control and warning [%s]\n",
2214 scsiErrString(err
));
2218 /* Need to refetch 'iec' since could be modified by previous call */
2219 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
2220 pout("unable to fetch IEC (SMART) mode page [%s]\n",
2221 scsiErrString(err
));
2224 modese_len
= iec
.modese_len
;
2226 pout("Informational Exceptions (SMART) %s\n",
2227 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
2228 pout("Temperature warning %s\n",
2229 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
2234 scsiPrintTemp(scsi_device
* device
)
2239 if (scsiGetTemp(device
, &temp
, &trip
))
2243 pout("Current Drive Temperature: <not available>\n");
2245 jout("Current Drive Temperature: %d C\n", temp
);
2246 jglb
["temperature"]["current"] = temp
;
2249 pout("Drive Trip Temperature: <not available>\n");
2251 jout("Drive Trip Temperature: %d C\n", trip
);
2252 jglb
["temperature"]["drive_trip"] = trip
;
2257 /* Main entry point used by smartctl command. Return 0 for success */
2259 scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
2261 int checkedSupportedLogPages
= 0;
2262 uint8_t peripheral_type
= 0;
2264 int res
, durationSec
;
2265 struct scsi_sense_disect sense_info
;
2269 bool any_output
= options
.drive_info
;
2271 if (supported_vpd_pages_p
) {
2272 delete supported_vpd_pages_p
;
2273 supported_vpd_pages_p
= NULL
;
2275 supported_vpd_pages_p
= new supported_vpd_pages(device
);
2277 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
2282 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
2285 is_disk
= ((SCSI_PT_DIRECT_ACCESS
== peripheral_type
) ||
2286 (SCSI_PT_HOST_MANAGED
== peripheral_type
));
2287 is_tape
= ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
2288 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
));
2290 short int wce
= -1, rcd
= -1;
2291 // Print read look-ahead status for disks
2292 if (options
.get_rcd
|| options
.get_wce
) {
2294 res
= scsiGetSetCache(device
, modese_len
, &wce
, &rcd
);
2295 if (options
.get_rcd
)
2296 pout("Read Cache is: %s\n",
2297 res
? "Unavailable" : // error
2298 rcd
? "Disabled" : "Enabled");
2299 if (options
.get_wce
)
2300 pout("Writeback Cache is: %s\n",
2301 res
? "Unavailable" : // error
2302 !wce
? "Disabled" : "Enabled");
2307 if (options
.drive_info
)
2310 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
2311 if (options
.smart_disable
|| options
.smart_enable
||
2312 options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
2313 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
2315 if (options
.smart_enable
) {
2316 if (scsiSmartEnable(device
))
2317 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
2321 if (options
.smart_disable
) {
2322 if (scsiSmartDisable(device
))
2323 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
2327 if (options
.smart_auto_save_enable
) {
2328 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
2329 pout("Enable autosave (clear GLTSD bit) failed\n");
2330 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
2332 pout("Autosave enabled (GLTSD bit cleared).\n");
2336 // Enable/Disable write cache
2337 if (options
.set_wce
&& is_disk
) {
2338 short int enable
= wce
= (options
.set_wce
> 0);
2341 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
2342 pout("Write cache %sable failed: %s\n", (enable
? "en" : "dis"),
2343 device
->get_errmsg());
2344 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
2346 pout("Write cache %sabled\n", (enable
? "en" : "dis"));
2350 // Enable/Disable read cache
2351 if (options
.set_rcd
&& is_disk
) {
2352 short int enable
= (options
.set_rcd
> 0);
2356 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
2357 pout("Read cache %sable failed: %s\n", (enable
? "en" : "dis"),
2358 device
->get_errmsg());
2359 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
2361 pout("Read cache %sabled\n", (enable
? "en" : "dis"));
2365 if (options
.smart_auto_save_disable
) {
2366 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
2367 pout("Disable autosave (set GLTSD bit) failed\n");
2368 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
2370 pout("Autosave disabled (GLTSD bit set).\n");
2373 if (options
.smart_disable
|| options
.smart_enable
||
2374 options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
2375 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
2377 // START OF READ-ONLY OPTIONS APART FROM -V and -i
2378 if (options
.smart_check_status
|| options
.smart_ss_media_log
||
2379 options
.smart_vendor_attrib
|| options
.smart_error_log
||
2380 options
.smart_selftest_log
|| options
.smart_background_log
||
2382 pout("=== START OF READ SMART DATA SECTION ===\n");
2384 if (options
.smart_check_status
) {
2385 scsiGetSupportedLogPages(device
);
2386 checkedSupportedLogPages
= 1;
2388 if (gTapeAlertsLPage
) {
2389 if (options
.drive_info
)
2390 pout("TapeAlert Supported\n");
2391 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
2392 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
2395 pout("TapeAlert Not Supported\n");
2396 } else { /* disk, cd/dvd, enclosure, etc */
2397 if ((res
= scsiGetSmartData(device
,
2398 options
.smart_vendor_attrib
))) {
2400 returnval
|= FAILSTATUS
;
2402 returnval
|= FAILSMART
;
2408 if (is_disk
&& options
.smart_ss_media_log
) {
2409 if (! checkedSupportedLogPages
)
2410 scsiGetSupportedLogPages(device
);
2413 res
= scsiPrintSSMedia(device
);
2415 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2416 if (gFormatStatusLPage
)
2417 res
= scsiPrintFormatStatus(device
);
2419 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2422 if (options
.smart_vendor_attrib
) {
2423 if (! checkedSupportedLogPages
)
2424 scsiGetSupportedLogPages(device
);
2426 scsiPrintTemp(device
);
2427 if (gStartStopLPage
)
2428 scsiGetStartStopData(device
);
2430 scsiPrintGrownDefectListLen(device
);
2431 if (gSeagateCacheLPage
)
2432 scsiPrintSeagateCacheLPage(device
);
2433 if (gSeagateFactoryLPage
)
2434 scsiPrintSeagateFactoryLPage(device
);
2438 if (options
.smart_error_log
) {
2439 if (! checkedSupportedLogPages
)
2440 scsiGetSupportedLogPages(device
);
2441 scsiPrintErrorCounterLog(device
);
2442 if (gPendDefectsLPage
)
2443 scsiPrintPendingDefectsLPage(device
);
2444 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
2445 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2446 "Enable Save with '-S on']\n");
2449 if (options
.smart_selftest_log
) {
2450 if (! checkedSupportedLogPages
)
2451 scsiGetSupportedLogPages(device
);
2454 res
= scsiPrintSelfTest(device
);
2456 pout("Device does not support Self Test logging\n");
2457 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2460 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2463 if (options
.smart_background_log
&& is_disk
) {
2464 if (! checkedSupportedLogPages
)
2465 scsiGetSupportedLogPages(device
);
2467 if (gBackgroundResultsLPage
)
2468 res
= scsiPrintBackgroundResults(device
);
2470 pout("Device does not support Background scan results logging\n");
2471 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2474 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2477 if (options
.smart_default_selftest
) {
2478 if (scsiSmartDefaultSelfTest(device
))
2479 return returnval
| FAILSMART
;
2480 pout("Default Self Test Successful\n");
2483 if (options
.smart_short_cap_selftest
) {
2484 if (scsiSmartShortCapSelfTest(device
))
2485 return returnval
| FAILSMART
;
2486 pout("Short Foreground Self Test Successful\n");
2489 // check if another test is running
2490 if (options
.smart_short_selftest
|| options
.smart_extend_selftest
) {
2491 if (!scsiRequestSense(device
, &sense_info
) &&
2492 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09)) {
2493 if (!options
.smart_selftest_force
) {
2494 pout("Can't start self-test without aborting current test");
2495 if (sense_info
.progress
!= -1)
2496 pout(" (%d%% remaining)",
2497 100 - sense_info
.progress
* 100 / 65535);
2498 pout(",\nadd '-t force' option to override, or run "
2499 "'smartctl -X' to abort test.\n");
2502 scsiSmartSelfTestAbort(device
);
2505 if (options
.smart_short_selftest
) {
2506 if (scsiSmartShortSelfTest(device
))
2507 return returnval
| FAILSMART
;
2508 pout("Short Background Self Test has begun\n");
2509 pout("Use smartctl -X to abort test\n");
2512 if (options
.smart_extend_selftest
) {
2513 if (scsiSmartExtendSelfTest(device
))
2514 return returnval
| FAILSMART
;
2515 pout("Extended Background Self Test has begun\n");
2516 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
2517 modese_len
)) && (durationSec
> 0)) {
2518 time_t t
= time(NULL
);
2521 pout("Please wait %d minutes for test to complete.\n",
2523 pout("Estimated completion time: %s\n", ctime(&t
));
2525 pout("Use smartctl -X to abort test\n");
2528 if (options
.smart_extend_cap_selftest
) {
2529 if (scsiSmartExtendCapSelfTest(device
))
2530 return returnval
| FAILSMART
;
2531 pout("Extended Foreground Self Test Successful\n");
2533 if (options
.smart_selftest_abort
) {
2534 if (scsiSmartSelfTestAbort(device
))
2535 return returnval
| FAILSMART
;
2536 pout("Self Test returned without error\n");
2539 if (options
.sasphy
&& gProtocolSpecificLPage
) {
2540 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
2541 return returnval
| FAILSMART
;
2546 pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
2547 "to print SMART (and more) information\n\n");