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 4292 2016-04-12 23:06:59Z dpgilbert $"
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
;
1213 t
= (ucp
[0] << 8) | ucp
[1];
1214 pout("relative target port id = %d\n", t
);
1215 pout(" generation code = %d\n", ucp
[6]);
1217 pout(" number of phys = %d\n", nphys
);
1219 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1220 vcp
+= spld_len
, j
+= spld_len
) {
1221 pout(" phy identifier = %d\n", vcp
[1]);
1224 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1227 t
= ((0x70 & vcp
[4]) >> 4);
1229 case 0: snprintf(s
, sz
, "no device attached"); break;
1230 case 1: snprintf(s
, sz
, "SAS or SATA device"); break;
1231 case 2: snprintf(s
, sz
, "expander device"); break;
1232 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1233 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1235 pout(" attached device type: %s\n", s
);
1238 case 0: snprintf(s
, sz
, "unknown"); break;
1239 case 1: snprintf(s
, sz
, "power on"); break;
1240 case 2: snprintf(s
, sz
, "hard reset"); break;
1241 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1242 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1243 case 5: snprintf(s
, sz
, "mux mix up"); break;
1244 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1246 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1247 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1248 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1250 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1252 pout(" attached reason: %s\n", s
);
1253 t
= (vcp
[5] & 0xf0) >> 4;
1255 case 0: snprintf(s
, sz
, "unknown"); break;
1256 case 1: snprintf(s
, sz
, "power on"); break;
1257 case 2: snprintf(s
, sz
, "hard reset"); break;
1258 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1259 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1260 case 5: snprintf(s
, sz
, "mux mix up"); break;
1261 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1263 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1264 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1265 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1267 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1269 pout(" reason: %s\n", s
);
1272 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1274 case 1: snprintf(s
, sz
, "phy disabled"); break;
1275 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1277 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1279 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1281 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1283 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1285 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1286 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1287 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1288 case 0xb: snprintf(s
, sz
, "phy enabled; 12 Gbps"); break;
1289 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1291 pout(" negotiated logical link rate: %s\n", s
);
1292 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1293 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1294 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1295 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1296 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1297 ull
<<= 8; ull
|= vcp
[8 + n
];
1299 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1300 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1301 ull
<<= 8; ull
|= vcp
[16 + n
];
1303 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1304 pout(" attached phy identifier = %d\n", vcp
[24]);
1306 ui
= (vcp
[32] << 24) | (vcp
[33] << 16) | (vcp
[34] << 8) | vcp
[35];
1307 pout(" Invalid DWORD count = %u\n", ui
);
1308 ui
= (vcp
[36] << 24) | (vcp
[37] << 16) | (vcp
[38] << 8) | vcp
[39];
1309 pout(" Running disparity error count = %u\n", ui
);
1310 ui
= (vcp
[40] << 24) | (vcp
[41] << 16) | (vcp
[42] << 8) | vcp
[43];
1311 pout(" Loss of DWORD synchronization = %u\n", ui
);
1312 ui
= (vcp
[44] << 24) | (vcp
[45] << 16) | (vcp
[46] << 8) | vcp
[47];
1313 pout(" Phy reset problem = %u\n", ui
);
1314 if (spld_len
> 51) {
1316 unsigned char * xcp
;
1320 pout(" Phy event descriptors:\n");
1322 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1326 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1328 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1330 show_sas_phy_event_info(peis
, ui
, pvdt
);
1336 // Returns 1 if okay, 0 if non SAS descriptors
1338 show_protocol_specific_page(unsigned char * resp
, int len
)
1341 unsigned char * ucp
;
1344 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1345 int param_len
= ucp
[3] + 4;
1346 if (6 != (0xf & ucp
[4]))
1347 return 0; /* only decode SAS log page */
1349 pout("Protocol Specific port log page for SAS SSP\n");
1350 show_sas_port_param(ucp
, param_len
);
1359 // See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1360 // log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1362 scsiPrintSasPhy(scsi_device
* device
, int reset
)
1366 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1367 LOG_RESP_LONG_LEN
, 0))) {
1369 pout("%s Log Sense Failed [%s]\n\n", __func__
, scsiErrString(err
));
1373 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1375 pout("Protocol specific Log Sense Failed, page mismatch\n\n");
1379 // compute page length
1380 num
= (gBuf
[2] << 8) + gBuf
[3];
1381 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1383 pout("Only support protocol specific log page on SAS devices\n\n");
1388 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1389 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1391 pout("%s Log Select (reset) Failed [%s]\n\n", __func__
,
1392 scsiErrString(err
));
1401 static const char * peripheral_dt_arr
[32] = {
1417 "optical card reader",
1419 "object based storage",
1420 "automation/driver interface",
1421 "security manager device",
1422 "host managed zoned block device",
1432 "well known logical unit",
1433 "unknown or no device type",
1436 static const char * transport_proto_arr
[] = {
1437 "Fibre channel (FCP-2)",
1438 "Parallel SCSI (SPI-4)",
1440 "IEEE 1394 (SBP-2)",
1455 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1457 scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1459 char timedatetz
[DATEANDEPOCHLEN
];
1460 struct scsi_iec_mode_page iec
;
1461 int err
, iec_err
, len
, req_len
, avail_len
, scsi_version
;
1462 bool is_tape
= false;
1465 int form_factor
= 0;
1469 memset(gBuf
, 0, 96);
1471 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1473 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1474 pout("Retrying with a 64 byte Standard Inquiry\n");
1476 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1478 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1480 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1481 scsiErrString(err
));
1486 avail_len
= gBuf
[4] + 5;
1487 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1488 peri_dt
= gBuf
[0] & 0x1f;
1489 *peripheral_type
= peri_dt
;
1490 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peri_dt
) ||
1491 (SCSI_PT_MEDIUM_CHANGER
== peri_dt
))
1496 pout("Short INQUIRY response, skip product id\n");
1500 // Upper bits of version bytes were used in older standards
1501 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
1502 scsi_version
= gBuf
[2] & 0x7;
1504 if (all
&& (0 != strncmp((char *)&gBuf
[8], "ATA", 3))) {
1505 char vendor
[8+1], product
[16+1], revision
[4+1];
1506 scsi_format_id_string(vendor
, (const unsigned char *)&gBuf
[8], 8);
1507 scsi_format_id_string(product
, (const unsigned char *)&gBuf
[16], 16);
1508 scsi_format_id_string(revision
, (const unsigned char *)&gBuf
[32], 4);
1510 pout("=== START OF INFORMATION SECTION ===\n");
1511 pout("Vendor: %.8s\n", vendor
);
1512 pout("Product: %.16s\n", product
);
1513 if (gBuf
[32] >= ' ')
1514 pout("Revision: %.4s\n", revision
);
1515 if (scsi_version
== 0x6)
1516 pout("Compliance: SPC-4\n");
1517 else if (scsi_version
== 0x7)
1518 pout("Compliance: SPC-5\n");
1521 if (!*device
->get_req_type()/*no type requested*/ &&
1522 (0 == strncmp((char *)&gBuf
[8], "ATA", 3))) {
1523 pout("\nProbable ATA device behind a SAT layer\n"
1524 "Try an additional '-d ata' or '-d sat' argument.\n");
1530 protect
= gBuf
[5] & 0x1; /* from and including SPC-3 */
1532 if (! is_tape
) { /* assume disk if not tape drive (or tape changer) */
1533 unsigned int lb_size
= 0;
1534 unsigned char lb_prov_resp
[8];
1536 int lb_per_pb_exp
= 0;
1537 uint64_t capacity
= scsiGetSize(device
, &lb_size
, &lb_per_pb_exp
);
1540 char cap_str
[64], si_str
[64];
1541 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1542 format_capacity(si_str
, sizeof(si_str
), capacity
);
1543 pout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1544 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u", lb_size
);
1545 pout("Logical block size: %s bytes\n", lb_str
);
1549 if (protect
|| lb_per_pb_exp
) {
1550 unsigned char rc16_12
[20] = {0, };
1552 if (0 == scsiGetProtPBInfo(device
, rc16_12
)) {
1553 lb_per_pb_exp
= rc16_12
[1] & 0xf; /* just in case */
1554 if (lb_per_pb_exp
> 0) {
1555 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u",
1556 (lb_size
* (1 << lb_per_pb_exp
)));
1557 pout("Physical block size: %s bytes\n", lb_str
);
1558 int n
= ((rc16_12
[2] & 0x3f) << 8) + rc16_12
[3];
1559 if (n
> 0) // not common so cut the clutter
1560 pout("Lowest aligned LBA: %d\n", n
);
1562 if (rc16_12
[0] & 0x1) { /* PROT_EN set */
1563 int p_type
= ((rc16_12
[0] >> 1) & 0x7);
1567 pout("Formatted with type 1 protection\n");
1570 pout("Formatted with type 2 protection\n");
1573 pout("Formatted with type 3 protection\n");
1576 pout("Formatted with unknown protection type [%d]\n",
1580 int p_i_exp
= ((rc16_12
[1] >> 4) & 0xf);
1583 pout("%d protection information intervals per "
1584 "logical block\n", (1 << p_i_exp
));
1586 /* Pick up some LB provisioning info since its available */
1587 lbpme
= !! (rc16_12
[2] & 0x80);
1588 lbprz
= !! (rc16_12
[2] & 0x40);
1591 /* Thin Provisioning VPD page renamed Logical Block Provisioning VPD
1592 * page in sbc3r25; some fields changed their meaning so that the
1593 * new page covered both thin and resource provisioned LUs. */
1594 if (0 == scsiInquiryVpd(device
, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING
,
1595 lb_prov_resp
, sizeof(lb_prov_resp
))) {
1596 int prov_type
= lb_prov_resp
[6] & 0x7; /* added sbc3r27 */
1597 int vpd_lbprz
= ((lb_prov_resp
[5] >> 2) & 0x7); /* sbc4r07 */
1601 else if ((0 == vpd_lbprz
) && (1 == lbprz
))
1602 ; /* vpd_lbprz introduced in sbc3r27, expanded in sbc4r07 */
1605 switch (prov_type
) {
1608 pout("LU is fully provisioned");
1610 pout(" [LBPRZ=%d]\n", lbprz
);
1614 pout("LB provisioning type: not reported [LBPME=1, "
1615 "LBPRZ=%d]\n", lbprz
);
1618 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz
);
1621 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz
);
1624 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1628 } else if (1 == lbpme
) {
1629 if (scsi_debugmode
> 0)
1630 pout("rcap_16 sets LBPME but no LB provisioning VPD page\n");
1631 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz
);
1634 int rpm
= scsiGetRPM(device
, modese_len
, &form_factor
, &haw_zbc
);
1639 pout("Rotation Rate: Solid State Device\n");
1640 else if ((rpm
<= 0x400) || (0xffff == rpm
))
1643 pout("Rotation Rate: %d rpm\n", rpm
);
1645 if (form_factor
> 0) {
1646 const char * cp
= NULL
;
1648 switch (form_factor
) {
1666 pout("Form Factor: %s inches\n", cp
);
1669 pout("Host aware zoned block capable\n");
1672 /* Do this here to try and detect badly conforming devices (some USB
1673 keys) that will lock up on a InquiryVpd or log sense or ... */
1674 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1675 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1676 pout(">> Terminate command early due to bad response to IEC "
1683 modese_len
= iec
.modese_len
;
1685 if (! dont_print_serial_number
) {
1686 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_DEVICE_IDENTIFICATION
,
1691 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
1693 pout("Logical Unit id: %s\n", s
);
1694 } else if (scsi_debugmode
> 0) {
1696 if (SIMPLE_ERR_BAD_RESP
== err
)
1697 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1699 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1702 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_UNIT_SERIAL_NUMBER
,
1707 gBuf
[4 + len
] = '\0';
1708 scsi_format_id_string(serial
, &gBuf
[4], len
);
1709 pout("Serial number: %s\n", serial
);
1710 } else if (scsi_debugmode
> 0) {
1712 if (SIMPLE_ERR_BAD_RESP
== err
)
1713 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1715 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1720 // print SCSI peripheral device type
1721 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1722 sizeof(peripheral_dt_arr
[0])))
1723 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1725 pout("Device type: <%d>\n", peri_dt
);
1727 // See if transport protocol is known
1729 transport
= scsiFetchTransportProtocol(device
, modese_len
);
1730 if ((transport
>= 0) && (transport
<= 0xf))
1731 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
1733 // print current time and date and timezone
1734 dateandtimezone(timedatetz
);
1735 pout("Local Time is: %s\n", timedatetz
);
1737 // See if unit accepts SCSI commmands from us
1738 if ((err
= scsiTestUnitReady(device
))) {
1739 if (SIMPLE_ERR_NOT_READY
== err
) {
1742 pout("device is NOT READY (e.g. spun down, busy)\n");
1744 pout("device is NOT READY (e.g. no tape)\n");
1746 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1749 pout("NO tape present in drive\n");
1751 pout("NO MEDIUM present in device\n");
1753 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1755 pout("device becoming ready (wait)\n");
1759 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1763 int returnval
= 0; // TODO: exit with FAILID if failuretest returns
1765 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1772 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
1773 if (scsi_debugmode
> 0)
1774 pout(" [%s]\n", scsiErrString(iec_err
));
1782 pout("SMART support is: Available - device has SMART capability.\n"
1783 "SMART support is: %s\n",
1784 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1785 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1786 "Temperature Warning: Enabled" :
1787 "Temperature Warning: Disabled or Not Supported");
1792 scsiSmartEnable(scsi_device
* device
)
1794 struct scsi_iec_mode_page iec
;
1797 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1799 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1800 scsiErrString(err
));
1804 modese_len
= iec
.modese_len
;
1806 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1808 pout("unable to enable Exception control and warning [%s]\n",
1809 scsiErrString(err
));
1813 /* Need to refetch 'iec' since could be modified by previous call */
1814 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1815 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1816 scsiErrString(err
));
1819 modese_len
= iec
.modese_len
;
1821 pout("Informational Exceptions (SMART) %s\n",
1822 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1823 pout("Temperature warning %s\n",
1824 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1829 scsiSmartDisable(scsi_device
* device
)
1831 struct scsi_iec_mode_page iec
;
1834 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1836 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1837 scsiErrString(err
));
1841 modese_len
= iec
.modese_len
;
1843 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1845 pout("unable to disable Exception control and warning [%s]\n",
1846 scsiErrString(err
));
1850 /* Need to refetch 'iec' since could be modified by previous call */
1851 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1852 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1853 scsiErrString(err
));
1856 modese_len
= iec
.modese_len
;
1858 pout("Informational Exceptions (SMART) %s\n",
1859 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1860 pout("Temperature warning %s\n",
1861 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1866 scsiPrintTemp(scsi_device
* device
)
1871 if (scsiGetTemp(device
, &temp
, &trip
))
1875 pout("Current Drive Temperature: <not available>\n");
1877 pout("Current Drive Temperature: %d C\n", temp
);
1879 pout("Drive Trip Temperature: <not available>\n");
1881 pout("Drive Trip Temperature: %d C\n", trip
);
1885 /* Main entry point used by smartctl command. Return 0 for success */
1887 scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1889 int checkedSupportedLogPages
= 0;
1890 UINT8 peripheral_type
= 0;
1892 int res
, durationSec
;
1893 struct scsi_sense_disect sense_info
;
1897 bool any_output
= options
.drive_info
;
1899 if (supported_vpd_pages_p
) {
1900 delete supported_vpd_pages_p
;
1901 supported_vpd_pages_p
= NULL
;
1903 supported_vpd_pages_p
= new supported_vpd_pages(device
);
1905 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1910 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1913 is_disk
= (SCSI_PT_DIRECT_ACCESS
== peripheral_type
);
1914 is_tape
= ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1915 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
));
1917 short int wce
= -1, rcd
= -1;
1918 // Print read look-ahead status for disks
1919 if (options
.get_rcd
|| options
.get_wce
) {
1921 res
= scsiGetSetCache(device
, modese_len
, &wce
, &rcd
);
1922 if (options
.get_rcd
)
1923 pout("Read Cache is: %s\n",
1924 res
? "Unavailable" : // error
1925 rcd
? "Disabled" : "Enabled");
1926 if (options
.get_wce
)
1927 pout("Writeback Cache is: %s\n",
1928 res
? "Unavailable" : // error
1929 !wce
? "Disabled" : "Enabled");
1934 if (options
.drive_info
)
1937 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1938 if (options
.smart_disable
|| options
.smart_enable
||
1939 options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1940 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1942 if (options
.smart_enable
) {
1943 if (scsiSmartEnable(device
))
1944 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1948 if (options
.smart_disable
) {
1949 if (scsiSmartDisable(device
))
1950 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1954 if (options
.smart_auto_save_enable
) {
1955 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1956 pout("Enable autosave (clear GLTSD bit) failed\n");
1957 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1959 pout("Autosave enabled (GLTSD bit cleared).\n");
1963 // Enable/Disable write cache
1964 if (options
.set_wce
&& is_disk
) {
1965 short int enable
= wce
= (options
.set_wce
> 0);
1968 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1969 pout("Write cache %sable failed: %s\n", (enable
? "en" : "dis"),
1970 device
->get_errmsg());
1971 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1973 pout("Write cache %sabled\n", (enable
? "en" : "dis"));
1977 // Enable/Disable read cache
1978 if (options
.set_rcd
&& is_disk
) {
1979 short int enable
= (options
.set_rcd
> 0);
1983 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1984 pout("Read cache %sable failed: %s\n", (enable
? "en" : "dis"),
1985 device
->get_errmsg());
1986 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1988 pout("Read cache %sabled\n", (enable
? "en" : "dis"));
1992 if (options
.smart_auto_save_disable
) {
1993 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1994 pout("Disable autosave (set GLTSD bit) failed\n");
1995 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1997 pout("Autosave disabled (GLTSD bit set).\n");
2000 if (options
.smart_disable
|| options
.smart_enable
||
2001 options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
2002 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
2004 // START OF READ-ONLY OPTIONS APART FROM -V and -i
2005 if (options
.smart_check_status
|| options
.smart_ss_media_log
||
2006 options
.smart_vendor_attrib
|| options
.smart_error_log
||
2007 options
.smart_selftest_log
|| options
.smart_background_log
||
2009 pout("=== START OF READ SMART DATA SECTION ===\n");
2011 if (options
.smart_check_status
) {
2012 scsiGetSupportedLogPages(device
);
2013 checkedSupportedLogPages
= 1;
2015 if (gTapeAlertsLPage
) {
2016 if (options
.drive_info
)
2017 pout("TapeAlert Supported\n");
2018 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
2019 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
2022 pout("TapeAlert Not Supported\n");
2023 } else { /* disk, cd/dvd, enclosure, etc */
2024 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
2026 returnval
|= FAILSTATUS
;
2028 returnval
|= FAILSMART
;
2034 if (is_disk
&& options
.smart_ss_media_log
) {
2035 if (! checkedSupportedLogPages
)
2036 scsiGetSupportedLogPages(device
);
2039 res
= scsiPrintSSMedia(device
);
2041 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2044 if (options
.smart_vendor_attrib
) {
2045 if (! checkedSupportedLogPages
)
2046 scsiGetSupportedLogPages(device
);
2048 scsiPrintTemp(device
);
2049 if (gStartStopLPage
)
2050 scsiGetStartStopData(device
);
2052 scsiPrintGrownDefectListLen(device
);
2053 if (gSeagateCacheLPage
)
2054 scsiPrintSeagateCacheLPage(device
);
2055 if (gSeagateFactoryLPage
)
2056 scsiPrintSeagateFactoryLPage(device
);
2060 if (options
.smart_error_log
) {
2061 if (! checkedSupportedLogPages
)
2062 scsiGetSupportedLogPages(device
);
2063 scsiPrintErrorCounterLog(device
);
2064 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
2065 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2066 "Enable Save with '-S on']\n");
2069 if (options
.smart_selftest_log
) {
2070 if (! checkedSupportedLogPages
)
2071 scsiGetSupportedLogPages(device
);
2074 res
= scsiPrintSelfTest(device
);
2076 pout("Device does not support Self Test logging\n");
2077 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2080 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2083 if (options
.smart_background_log
&& is_disk
) {
2084 if (! checkedSupportedLogPages
)
2085 scsiGetSupportedLogPages(device
);
2087 if (gBackgroundResultsLPage
)
2088 res
= scsiPrintBackgroundResults(device
);
2090 pout("Device does not support Background scan results logging\n");
2091 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2094 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2097 if (options
.smart_default_selftest
) {
2098 if (scsiSmartDefaultSelfTest(device
))
2099 return returnval
| FAILSMART
;
2100 pout("Default Self Test Successful\n");
2103 if (options
.smart_short_cap_selftest
) {
2104 if (scsiSmartShortCapSelfTest(device
))
2105 return returnval
| FAILSMART
;
2106 pout("Short Foreground Self Test Successful\n");
2109 // check if another test is running
2110 if (options
.smart_short_selftest
|| options
.smart_extend_selftest
) {
2111 if (!scsiRequestSense(device
, &sense_info
) &&
2112 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09)) {
2113 if (!options
.smart_selftest_force
) {
2114 pout("Can't start self-test without aborting current test");
2115 if (sense_info
.progress
!= -1)
2116 pout(" (%d%% remaining)",
2117 100 - sense_info
.progress
* 100 / 65535);
2118 pout(",\nadd '-t force' option to override, or run "
2119 "'smartctl -X' to abort test.\n");
2122 scsiSmartSelfTestAbort(device
);
2125 if (options
.smart_short_selftest
) {
2126 if (scsiSmartShortSelfTest(device
))
2127 return returnval
| FAILSMART
;
2128 pout("Short Background Self Test has begun\n");
2129 pout("Use smartctl -X to abort test\n");
2132 if (options
.smart_extend_selftest
) {
2133 if (scsiSmartExtendSelfTest(device
))
2134 return returnval
| FAILSMART
;
2135 pout("Extended Background Self Test has begun\n");
2136 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
2137 modese_len
)) && (durationSec
> 0)) {
2138 time_t t
= time(NULL
);
2141 pout("Please wait %d minutes for test to complete.\n",
2143 pout("Estimated completion time: %s\n", ctime(&t
));
2145 pout("Use smartctl -X to abort test\n");
2148 if (options
.smart_extend_cap_selftest
) {
2149 if (scsiSmartExtendCapSelfTest(device
))
2150 return returnval
| FAILSMART
;
2151 pout("Extended Foreground Self Test Successful\n");
2153 if (options
.smart_selftest_abort
) {
2154 if (scsiSmartSelfTestAbort(device
))
2155 return returnval
| FAILSMART
;
2156 pout("Self Test returned without error\n");
2159 if (options
.sasphy
&& gProtocolSpecificLPage
) {
2160 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
2161 return returnval
| FAILSMART
;
2166 pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
2167 "to print SMART (and more) information\n\n");