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 4040 2015-03-10 22:30:44Z 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
));
342 } else if (101 == err
) /* Defect list not found, leave quietly */
345 if (scsi_debugmode
> 0) {
347 pout("Read defect list (12) Failed: %s\n", scsiErrString(err
));
356 generation
= (gBuf
[2] << 8) + gBuf
[3];
357 if ((generation
> 1) && (scsi_debugmode
> 0)) {
359 pout("Read defect list (12): generation=%d\n", generation
);
362 dl_len
= (gBuf
[4] << 24) + (gBuf
[5] << 16) + (gBuf
[6] << 8) + gBuf
[7];
364 dl_len
= (gBuf
[2] << 8) + gBuf
[3];
366 if (0x8 != (gBuf
[1] & 0x18)) {
368 pout("Read defect list: asked for grown list but didn't get it\n");
373 dl_format
= (gBuf
[1] & 0x7);
375 case 0: /* short block */
378 case 1: /* extended bytes from index */
379 case 2: /* extended physical sector */
380 /* extended = 1; # might use in future */
383 case 3: /* long block */
384 case 4: /* bytes from index */
385 case 5: /* physical sector */
390 pout("defect list format %d unknown\n", dl_format
);
395 pout("Elements in grown defect list: 0\n\n");
398 pout("Grown defect list length=%u bytes [unknown "
399 "number of elements]\n\n", dl_len
);
401 pout("Elements in grown defect list: %u\n\n", dl_len
/ div
);
406 scsiPrintSeagateCacheLPage(scsi_device
* device
)
408 int k
, j
, num
, pl
, pc
, err
, len
;
413 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
416 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err
));
420 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
422 pout("Seagate Cache Log Sense Failed, page mismatch\n");
426 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
430 pc
= (ucp
[0] << 8) | ucp
[1];
433 case 0: case 1: case 2: case 3: case 4:
436 if (scsi_debugmode
> 0) {
438 pout("Vendor (Seagate) cache lpage has unexpected parameter"
447 pout("Vendor (Seagate) cache information\n");
451 pc
= (ucp
[0] << 8) | ucp
[1];
454 case 0: pout(" Blocks sent to initiator"); break;
455 case 1: pout(" Blocks received from initiator"); break;
456 case 2: pout(" Blocks read from cache and sent to initiator"); break;
457 case 3: pout(" Number of read and write commands whose size "
458 "<= segment size"); break;
459 case 4: pout(" Number of read and write commands whose size "
460 "> segment size"); break;
461 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
465 if (k
> (int)sizeof(ull
)) {
466 xp
+= (k
- (int)sizeof(ull
));
467 k
= (int)sizeof(ull
);
470 for (j
= 0; j
< k
; ++j
) {
475 pout(" = %" PRIu64
"\n", ull
);
483 scsiPrintSeagateFactoryLPage(scsi_device
* device
)
485 int k
, j
, num
, pl
, pc
, len
, err
, good
, bad
;
490 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
493 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err
));
497 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
499 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
503 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
509 pc
= (ucp
[0] << 8) | ucp
[1];
522 if ((good
< 2) || (bad
> 4)) { /* heuristic */
523 if (scsi_debugmode
> 0) {
525 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
526 "unexpected parameters, skip\n");
531 pout("Vendor (Seagate/Hitachi) factory information\n");
535 pc
= (ucp
[0] << 8) | ucp
[1];
539 case 0: pout(" number of hours powered up");
542 case 8: pout(" number of minutes until next internal SMART test");
546 if (scsi_debugmode
> 0) {
548 pout("Vendor (Seagate/Hitachi) factory lpage: "
549 "unknown parameter code [0x%x]\n", pc
);
557 if (k
> (int)sizeof(ull
)) {
558 xp
+= (k
- (int)sizeof(ull
));
559 k
= (int)sizeof(ull
);
562 for (j
= 0; j
< k
; ++j
) {
568 pout(" = %.2f\n", ull
/ 60.0 );
570 pout(" = %" PRIu64
"\n", ull
);
579 scsiPrintErrorCounterLog(scsi_device
* device
)
581 struct scsiErrorCounter errCounterArr
[3];
582 struct scsiErrorCounter
* ecp
;
583 struct scsiNonMediumError nme
;
584 int found
[3] = {0, 0, 0};
585 const char * pageNames
[3] = {"read: ", "write: ", "verify: "};
588 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
589 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
590 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
593 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
594 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
595 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
598 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
599 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
600 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
601 ecp
= &errCounterArr
[2];
602 for (int k
= 0; k
< 7; ++k
) {
603 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
609 if (found
[0] || found
[1] || found
[2]) {
610 pout("Error counter log:\n");
611 pout(" Errors Corrected by Total "
612 "Correction Gigabytes Total\n");
613 pout(" ECC rereads/ errors "
614 "algorithm processed uncorrected\n");
615 pout(" fast | delayed rewrites corrected "
616 "invocations [10^9 bytes] errors\n");
617 for (int k
= 0; k
< 3; ++k
) {
620 ecp
= &errCounterArr
[k
];
621 pout("%s%8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
,
622 pageNames
[k
], ecp
->counter
[0], ecp
->counter
[1],
623 ecp
->counter
[2], ecp
->counter
[3], ecp
->counter
[4]);
624 processed_gb
= ecp
->counter
[5] / 1000000000.0;
625 pout(" %12.3f %8" PRIu64
"\n", processed_gb
, ecp
->counter
[6]);
629 pout("Error Counter logging not supported\n");
630 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
631 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
632 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
634 pout("\nNon-medium error count: %8" PRIu64
"\n", nme
.counterPC0
);
636 pout("Track following error count [Hitachi]: %8" PRIu64
"\n",
639 pout("Positioning error count [Hitachi]: %8" PRIu64
"\n",
642 if (gLastNErrorLPage
&& (0 == scsiLogSense(device
,
643 LAST_N_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LONG_LEN
, 0))) {
644 int num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
645 int truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
647 num
= LOG_RESP_LONG_LEN
;
648 unsigned char * ucp
= gBuf
+ 4;
651 pout("\nNo error events logged\n");
653 pout("\nLast n error events log page\n");
654 for (int k
= num
, pl
; k
> 0; k
-= pl
, ucp
+= pl
) {
656 pout(" <<short Last n error events log page>>\n");
660 int pc
= (ucp
[0] << 8) + ucp
[1];
662 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
663 pout(" Error event %d:\n", pc
);
664 pout(" [binary]:\n");
665 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
666 } else if (ucp
[2] & 0x1) {
667 pout(" Error event %d:\n", pc
);
668 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
670 if (scsi_debugmode
> 0) {
671 pout(" Error event %d:\n", pc
);
672 pout(" [data counter??]:\n");
673 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
679 pout(" >>>> log truncated, fetched %d of %d available "
680 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
686 static const char * self_test_code
[] = {
697 static const char * self_test_result
[] = {
699 "Aborted (by user command)",
700 "Aborted (device reset ?) ",
701 "Unknown error, incomplete",
702 "Completed, segment failed",
703 "Failed in first segment ",
704 "Failed in second segment ",
705 "Failed in segment --> ",
713 "Self test in progress ..."
716 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
717 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
718 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
719 // FAILSMART is returned.
721 scsiPrintSelfTest(scsi_device
* device
)
723 int num
, k
, n
, res
, err
, durationSec
;
728 struct scsi_sense_disect sense_info
;
730 // check if test is running
731 if (!scsiRequestSense(device
, &sense_info
) &&
732 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09 &&
733 sense_info
.progress
!= -1)) {
734 pout("Self-test execution status:\t\t%d%% of test remaining\n",
735 100 - ((sense_info
.progress
* 100) / 65535));
738 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
739 LOG_RESP_SELF_TEST_LEN
, 0))) {
741 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err
));
745 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
747 pout("Self-test Log Sense Failed, page mismatch\n");
751 // compute page length
752 num
= (gBuf
[2] << 8) + gBuf
[3];
753 // Log sense page length 0x190 bytes
756 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num
);
760 // loop through the twenty possible entries
761 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
764 // timestamp in power-on hours (or zero if test in progress)
765 n
= (ucp
[6] << 8) | ucp
[7];
767 // The spec says "all 20 bytes will be zero if no test" but
768 // DG has found otherwise. So this is a heuristic.
769 if ((0 == n
) && (0 == ucp
[4]))
772 // only print header if needed
774 pout("SMART Self-test log\n");
775 pout("Num Test Status segment "
776 "LifeTime LBA_first_err [SK ASC ASQ]\n");
777 pout(" Description number "
782 // print parameter code (test number) & self-test code text
783 pout("#%2d %s", (ucp
[0] << 8) | ucp
[1],
784 self_test_code
[(ucp
[4] >> 5) & 0x7]);
786 // check the self-test result nibble, using the self-test results
787 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
788 switch ((res
= ucp
[4] & 0xf)) {
790 // an unknown error occurred while the device server
791 // was processing the self-test and the device server
792 // was unable to complete the self-test
796 // the self-test completed with a failure in a test
797 // segment, and the test segment that failed is not
802 // the first segment of the self-test failed
806 // the second segment of the self-test failed
810 // another segment of the self-test failed and which
811 // test is indicated by the contents of the SELF-TEST
818 pout(" %s", self_test_result
[res
]);
820 // self-test number identifies test that failed and consists
821 // of either the number of the segment that failed during
822 // the test, or the number of the test that failed and the
823 // number of the segment in which the test was run, using a
824 // vendor-specific method of putting both numbers into a
827 pout(" %3d", (int)ucp
[5]);
831 // print time that the self-test was completed
832 if (n
==0 && res
==0xf)
833 // self-test in progress
838 // construct 8-byte integer address of first failure
839 for (i
= 0; i
< 8; i
++) {
843 // print Address of First Failure, if sensible
844 if ((~(uint64_t)0 != ull
) && (res
> 0) && (res
< 0xf)) {
847 // was hex but change to decimal to conform with ATA
848 snprintf(buff
, sizeof(buff
), "%" PRIu64
, ull
);
849 // snprintf(buff, sizeof(buff), "0x%" PRIx64, ull);
854 // if sense key nonzero, then print it, along with
855 // additional sense code and additional sense code qualifier
857 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
862 // if header never printed, then there was no output
864 pout("No self-tests have been logged\n");
866 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
867 modese_len
)) && (durationSec
> 0)) {
868 pout("\nLong (extended) Self Test duration: %d seconds "
869 "[%.1f minutes]\n", durationSec
, durationSec
/ 60.0);
875 static const char * bms_status
[] = {
878 "pre-scan is active",
879 "halted due to fatal error",
880 "halted due to a vendor specific pattern of error",
881 "halted due to medium formatted without P-List",
882 "halted - vendor specific cause",
883 "halted due to temperature out of range",
884 "waiting until BMS interval timer expires", /* 8 */
887 static const char * reassign_status
[] = {
889 "Require Write or Reassign Blocks command",
890 "Successfully reassigned",
892 "Reassignment by disk failed",
893 "Recovered via rewrite in-place",
894 "Reassigned by app, has valid data",
895 "Reassigned by app, has no valid data",
896 "Unsuccessfully reassigned by app", /* 8 */
899 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
900 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
901 // and up to 2048 events (although would hope to have less). May set
902 // FAILLOG if serious errors detected (in the future).
904 scsiPrintBackgroundResults(scsi_device
* device
)
906 int num
, j
, m
, err
, pc
, pl
, truncated
;
912 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
913 LOG_RESP_LONG_LEN
, 0))) {
915 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err
));
919 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
921 pout("Background scan results Log Sense Failed, page mismatch\n");
925 // compute page length
926 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
929 pout("Background scan results Log Sense length is %d, no scan "
934 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
936 num
= LOG_RESP_LONG_LEN
;
940 pc
= (ucp
[0] << 8) | ucp
[1];
947 pout("Background scan results log\n");
950 if ((pl
< 16) || (num
< 16)) {
955 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
956 pout("%s\n", bms_status
[j
]);
958 pout("unknown [0x%x] background scan status value\n", j
);
959 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
960 pout(" Accumulated power on time, hours:minutes %d:%02d "
961 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
962 pout(" Number of background scans performed: %d, ",
963 (ucp
[10] << 8) + ucp
[11]);
964 pout("scan progress: %.2f%%\n",
965 (double)((ucp
[12] << 8) + ucp
[13]) * 100.0 / 65536.0);
966 pout(" Number of background medium scans performed: %d\n",
967 (ucp
[14] << 8) + ucp
[15]);
972 pout("\nBackground scan results log\n");
976 pout("\n # when lba(hex) [sk,asc,ascq] "
977 "reassign_status\n");
980 if ((pl
< 24) || (num
< 24)) {
982 pout("parameter length >= 24 expected, got %d\n", pl
);
985 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
986 pout("%4d:%02d ", (j
/ 60), (j
% 60));
987 for (m
= 0; m
< 8; ++m
)
988 pout("%02x", ucp
[16 + m
]);
989 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
990 j
= (ucp
[8] >> 4) & 0xf;
992 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
993 pout("%s\n", reassign_status
[j
]);
995 pout("Reassign status: reserved [0x%x]\n", j
);
1002 pout(" >>>> log truncated, fetched %d of %d available "
1003 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
1008 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1009 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1010 // and up to 2048 events (although would hope to have less). May set
1011 // FAILLOG if serious errors detected (in the future).
1013 scsiPrintSSMedia(scsi_device
* device
)
1015 int num
, err
, pc
, pl
, truncated
;
1019 if ((err
= scsiLogSense(device
, SS_MEDIA_LPAGE
, 0, gBuf
,
1020 LOG_RESP_LONG_LEN
, 0))) {
1022 pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err
));
1026 if ((gBuf
[0] & 0x3f) != SS_MEDIA_LPAGE
) {
1028 pout("Solid state media Log Sense Failed, page mismatch\n");
1032 // compute page length
1033 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
1036 pout("Solid state media Log Sense length is %d, too short\n", num
);
1040 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
1042 num
= LOG_RESP_LONG_LEN
;
1046 pc
= (ucp
[0] << 8) | ucp
[1];
1053 pout("SS Media Percentage used endurance indicator parameter "
1054 "too short (pl=%d)\n", pl
);
1058 pout("Percentage used endurance indicator: %d%%\n", ucp
[7]);
1059 default: /* ignore other parameter codes */
1069 show_sas_phy_event_info(int peis
, unsigned int val
, unsigned thresh_val
)
1075 pout(" No event\n");
1078 pout(" Invalid word count: %u\n", val
);
1081 pout(" Running disparity error count: %u\n", val
);
1084 pout(" Loss of dword synchronization count: %u\n", val
);
1087 pout(" Phy reset problem count: %u\n", val
);
1090 pout(" Elasticity buffer overflow count: %u\n", val
);
1093 pout(" Received ERROR count: %u\n", val
);
1096 pout(" Received address frame error count: %u\n", val
);
1099 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
1102 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
1105 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
1108 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
1111 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val
);
1114 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
1117 pout(" Transmitted BREAK count: %u\n", val
);
1120 pout(" Received BREAK count: %u\n", val
);
1123 pout(" Break timeout count: %u\n", val
);
1126 pout(" Connection count: %u\n", val
);
1129 pout(" Peak transmitted pathway blocked count: %u\n",
1131 pout(" Peak value detector threshold: %u\n",
1137 pout(" Peak transmitted arbitration wait time (us): "
1140 pout(" Peak transmitted arbitration wait time (ms): "
1141 "%u\n", 33 + (u
- 0x8000));
1142 u
= thresh_val
& 0xffff;
1144 pout(" Peak value detector threshold (us): %u\n",
1147 pout(" Peak value detector threshold (ms): %u\n",
1151 pout(" Peak arbitration time (us): %u\n", val
);
1152 pout(" Peak value detector threshold: %u\n", thresh_val
);
1155 pout(" Peak connection time (us): %u\n", val
);
1156 pout(" Peak value detector threshold: %u\n", thresh_val
);
1159 pout(" Transmitted SSP frame count: %u\n", val
);
1162 pout(" Received SSP frame count: %u\n", val
);
1165 pout(" Transmitted SSP frame error count: %u\n", val
);
1168 pout(" Received SSP frame error count: %u\n", val
);
1171 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1174 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1177 pout(" Transmitted SATA frame count: %u\n", val
);
1180 pout(" Received SATA frame count: %u\n", val
);
1183 pout(" SATA flow control buffer overflow count: %u\n", val
);
1186 pout(" Transmitted SMP frame count: %u\n", val
);
1189 pout(" Received SMP frame count: %u\n", val
);
1192 pout(" Received SMP frame error count: %u\n", val
);
1200 show_sas_port_param(unsigned char * ucp
, int param_len
)
1202 int j
, m
, n
, nphys
, t
, sz
, spld_len
;
1203 unsigned char * vcp
;
1210 t
= (ucp
[0] << 8) | ucp
[1];
1211 pout("relative target port id = %d\n", t
);
1212 pout(" generation code = %d\n", ucp
[6]);
1214 pout(" number of phys = %d\n", nphys
);
1216 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1217 vcp
+= spld_len
, j
+= spld_len
) {
1218 pout(" phy identifier = %d\n", vcp
[1]);
1221 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1224 t
= ((0x70 & vcp
[4]) >> 4);
1226 case 0: snprintf(s
, sz
, "no device attached"); break;
1227 case 1: snprintf(s
, sz
, "SAS or SATA device"); break;
1228 case 2: snprintf(s
, sz
, "expander device"); break;
1229 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1230 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1232 pout(" attached device type: %s\n", s
);
1235 case 0: snprintf(s
, sz
, "unknown"); break;
1236 case 1: snprintf(s
, sz
, "power on"); break;
1237 case 2: snprintf(s
, sz
, "hard reset"); break;
1238 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1239 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1240 case 5: snprintf(s
, sz
, "mux mix up"); break;
1241 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1243 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1244 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1245 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1247 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1249 pout(" attached reason: %s\n", s
);
1250 t
= (vcp
[5] & 0xf0) >> 4;
1252 case 0: snprintf(s
, sz
, "unknown"); break;
1253 case 1: snprintf(s
, sz
, "power on"); break;
1254 case 2: snprintf(s
, sz
, "hard reset"); break;
1255 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1256 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1257 case 5: snprintf(s
, sz
, "mux mix up"); break;
1258 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1260 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1261 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1262 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1264 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1266 pout(" reason: %s\n", s
);
1269 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1271 case 1: snprintf(s
, sz
, "phy disabled"); break;
1272 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1274 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1276 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1278 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1280 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1282 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1283 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1284 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1285 case 0xb: snprintf(s
, sz
, "phy enabled; 12 Gbps"); break;
1286 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1288 pout(" negotiated logical link rate: %s\n", s
);
1289 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1290 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1291 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1292 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1293 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1294 ull
<<= 8; ull
|= vcp
[8 + n
];
1296 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1297 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1298 ull
<<= 8; ull
|= vcp
[16 + n
];
1300 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1301 pout(" attached phy identifier = %d\n", vcp
[24]);
1302 ui
= (vcp
[32] << 24) | (vcp
[33] << 16) | (vcp
[34] << 8) | vcp
[35];
1303 pout(" Invalid DWORD count = %u\n", ui
);
1304 ui
= (vcp
[36] << 24) | (vcp
[37] << 16) | (vcp
[38] << 8) | vcp
[39];
1305 pout(" Running disparity error count = %u\n", ui
);
1306 ui
= (vcp
[40] << 24) | (vcp
[41] << 16) | (vcp
[42] << 8) | vcp
[43];
1307 pout(" Loss of DWORD synchronization = %u\n", ui
);
1308 ui
= (vcp
[44] << 24) | (vcp
[45] << 16) | (vcp
[46] << 8) | vcp
[47];
1309 pout(" Phy reset problem = %u\n", ui
);
1310 if (spld_len
> 51) {
1312 unsigned char * xcp
;
1317 pout(" Phy event descriptors:\n");
1319 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1321 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1323 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1325 show_sas_phy_event_info(peis
, ui
, pvdt
);
1331 // Returns 1 if okay, 0 if non SAS descriptors
1333 show_protocol_specific_page(unsigned char * resp
, int len
)
1335 int k
, num
, param_len
;
1336 unsigned char * ucp
;
1339 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1340 param_len
= ucp
[3] + 4;
1341 if (6 != (0xf & ucp
[4]))
1342 return 0; /* only decode SAS log page */
1344 pout("Protocol Specific port log page for SAS SSP\n");
1345 show_sas_port_param(ucp
, param_len
);
1354 // See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1355 // log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1357 scsiPrintSasPhy(scsi_device
* device
, int reset
)
1361 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1362 LOG_RESP_LONG_LEN
, 0))) {
1364 pout("scsiPrintSasPhy Log Sense Failed [%s]\n\n", scsiErrString(err
));
1368 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1370 pout("Protocol specific Log Sense Failed, page mismatch\n\n");
1374 // compute page length
1375 num
= (gBuf
[2] << 8) + gBuf
[3];
1376 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1378 pout("Only support protocol specific log page on SAS devices\n\n");
1383 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1384 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1386 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n\n",
1387 scsiErrString(err
));
1396 static const char * peripheral_dt_arr
[] = {
1412 "optical card reader"
1414 "object based storage"
1415 "automation/driver interface"
1416 "security manager device"
1417 "host managed zoned block device"
1427 "well known logical unit"
1428 "unknown or no device type"
1431 static const char * transport_proto_arr
[] = {
1432 "Fibre channel (FCP-2)",
1433 "Parallel SCSI (SPI-4)",
1435 "IEEE 1394 (SBP-2)",
1450 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1452 scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1454 char timedatetz
[DATEANDEPOCHLEN
];
1455 struct scsi_iec_mode_page iec
;
1456 int err
, iec_err
, len
, req_len
, avail_len
, n
, scsi_version
;
1461 int form_factor
= 0;
1465 memset(gBuf
, 0, 96);
1467 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1469 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1470 pout("Retrying with a 64 byte Standard Inquiry\n");
1472 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1474 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1476 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1477 scsiErrString(err
));
1482 avail_len
= gBuf
[4] + 5;
1483 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1484 peri_dt
= gBuf
[0] & 0x1f;
1485 if (peripheral_type
)
1486 *peripheral_type
= peri_dt
;
1490 pout("Short INQUIRY response, skip product id\n");
1494 // Upper bits of version bytes were used in older standards
1495 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
1496 scsi_version
= gBuf
[2] & 0x7;
1498 if (all
&& (0 != strncmp((char *)&gBuf
[8], "ATA", 3))) {
1499 char vendor
[8+1], product
[16+1], revision
[4+1];
1500 scsi_format_id_string(vendor
, (const unsigned char *)&gBuf
[8], 8);
1501 scsi_format_id_string(product
, (const unsigned char *)&gBuf
[16], 16);
1502 scsi_format_id_string(revision
, (const unsigned char *)&gBuf
[32], 4);
1504 pout("=== START OF INFORMATION SECTION ===\n");
1505 pout("Vendor: %.8s\n", vendor
);
1506 pout("Product: %.16s\n", product
);
1507 if (gBuf
[32] >= ' ')
1508 pout("Revision: %.4s\n", revision
);
1509 if (scsi_version
== 0x6)
1510 pout("Compliance: SPC-4\n");
1511 else if (scsi_version
== 0x7)
1512 pout("Compliance: SPC-5\n");
1515 if (!*device
->get_req_type()/*no type requested*/ &&
1516 (0 == strncmp((char *)&gBuf
[8], "ATA", 3))) {
1517 pout("\nProbable ATA device behind a SAT layer\n"
1518 "Try an additional '-d ata' or '-d sat' argument.\n");
1524 protect
= gBuf
[5] & 0x1; /* from and including SPC-3 */
1526 if (! is_tape
) { /* only do this for disks */
1527 unsigned int lb_size
= 0;
1528 unsigned char lb_prov_resp
[8];
1532 int lb_per_pb_exp
= 0;
1533 uint64_t capacity
= scsiGetSize(device
, &lb_size
, &lb_per_pb_exp
);
1536 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1537 format_capacity(si_str
, sizeof(si_str
), capacity
);
1538 pout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1539 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u", lb_size
);
1540 pout("Logical block size: %s bytes\n", lb_str
);
1544 if (protect
|| lb_per_pb_exp
) {
1545 unsigned char rc16_12
[20] = {0, };
1547 if (0 == scsiGetProtPBInfo(device
, rc16_12
)) {
1548 lb_per_pb_exp
= rc16_12
[1] & 0xf; /* just in case */
1549 if (lb_per_pb_exp
> 0) {
1550 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u",
1551 (lb_size
* (1 << lb_per_pb_exp
)));
1552 pout("Physical block size: %s bytes\n", lb_str
);
1553 n
= ((rc16_12
[2] & 0x3f) << 8) + rc16_12
[3];
1554 if (n
> 0) // not common so cut the clutter
1555 pout("Lowest aligned LBA: %d\n", n
);
1557 if (rc16_12
[0] & 0x1) { /* PROT_EN set */
1558 int p_type
= ((rc16_12
[0] >> 1) & 0x7);
1562 pout("Formatted with type 1 protection\n");
1565 pout("Formatted with type 2 protection\n");
1568 pout("Formatted with type 3 protection\n");
1571 pout("Formatted with unknown protection type [%d]\n",
1575 int p_i_exp
= ((rc16_12
[1] >> 4) & 0xf);
1578 pout("%d protection information intervals per "
1579 "logical block\n", (1 << p_i_exp
));
1581 /* Pick up some LB provisioning info since its available */
1582 lbpme
= !! (rc16_12
[2] & 0x80);
1583 lbprz
= !! (rc16_12
[2] & 0x40);
1586 if (0 == scsiInquiryVpd(device
, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING
,
1587 lb_prov_resp
, sizeof(lb_prov_resp
))) {
1588 int prov_type
= lb_prov_resp
[6] & 0x7;
1591 lbprz
= !! (lb_prov_resp
[5] & 0x4);
1592 switch (prov_type
) {
1594 pout("LB provisioning type: unreported, LBPME=%d, LBPRZ=%d\n",
1598 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz
);
1601 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz
);
1604 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1608 } else if (1 == lbpme
)
1609 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz
);
1611 int rpm
= scsiGetRPM(device
, modese_len
, &form_factor
, &haw_zbc
);
1616 pout("Rotation Rate: Solid State Device\n");
1617 else if ((rpm
<= 0x400) || (0xffff == rpm
))
1620 pout("Rotation Rate: %d rpm\n", rpm
);
1622 if (form_factor
> 0) {
1623 const char * cp
= NULL
;
1625 switch (form_factor
) {
1643 pout("Form Factor: %s inches\n", cp
);
1646 pout("Host aware zoned block capable\n");
1649 /* Do this here to try and detect badly conforming devices (some USB
1650 keys) that will lock up on a InquiryVpd or log sense or ... */
1651 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1652 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1653 pout(">> Terminate command early due to bad response to IEC "
1660 modese_len
= iec
.modese_len
;
1662 if (! dont_print_serial_number
) {
1663 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_DEVICE_IDENTIFICATION
,
1668 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
1670 pout("Logical Unit id: %s\n", s
);
1671 } else if (scsi_debugmode
> 0) {
1673 if (SIMPLE_ERR_BAD_RESP
== err
)
1674 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1676 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1679 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_UNIT_SERIAL_NUMBER
,
1684 gBuf
[4 + len
] = '\0';
1685 scsi_format_id_string(serial
, &gBuf
[4], len
);
1686 pout("Serial number: %s\n", serial
);
1687 } else if (scsi_debugmode
> 0) {
1689 if (SIMPLE_ERR_BAD_RESP
== err
)
1690 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1692 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1697 // print SCSI peripheral device type
1698 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1699 sizeof(peripheral_dt_arr
[0])))
1700 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1702 pout("Device type: <%d>\n", peri_dt
);
1704 // See if transport protocol is known
1706 transport
= scsiFetchTransportProtocol(device
, modese_len
);
1707 if ((transport
>= 0) && (transport
<= 0xf))
1708 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
1710 // print current time and date and timezone
1711 dateandtimezone(timedatetz
);
1712 pout("Local Time is: %s\n", timedatetz
);
1714 if ((SCSI_PT_SEQUENTIAL_ACCESS
== *peripheral_type
) ||
1715 (SCSI_PT_MEDIUM_CHANGER
== *peripheral_type
))
1717 // See if unit accepts SCSI commmands from us
1718 if ((err
= scsiTestUnitReady(device
))) {
1719 if (SIMPLE_ERR_NOT_READY
== err
) {
1722 pout("device is NOT READY (e.g. spun down, busy)\n");
1724 pout("device is NOT READY (e.g. no tape)\n");
1726 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1728 pout("NO MEDIUM present on device\n");
1730 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1732 pout("device becoming ready (wait)\n");
1736 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1739 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1745 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
1746 if (scsi_debugmode
> 0)
1747 pout(" [%s]\n", scsiErrString(iec_err
));
1755 pout("SMART support is: Available - device has SMART capability.\n"
1756 "SMART support is: %s\n",
1757 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1758 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1759 "Temperature Warning: Enabled" :
1760 "Temperature Warning: Disabled or Not Supported");
1765 scsiSmartEnable(scsi_device
* device
)
1767 struct scsi_iec_mode_page iec
;
1770 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1772 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1773 scsiErrString(err
));
1777 modese_len
= iec
.modese_len
;
1779 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1781 pout("unable to enable Exception control and warning [%s]\n",
1782 scsiErrString(err
));
1786 /* Need to refetch 'iec' since could be modified by previous call */
1787 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1788 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1789 scsiErrString(err
));
1792 modese_len
= iec
.modese_len
;
1794 pout("Informational Exceptions (SMART) %s\n",
1795 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1796 pout("Temperature warning %s\n",
1797 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1802 scsiSmartDisable(scsi_device
* device
)
1804 struct scsi_iec_mode_page iec
;
1807 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1809 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1810 scsiErrString(err
));
1814 modese_len
= iec
.modese_len
;
1816 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1818 pout("unable to disable Exception control and warning [%s]\n",
1819 scsiErrString(err
));
1823 /* Need to refetch 'iec' since could be modified by previous call */
1824 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1825 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1826 scsiErrString(err
));
1829 modese_len
= iec
.modese_len
;
1831 pout("Informational Exceptions (SMART) %s\n",
1832 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1833 pout("Temperature warning %s\n",
1834 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1839 scsiPrintTemp(scsi_device
* device
)
1844 if (scsiGetTemp(device
, &temp
, &trip
))
1849 pout("Current Drive Temperature: %d C\n", temp
);
1851 pout("Current Drive Temperature: <not available>\n");
1854 pout("Drive Trip Temperature: %d C\n", trip
);
1859 /* Main entry point used by smartctl command. Return 0 for success */
1861 scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1863 int checkedSupportedLogPages
= 0;
1864 UINT8 peripheral_type
= 0;
1866 int res
, durationSec
;
1867 struct scsi_sense_disect sense_info
;
1869 bool any_output
= options
.drive_info
;
1871 if (supported_vpd_pages_p
) {
1872 delete supported_vpd_pages_p
;
1873 supported_vpd_pages_p
= NULL
;
1875 supported_vpd_pages_p
= new supported_vpd_pages(device
);
1877 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1882 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1886 // Print read look-ahead status for disks
1887 short int wce
= -1, rcd
= -1;
1888 if (options
.get_rcd
|| options
.get_wce
) {
1889 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
)
1890 res
= scsiGetSetCache(device
, modese_len
, &wce
, &rcd
);
1892 res
= -1; // fetch for disks only
1896 if (options
.get_rcd
) {
1897 pout("Read Cache is: %s\n",
1898 res
? "Unavailable" : // error
1899 rcd
? "Disabled" : "Enabled");
1902 if (options
.get_wce
) {
1903 pout("Writeback Cache is: %s\n",
1904 res
? "Unavailable" : // error
1905 !wce
? "Disabled" : "Enabled");
1907 if (options
.drive_info
)
1910 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1911 if ( options
.smart_disable
|| options
.smart_enable
1912 || options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1913 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1915 if (options
.smart_enable
) {
1916 if (scsiSmartEnable(device
))
1917 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1921 if (options
.smart_disable
) {
1922 if (scsiSmartDisable(device
))
1923 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1927 if (options
.smart_auto_save_enable
) {
1928 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1929 pout("Enable autosave (clear GLTSD bit) failed\n");
1930 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1933 pout("Autosave enabled (GLTSD bit set).\n");
1938 // Enable/Disable write cache
1939 if (options
.set_wce
&& SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1940 short int enable
= wce
= (options
.set_wce
> 0);
1942 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1943 pout("Write cache %sable failed: %s\n", (enable
? "en" : "dis"),
1944 device
->get_errmsg());
1945 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1948 pout("Write cache %sabled\n", (enable
? "en" : "dis"));
1952 // Enable/Disable read cache
1953 if (options
.set_rcd
&& SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1954 short int enable
= (options
.set_rcd
> 0);
1957 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1958 pout("Read cache %sable failed: %s\n", (enable
? "en" : "dis"),
1959 device
->get_errmsg());
1960 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1963 pout("Read cache %sabled\n", (enable
? "en" : "dis"));
1967 if (options
.smart_auto_save_disable
) {
1968 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1969 pout("Disable autosave (set GLTSD bit) failed\n");
1970 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1973 pout("Autosave disabled (GLTSD bit cleared).\n");
1977 if ( options
.smart_disable
|| options
.smart_enable
1978 || options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1979 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
1981 // START OF READ-ONLY OPTIONS APART FROM -V and -i
1982 if ( options
.smart_check_status
|| options
.smart_ss_media_log
1983 || options
.smart_vendor_attrib
|| options
.smart_error_log
1984 || options
.smart_selftest_log
|| options
.smart_vendor_attrib
1985 || options
.smart_background_log
|| options
.sasphy
1987 pout("=== START OF READ SMART DATA SECTION ===\n");
1989 if (options
.smart_check_status
) {
1990 scsiGetSupportedLogPages(device
);
1991 checkedSupportedLogPages
= 1;
1992 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1993 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
)) { /* tape device */
1994 if (gTapeAlertsLPage
) {
1995 if (options
.drive_info
)
1996 pout("TapeAlert Supported\n");
1997 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
1998 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
2001 pout("TapeAlert Not Supported\n");
2002 } else { /* disk, cd/dvd, enclosure, etc */
2003 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
2005 returnval
|= FAILSTATUS
;
2007 returnval
|= FAILSMART
;
2013 if (options
.smart_ss_media_log
) {
2014 if (! checkedSupportedLogPages
)
2015 scsiGetSupportedLogPages(device
);
2018 res
= scsiPrintSSMedia(device
);
2020 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2023 if (options
.smart_vendor_attrib
) {
2024 if (! checkedSupportedLogPages
)
2025 scsiGetSupportedLogPages(device
);
2027 scsiPrintTemp(device
);
2029 if (gStartStopLPage
)
2030 scsiGetStartStopData(device
);
2031 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
2032 scsiPrintGrownDefectListLen(device
);
2033 if (gSeagateCacheLPage
)
2034 scsiPrintSeagateCacheLPage(device
);
2035 if (gSeagateFactoryLPage
)
2036 scsiPrintSeagateFactoryLPage(device
);
2040 if (options
.smart_error_log
) {
2041 if (! checkedSupportedLogPages
)
2042 scsiGetSupportedLogPages(device
);
2043 scsiPrintErrorCounterLog(device
);
2044 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
2045 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2046 "Enable Save with '-S on']\n");
2049 if (options
.smart_selftest_log
) {
2050 if (! checkedSupportedLogPages
)
2051 scsiGetSupportedLogPages(device
);
2054 res
= scsiPrintSelfTest(device
);
2056 pout("Device does not support Self Test logging\n");
2057 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2060 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2063 if (options
.smart_background_log
) {
2064 if (! checkedSupportedLogPages
)
2065 scsiGetSupportedLogPages(device
);
2067 if (gBackgroundResultsLPage
)
2068 res
= scsiPrintBackgroundResults(device
);
2070 pout("Device does not support Background scan results logging\n");
2071 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2074 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2077 if (options
.smart_default_selftest
) {
2078 if (scsiSmartDefaultSelfTest(device
))
2079 return returnval
| FAILSMART
;
2080 pout("Default Self Test Successful\n");
2083 if (options
.smart_short_cap_selftest
) {
2084 if (scsiSmartShortCapSelfTest(device
))
2085 return returnval
| FAILSMART
;
2086 pout("Short Foreground Self Test Successful\n");
2089 // check if another test is running
2090 if (options
.smart_short_selftest
|| options
.smart_extend_selftest
) {
2091 if (!scsiRequestSense(device
, &sense_info
) &&
2092 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09)) {
2093 if (!options
.smart_selftest_force
) {
2094 pout("Can't start self-test without aborting current test");
2095 if (sense_info
.progress
!= -1) {
2096 pout(" (%d%% remaining)",
2097 100 - sense_info
.progress
* 100 / 65535);
2099 pout(",\nadd '-t force' option to override, or run 'smartctl -X' "
2100 "to abort test.\n");
2104 scsiSmartSelfTestAbort(device
);
2107 if (options
.smart_short_selftest
) {
2108 if (scsiSmartShortSelfTest(device
))
2109 return returnval
| FAILSMART
;
2110 pout("Short Background Self Test has begun\n");
2111 pout("Use smartctl -X to abort test\n");
2114 if (options
.smart_extend_selftest
) {
2115 if (scsiSmartExtendSelfTest(device
))
2116 return returnval
| FAILSMART
;
2117 pout("Extended Background Self Test has begun\n");
2118 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
2119 modese_len
)) && (durationSec
> 0)) {
2120 time_t t
= time(NULL
);
2123 pout("Please wait %d minutes for test to complete.\n",
2125 pout("Estimated completion time: %s\n", ctime(&t
));
2127 pout("Use smartctl -X to abort test\n");
2130 if (options
.smart_extend_cap_selftest
) {
2131 if (scsiSmartExtendCapSelfTest(device
))
2132 return returnval
| FAILSMART
;
2133 pout("Extended Foreground Self Test Successful\n");
2135 if (options
.smart_selftest_abort
) {
2136 if (scsiSmartSelfTestAbort(device
))
2137 return returnval
| FAILSMART
;
2138 pout("Self Test returned without error\n");
2141 if (options
.sasphy
&& gProtocolSpecificLPage
) {
2142 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
2143 return returnval
| FAILSMART
;
2148 pout("SCSI device successfully opened\n\n"
2149 "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");