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-15 Douglas Gilbert <dgilbert@interlog.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * You should have received a copy of the GNU General Public License
16 * (for example COPYING); if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * This code was originally developed as a Senior Thesis by Michael Cornwell
20 * at the Concurrent Systems Laboratory (now part of the Storage Systems
21 * Research Center), Jack Baskin School of Engineering, University of
22 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
35 #include "atacmds.h" // smart_command_set
36 #include "dev_interface.h"
37 #include "scsiprint.h"
41 #define GBUF_SIZE 65535
43 const char * scsiprint_c_cvsid
= "$Id: scsiprint.cpp 4415 2017-03-27 21:14:53Z chrfranke $"
47 UINT8 gBuf
[GBUF_SIZE
];
48 #define LOG_RESP_LEN 252
49 #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
50 #define LOG_RESP_TAPE_ALERT_LEN 0x144
52 /* Log pages supported */
53 static int gSmartLPage
= 0; /* Informational Exceptions log page */
54 static int gTempLPage
= 0;
55 static int gSelfTestLPage
= 0;
56 static int gStartStopLPage
= 0;
57 static int gReadECounterLPage
= 0;
58 static int gWriteECounterLPage
= 0;
59 static int gVerifyECounterLPage
= 0;
60 static int gNonMediumELPage
= 0;
61 static int gLastNErrorLPage
= 0;
62 static int gBackgroundResultsLPage
= 0;
63 static int gProtocolSpecificLPage
= 0;
64 static int gTapeAlertsLPage
= 0;
65 static int gSSMediaLPage
= 0;
67 /* Vendor specific log pages */
68 static int gSeagateCacheLPage
= 0;
69 static int gSeagateFactoryLPage
= 0;
71 /* Mode pages supported */
72 static int gIecMPage
= 1; /* N.B. assume it until we know otherwise */
74 /* Remember last successful mode sense/select command */
75 static int modese_len
= 0;
79 scsiGetSupportedLogPages(scsi_device
* device
)
83 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
85 if (scsi_debugmode
> 0)
86 pout("Log Sense for supported pages failed [%s]\n",
88 /* try one more time with defined length, workaround for the bug #678
89 found with ST8000NM0075/E001 */
90 err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
91 LOG_RESP_LEN
, 68); /* 64 max pages + 4b header */
92 if (scsi_debugmode
> 0)
93 pout("Log Sense for supported pages failed (second attempt) [%s]\n",
99 for (i
= 4; i
< gBuf
[3] + LOGPAGEHDRSIZE
; i
++) {
102 case READ_ERROR_COUNTER_LPAGE
:
103 gReadECounterLPage
= 1;
105 case WRITE_ERROR_COUNTER_LPAGE
:
106 gWriteECounterLPage
= 1;
108 case VERIFY_ERROR_COUNTER_LPAGE
:
109 gVerifyECounterLPage
= 1;
111 case LAST_N_ERROR_LPAGE
:
112 gLastNErrorLPage
= 1;
114 case NON_MEDIUM_ERROR_LPAGE
:
115 gNonMediumELPage
= 1;
117 case TEMPERATURE_LPAGE
:
120 case STARTSTOP_CYCLE_COUNTER_LPAGE
:
123 case SELFTEST_RESULTS_LPAGE
:
129 case BACKGROUND_RESULTS_LPAGE
:
130 gBackgroundResultsLPage
= 1;
132 case PROTOCOL_SPECIFIC_LPAGE
:
133 gProtocolSpecificLPage
= 1;
135 case TAPE_ALERTS_LPAGE
:
136 gTapeAlertsLPage
= 1;
141 case SEAGATE_CACHE_LPAGE
:
142 gSeagateCacheLPage
= 1;
144 case SEAGATE_FACTORY_LPAGE
:
145 gSeagateFactoryLPage
= 1;
153 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
154 (or at least something to report). */
156 scsiGetSmartData(scsi_device
* device
, bool attribs
)
160 UINT8 currenttemp
= 255;
161 UINT8 triptemp
= 255;
165 if (scsiCheckIE(device
, gSmartLPage
, gTempLPage
, &asc
, &ascq
,
166 ¤ttemp
, &triptemp
)) {
167 /* error message already announced */
172 cp
= scsiGetIEString(asc
, ascq
);
176 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp
, asc
, ascq
);
178 } else if (gIecMPage
)
179 pout("SMART Health Status: OK\n");
181 if (attribs
&& !gTempLPage
) {
182 if (255 == currenttemp
)
183 pout("Current Drive Temperature: <not available>\n");
185 pout("Current Drive Temperature: %d C\n", currenttemp
);
187 pout("Drive Trip Temperature: <not available>\n");
189 pout("Drive Trip Temperature: %d C\n", triptemp
);
196 // Returns number of logged errors or zero if none or -1 if fetching
198 static const char * const severities
= "CWI";
201 scsiGetTapeAlertsData(scsi_device
* device
, int peripheral_type
)
203 unsigned short pagelength
;
204 unsigned short parametercode
;
211 if ((err
= scsiLogSense(device
, TAPE_ALERTS_LPAGE
, 0, gBuf
,
212 LOG_RESP_TAPE_ALERT_LEN
, LOG_RESP_TAPE_ALERT_LEN
))) {
213 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
217 if (gBuf
[0] != 0x2e) {
218 pout("TapeAlerts Log Sense Failed\n");
222 pagelength
= (unsigned short) gBuf
[2] << 8 | gBuf
[3];
224 for (s
=severities
; *s
; s
++) {
225 for (i
= 4; i
< pagelength
; i
+= 5) {
226 parametercode
= (unsigned short) gBuf
[i
] << 8 | gBuf
[i
+1];
229 ts
= SCSI_PT_MEDIUM_CHANGER
== peripheral_type
?
230 scsiTapeAlertsChangerDevice(parametercode
) :
231 scsiTapeAlertsTapeDevice(parametercode
);
234 pout("TapeAlert Errors (C=Critical, W=Warning, "
235 "I=Informational):\n");
236 pout("[0x%02x] %s\n", parametercode
, ts
);
245 pout("TapeAlert: OK\n");
251 scsiGetStartStopData(scsi_device
* device
)
253 int err
, len
, k
, extra
;
256 if ((err
= scsiLogSense(device
, STARTSTOP_CYCLE_COUNTER_LPAGE
, 0, gBuf
,
259 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
263 if ((gBuf
[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE
) {
265 pout("StartStop Log Sense Failed, page mismatch\n");
269 len
= ((gBuf
[2] << 8) | gBuf
[3]);
271 for (k
= len
; k
> 0; k
-= extra
, ucp
+= extra
) {
274 pout("StartStop Log Sense Failed: short\n");
279 int pc
= (ucp
[0] << 8) + ucp
[1];
284 pout("Manufactured in week %.2s of year %.4s\n", ucp
+ 8,
288 /* ignore Accounting date */
292 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
294 pout("Specified cycle count over device lifetime: %u\n",
300 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
302 pout("Accumulated start-stop cycles: %u\n", u
);
307 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
309 pout("Specified load-unload count over device "
310 "lifetime: %u\n", u
);
315 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
317 pout("Accumulated load-unload cycles: %u\n", u
);
328 scsiPrintGrownDefectListLen(scsi_device
* device
)
330 int err
, dl_format
, got_rd12
;
331 unsigned int dl_len
, div
;
334 if ((err
= scsiReadDefect12(device
, 0 /* req_plist */, 1 /* req_glist */,
335 4 /* format: bytes from index */,
336 0 /* addr desc index */, gBuf
, 8))) {
337 if (2 == err
) { /* command not supported */
338 if ((err
= scsiReadDefect10(device
, 0 /* req_plist */, 1 /* req_glist */,
339 4 /* format: bytes from index */, gBuf
, 4))) {
340 if (scsi_debugmode
> 0) {
342 pout("Read defect list (10) Failed: %s\n", scsiErrString(err
));
348 } else if (101 == err
) /* Defect list not found, leave quietly */
351 if (scsi_debugmode
> 0) {
353 pout("Read defect list (12) Failed: %s\n", scsiErrString(err
));
362 int generation
= (gBuf
[2] << 8) + gBuf
[3];
363 if ((generation
> 1) && (scsi_debugmode
> 0)) {
365 pout("Read defect list (12): generation=%d\n", generation
);
368 dl_len
= (gBuf
[4] << 24) + (gBuf
[5] << 16) + (gBuf
[6] << 8) + gBuf
[7];
370 dl_len
= (gBuf
[2] << 8) + gBuf
[3];
372 if (0x8 != (gBuf
[1] & 0x18)) {
374 pout("Read defect list: asked for grown list but didn't get it\n");
379 dl_format
= (gBuf
[1] & 0x7);
381 case 0: /* short block */
384 case 1: /* extended bytes from index */
385 case 2: /* extended physical sector */
386 /* extended = 1; # might use in future */
389 case 3: /* long block */
390 case 4: /* bytes from index */
391 case 5: /* physical sector */
396 pout("defect list format %d unknown\n", dl_format
);
401 pout("Elements in grown defect list: 0\n\n");
404 pout("Grown defect list length=%u bytes [unknown "
405 "number of elements]\n\n", dl_len
);
407 pout("Elements in grown defect list: %u\n\n", dl_len
/ div
);
412 scsiPrintSeagateCacheLPage(scsi_device
* device
)
414 int num
, pl
, pc
, err
, len
;
418 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
421 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err
));
425 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
427 pout("Seagate Cache Log Sense Failed, page mismatch\n");
431 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
435 pc
= (ucp
[0] << 8) | ucp
[1];
438 case 0: case 1: case 2: case 3: case 4:
441 if (scsi_debugmode
> 0) {
443 pout("Vendor (Seagate) cache lpage has unexpected parameter"
452 pout("Vendor (Seagate) cache information\n");
456 pc
= (ucp
[0] << 8) | ucp
[1];
459 case 0: pout(" Blocks sent to initiator"); break;
460 case 1: pout(" Blocks received from initiator"); break;
461 case 2: pout(" Blocks read from cache and sent to initiator"); break;
462 case 3: pout(" Number of read and write commands whose size "
463 "<= segment size"); break;
464 case 4: pout(" Number of read and write commands whose size "
465 "> segment size"); break;
466 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
469 unsigned char * xp
= ucp
+ 4;
470 if (k
> (int)sizeof(ull
)) {
471 xp
+= (k
- (int)sizeof(ull
));
472 k
= (int)sizeof(ull
);
475 for (int j
= 0; j
< k
; ++j
) {
480 pout(" = %" PRIu64
"\n", ull
);
488 scsiPrintSeagateFactoryLPage(scsi_device
* device
)
490 int num
, pl
, pc
, len
, err
, good
, bad
;
494 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
497 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
501 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
503 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
507 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
513 pc
= (ucp
[0] << 8) | ucp
[1];
526 if ((good
< 2) || (bad
> 4)) { /* heuristic */
527 if (scsi_debugmode
> 0) {
529 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
530 "unexpected parameters, skip\n");
535 pout("Vendor (Seagate/Hitachi) factory information\n");
539 pc
= (ucp
[0] << 8) | ucp
[1];
543 case 0: pout(" number of hours powered up");
546 case 8: pout(" number of minutes until next internal SMART test");
550 if (scsi_debugmode
> 0) {
552 pout("Vendor (Seagate/Hitachi) factory lpage: "
553 "unknown parameter code [0x%x]\n", pc
);
560 unsigned char * xp
= ucp
+ 4;
561 if (k
> (int)sizeof(ull
)) {
562 xp
+= (k
- (int)sizeof(ull
));
563 k
= (int)sizeof(ull
);
566 for (int j
= 0; j
< k
; ++j
) {
572 pout(" = %.2f\n", ull
/ 60.0 );
574 pout(" = %" PRIu64
"\n", ull
);
583 scsiPrintErrorCounterLog(scsi_device
* device
)
585 struct scsiErrorCounter errCounterArr
[3];
586 struct scsiErrorCounter
* ecp
;
587 int found
[3] = {0, 0, 0};
589 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
590 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
591 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
594 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
595 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
596 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
599 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
600 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
601 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
602 ecp
= &errCounterArr
[2];
603 for (int k
= 0; k
< 7; ++k
) {
604 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
610 if (found
[0] || found
[1] || found
[2]) {
611 pout("Error counter log:\n");
612 pout(" Errors Corrected by Total "
613 "Correction Gigabytes Total\n");
614 pout(" ECC rereads/ errors "
615 "algorithm processed uncorrected\n");
616 pout(" fast | delayed rewrites corrected "
617 "invocations [10^9 bytes] errors\n");
618 for (int k
= 0; k
< 3; ++k
) {
621 ecp
= &errCounterArr
[k
];
622 static const char * const pageNames
[3] = {"read: ", "write: ", "verify: "};
623 pout("%s%8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
,
624 pageNames
[k
], ecp
->counter
[0], ecp
->counter
[1],
625 ecp
->counter
[2], ecp
->counter
[3], ecp
->counter
[4]);
626 double processed_gb
= ecp
->counter
[5] / 1000000000.0;
627 pout(" %12.3f %8" PRIu64
"\n", processed_gb
, ecp
->counter
[6]);
631 pout("Error Counter logging not supported\n");
632 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
633 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
634 struct scsiNonMediumError nme
;
635 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
637 pout("\nNon-medium error count: %8" PRIu64
"\n", nme
.counterPC0
);
639 pout("Track following error count [Hitachi]: %8" PRIu64
"\n",
642 pout("Positioning error count [Hitachi]: %8" PRIu64
"\n",
645 if (gLastNErrorLPage
&& (0 == scsiLogSense(device
,
646 LAST_N_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LONG_LEN
, 0))) {
647 int num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
648 int truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
650 num
= LOG_RESP_LONG_LEN
;
651 unsigned char * ucp
= gBuf
+ 4;
654 pout("\nNo error events logged\n");
656 pout("\nLast n error events log page\n");
657 for (int k
= num
, pl
; k
> 0; k
-= pl
, ucp
+= pl
) {
659 pout(" <<short Last n error events log page>>\n");
663 int pc
= (ucp
[0] << 8) + ucp
[1];
665 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
666 pout(" Error event %d:\n", pc
);
667 pout(" [binary]:\n");
668 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
669 } else if (ucp
[2] & 0x1) {
670 pout(" Error event %d:\n", pc
);
671 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
673 if (scsi_debugmode
> 0) {
674 pout(" Error event %d:\n", pc
);
675 pout(" [data counter??]:\n");
676 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
682 pout(" >>>> log truncated, fetched %d of %d available "
683 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
689 static const char * self_test_code
[] = {
700 static const char * self_test_result
[] = {
702 "Aborted (by user command)",
703 "Aborted (device reset ?) ",
704 "Unknown error, incomplete",
705 "Completed, segment failed",
706 "Failed in first segment ",
707 "Failed in second segment ",
708 "Failed in segment --> ",
716 "Self test in progress ..."
719 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
720 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
721 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
722 // FAILSMART is returned.
724 scsiPrintSelfTest(scsi_device
* device
)
726 int num
, k
, err
, durationSec
;
731 struct scsi_sense_disect sense_info
;
733 // check if test is running
734 if (!scsiRequestSense(device
, &sense_info
) &&
735 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09 &&
736 sense_info
.progress
!= -1)) {
737 pout("Self-test execution status:\t\t%d%% of test remaining\n",
738 100 - ((sense_info
.progress
* 100) / 65535));
741 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
742 LOG_RESP_SELF_TEST_LEN
, 0))) {
744 pout("%s: Failed [%s]\n", __func__
, scsiErrString(err
));
748 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
750 pout("Self-test Log Sense Failed, page mismatch\n");
754 // compute page length
755 num
= (gBuf
[2] << 8) + gBuf
[3];
756 // Log sense page length 0x190 bytes
759 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num
);
763 // loop through the twenty possible entries
764 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
767 // timestamp in power-on hours (or zero if test in progress)
768 int n
= (ucp
[6] << 8) | ucp
[7];
770 // The spec says "all 20 bytes will be zero if no test" but
771 // DG has found otherwise. So this is a heuristic.
772 if ((0 == n
) && (0 == ucp
[4]))
775 // only print header if needed
777 pout("SMART Self-test log\n");
778 pout("Num Test Status segment "
779 "LifeTime LBA_first_err [SK ASC ASQ]\n");
780 pout(" Description number "
785 // print parameter code (test number) & self-test code text
786 pout("#%2d %s", (ucp
[0] << 8) | ucp
[1],
787 self_test_code
[(ucp
[4] >> 5) & 0x7]);
789 // check the self-test result nibble, using the self-test results
790 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
792 switch ((res
= ucp
[4] & 0xf)) {
794 // an unknown error occurred while the device server
795 // was processing the self-test and the device server
796 // was unable to complete the self-test
800 // the self-test completed with a failure in a test
801 // segment, and the test segment that failed is not
806 // the first segment of the self-test failed
810 // the second segment of the self-test failed
814 // another segment of the self-test failed and which
815 // test is indicated by the contents of the SELF-TEST
822 pout(" %s", self_test_result
[res
]);
824 // self-test number identifies test that failed and consists
825 // of either the number of the segment that failed during
826 // the test, or the number of the test that failed and the
827 // number of the segment in which the test was run, using a
828 // vendor-specific method of putting both numbers into a
831 pout(" %3d", (int)ucp
[5]);
835 // print time that the self-test was completed
836 if (n
==0 && res
==0xf)
837 // self-test in progress
842 // construct 8-byte integer address of first failure
843 for (i
= 0; i
< 8; i
++) {
847 // print Address of First Failure, if sensible
848 if ((~(uint64_t)0 != ull
) && (res
> 0) && (res
< 0xf)) {
851 // was hex but change to decimal to conform with ATA
852 snprintf(buff
, sizeof(buff
), "%" PRIu64
, ull
);
853 // snprintf(buff, sizeof(buff), "0x%" PRIx64, ull);
858 // if sense key nonzero, then print it, along with
859 // additional sense code and additional sense code qualifier
861 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
866 // if header never printed, then there was no output
868 pout("No self-tests have been logged\n");
870 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
871 modese_len
)) && (durationSec
> 0)) {
872 pout("\nLong (extended) Self Test duration: %d seconds "
873 "[%.1f minutes]\n", durationSec
, durationSec
/ 60.0);
879 static const char * bms_status
[] = {
882 "pre-scan is active",
883 "halted due to fatal error",
884 "halted due to a vendor specific pattern of error",
885 "halted due to medium formatted without P-List",
886 "halted - vendor specific cause",
887 "halted due to temperature out of range",
888 "waiting until BMS interval timer expires", /* 8 */
891 static const char * reassign_status
[] = {
893 "Require Write or Reassign Blocks command",
894 "Successfully reassigned",
896 "Reassignment by disk failed",
897 "Recovered via rewrite in-place",
898 "Reassigned by app, has valid data",
899 "Reassigned by app, has no valid data",
900 "Unsuccessfully reassigned by app", /* 8 */
903 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
904 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
905 // and up to 2048 events (although would hope to have less). May set
906 // FAILLOG if serious errors detected (in the future).
908 scsiPrintBackgroundResults(scsi_device
* device
)
910 int num
, j
, m
, err
, truncated
;
916 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
917 LOG_RESP_LONG_LEN
, 0))) {
919 pout("%s Failed [%s]\n", __func__
, scsiErrString(err
));
923 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
925 pout("Background scan results Log Sense Failed, page mismatch\n");
929 // compute page length
930 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
933 pout("Background scan results Log Sense length is %d, no scan "
938 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
940 num
= LOG_RESP_LONG_LEN
;
944 int pc
= (ucp
[0] << 8) | ucp
[1];
951 pout("Background scan results log\n");
954 if ((pl
< 16) || (num
< 16)) {
959 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
960 pout("%s\n", bms_status
[j
]);
962 pout("unknown [0x%x] background scan status value\n", j
);
963 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
964 pout(" Accumulated power on time, hours:minutes %d:%02d "
965 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
966 pout(" Number of background scans performed: %d, ",
967 (ucp
[10] << 8) + ucp
[11]);
968 pout("scan progress: %.2f%%\n",
969 (double)((ucp
[12] << 8) + ucp
[13]) * 100.0 / 65536.0);
970 pout(" Number of background medium scans performed: %d\n",
971 (ucp
[14] << 8) + ucp
[15]);
976 pout("\nBackground scan results log\n");
980 pout("\n # when lba(hex) [sk,asc,ascq] "
981 "reassign_status\n");
984 if ((pl
< 24) || (num
< 24)) {
986 pout("parameter length >= 24 expected, got %d\n", pl
);
989 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
990 pout("%4d:%02d ", (j
/ 60), (j
% 60));
991 for (m
= 0; m
< 8; ++m
)
992 pout("%02x", ucp
[16 + m
]);
993 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
994 j
= (ucp
[8] >> 4) & 0xf;
996 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
997 pout("%s\n", reassign_status
[j
]);
999 pout("Reassign status: reserved [0x%x]\n", j
);
1006 pout(" >>>> log truncated, fetched %d of %d available "
1007 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
1012 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1013 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1014 // and up to 2048 events (although would hope to have less). May set
1015 // FAILLOG if serious errors detected (in the future).
1017 scsiPrintSSMedia(scsi_device
* device
)
1019 int num
, err
, truncated
;
1023 if ((err
= scsiLogSense(device
, SS_MEDIA_LPAGE
, 0, gBuf
,
1024 LOG_RESP_LONG_LEN
, 0))) {
1026 pout("%s: Failed [%s]\n", __func__
, scsiErrString(err
));
1030 if ((gBuf
[0] & 0x3f) != SS_MEDIA_LPAGE
) {
1032 pout("Solid state media Log Sense Failed, page mismatch\n");
1036 // compute page length
1037 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
1040 pout("Solid state media Log Sense length is %d, too short\n", num
);
1044 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
1046 num
= LOG_RESP_LONG_LEN
;
1050 int pc
= (ucp
[0] << 8) | ucp
[1];
1052 int pl
= ucp
[3] + 4;
1057 pout("SS Media Percentage used endurance indicator parameter "
1058 "too short (pl=%d)\n", pl
);
1062 pout("Percentage used endurance indicator: %d%%\n", ucp
[7]);
1063 default: /* ignore other parameter codes */
1073 show_sas_phy_event_info(int peis
, unsigned int val
, unsigned thresh_val
)
1079 pout(" No event\n");
1082 pout(" Invalid word count: %u\n", val
);
1085 pout(" Running disparity error count: %u\n", val
);
1088 pout(" Loss of dword synchronization count: %u\n", val
);
1091 pout(" Phy reset problem count: %u\n", val
);
1094 pout(" Elasticity buffer overflow count: %u\n", val
);
1097 pout(" Received ERROR count: %u\n", val
);
1100 pout(" Received address frame error count: %u\n", val
);
1103 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
1106 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
1109 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
1112 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
1115 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val
);
1118 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
1121 pout(" Transmitted BREAK count: %u\n", val
);
1124 pout(" Received BREAK count: %u\n", val
);
1127 pout(" Break timeout count: %u\n", val
);
1130 pout(" Connection count: %u\n", val
);
1133 pout(" Peak transmitted pathway blocked count: %u\n",
1135 pout(" Peak value detector threshold: %u\n",
1141 pout(" Peak transmitted arbitration wait time (us): "
1144 pout(" Peak transmitted arbitration wait time (ms): "
1145 "%u\n", 33 + (u
- 0x8000));
1146 u
= thresh_val
& 0xffff;
1148 pout(" Peak value detector threshold (us): %u\n",
1151 pout(" Peak value detector threshold (ms): %u\n",
1155 pout(" Peak arbitration time (us): %u\n", val
);
1156 pout(" Peak value detector threshold: %u\n", thresh_val
);
1159 pout(" Peak connection time (us): %u\n", val
);
1160 pout(" Peak value detector threshold: %u\n", thresh_val
);
1163 pout(" Transmitted SSP frame count: %u\n", val
);
1166 pout(" Received SSP frame count: %u\n", val
);
1169 pout(" Transmitted SSP frame error count: %u\n", val
);
1172 pout(" Received SSP frame error count: %u\n", val
);
1175 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1178 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1181 pout(" Transmitted SATA frame count: %u\n", val
);
1184 pout(" Received SATA frame count: %u\n", val
);
1187 pout(" SATA flow control buffer overflow count: %u\n", val
);
1190 pout(" Transmitted SMP frame count: %u\n", val
);
1193 pout(" Received SMP frame count: %u\n", val
);
1196 pout(" Received SMP frame error count: %u\n", val
);
1204 show_sas_port_param(unsigned char * ucp
, int param_len
)
1206 int j
, m
, n
, nphys
, t
, sz
, spld_len
;
1207 unsigned char * vcp
;
1212 t
= (ucp
[0] << 8) | ucp
[1];
1213 pout("relative target port id = %d\n", t
);
1214 pout(" generation code = %d\n", ucp
[6]);
1216 pout(" number of phys = %d\n", nphys
);
1218 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1219 vcp
+= spld_len
, j
+= spld_len
) {
1220 pout(" phy identifier = %d\n", vcp
[1]);
1223 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1226 t
= ((0x70 & vcp
[4]) >> 4);
1228 case 0: snprintf(s
, sz
, "no device attached"); break;
1229 case 1: snprintf(s
, sz
, "SAS or SATA device"); break;
1230 case 2: snprintf(s
, sz
, "expander device"); break;
1231 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1232 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1234 pout(" attached device type: %s\n", s
);
1237 case 0: snprintf(s
, sz
, "unknown"); break;
1238 case 1: snprintf(s
, sz
, "power on"); break;
1239 case 2: snprintf(s
, sz
, "hard reset"); break;
1240 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1241 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1242 case 5: snprintf(s
, sz
, "mux mix up"); break;
1243 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1245 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1246 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1247 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1249 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1251 pout(" attached reason: %s\n", s
);
1252 t
= (vcp
[5] & 0xf0) >> 4;
1254 case 0: snprintf(s
, sz
, "unknown"); break;
1255 case 1: snprintf(s
, sz
, "power on"); break;
1256 case 2: snprintf(s
, sz
, "hard reset"); break;
1257 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1258 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1259 case 5: snprintf(s
, sz
, "mux mix up"); break;
1260 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1262 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1263 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1264 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1266 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1268 pout(" reason: %s\n", s
);
1271 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1273 case 1: snprintf(s
, sz
, "phy disabled"); break;
1274 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1276 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1278 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1280 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1282 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1284 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1285 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1286 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1287 case 0xb: snprintf(s
, sz
, "phy enabled; 12 Gbps"); break;
1288 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1290 pout(" negotiated logical link rate: %s\n", s
);
1291 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1292 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1293 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1294 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1295 if (!dont_print_serial_number
) {
1297 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1298 ull
<<= 8; ull
|= vcp
[8 + n
];
1300 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1301 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1302 ull
<<= 8; ull
|= vcp
[16 + n
];
1304 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1306 pout(" attached phy identifier = %d\n", vcp
[24]);
1308 ui
= (vcp
[32] << 24) | (vcp
[33] << 16) | (vcp
[34] << 8) | vcp
[35];
1309 pout(" Invalid DWORD count = %u\n", ui
);
1310 ui
= (vcp
[36] << 24) | (vcp
[37] << 16) | (vcp
[38] << 8) | vcp
[39];
1311 pout(" Running disparity error count = %u\n", ui
);
1312 ui
= (vcp
[40] << 24) | (vcp
[41] << 16) | (vcp
[42] << 8) | vcp
[43];
1313 pout(" Loss of DWORD synchronization = %u\n", ui
);
1314 ui
= (vcp
[44] << 24) | (vcp
[45] << 16) | (vcp
[46] << 8) | vcp
[47];
1315 pout(" Phy reset problem = %u\n", ui
);
1316 if (spld_len
> 51) {
1318 unsigned char * xcp
;
1322 pout(" Phy event descriptors:\n");
1324 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1328 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1330 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1332 show_sas_phy_event_info(peis
, ui
, pvdt
);
1338 // Returns 1 if okay, 0 if non SAS descriptors
1340 show_protocol_specific_page(unsigned char * resp
, int len
)
1343 unsigned char * ucp
;
1346 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1347 int param_len
= ucp
[3] + 4;
1348 if (6 != (0xf & ucp
[4]))
1349 return 0; /* only decode SAS log page */
1351 pout("Protocol Specific port log page for SAS SSP\n");
1352 show_sas_port_param(ucp
, param_len
);
1361 // See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1362 // log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1364 scsiPrintSasPhy(scsi_device
* device
, int reset
)
1368 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1369 LOG_RESP_LONG_LEN
, 0))) {
1371 pout("%s Log Sense Failed [%s]\n\n", __func__
, scsiErrString(err
));
1375 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1377 pout("Protocol specific Log Sense Failed, page mismatch\n\n");
1381 // compute page length
1382 num
= (gBuf
[2] << 8) + gBuf
[3];
1383 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1385 pout("Only support protocol specific log page on SAS devices\n\n");
1390 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1391 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1393 pout("%s Log Select (reset) Failed [%s]\n\n", __func__
,
1394 scsiErrString(err
));
1403 static const char * peripheral_dt_arr
[32] = {
1419 "optical card reader",
1421 "object based storage",
1422 "automation/driver interface",
1423 "security manager device",
1424 "host managed zoned block device",
1434 "well known logical unit",
1435 "unknown or no device type",
1438 static const char * transport_proto_arr
[] = {
1439 "Fibre channel (FCP-2)",
1440 "Parallel SCSI (SPI-4)",
1442 "IEEE 1394 (SBP-2)",
1457 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1459 scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1461 char timedatetz
[DATEANDEPOCHLEN
];
1462 struct scsi_iec_mode_page iec
;
1463 int err
, iec_err
, len
, req_len
, avail_len
, scsi_version
;
1464 bool is_tape
= false;
1467 int form_factor
= 0;
1471 memset(gBuf
, 0, 96);
1473 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1475 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1476 pout("Retrying with a 64 byte Standard Inquiry\n");
1478 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1480 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1482 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1483 scsiErrString(err
));
1488 avail_len
= gBuf
[4] + 5;
1489 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1490 peri_dt
= gBuf
[0] & 0x1f;
1491 *peripheral_type
= peri_dt
;
1492 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peri_dt
) ||
1493 (SCSI_PT_MEDIUM_CHANGER
== peri_dt
))
1498 pout("Short INQUIRY response, skip product id\n");
1502 // Upper bits of version bytes were used in older standards
1503 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
1504 scsi_version
= gBuf
[2] & 0x7;
1506 if (all
&& (0 != strncmp((char *)&gBuf
[8], "ATA", 3))) {
1507 char vendor
[8+1], product
[16+1], revision
[4+1];
1508 scsi_format_id_string(vendor
, (const unsigned char *)&gBuf
[8], 8);
1509 scsi_format_id_string(product
, (const unsigned char *)&gBuf
[16], 16);
1510 scsi_format_id_string(revision
, (const unsigned char *)&gBuf
[32], 4);
1512 pout("=== START OF INFORMATION SECTION ===\n");
1513 pout("Vendor: %.8s\n", vendor
);
1514 pout("Product: %.16s\n", product
);
1515 if (gBuf
[32] >= ' ')
1516 pout("Revision: %.4s\n", revision
);
1517 if (scsi_version
== 0x6)
1518 pout("Compliance: SPC-4\n");
1519 else if (scsi_version
== 0x7)
1520 pout("Compliance: SPC-5\n");
1523 if (!*device
->get_req_type()/*no type requested*/ &&
1524 (0 == strncmp((char *)&gBuf
[8], "ATA", 3))) {
1525 pout("\nProbable ATA device behind a SAT layer\n"
1526 "Try an additional '-d ata' or '-d sat' argument.\n");
1532 protect
= gBuf
[5] & 0x1; /* from and including SPC-3 */
1534 if (! is_tape
) { /* assume disk if not tape drive (or tape changer) */
1535 unsigned int lb_size
= 0;
1536 unsigned char lb_prov_resp
[8];
1538 int lb_per_pb_exp
= 0;
1539 uint64_t capacity
= scsiGetSize(device
, &lb_size
, &lb_per_pb_exp
);
1542 char cap_str
[64], si_str
[64];
1543 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1544 format_capacity(si_str
, sizeof(si_str
), capacity
);
1545 pout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1546 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u", lb_size
);
1547 pout("Logical block size: %s bytes\n", lb_str
);
1551 if (protect
|| lb_per_pb_exp
) {
1552 unsigned char rc16_12
[20] = {0, };
1554 if (0 == scsiGetProtPBInfo(device
, rc16_12
)) {
1555 lb_per_pb_exp
= rc16_12
[1] & 0xf; /* just in case */
1556 if (lb_per_pb_exp
> 0) {
1557 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u",
1558 (lb_size
* (1 << lb_per_pb_exp
)));
1559 pout("Physical block size: %s bytes\n", lb_str
);
1560 int n
= ((rc16_12
[2] & 0x3f) << 8) + rc16_12
[3];
1561 if (n
> 0) // not common so cut the clutter
1562 pout("Lowest aligned LBA: %d\n", n
);
1564 if (rc16_12
[0] & 0x1) { /* PROT_EN set */
1565 int p_type
= ((rc16_12
[0] >> 1) & 0x7);
1569 pout("Formatted with type 1 protection\n");
1572 pout("Formatted with type 2 protection\n");
1575 pout("Formatted with type 3 protection\n");
1578 pout("Formatted with unknown protection type [%d]\n",
1582 int p_i_exp
= ((rc16_12
[1] >> 4) & 0xf);
1585 pout("%d protection information intervals per "
1586 "logical block\n", (1 << p_i_exp
));
1588 /* Pick up some LB provisioning info since its available */
1589 lbpme
= !! (rc16_12
[2] & 0x80);
1590 lbprz
= !! (rc16_12
[2] & 0x40);
1593 /* Thin Provisioning VPD page renamed Logical Block Provisioning VPD
1594 * page in sbc3r25; some fields changed their meaning so that the
1595 * new page covered both thin and resource provisioned LUs. */
1596 if (0 == scsiInquiryVpd(device
, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING
,
1597 lb_prov_resp
, sizeof(lb_prov_resp
))) {
1598 int prov_type
= lb_prov_resp
[6] & 0x7; /* added sbc3r27 */
1599 int vpd_lbprz
= ((lb_prov_resp
[5] >> 2) & 0x7); /* sbc4r07 */
1603 else if ((0 == vpd_lbprz
) && (1 == lbprz
))
1604 ; /* vpd_lbprz introduced in sbc3r27, expanded in sbc4r07 */
1607 switch (prov_type
) {
1610 pout("LU is fully provisioned");
1612 pout(" [LBPRZ=%d]\n", lbprz
);
1616 pout("LB provisioning type: not reported [LBPME=1, "
1617 "LBPRZ=%d]\n", lbprz
);
1620 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz
);
1623 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz
);
1626 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1630 } else if (1 == lbpme
) {
1631 if (scsi_debugmode
> 0)
1632 pout("rcap_16 sets LBPME but no LB provisioning VPD page\n");
1633 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz
);
1636 int rpm
= scsiGetRPM(device
, modese_len
, &form_factor
, &haw_zbc
);
1641 pout("Rotation Rate: Solid State Device\n");
1642 else if ((rpm
<= 0x400) || (0xffff == rpm
))
1645 pout("Rotation Rate: %d rpm\n", rpm
);
1647 if (form_factor
> 0) {
1648 const char * cp
= NULL
;
1650 switch (form_factor
) {
1668 pout("Form Factor: %s inches\n", cp
);
1671 pout("Host aware zoned block capable\n");
1674 /* Do this here to try and detect badly conforming devices (some USB
1675 keys) that will lock up on a InquiryVpd or log sense or ... */
1676 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1677 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1678 pout(">> Terminate command early due to bad response to IEC "
1685 modese_len
= iec
.modese_len
;
1687 if (! dont_print_serial_number
) {
1688 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_DEVICE_IDENTIFICATION
,
1693 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
1695 pout("Logical Unit id: %s\n", s
);
1696 } else if (scsi_debugmode
> 0) {
1698 if (SIMPLE_ERR_BAD_RESP
== err
)
1699 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1701 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1704 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_UNIT_SERIAL_NUMBER
,
1709 gBuf
[4 + len
] = '\0';
1710 scsi_format_id_string(serial
, &gBuf
[4], len
);
1711 pout("Serial number: %s\n", serial
);
1712 } else if (scsi_debugmode
> 0) {
1714 if (SIMPLE_ERR_BAD_RESP
== err
)
1715 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1717 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1722 // print SCSI peripheral device type
1723 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1724 sizeof(peripheral_dt_arr
[0])))
1725 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1727 pout("Device type: <%d>\n", peri_dt
);
1729 // See if transport protocol is known
1731 transport
= scsiFetchTransportProtocol(device
, modese_len
);
1732 if ((transport
>= 0) && (transport
<= 0xf))
1733 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
1735 // print current time and date and timezone
1736 dateandtimezone(timedatetz
);
1737 pout("Local Time is: %s\n", timedatetz
);
1739 // See if unit accepts SCSI commmands from us
1740 if ((err
= scsiTestUnitReady(device
))) {
1741 if (SIMPLE_ERR_NOT_READY
== err
) {
1744 pout("device is NOT READY (e.g. spun down, busy)\n");
1746 pout("device is NOT READY (e.g. no tape)\n");
1748 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1751 pout("NO tape present in drive\n");
1753 pout("NO MEDIUM present in device\n");
1755 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1757 pout("device becoming ready (wait)\n");
1761 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1765 int returnval
= 0; // TODO: exit with FAILID if failuretest returns
1767 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1774 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
1775 if (scsi_debugmode
> 0)
1776 pout(" [%s]\n", scsiErrString(iec_err
));
1784 pout("SMART support is: Available - device has SMART capability.\n"
1785 "SMART support is: %s\n",
1786 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1787 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1788 "Temperature Warning: Enabled" :
1789 "Temperature Warning: Disabled or Not Supported");
1794 scsiSmartEnable(scsi_device
* device
)
1796 struct scsi_iec_mode_page iec
;
1799 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1801 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1802 scsiErrString(err
));
1806 modese_len
= iec
.modese_len
;
1808 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1810 pout("unable to enable Exception control and warning [%s]\n",
1811 scsiErrString(err
));
1815 /* Need to refetch 'iec' since could be modified by previous call */
1816 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1817 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1818 scsiErrString(err
));
1821 modese_len
= iec
.modese_len
;
1823 pout("Informational Exceptions (SMART) %s\n",
1824 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1825 pout("Temperature warning %s\n",
1826 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1831 scsiSmartDisable(scsi_device
* device
)
1833 struct scsi_iec_mode_page iec
;
1836 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1838 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1839 scsiErrString(err
));
1843 modese_len
= iec
.modese_len
;
1845 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1847 pout("unable to disable Exception control and warning [%s]\n",
1848 scsiErrString(err
));
1852 /* Need to refetch 'iec' since could be modified by previous call */
1853 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1854 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1855 scsiErrString(err
));
1858 modese_len
= iec
.modese_len
;
1860 pout("Informational Exceptions (SMART) %s\n",
1861 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1862 pout("Temperature warning %s\n",
1863 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1868 scsiPrintTemp(scsi_device
* device
)
1873 if (scsiGetTemp(device
, &temp
, &trip
))
1877 pout("Current Drive Temperature: <not available>\n");
1879 pout("Current Drive Temperature: %d C\n", temp
);
1881 pout("Drive Trip Temperature: <not available>\n");
1883 pout("Drive Trip Temperature: %d C\n", trip
);
1887 /* Main entry point used by smartctl command. Return 0 for success */
1889 scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1891 int checkedSupportedLogPages
= 0;
1892 UINT8 peripheral_type
= 0;
1894 int res
, durationSec
;
1895 struct scsi_sense_disect sense_info
;
1899 bool any_output
= options
.drive_info
;
1901 if (supported_vpd_pages_p
) {
1902 delete supported_vpd_pages_p
;
1903 supported_vpd_pages_p
= NULL
;
1905 supported_vpd_pages_p
= new supported_vpd_pages(device
);
1907 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1912 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1915 is_disk
= (SCSI_PT_DIRECT_ACCESS
== peripheral_type
);
1916 is_tape
= ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1917 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
));
1919 short int wce
= -1, rcd
= -1;
1920 // Print read look-ahead status for disks
1921 if (options
.get_rcd
|| options
.get_wce
) {
1923 res
= scsiGetSetCache(device
, modese_len
, &wce
, &rcd
);
1924 if (options
.get_rcd
)
1925 pout("Read Cache is: %s\n",
1926 res
? "Unavailable" : // error
1927 rcd
? "Disabled" : "Enabled");
1928 if (options
.get_wce
)
1929 pout("Writeback Cache is: %s\n",
1930 res
? "Unavailable" : // error
1931 !wce
? "Disabled" : "Enabled");
1936 if (options
.drive_info
)
1939 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1940 if (options
.smart_disable
|| options
.smart_enable
||
1941 options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1942 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1944 if (options
.smart_enable
) {
1945 if (scsiSmartEnable(device
))
1946 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1950 if (options
.smart_disable
) {
1951 if (scsiSmartDisable(device
))
1952 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1956 if (options
.smart_auto_save_enable
) {
1957 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1958 pout("Enable autosave (clear GLTSD bit) failed\n");
1959 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1961 pout("Autosave enabled (GLTSD bit cleared).\n");
1965 // Enable/Disable write cache
1966 if (options
.set_wce
&& is_disk
) {
1967 short int enable
= wce
= (options
.set_wce
> 0);
1970 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1971 pout("Write cache %sable failed: %s\n", (enable
? "en" : "dis"),
1972 device
->get_errmsg());
1973 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1975 pout("Write cache %sabled\n", (enable
? "en" : "dis"));
1979 // Enable/Disable read cache
1980 if (options
.set_rcd
&& is_disk
) {
1981 short int enable
= (options
.set_rcd
> 0);
1985 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1986 pout("Read cache %sable failed: %s\n", (enable
? "en" : "dis"),
1987 device
->get_errmsg());
1988 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1990 pout("Read cache %sabled\n", (enable
? "en" : "dis"));
1994 if (options
.smart_auto_save_disable
) {
1995 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1996 pout("Disable autosave (set GLTSD bit) failed\n");
1997 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1999 pout("Autosave disabled (GLTSD bit set).\n");
2002 if (options
.smart_disable
|| options
.smart_enable
||
2003 options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
2004 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
2006 // START OF READ-ONLY OPTIONS APART FROM -V and -i
2007 if (options
.smart_check_status
|| options
.smart_ss_media_log
||
2008 options
.smart_vendor_attrib
|| options
.smart_error_log
||
2009 options
.smart_selftest_log
|| options
.smart_background_log
||
2011 pout("=== START OF READ SMART DATA SECTION ===\n");
2013 if (options
.smart_check_status
) {
2014 scsiGetSupportedLogPages(device
);
2015 checkedSupportedLogPages
= 1;
2017 if (gTapeAlertsLPage
) {
2018 if (options
.drive_info
)
2019 pout("TapeAlert Supported\n");
2020 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
2021 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
2024 pout("TapeAlert Not Supported\n");
2025 } else { /* disk, cd/dvd, enclosure, etc */
2026 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
2028 returnval
|= FAILSTATUS
;
2030 returnval
|= FAILSMART
;
2036 if (is_disk
&& options
.smart_ss_media_log
) {
2037 if (! checkedSupportedLogPages
)
2038 scsiGetSupportedLogPages(device
);
2041 res
= scsiPrintSSMedia(device
);
2043 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2046 if (options
.smart_vendor_attrib
) {
2047 if (! checkedSupportedLogPages
)
2048 scsiGetSupportedLogPages(device
);
2050 scsiPrintTemp(device
);
2051 if (gStartStopLPage
)
2052 scsiGetStartStopData(device
);
2054 scsiPrintGrownDefectListLen(device
);
2055 if (gSeagateCacheLPage
)
2056 scsiPrintSeagateCacheLPage(device
);
2057 if (gSeagateFactoryLPage
)
2058 scsiPrintSeagateFactoryLPage(device
);
2062 if (options
.smart_error_log
) {
2063 if (! checkedSupportedLogPages
)
2064 scsiGetSupportedLogPages(device
);
2065 scsiPrintErrorCounterLog(device
);
2066 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
2067 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2068 "Enable Save with '-S on']\n");
2071 if (options
.smart_selftest_log
) {
2072 if (! checkedSupportedLogPages
)
2073 scsiGetSupportedLogPages(device
);
2076 res
= scsiPrintSelfTest(device
);
2078 pout("Device does not support Self Test logging\n");
2079 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2082 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2085 if (options
.smart_background_log
&& is_disk
) {
2086 if (! checkedSupportedLogPages
)
2087 scsiGetSupportedLogPages(device
);
2089 if (gBackgroundResultsLPage
)
2090 res
= scsiPrintBackgroundResults(device
);
2092 pout("Device does not support Background scan results logging\n");
2093 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2096 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2099 if (options
.smart_default_selftest
) {
2100 if (scsiSmartDefaultSelfTest(device
))
2101 return returnval
| FAILSMART
;
2102 pout("Default Self Test Successful\n");
2105 if (options
.smart_short_cap_selftest
) {
2106 if (scsiSmartShortCapSelfTest(device
))
2107 return returnval
| FAILSMART
;
2108 pout("Short Foreground Self Test Successful\n");
2111 // check if another test is running
2112 if (options
.smart_short_selftest
|| options
.smart_extend_selftest
) {
2113 if (!scsiRequestSense(device
, &sense_info
) &&
2114 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09)) {
2115 if (!options
.smart_selftest_force
) {
2116 pout("Can't start self-test without aborting current test");
2117 if (sense_info
.progress
!= -1)
2118 pout(" (%d%% remaining)",
2119 100 - sense_info
.progress
* 100 / 65535);
2120 pout(",\nadd '-t force' option to override, or run "
2121 "'smartctl -X' to abort test.\n");
2124 scsiSmartSelfTestAbort(device
);
2127 if (options
.smart_short_selftest
) {
2128 if (scsiSmartShortSelfTest(device
))
2129 return returnval
| FAILSMART
;
2130 pout("Short Background Self Test has begun\n");
2131 pout("Use smartctl -X to abort test\n");
2134 if (options
.smart_extend_selftest
) {
2135 if (scsiSmartExtendSelfTest(device
))
2136 return returnval
| FAILSMART
;
2137 pout("Extended Background Self Test has begun\n");
2138 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
2139 modese_len
)) && (durationSec
> 0)) {
2140 time_t t
= time(NULL
);
2143 pout("Please wait %d minutes for test to complete.\n",
2145 pout("Estimated completion time: %s\n", ctime(&t
));
2147 pout("Use smartctl -X to abort test\n");
2150 if (options
.smart_extend_cap_selftest
) {
2151 if (scsiSmartExtendCapSelfTest(device
))
2152 return returnval
| FAILSMART
;
2153 pout("Extended Foreground Self Test Successful\n");
2155 if (options
.smart_selftest_abort
) {
2156 if (scsiSmartSelfTestAbort(device
))
2157 return returnval
| FAILSMART
;
2158 pout("Self Test returned without error\n");
2161 if (options
.sasphy
&& gProtocolSpecificLPage
) {
2162 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
2163 return returnval
| FAILSMART
;
2168 pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
2169 "to print SMART (and more) information\n\n");