4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
9 * Additional SCSI work:
10 * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2, or (at your option)
17 * You should have received a copy of the GNU General Public License
18 * (for example COPYING); if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * This code was originally developed as a Senior Thesis by Michael Cornwell
22 * at the Concurrent Systems Laboratory (now part of the Storage Systems
23 * Research Center), Jack Baskin School of Engineering, University of
24 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
37 #include "atacmds.h" // smart_command_set
38 #include "dev_interface.h"
39 #include "scsiprint.h"
43 #define GBUF_SIZE 65535
45 const char * scsiprint_c_cvsid
= "$Id: scsiprint.cpp 3898 2014-04-30 17:44:13Z dpgilbert $"
49 UINT8 gBuf
[GBUF_SIZE
];
50 #define LOG_RESP_LEN 252
51 #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
52 #define LOG_RESP_TAPE_ALERT_LEN 0x144
54 /* Log pages supported */
55 static int gSmartLPage
= 0; /* Informational Exceptions log page */
56 static int gTempLPage
= 0;
57 static int gSelfTestLPage
= 0;
58 static int gStartStopLPage
= 0;
59 static int gReadECounterLPage
= 0;
60 static int gWriteECounterLPage
= 0;
61 static int gVerifyECounterLPage
= 0;
62 static int gNonMediumELPage
= 0;
63 static int gLastNErrorLPage
= 0;
64 static int gBackgroundResultsLPage
= 0;
65 static int gProtocolSpecificLPage
= 0;
66 static int gTapeAlertsLPage
= 0;
67 static int gSSMediaLPage
= 0;
69 /* Vendor specific log pages */
70 static int gSeagateCacheLPage
= 0;
71 static int gSeagateFactoryLPage
= 0;
73 /* Mode pages supported */
74 static int gIecMPage
= 1; /* N.B. assume it until we know otherwise */
76 /* Remember last successful mode sense/select command */
77 static int modese_len
= 0;
81 scsiGetSupportedLogPages(scsi_device
* device
)
85 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
87 if (scsi_debugmode
> 0)
88 pout("Log Sense for supported pages failed [%s]\n",
93 for (i
= 4; i
< gBuf
[3] + LOGPAGEHDRSIZE
; i
++) {
96 case READ_ERROR_COUNTER_LPAGE
:
97 gReadECounterLPage
= 1;
99 case WRITE_ERROR_COUNTER_LPAGE
:
100 gWriteECounterLPage
= 1;
102 case VERIFY_ERROR_COUNTER_LPAGE
:
103 gVerifyECounterLPage
= 1;
105 case LAST_N_ERROR_LPAGE
:
106 gLastNErrorLPage
= 1;
108 case NON_MEDIUM_ERROR_LPAGE
:
109 gNonMediumELPage
= 1;
111 case TEMPERATURE_LPAGE
:
114 case STARTSTOP_CYCLE_COUNTER_LPAGE
:
117 case SELFTEST_RESULTS_LPAGE
:
123 case BACKGROUND_RESULTS_LPAGE
:
124 gBackgroundResultsLPage
= 1;
126 case PROTOCOL_SPECIFIC_LPAGE
:
127 gProtocolSpecificLPage
= 1;
129 case TAPE_ALERTS_LPAGE
:
130 gTapeAlertsLPage
= 1;
135 case SEAGATE_CACHE_LPAGE
:
136 gSeagateCacheLPage
= 1;
138 case SEAGATE_FACTORY_LPAGE
:
139 gSeagateFactoryLPage
= 1;
147 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
148 (or at least something to report). */
150 scsiGetSmartData(scsi_device
* device
, bool attribs
)
154 UINT8 currenttemp
= 0;
159 if (scsiCheckIE(device
, gSmartLPage
, gTempLPage
, &asc
, &ascq
,
160 ¤ttemp
, &triptemp
)) {
161 /* error message already announced */
166 cp
= scsiGetIEString(asc
, ascq
);
170 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp
, asc
, ascq
);
172 } else if (gIecMPage
)
173 pout("SMART Health Status: OK\n");
175 if (attribs
&& !gTempLPage
) {
177 if (255 != currenttemp
)
178 pout("Current Drive Temperature: %d C\n", currenttemp
);
180 pout("Current Drive Temperature: <not available>\n");
183 pout("Drive Trip Temperature: %d C\n", triptemp
);
190 // Returns number of logged errors or zero if none or -1 if fetching
192 static const char * const severities
= "CWI";
195 scsiGetTapeAlertsData(scsi_device
* device
, int peripheral_type
)
197 unsigned short pagelength
;
198 unsigned short parametercode
;
205 if ((err
= scsiLogSense(device
, TAPE_ALERTS_LPAGE
, 0, gBuf
,
206 LOG_RESP_TAPE_ALERT_LEN
, LOG_RESP_TAPE_ALERT_LEN
))) {
207 pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err
));
211 if (gBuf
[0] != 0x2e) {
212 pout("TapeAlerts Log Sense Failed\n");
216 pagelength
= (unsigned short) gBuf
[2] << 8 | gBuf
[3];
218 for (s
=severities
; *s
; s
++) {
219 for (i
= 4; i
< pagelength
; i
+= 5) {
220 parametercode
= (unsigned short) gBuf
[i
] << 8 | gBuf
[i
+1];
223 ts
= SCSI_PT_MEDIUM_CHANGER
== peripheral_type
?
224 scsiTapeAlertsChangerDevice(parametercode
) :
225 scsiTapeAlertsTapeDevice(parametercode
);
228 pout("TapeAlert Errors (C=Critical, W=Warning, "
229 "I=Informational):\n");
230 pout("[0x%02x] %s\n", parametercode
, ts
);
239 pout("TapeAlert: OK\n");
245 scsiGetStartStopData(scsi_device
* device
)
248 int err
, len
, k
, extra
, pc
;
251 if ((err
= scsiLogSense(device
, STARTSTOP_CYCLE_COUNTER_LPAGE
, 0, gBuf
,
254 pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err
));
258 if ((gBuf
[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE
) {
260 pout("StartStop Log Sense Failed, page mismatch\n");
264 len
= ((gBuf
[2] << 8) | gBuf
[3]);
266 for (k
= len
; k
> 0; k
-= extra
, ucp
+= extra
) {
269 pout("StartStop Log Sense Failed: short\n");
274 pc
= (ucp
[0] << 8) + ucp
[1];
278 pout("Manufactured in week %.2s of year %.4s\n", ucp
+ 8,
282 /* ignore Accounting date */
286 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
288 pout("Specified cycle count over device lifetime: %u\n",
294 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
296 pout("Accumulated start-stop cycles: %u\n", u
);
301 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
303 pout("Specified load-unload count over device "
304 "lifetime: %u\n", u
);
309 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
311 pout("Accumulated load-unload cycles: %u\n", u
);
322 scsiPrintGrownDefectListLen(scsi_device
* device
)
324 int err
, dl_format
, got_rd12
, generation
;
325 unsigned int dl_len
, div
;
328 if ((err
= scsiReadDefect12(device
, 0 /* req_plist */, 1 /* req_glist */,
329 4 /* format: bytes from index */,
330 0 /* addr desc index */, gBuf
, 8))) {
331 if (2 == err
) { /* command not supported */
332 if ((err
= scsiReadDefect10(device
, 0 /* req_plist */, 1 /* req_glist */,
333 4 /* format: bytes from index */, gBuf
, 4))) {
334 if (scsi_debugmode
> 0) {
336 pout("Read defect list (10) Failed: %s\n", scsiErrString(err
));
343 if (scsi_debugmode
> 0) {
345 pout("Read defect list (12) Failed: %s\n", scsiErrString(err
));
354 generation
= (gBuf
[2] << 8) + gBuf
[3];
355 if ((generation
> 1) && (scsi_debugmode
> 0)) {
357 pout("Read defect list (12): generation=%d\n", generation
);
360 dl_len
= (gBuf
[4] << 24) + (gBuf
[5] << 16) + (gBuf
[6] << 8) + gBuf
[7];
362 dl_len
= (gBuf
[2] << 8) + gBuf
[3];
364 if (0x8 != (gBuf
[1] & 0x18)) {
366 pout("Read defect list: asked for grown list but didn't get it\n");
371 dl_format
= (gBuf
[1] & 0x7);
373 case 0: /* short block */
376 case 1: /* extended bytes from index */
377 case 2: /* extended physical sector */
378 /* extended = 1; # might use in future */
381 case 3: /* long block */
382 case 4: /* bytes from index */
383 case 5: /* physical sector */
388 pout("defect list format %d unknown\n", dl_format
);
393 pout("Elements in grown defect list: 0\n\n");
396 pout("Grown defect list length=%u bytes [unknown "
397 "number of elements]\n\n", dl_len
);
399 pout("Elements in grown defect list: %u\n\n", dl_len
/ div
);
404 scsiPrintSeagateCacheLPage(scsi_device
* device
)
406 int k
, j
, num
, pl
, pc
, err
, len
;
411 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
414 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err
));
418 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
420 pout("Seagate Cache Log Sense Failed, page mismatch\n");
424 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
428 pc
= (ucp
[0] << 8) | ucp
[1];
431 case 0: case 1: case 2: case 3: case 4:
434 if (scsi_debugmode
> 0) {
436 pout("Vendor (Seagate) cache lpage has unexpected parameter"
445 pout("Vendor (Seagate) cache information\n");
449 pc
= (ucp
[0] << 8) | ucp
[1];
452 case 0: pout(" Blocks sent to initiator"); break;
453 case 1: pout(" Blocks received from initiator"); break;
454 case 2: pout(" Blocks read from cache and sent to initiator"); break;
455 case 3: pout(" Number of read and write commands whose size "
456 "<= segment size"); break;
457 case 4: pout(" Number of read and write commands whose size "
458 "> segment size"); break;
459 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
463 if (k
> (int)sizeof(ull
)) {
464 xp
+= (k
- (int)sizeof(ull
));
465 k
= (int)sizeof(ull
);
468 for (j
= 0; j
< k
; ++j
) {
473 pout(" = %" PRIu64
"\n", ull
);
481 scsiPrintSeagateFactoryLPage(scsi_device
* device
)
483 int k
, j
, num
, pl
, pc
, len
, err
, good
, bad
;
488 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
491 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err
));
495 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
497 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
501 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
507 pc
= (ucp
[0] << 8) | ucp
[1];
520 if ((good
< 2) || (bad
> 4)) { /* heuristic */
521 if (scsi_debugmode
> 0) {
523 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
524 "unexpected parameters, skip\n");
529 pout("Vendor (Seagate/Hitachi) factory information\n");
533 pc
= (ucp
[0] << 8) | ucp
[1];
537 case 0: pout(" number of hours powered up");
540 case 8: pout(" number of minutes until next internal SMART test");
544 if (scsi_debugmode
> 0) {
546 pout("Vendor (Seagate/Hitachi) factory lpage: "
547 "unknown parameter code [0x%x]\n", pc
);
555 if (k
> (int)sizeof(ull
)) {
556 xp
+= (k
- (int)sizeof(ull
));
557 k
= (int)sizeof(ull
);
560 for (j
= 0; j
< k
; ++j
) {
566 pout(" = %.2f\n", ull
/ 60.0 );
568 pout(" = %" PRIu64
"\n", ull
);
577 scsiPrintErrorCounterLog(scsi_device
* device
)
579 struct scsiErrorCounter errCounterArr
[3];
580 struct scsiErrorCounter
* ecp
;
581 struct scsiNonMediumError nme
;
582 int found
[3] = {0, 0, 0};
583 const char * pageNames
[3] = {"read: ", "write: ", "verify: "};
586 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
587 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
588 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
591 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
592 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
593 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
596 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
597 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
598 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
599 ecp
= &errCounterArr
[2];
600 for (int k
= 0; k
< 7; ++k
) {
601 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
607 if (found
[0] || found
[1] || found
[2]) {
608 pout("Error counter log:\n");
609 pout(" Errors Corrected by Total "
610 "Correction Gigabytes Total\n");
611 pout(" ECC rereads/ errors "
612 "algorithm processed uncorrected\n");
613 pout(" fast | delayed rewrites corrected "
614 "invocations [10^9 bytes] errors\n");
615 for (int k
= 0; k
< 3; ++k
) {
618 ecp
= &errCounterArr
[k
];
619 pout("%s%8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
,
620 pageNames
[k
], ecp
->counter
[0], ecp
->counter
[1],
621 ecp
->counter
[2], ecp
->counter
[3], ecp
->counter
[4]);
622 processed_gb
= ecp
->counter
[5] / 1000000000.0;
623 pout(" %12.3f %8" PRIu64
"\n", processed_gb
, ecp
->counter
[6]);
627 pout("Error Counter logging not supported\n");
628 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
629 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
630 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
632 pout("\nNon-medium error count: %8" PRIu64
"\n", nme
.counterPC0
);
634 pout("Track following error count [Hitachi]: %8" PRIu64
"\n",
637 pout("Positioning error count [Hitachi]: %8" PRIu64
"\n",
640 if (gLastNErrorLPage
&& (0 == scsiLogSense(device
,
641 LAST_N_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LONG_LEN
, 0))) {
642 int num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
643 int truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
645 num
= LOG_RESP_LONG_LEN
;
646 unsigned char * ucp
= gBuf
+ 4;
649 pout("\nNo error events logged\n");
651 pout("\nLast n error events log page\n");
652 for (int k
= num
, pl
; k
> 0; k
-= pl
, ucp
+= pl
) {
654 pout(" <<short Last n error events log page>>\n");
658 int pc
= (ucp
[0] << 8) + ucp
[1];
660 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
661 pout(" Error event %d:\n", pc
);
662 pout(" [binary]:\n");
663 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
664 } else if (ucp
[2] & 0x1) {
665 pout(" Error event %d:\n", pc
);
666 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
668 if (scsi_debugmode
> 0) {
669 pout(" Error event %d:\n", pc
);
670 pout(" [data counter??]:\n");
671 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
677 pout(" >>>> log truncated, fetched %d of %d available "
678 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
684 static const char * self_test_code
[] = {
695 static const char * self_test_result
[] = {
697 "Aborted (by user command)",
698 "Aborted (device reset ?) ",
699 "Unknown error, incomplete",
700 "Completed, segment failed",
701 "Failed in first segment ",
702 "Failed in second segment ",
703 "Failed in segment --> ",
711 "Self test in progress ..."
714 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
715 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
716 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
717 // FAILSMART is returned.
719 scsiPrintSelfTest(scsi_device
* device
)
721 int num
, k
, n
, res
, err
, durationSec
;
726 struct scsi_sense_disect sense_info
;
728 // check if test is running
729 if (!scsiRequestSense(device
, &sense_info
) &&
730 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09 &&
731 sense_info
.progress
!= -1)) {
732 pout("Self-test execution status:\t\t%d%% of test remaining\n",
733 100 - ((sense_info
.progress
* 100) / 65535));
736 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
737 LOG_RESP_SELF_TEST_LEN
, 0))) {
739 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err
));
743 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
745 pout("Self-test Log Sense Failed, page mismatch\n");
749 // compute page length
750 num
= (gBuf
[2] << 8) + gBuf
[3];
751 // Log sense page length 0x190 bytes
754 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num
);
758 // loop through the twenty possible entries
759 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
762 // timestamp in power-on hours (or zero if test in progress)
763 n
= (ucp
[6] << 8) | ucp
[7];
765 // The spec says "all 20 bytes will be zero if no test" but
766 // DG has found otherwise. So this is a heuristic.
767 if ((0 == n
) && (0 == ucp
[4]))
770 // only print header if needed
772 pout("SMART Self-test log\n");
773 pout("Num Test Status segment "
774 "LifeTime LBA_first_err [SK ASC ASQ]\n");
775 pout(" Description number "
780 // print parameter code (test number) & self-test code text
781 pout("#%2d %s", (ucp
[0] << 8) | ucp
[1],
782 self_test_code
[(ucp
[4] >> 5) & 0x7]);
784 // check the self-test result nibble, using the self-test results
785 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
786 switch ((res
= ucp
[4] & 0xf)) {
788 // an unknown error occurred while the device server
789 // was processing the self-test and the device server
790 // was unable to complete the self-test
794 // the self-test completed with a failure in a test
795 // segment, and the test segment that failed is not
800 // the first segment of the self-test failed
804 // the second segment of the self-test failed
808 // another segment of the self-test failed and which
809 // test is indicated by the contents of the SELF-TEST
816 pout(" %s", self_test_result
[res
]);
818 // self-test number identifies test that failed and consists
819 // of either the number of the segment that failed during
820 // the test, or the number of the test that failed and the
821 // number of the segment in which the test was run, using a
822 // vendor-specific method of putting both numbers into a
825 pout(" %3d", (int)ucp
[5]);
829 // print time that the self-test was completed
830 if (n
==0 && res
==0xf)
831 // self-test in progress
836 // construct 8-byte integer address of first failure
837 for (i
= 0; i
< 8; i
++) {
841 // print Address of First Failure, if sensible
842 if ((~(uint64_t)0 != ull
) && (res
> 0) && (res
< 0xf)) {
845 // was hex but change to decimal to conform with ATA
846 snprintf(buff
, sizeof(buff
), "%" PRIu64
, ull
);
847 // snprintf(buff, sizeof(buff), "0x%" PRIx64, ull);
852 // if sense key nonzero, then print it, along with
853 // additional sense code and additional sense code qualifier
855 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
860 // if header never printed, then there was no output
862 pout("No self-tests have been logged\n");
864 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
865 modese_len
)) && (durationSec
> 0)) {
866 pout("\nLong (extended) Self Test duration: %d seconds "
867 "[%.1f minutes]\n", durationSec
, durationSec
/ 60.0);
873 static const char * bms_status
[] = {
876 "pre-scan is active",
877 "halted due to fatal error",
878 "halted due to a vendor specific pattern of error",
879 "halted due to medium formatted without P-List",
880 "halted - vendor specific cause",
881 "halted due to temperature out of range",
882 "waiting until BMS interval timer expires", /* 8 */
885 static const char * reassign_status
[] = {
887 "Require Write or Reassign Blocks command",
888 "Successfully reassigned",
890 "Reassignment by disk failed",
891 "Recovered via rewrite in-place",
892 "Reassigned by app, has valid data",
893 "Reassigned by app, has no valid data",
894 "Unsuccessfully reassigned by app", /* 8 */
897 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
898 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
899 // and up to 2048 events (although would hope to have less). May set
900 // FAILLOG if serious errors detected (in the future).
902 scsiPrintBackgroundResults(scsi_device
* device
)
904 int num
, j
, m
, err
, pc
, pl
, truncated
;
910 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
911 LOG_RESP_LONG_LEN
, 0))) {
913 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err
));
917 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
919 pout("Background scan results Log Sense Failed, page mismatch\n");
923 // compute page length
924 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
927 pout("Background scan results Log Sense length is %d, no scan "
932 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
934 num
= LOG_RESP_LONG_LEN
;
938 pc
= (ucp
[0] << 8) | ucp
[1];
945 pout("Background scan results log\n");
948 if ((pl
< 16) || (num
< 16)) {
953 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
954 pout("%s\n", bms_status
[j
]);
956 pout("unknown [0x%x] background scan status value\n", j
);
957 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
958 pout(" Accumulated power on time, hours:minutes %d:%02d "
959 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
960 pout(" Number of background scans performed: %d, ",
961 (ucp
[10] << 8) + ucp
[11]);
962 pout("scan progress: %.2f%%\n",
963 (double)((ucp
[12] << 8) + ucp
[13]) * 100.0 / 65536.0);
964 pout(" Number of background medium scans performed: %d\n",
965 (ucp
[14] << 8) + ucp
[15]);
970 pout("\nBackground scan results log\n");
974 pout("\n # when lba(hex) [sk,asc,ascq] "
975 "reassign_status\n");
978 if ((pl
< 24) || (num
< 24)) {
980 pout("parameter length >= 24 expected, got %d\n", pl
);
983 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
984 pout("%4d:%02d ", (j
/ 60), (j
% 60));
985 for (m
= 0; m
< 8; ++m
)
986 pout("%02x", ucp
[16 + m
]);
987 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
988 j
= (ucp
[8] >> 4) & 0xf;
990 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
991 pout("%s\n", reassign_status
[j
]);
993 pout("Reassign status: reserved [0x%x]\n", j
);
1000 pout(" >>>> log truncated, fetched %d of %d available "
1001 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
1006 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1007 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1008 // and up to 2048 events (although would hope to have less). May set
1009 // FAILLOG if serious errors detected (in the future).
1011 scsiPrintSSMedia(scsi_device
* device
)
1013 int num
, err
, pc
, pl
, truncated
;
1017 if ((err
= scsiLogSense(device
, SS_MEDIA_LPAGE
, 0, gBuf
,
1018 LOG_RESP_LONG_LEN
, 0))) {
1020 pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err
));
1024 if ((gBuf
[0] & 0x3f) != SS_MEDIA_LPAGE
) {
1026 pout("Solid state media Log Sense Failed, page mismatch\n");
1030 // compute page length
1031 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
1034 pout("Solid state media Log Sense length is %d, too short\n", num
);
1038 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
1040 num
= LOG_RESP_LONG_LEN
;
1044 pc
= (ucp
[0] << 8) | ucp
[1];
1051 pout("SS Media Percentage used endurance indicator parameter "
1052 "too short (pl=%d)\n", pl
);
1056 pout("Percentage used endurance indicator: %d%%\n", ucp
[7]);
1057 default: /* ignore other parameter codes */
1067 show_sas_phy_event_info(int peis
, unsigned int val
, unsigned thresh_val
)
1073 pout(" No event\n");
1076 pout(" Invalid word count: %u\n", val
);
1079 pout(" Running disparity error count: %u\n", val
);
1082 pout(" Loss of dword synchronization count: %u\n", val
);
1085 pout(" Phy reset problem count: %u\n", val
);
1088 pout(" Elasticity buffer overflow count: %u\n", val
);
1091 pout(" Received ERROR count: %u\n", val
);
1094 pout(" Received address frame error count: %u\n", val
);
1097 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
1100 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
1103 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
1106 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
1109 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val
);
1112 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
1115 pout(" Transmitted BREAK count: %u\n", val
);
1118 pout(" Received BREAK count: %u\n", val
);
1121 pout(" Break timeout count: %u\n", val
);
1124 pout(" Connection count: %u\n", val
);
1127 pout(" Peak transmitted pathway blocked count: %u\n",
1129 pout(" Peak value detector threshold: %u\n",
1135 pout(" Peak transmitted arbitration wait time (us): "
1138 pout(" Peak transmitted arbitration wait time (ms): "
1139 "%u\n", 33 + (u
- 0x8000));
1140 u
= thresh_val
& 0xffff;
1142 pout(" Peak value detector threshold (us): %u\n",
1145 pout(" Peak value detector threshold (ms): %u\n",
1149 pout(" Peak arbitration time (us): %u\n", val
);
1150 pout(" Peak value detector threshold: %u\n", thresh_val
);
1153 pout(" Peak connection time (us): %u\n", val
);
1154 pout(" Peak value detector threshold: %u\n", thresh_val
);
1157 pout(" Transmitted SSP frame count: %u\n", val
);
1160 pout(" Received SSP frame count: %u\n", val
);
1163 pout(" Transmitted SSP frame error count: %u\n", val
);
1166 pout(" Received SSP frame error count: %u\n", val
);
1169 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1172 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1175 pout(" Transmitted SATA frame count: %u\n", val
);
1178 pout(" Received SATA frame count: %u\n", val
);
1181 pout(" SATA flow control buffer overflow count: %u\n", val
);
1184 pout(" Transmitted SMP frame count: %u\n", val
);
1187 pout(" Received SMP frame count: %u\n", val
);
1190 pout(" Received SMP frame error count: %u\n", val
);
1198 show_sas_port_param(unsigned char * ucp
, int param_len
)
1200 int j
, m
, n
, nphys
, t
, sz
, spld_len
;
1201 unsigned char * vcp
;
1208 t
= (ucp
[0] << 8) | ucp
[1];
1209 pout("relative target port id = %d\n", t
);
1210 pout(" generation code = %d\n", ucp
[6]);
1212 pout(" number of phys = %d\n", nphys
);
1214 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1215 vcp
+= spld_len
, j
+= spld_len
) {
1216 pout(" phy identifier = %d\n", vcp
[1]);
1219 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1222 t
= ((0x70 & vcp
[4]) >> 4);
1224 case 0: snprintf(s
, sz
, "no device attached"); break;
1225 case 1: snprintf(s
, sz
, "SAS or SATA device"); break;
1226 case 2: snprintf(s
, sz
, "expander device"); break;
1227 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1228 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1230 pout(" attached device type: %s\n", s
);
1233 case 0: snprintf(s
, sz
, "unknown"); break;
1234 case 1: snprintf(s
, sz
, "power on"); break;
1235 case 2: snprintf(s
, sz
, "hard reset"); break;
1236 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1237 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1238 case 5: snprintf(s
, sz
, "mux mix up"); break;
1239 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1241 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1242 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1243 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1245 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1247 pout(" attached reason: %s\n", s
);
1248 t
= (vcp
[5] & 0xf0) >> 4;
1250 case 0: snprintf(s
, sz
, "unknown"); break;
1251 case 1: snprintf(s
, sz
, "power on"); break;
1252 case 2: snprintf(s
, sz
, "hard reset"); break;
1253 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1254 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1255 case 5: snprintf(s
, sz
, "mux mix up"); break;
1256 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1258 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1259 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1260 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1262 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1264 pout(" reason: %s\n", s
);
1267 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1269 case 1: snprintf(s
, sz
, "phy disabled"); break;
1270 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1272 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1274 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1276 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1278 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1280 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1281 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1282 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1283 case 0xb: snprintf(s
, sz
, "phy enabled; 12 Gbps"); break;
1284 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1286 pout(" negotiated logical link rate: %s\n", s
);
1287 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1288 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1289 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1290 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1291 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1292 ull
<<= 8; ull
|= vcp
[8 + n
];
1294 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1295 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1296 ull
<<= 8; ull
|= vcp
[16 + n
];
1298 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1299 pout(" attached phy identifier = %d\n", vcp
[24]);
1300 ui
= (vcp
[32] << 24) | (vcp
[33] << 16) | (vcp
[34] << 8) | vcp
[35];
1301 pout(" Invalid DWORD count = %u\n", ui
);
1302 ui
= (vcp
[36] << 24) | (vcp
[37] << 16) | (vcp
[38] << 8) | vcp
[39];
1303 pout(" Running disparity error count = %u\n", ui
);
1304 ui
= (vcp
[40] << 24) | (vcp
[41] << 16) | (vcp
[42] << 8) | vcp
[43];
1305 pout(" Loss of DWORD synchronization = %u\n", ui
);
1306 ui
= (vcp
[44] << 24) | (vcp
[45] << 16) | (vcp
[46] << 8) | vcp
[47];
1307 pout(" Phy reset problem = %u\n", ui
);
1308 if (spld_len
> 51) {
1310 unsigned char * xcp
;
1315 pout(" Phy event descriptors:\n");
1317 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1319 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1321 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1323 show_sas_phy_event_info(peis
, ui
, pvdt
);
1329 // Returns 1 if okay, 0 if non SAS descriptors
1331 show_protocol_specific_page(unsigned char * resp
, int len
)
1333 int k
, num
, param_len
;
1334 unsigned char * ucp
;
1337 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1338 param_len
= ucp
[3] + 4;
1339 if (6 != (0xf & ucp
[4]))
1340 return 0; /* only decode SAS log page */
1342 pout("Protocol Specific port log page for SAS SSP\n");
1343 show_sas_port_param(ucp
, param_len
);
1352 // See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1353 // log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1355 scsiPrintSasPhy(scsi_device
* device
, int reset
)
1359 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1360 LOG_RESP_LONG_LEN
, 0))) {
1362 pout("scsiPrintSasPhy Log Sense Failed [%s]\n\n", scsiErrString(err
));
1366 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1368 pout("Protocol specific Log Sense Failed, page mismatch\n\n");
1372 // compute page length
1373 num
= (gBuf
[2] << 8) + gBuf
[3];
1374 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1376 pout("Only support protocol specific log page on SAS devices\n\n");
1381 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1382 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1384 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n\n",
1385 scsiErrString(err
));
1394 static const char * peripheral_dt_arr
[] = {
1410 "optical card reader"
1412 "object based storage"
1413 "automation/driver interface"
1414 "security manager device"
1415 "host managed zoned block device"
1425 "well known logical unit"
1426 "unknown or no device type"
1429 static const char * transport_proto_arr
[] = {
1430 "Fibre channel (FCP-2)",
1431 "Parallel SCSI (SPI-4)",
1433 "IEEE 1394 (SBP-2)",
1448 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1450 scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1452 char timedatetz
[DATEANDEPOCHLEN
];
1453 struct scsi_iec_mode_page iec
;
1454 int err
, iec_err
, len
, req_len
, avail_len
, n
, scsi_version
;
1459 int form_factor
= 0;
1463 memset(gBuf
, 0, 96);
1465 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1467 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1468 pout("Retrying with a 64 byte Standard Inquiry\n");
1470 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1472 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1474 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1475 scsiErrString(err
));
1480 avail_len
= gBuf
[4] + 5;
1481 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1482 peri_dt
= gBuf
[0] & 0x1f;
1483 if (peripheral_type
)
1484 *peripheral_type
= peri_dt
;
1488 pout("Short INQUIRY response, skip product id\n");
1492 // Upper bits of version bytes were used in older standards
1493 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
1494 scsi_version
= gBuf
[2] & 0x7;
1496 if (all
&& (0 != strncmp((char *)&gBuf
[8], "ATA", 3))) {
1497 char vendor
[8+1], product
[16+1], revision
[4+1];
1498 scsi_format_id_string(vendor
, (const unsigned char *)&gBuf
[8], 8);
1499 scsi_format_id_string(product
, (const unsigned char *)&gBuf
[16], 16);
1500 scsi_format_id_string(revision
, (const unsigned char *)&gBuf
[32], 4);
1502 pout("=== START OF INFORMATION SECTION ===\n");
1503 pout("Vendor: %.8s\n", vendor
);
1504 pout("Product: %.16s\n", product
);
1505 if (gBuf
[32] >= ' ')
1506 pout("Revision: %.4s\n", revision
);
1507 if (scsi_version
== 0x6)
1508 pout("Compliance: SPC-4\n");
1509 else if (scsi_version
== 0x7)
1510 pout("Compliance: SPC-5\n");
1513 if (!*device
->get_req_type()/*no type requested*/ &&
1514 (0 == strncmp((char *)&gBuf
[8], "ATA", 3))) {
1515 pout("\nProbable ATA device behind a SAT layer\n"
1516 "Try an additional '-d ata' or '-d sat' argument.\n");
1522 protect
= gBuf
[5] & 0x1; /* from and including SPC-3 */
1524 if (! is_tape
) { /* only do this for disks */
1525 unsigned int lb_size
= 0;
1526 unsigned char lb_prov_resp
[8];
1530 int lb_per_pb_exp
= 0;
1531 uint64_t capacity
= scsiGetSize(device
, &lb_size
, &lb_per_pb_exp
);
1534 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1535 format_capacity(si_str
, sizeof(si_str
), capacity
);
1536 pout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1537 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u", lb_size
);
1538 pout("Logical block size: %s bytes\n", lb_str
);
1542 if (protect
|| lb_per_pb_exp
) {
1543 unsigned char rc16_12
[20] = {0, };
1545 if (0 == scsiGetProtPBInfo(device
, rc16_12
)) {
1546 lb_per_pb_exp
= rc16_12
[1] & 0xf; /* just in case */
1547 if (lb_per_pb_exp
> 0) {
1548 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u",
1549 (lb_size
* (1 << lb_per_pb_exp
)));
1550 pout("Physical block size: %s bytes\n", lb_str
);
1551 n
= ((rc16_12
[2] & 0x3f) << 8) + rc16_12
[3];
1552 if (n
> 0) // not common so cut the clutter
1553 pout("Lowest aligned LBA: %d\n", n
);
1555 if (rc16_12
[0] & 0x1) { /* PROT_EN set */
1556 int p_type
= ((rc16_12
[0] >> 1) & 0x7);
1560 pout("Formatted with type 1 protection\n");
1563 pout("Formatted with type 2 protection\n");
1566 pout("Formatted with type 3 protection\n");
1569 pout("Formatted with unknown protection type [%d]\n",
1573 int p_i_exp
= ((rc16_12
[1] >> 4) & 0xf);
1576 pout("%d protection information intervals per "
1577 "logical block\n", (1 << p_i_exp
));
1579 /* Pick up some LB provisioning info since its available */
1580 lbpme
= !! (rc16_12
[2] & 0x80);
1581 lbprz
= !! (rc16_12
[2] & 0x40);
1584 if (0 == scsiInquiryVpd(device
, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING
,
1585 lb_prov_resp
, sizeof(lb_prov_resp
))) {
1586 int prov_type
= lb_prov_resp
[6] & 0x7;
1589 lbprz
= !! (lb_prov_resp
[5] & 0x4);
1590 switch (prov_type
) {
1592 pout("LB provisioning type: unreported, LBPME=%d, LBPRZ=%d\n",
1596 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz
);
1599 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz
);
1602 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1606 } else if (1 == lbpme
)
1607 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz
);
1609 int rpm
= scsiGetRPM(device
, modese_len
, &form_factor
, &haw_zbc
);
1614 pout("Rotation Rate: Solid State Device\n");
1615 else if ((rpm
<= 0x400) || (0xffff == rpm
))
1618 pout("Rotation Rate: %d rpm\n", rpm
);
1620 if (form_factor
> 0) {
1621 const char * cp
= NULL
;
1623 switch (form_factor
) {
1641 pout("Form Factor: %s inches\n", cp
);
1644 pout("Host aware zoned block capable\n");
1647 /* Do this here to try and detect badly conforming devices (some USB
1648 keys) that will lock up on a InquiryVpd or log sense or ... */
1649 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1650 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1651 pout(">> Terminate command early due to bad response to IEC "
1658 modese_len
= iec
.modese_len
;
1660 if (! dont_print_serial_number
) {
1661 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_DEVICE_IDENTIFICATION
,
1666 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
1668 pout("Logical Unit id: %s\n", s
);
1669 } else if (scsi_debugmode
> 0) {
1671 if (SIMPLE_ERR_BAD_RESP
== err
)
1672 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1674 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1677 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_UNIT_SERIAL_NUMBER
,
1682 gBuf
[4 + len
] = '\0';
1683 scsi_format_id_string(serial
, &gBuf
[4], len
);
1684 pout("Serial number: %s\n", serial
);
1685 } else if (scsi_debugmode
> 0) {
1687 if (SIMPLE_ERR_BAD_RESP
== err
)
1688 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1690 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1695 // print SCSI peripheral device type
1696 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1697 sizeof(peripheral_dt_arr
[0])))
1698 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1700 pout("Device type: <%d>\n", peri_dt
);
1702 // See if transport protocol is known
1704 transport
= scsiFetchTransportProtocol(device
, modese_len
);
1705 if ((transport
>= 0) && (transport
<= 0xf))
1706 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
1708 // print current time and date and timezone
1709 dateandtimezone(timedatetz
);
1710 pout("Local Time is: %s\n", timedatetz
);
1712 if ((SCSI_PT_SEQUENTIAL_ACCESS
== *peripheral_type
) ||
1713 (SCSI_PT_MEDIUM_CHANGER
== *peripheral_type
))
1715 // See if unit accepts SCSI commmands from us
1716 if ((err
= scsiTestUnitReady(device
))) {
1717 if (SIMPLE_ERR_NOT_READY
== err
) {
1720 pout("device is NOT READY (e.g. spun down, busy)\n");
1722 pout("device is NOT READY (e.g. no tape)\n");
1724 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1726 pout("NO MEDIUM present on device\n");
1728 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1730 pout("device becoming ready (wait)\n");
1734 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1737 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1743 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
1744 if (scsi_debugmode
> 0)
1745 pout(" [%s]\n", scsiErrString(iec_err
));
1753 pout("SMART support is: Available - device has SMART capability.\n"
1754 "SMART support is: %s\n",
1755 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1756 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1757 "Temperature Warning: Enabled" :
1758 "Temperature Warning: Disabled or Not Supported");
1763 scsiSmartEnable(scsi_device
* device
)
1765 struct scsi_iec_mode_page iec
;
1768 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1770 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1771 scsiErrString(err
));
1775 modese_len
= iec
.modese_len
;
1777 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1779 pout("unable to enable Exception control and warning [%s]\n",
1780 scsiErrString(err
));
1784 /* Need to refetch 'iec' since could be modified by previous call */
1785 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1786 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1787 scsiErrString(err
));
1790 modese_len
= iec
.modese_len
;
1792 pout("Informational Exceptions (SMART) %s\n",
1793 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1794 pout("Temperature warning %s\n",
1795 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1800 scsiSmartDisable(scsi_device
* device
)
1802 struct scsi_iec_mode_page iec
;
1805 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1807 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1808 scsiErrString(err
));
1812 modese_len
= iec
.modese_len
;
1814 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1816 pout("unable to disable Exception control and warning [%s]\n",
1817 scsiErrString(err
));
1821 /* Need to refetch 'iec' since could be modified by previous call */
1822 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1823 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1824 scsiErrString(err
));
1827 modese_len
= iec
.modese_len
;
1829 pout("Informational Exceptions (SMART) %s\n",
1830 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1831 pout("Temperature warning %s\n",
1832 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1837 scsiPrintTemp(scsi_device
* device
)
1842 if (scsiGetTemp(device
, &temp
, &trip
))
1847 pout("Current Drive Temperature: %d C\n", temp
);
1849 pout("Current Drive Temperature: <not available>\n");
1852 pout("Drive Trip Temperature: %d C\n", trip
);
1857 /* Main entry point used by smartctl command. Return 0 for success */
1859 scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1861 int checkedSupportedLogPages
= 0;
1862 UINT8 peripheral_type
= 0;
1864 int res
, durationSec
;
1865 struct scsi_sense_disect sense_info
;
1867 bool any_output
= options
.drive_info
;
1869 if (supported_vpd_pages_p
) {
1870 delete supported_vpd_pages_p
;
1871 supported_vpd_pages_p
= NULL
;
1873 supported_vpd_pages_p
= new supported_vpd_pages(device
);
1875 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1880 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1884 // Print read look-ahead status for disks
1885 short int wce
= -1, rcd
= -1;
1886 if (options
.get_rcd
|| options
.get_wce
) {
1887 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
)
1888 res
= scsiGetSetCache(device
, modese_len
, &wce
, &rcd
);
1890 res
= -1; // fetch for disks only
1894 if (options
.get_rcd
) {
1895 pout("Read Cache is: %s\n",
1896 res
? "Unavailable" : // error
1897 rcd
? "Disabled" : "Enabled");
1900 if (options
.get_wce
) {
1901 pout("Writeback Cache is: %s\n",
1902 res
? "Unavailable" : // error
1903 !wce
? "Disabled" : "Enabled");
1905 if (options
.drive_info
)
1908 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1909 if ( options
.smart_disable
|| options
.smart_enable
1910 || options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1911 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1913 if (options
.smart_enable
) {
1914 if (scsiSmartEnable(device
))
1915 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1919 if (options
.smart_disable
) {
1920 if (scsiSmartDisable(device
))
1921 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1925 if (options
.smart_auto_save_enable
) {
1926 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1927 pout("Enable autosave (clear GLTSD bit) failed\n");
1928 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1931 pout("Autosave enabled (GLTSD bit set).\n");
1936 // Enable/Disable write cache
1937 if (options
.set_wce
&& SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1938 short int enable
= wce
= (options
.set_wce
> 0);
1940 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1941 pout("Write cache %sable failed: %s\n", (enable
? "en" : "dis"),
1942 device
->get_errmsg());
1943 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1946 pout("Write cache %sabled\n", (enable
? "en" : "dis"));
1950 // Enable/Disable read cache
1951 if (options
.set_rcd
&& SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1952 short int enable
= (options
.set_rcd
> 0);
1955 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1956 pout("Read cache %sable failed: %s\n", (enable
? "en" : "dis"),
1957 device
->get_errmsg());
1958 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1961 pout("Read cache %sabled\n", (enable
? "en" : "dis"));
1965 if (options
.smart_auto_save_disable
) {
1966 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1967 pout("Disable autosave (set GLTSD bit) failed\n");
1968 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1971 pout("Autosave disabled (GLTSD bit cleared).\n");
1975 if ( options
.smart_disable
|| options
.smart_enable
1976 || options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1977 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
1979 // START OF READ-ONLY OPTIONS APART FROM -V and -i
1980 if ( options
.smart_check_status
|| options
.smart_ss_media_log
1981 || options
.smart_vendor_attrib
|| options
.smart_error_log
1982 || options
.smart_selftest_log
|| options
.smart_vendor_attrib
1983 || options
.smart_background_log
|| options
.sasphy
1985 pout("=== START OF READ SMART DATA SECTION ===\n");
1987 if (options
.smart_check_status
) {
1988 scsiGetSupportedLogPages(device
);
1989 checkedSupportedLogPages
= 1;
1990 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1991 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
)) { /* tape device */
1992 if (gTapeAlertsLPage
) {
1993 if (options
.drive_info
)
1994 pout("TapeAlert Supported\n");
1995 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
1996 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
1999 pout("TapeAlert Not Supported\n");
2000 } else { /* disk, cd/dvd, enclosure, etc */
2001 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
2003 returnval
|= FAILSTATUS
;
2005 returnval
|= FAILSMART
;
2011 if (options
.smart_ss_media_log
) {
2012 if (! checkedSupportedLogPages
)
2013 scsiGetSupportedLogPages(device
);
2016 res
= scsiPrintSSMedia(device
);
2018 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2021 if (options
.smart_vendor_attrib
) {
2022 if (! checkedSupportedLogPages
)
2023 scsiGetSupportedLogPages(device
);
2025 scsiPrintTemp(device
);
2027 if (gStartStopLPage
)
2028 scsiGetStartStopData(device
);
2029 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
2030 scsiPrintGrownDefectListLen(device
);
2031 if (gSeagateCacheLPage
)
2032 scsiPrintSeagateCacheLPage(device
);
2033 if (gSeagateFactoryLPage
)
2034 scsiPrintSeagateFactoryLPage(device
);
2038 if (options
.smart_error_log
) {
2039 if (! checkedSupportedLogPages
)
2040 scsiGetSupportedLogPages(device
);
2041 scsiPrintErrorCounterLog(device
);
2042 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
2043 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2044 "Enable Save with '-S on']\n");
2047 if (options
.smart_selftest_log
) {
2048 if (! checkedSupportedLogPages
)
2049 scsiGetSupportedLogPages(device
);
2052 res
= scsiPrintSelfTest(device
);
2054 pout("Device does not support Self Test logging\n");
2055 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2058 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2061 if (options
.smart_background_log
) {
2062 if (! checkedSupportedLogPages
)
2063 scsiGetSupportedLogPages(device
);
2065 if (gBackgroundResultsLPage
)
2066 res
= scsiPrintBackgroundResults(device
);
2068 pout("Device does not support Background scan results logging\n");
2069 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2072 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2075 if (options
.smart_default_selftest
) {
2076 if (scsiSmartDefaultSelfTest(device
))
2077 return returnval
| FAILSMART
;
2078 pout("Default Self Test Successful\n");
2081 if (options
.smart_short_cap_selftest
) {
2082 if (scsiSmartShortCapSelfTest(device
))
2083 return returnval
| FAILSMART
;
2084 pout("Short Foreground Self Test Successful\n");
2087 // check if another test is running
2088 if (options
.smart_short_selftest
|| options
.smart_extend_selftest
) {
2089 if (!scsiRequestSense(device
, &sense_info
) &&
2090 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09)) {
2091 if (!options
.smart_selftest_force
) {
2092 pout("Can't start self-test without aborting current test");
2093 if (sense_info
.progress
!= -1) {
2094 pout(" (%d%% remaining)",
2095 100 - sense_info
.progress
* 100 / 65535);
2097 pout(",\nadd '-t force' option to override, or run 'smartctl -X' "
2098 "to abort test.\n");
2102 scsiSmartSelfTestAbort(device
);
2105 if (options
.smart_short_selftest
) {
2106 if (scsiSmartShortSelfTest(device
))
2107 return returnval
| FAILSMART
;
2108 pout("Short Background Self Test has begun\n");
2109 pout("Use smartctl -X to abort test\n");
2112 if (options
.smart_extend_selftest
) {
2113 if (scsiSmartExtendSelfTest(device
))
2114 return returnval
| FAILSMART
;
2115 pout("Extended Background Self Test has begun\n");
2116 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
2117 modese_len
)) && (durationSec
> 0)) {
2118 time_t t
= time(NULL
);
2121 pout("Please wait %d minutes for test to complete.\n",
2123 pout("Estimated completion time: %s\n", ctime(&t
));
2125 pout("Use smartctl -X to abort test\n");
2128 if (options
.smart_extend_cap_selftest
) {
2129 if (scsiSmartExtendCapSelfTest(device
))
2130 return returnval
| FAILSMART
;
2131 pout("Extended Foreground Self Test Successful\n");
2133 if (options
.smart_selftest_abort
) {
2134 if (scsiSmartSelfTestAbort(device
))
2135 return returnval
| FAILSMART
;
2136 pout("Self Test returned without error\n");
2139 if (options
.sasphy
&& gProtocolSpecificLPage
) {
2140 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
2141 return returnval
| FAILSMART
;
2146 pout("SCSI device successfully opened\n\n"
2147 "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");