4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2002-11 Bruce Allen
7 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
8 * Copyright (C) 2003-15 Douglas Gilbert <dgilbert@interlog.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * You should have received a copy of the GNU General Public License
16 * (for example COPYING); if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * This code was originally developed as a Senior Thesis by Michael Cornwell
20 * at the Concurrent Systems Laboratory (now part of the Storage Systems
21 * Research Center), Jack Baskin School of Engineering, University of
22 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
35 #include "atacmds.h" // smart_command_set
36 #include "dev_interface.h"
37 #include "scsiprint.h"
41 #define GBUF_SIZE 65535
43 const char * scsiprint_c_cvsid
= "$Id: scsiprint.cpp 4189 2015-12-16 14:53:41Z dpgilbert $"
47 UINT8 gBuf
[GBUF_SIZE
];
48 #define LOG_RESP_LEN 252
49 #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
50 #define LOG_RESP_TAPE_ALERT_LEN 0x144
52 /* Log pages supported */
53 static int gSmartLPage
= 0; /* Informational Exceptions log page */
54 static int gTempLPage
= 0;
55 static int gSelfTestLPage
= 0;
56 static int gStartStopLPage
= 0;
57 static int gReadECounterLPage
= 0;
58 static int gWriteECounterLPage
= 0;
59 static int gVerifyECounterLPage
= 0;
60 static int gNonMediumELPage
= 0;
61 static int gLastNErrorLPage
= 0;
62 static int gBackgroundResultsLPage
= 0;
63 static int gProtocolSpecificLPage
= 0;
64 static int gTapeAlertsLPage
= 0;
65 static int gSSMediaLPage
= 0;
67 /* Vendor specific log pages */
68 static int gSeagateCacheLPage
= 0;
69 static int gSeagateFactoryLPage
= 0;
71 /* Mode pages supported */
72 static int gIecMPage
= 1; /* N.B. assume it until we know otherwise */
74 /* Remember last successful mode sense/select command */
75 static int modese_len
= 0;
79 scsiGetSupportedLogPages(scsi_device
* device
)
83 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
85 if (scsi_debugmode
> 0)
86 pout("Log Sense for supported pages failed [%s]\n",
91 for (i
= 4; i
< gBuf
[3] + LOGPAGEHDRSIZE
; i
++) {
94 case READ_ERROR_COUNTER_LPAGE
:
95 gReadECounterLPage
= 1;
97 case WRITE_ERROR_COUNTER_LPAGE
:
98 gWriteECounterLPage
= 1;
100 case VERIFY_ERROR_COUNTER_LPAGE
:
101 gVerifyECounterLPage
= 1;
103 case LAST_N_ERROR_LPAGE
:
104 gLastNErrorLPage
= 1;
106 case NON_MEDIUM_ERROR_LPAGE
:
107 gNonMediumELPage
= 1;
109 case TEMPERATURE_LPAGE
:
112 case STARTSTOP_CYCLE_COUNTER_LPAGE
:
115 case SELFTEST_RESULTS_LPAGE
:
121 case BACKGROUND_RESULTS_LPAGE
:
122 gBackgroundResultsLPage
= 1;
124 case PROTOCOL_SPECIFIC_LPAGE
:
125 gProtocolSpecificLPage
= 1;
127 case TAPE_ALERTS_LPAGE
:
128 gTapeAlertsLPage
= 1;
133 case SEAGATE_CACHE_LPAGE
:
134 gSeagateCacheLPage
= 1;
136 case SEAGATE_FACTORY_LPAGE
:
137 gSeagateFactoryLPage
= 1;
145 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
146 (or at least something to report). */
148 scsiGetSmartData(scsi_device
* device
, bool attribs
)
152 UINT8 currenttemp
= 0;
157 if (scsiCheckIE(device
, gSmartLPage
, gTempLPage
, &asc
, &ascq
,
158 ¤ttemp
, &triptemp
)) {
159 /* error message already announced */
164 cp
= scsiGetIEString(asc
, ascq
);
168 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp
, asc
, ascq
);
170 } else if (gIecMPage
)
171 pout("SMART Health Status: OK\n");
173 if (attribs
&& !gTempLPage
) {
175 if (255 != currenttemp
)
176 pout("Current Drive Temperature: %d C\n", currenttemp
);
178 pout("Current Drive Temperature: <not available>\n");
181 pout("Drive Trip Temperature: %d C\n", triptemp
);
188 // Returns number of logged errors or zero if none or -1 if fetching
190 static const char * const severities
= "CWI";
193 scsiGetTapeAlertsData(scsi_device
* device
, int peripheral_type
)
195 unsigned short pagelength
;
196 unsigned short parametercode
;
203 if ((err
= scsiLogSense(device
, TAPE_ALERTS_LPAGE
, 0, gBuf
,
204 LOG_RESP_TAPE_ALERT_LEN
, LOG_RESP_TAPE_ALERT_LEN
))) {
205 pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err
));
209 if (gBuf
[0] != 0x2e) {
210 pout("TapeAlerts Log Sense Failed\n");
214 pagelength
= (unsigned short) gBuf
[2] << 8 | gBuf
[3];
216 for (s
=severities
; *s
; s
++) {
217 for (i
= 4; i
< pagelength
; i
+= 5) {
218 parametercode
= (unsigned short) gBuf
[i
] << 8 | gBuf
[i
+1];
221 ts
= SCSI_PT_MEDIUM_CHANGER
== peripheral_type
?
222 scsiTapeAlertsChangerDevice(parametercode
) :
223 scsiTapeAlertsTapeDevice(parametercode
);
226 pout("TapeAlert Errors (C=Critical, W=Warning, "
227 "I=Informational):\n");
228 pout("[0x%02x] %s\n", parametercode
, ts
);
237 pout("TapeAlert: OK\n");
243 scsiGetStartStopData(scsi_device
* device
)
245 int err
, len
, k
, extra
;
248 if ((err
= scsiLogSense(device
, STARTSTOP_CYCLE_COUNTER_LPAGE
, 0, gBuf
,
251 pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err
));
255 if ((gBuf
[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE
) {
257 pout("StartStop Log Sense Failed, page mismatch\n");
261 len
= ((gBuf
[2] << 8) | gBuf
[3]);
263 for (k
= len
; k
> 0; k
-= extra
, ucp
+= extra
) {
266 pout("StartStop Log Sense Failed: short\n");
271 int pc
= (ucp
[0] << 8) + ucp
[1];
276 pout("Manufactured in week %.2s of year %.4s\n", ucp
+ 8,
280 /* ignore Accounting date */
284 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
286 pout("Specified cycle count over device lifetime: %u\n",
292 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
294 pout("Accumulated start-stop cycles: %u\n", u
);
299 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
301 pout("Specified load-unload count over device "
302 "lifetime: %u\n", u
);
307 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
309 pout("Accumulated load-unload cycles: %u\n", u
);
320 scsiPrintGrownDefectListLen(scsi_device
* device
)
322 int err
, dl_format
, got_rd12
;
323 unsigned int dl_len
, div
;
326 if ((err
= scsiReadDefect12(device
, 0 /* req_plist */, 1 /* req_glist */,
327 4 /* format: bytes from index */,
328 0 /* addr desc index */, gBuf
, 8))) {
329 if (2 == err
) { /* command not supported */
330 if ((err
= scsiReadDefect10(device
, 0 /* req_plist */, 1 /* req_glist */,
331 4 /* format: bytes from index */, gBuf
, 4))) {
332 if (scsi_debugmode
> 0) {
334 pout("Read defect list (10) Failed: %s\n", scsiErrString(err
));
340 } else if (101 == err
) /* Defect list not found, leave quietly */
343 if (scsi_debugmode
> 0) {
345 pout("Read defect list (12) Failed: %s\n", scsiErrString(err
));
354 int 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 num
, pl
, pc
, err
, len
;
410 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
413 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err
));
417 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
419 pout("Seagate Cache Log Sense Failed, page mismatch\n");
423 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
427 pc
= (ucp
[0] << 8) | ucp
[1];
430 case 0: case 1: case 2: case 3: case 4:
433 if (scsi_debugmode
> 0) {
435 pout("Vendor (Seagate) cache lpage has unexpected parameter"
444 pout("Vendor (Seagate) cache information\n");
448 pc
= (ucp
[0] << 8) | ucp
[1];
451 case 0: pout(" Blocks sent to initiator"); break;
452 case 1: pout(" Blocks received from initiator"); break;
453 case 2: pout(" Blocks read from cache and sent to initiator"); break;
454 case 3: pout(" Number of read and write commands whose size "
455 "<= segment size"); break;
456 case 4: pout(" Number of read and write commands whose size "
457 "> segment size"); break;
458 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
461 unsigned char * xp
= ucp
+ 4;
462 if (k
> (int)sizeof(ull
)) {
463 xp
+= (k
- (int)sizeof(ull
));
464 k
= (int)sizeof(ull
);
467 for (int j
= 0; j
< k
; ++j
) {
472 pout(" = %" PRIu64
"\n", ull
);
480 scsiPrintSeagateFactoryLPage(scsi_device
* device
)
482 int num
, pl
, pc
, len
, err
, good
, bad
;
486 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
489 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err
));
493 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
495 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
499 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
505 pc
= (ucp
[0] << 8) | ucp
[1];
518 if ((good
< 2) || (bad
> 4)) { /* heuristic */
519 if (scsi_debugmode
> 0) {
521 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
522 "unexpected parameters, skip\n");
527 pout("Vendor (Seagate/Hitachi) factory information\n");
531 pc
= (ucp
[0] << 8) | ucp
[1];
535 case 0: pout(" number of hours powered up");
538 case 8: pout(" number of minutes until next internal SMART test");
542 if (scsi_debugmode
> 0) {
544 pout("Vendor (Seagate/Hitachi) factory lpage: "
545 "unknown parameter code [0x%x]\n", pc
);
552 unsigned char * xp
= ucp
+ 4;
553 if (k
> (int)sizeof(ull
)) {
554 xp
+= (k
- (int)sizeof(ull
));
555 k
= (int)sizeof(ull
);
558 for (int j
= 0; j
< k
; ++j
) {
564 pout(" = %.2f\n", ull
/ 60.0 );
566 pout(" = %" PRIu64
"\n", ull
);
575 scsiPrintErrorCounterLog(scsi_device
* device
)
577 struct scsiErrorCounter errCounterArr
[3];
578 struct scsiErrorCounter
* ecp
;
579 int found
[3] = {0, 0, 0};
581 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
582 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
583 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
586 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
587 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
588 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
591 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
592 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
593 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
594 ecp
= &errCounterArr
[2];
595 for (int k
= 0; k
< 7; ++k
) {
596 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
602 if (found
[0] || found
[1] || found
[2]) {
603 pout("Error counter log:\n");
604 pout(" Errors Corrected by Total "
605 "Correction Gigabytes Total\n");
606 pout(" ECC rereads/ errors "
607 "algorithm processed uncorrected\n");
608 pout(" fast | delayed rewrites corrected "
609 "invocations [10^9 bytes] errors\n");
610 for (int k
= 0; k
< 3; ++k
) {
613 ecp
= &errCounterArr
[k
];
614 static const char * const pageNames
[3] = {"read: ", "write: ", "verify: "};
615 pout("%s%8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
" %8" PRIu64
,
616 pageNames
[k
], ecp
->counter
[0], ecp
->counter
[1],
617 ecp
->counter
[2], ecp
->counter
[3], ecp
->counter
[4]);
618 double processed_gb
= ecp
->counter
[5] / 1000000000.0;
619 pout(" %12.3f %8" PRIu64
"\n", processed_gb
, ecp
->counter
[6]);
623 pout("Error Counter logging not supported\n");
624 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
625 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
626 struct scsiNonMediumError nme
;
627 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
629 pout("\nNon-medium error count: %8" PRIu64
"\n", nme
.counterPC0
);
631 pout("Track following error count [Hitachi]: %8" PRIu64
"\n",
634 pout("Positioning error count [Hitachi]: %8" PRIu64
"\n",
637 if (gLastNErrorLPage
&& (0 == scsiLogSense(device
,
638 LAST_N_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LONG_LEN
, 0))) {
639 int num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
640 int truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
642 num
= LOG_RESP_LONG_LEN
;
643 unsigned char * ucp
= gBuf
+ 4;
646 pout("\nNo error events logged\n");
648 pout("\nLast n error events log page\n");
649 for (int k
= num
, pl
; k
> 0; k
-= pl
, ucp
+= pl
) {
651 pout(" <<short Last n error events log page>>\n");
655 int pc
= (ucp
[0] << 8) + ucp
[1];
657 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
658 pout(" Error event %d:\n", pc
);
659 pout(" [binary]:\n");
660 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
661 } else if (ucp
[2] & 0x1) {
662 pout(" Error event %d:\n", pc
);
663 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
665 if (scsi_debugmode
> 0) {
666 pout(" Error event %d:\n", pc
);
667 pout(" [data counter??]:\n");
668 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
674 pout(" >>>> log truncated, fetched %d of %d available "
675 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
681 static const char * self_test_code
[] = {
692 static const char * self_test_result
[] = {
694 "Aborted (by user command)",
695 "Aborted (device reset ?) ",
696 "Unknown error, incomplete",
697 "Completed, segment failed",
698 "Failed in first segment ",
699 "Failed in second segment ",
700 "Failed in segment --> ",
708 "Self test in progress ..."
711 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
712 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
713 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
714 // FAILSMART is returned.
716 scsiPrintSelfTest(scsi_device
* device
)
718 int num
, k
, err
, durationSec
;
723 struct scsi_sense_disect sense_info
;
725 // check if test is running
726 if (!scsiRequestSense(device
, &sense_info
) &&
727 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09 &&
728 sense_info
.progress
!= -1)) {
729 pout("Self-test execution status:\t\t%d%% of test remaining\n",
730 100 - ((sense_info
.progress
* 100) / 65535));
733 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
734 LOG_RESP_SELF_TEST_LEN
, 0))) {
736 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err
));
740 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
742 pout("Self-test Log Sense Failed, page mismatch\n");
746 // compute page length
747 num
= (gBuf
[2] << 8) + gBuf
[3];
748 // Log sense page length 0x190 bytes
751 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num
);
755 // loop through the twenty possible entries
756 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
759 // timestamp in power-on hours (or zero if test in progress)
760 int n
= (ucp
[6] << 8) | ucp
[7];
762 // The spec says "all 20 bytes will be zero if no test" but
763 // DG has found otherwise. So this is a heuristic.
764 if ((0 == n
) && (0 == ucp
[4]))
767 // only print header if needed
769 pout("SMART Self-test log\n");
770 pout("Num Test Status segment "
771 "LifeTime LBA_first_err [SK ASC ASQ]\n");
772 pout(" Description number "
777 // print parameter code (test number) & self-test code text
778 pout("#%2d %s", (ucp
[0] << 8) | ucp
[1],
779 self_test_code
[(ucp
[4] >> 5) & 0x7]);
781 // check the self-test result nibble, using the self-test results
782 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
784 switch ((res
= ucp
[4] & 0xf)) {
786 // an unknown error occurred while the device server
787 // was processing the self-test and the device server
788 // was unable to complete the self-test
792 // the self-test completed with a failure in a test
793 // segment, and the test segment that failed is not
798 // the first segment of the self-test failed
802 // the second segment of the self-test failed
806 // another segment of the self-test failed and which
807 // test is indicated by the contents of the SELF-TEST
814 pout(" %s", self_test_result
[res
]);
816 // self-test number identifies test that failed and consists
817 // of either the number of the segment that failed during
818 // the test, or the number of the test that failed and the
819 // number of the segment in which the test was run, using a
820 // vendor-specific method of putting both numbers into a
823 pout(" %3d", (int)ucp
[5]);
827 // print time that the self-test was completed
828 if (n
==0 && res
==0xf)
829 // self-test in progress
834 // construct 8-byte integer address of first failure
835 for (i
= 0; i
< 8; i
++) {
839 // print Address of First Failure, if sensible
840 if ((~(uint64_t)0 != ull
) && (res
> 0) && (res
< 0xf)) {
843 // was hex but change to decimal to conform with ATA
844 snprintf(buff
, sizeof(buff
), "%" PRIu64
, ull
);
845 // snprintf(buff, sizeof(buff), "0x%" PRIx64, ull);
850 // if sense key nonzero, then print it, along with
851 // additional sense code and additional sense code qualifier
853 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
858 // if header never printed, then there was no output
860 pout("No self-tests have been logged\n");
862 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
863 modese_len
)) && (durationSec
> 0)) {
864 pout("\nLong (extended) Self Test duration: %d seconds "
865 "[%.1f minutes]\n", durationSec
, durationSec
/ 60.0);
871 static const char * bms_status
[] = {
874 "pre-scan is active",
875 "halted due to fatal error",
876 "halted due to a vendor specific pattern of error",
877 "halted due to medium formatted without P-List",
878 "halted - vendor specific cause",
879 "halted due to temperature out of range",
880 "waiting until BMS interval timer expires", /* 8 */
883 static const char * reassign_status
[] = {
885 "Require Write or Reassign Blocks command",
886 "Successfully reassigned",
888 "Reassignment by disk failed",
889 "Recovered via rewrite in-place",
890 "Reassigned by app, has valid data",
891 "Reassigned by app, has no valid data",
892 "Unsuccessfully reassigned by app", /* 8 */
895 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
896 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
897 // and up to 2048 events (although would hope to have less). May set
898 // FAILLOG if serious errors detected (in the future).
900 scsiPrintBackgroundResults(scsi_device
* device
)
902 int num
, j
, m
, err
, truncated
;
908 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
909 LOG_RESP_LONG_LEN
, 0))) {
911 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err
));
915 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
917 pout("Background scan results Log Sense Failed, page mismatch\n");
921 // compute page length
922 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
925 pout("Background scan results Log Sense length is %d, no scan "
930 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
932 num
= LOG_RESP_LONG_LEN
;
936 int pc
= (ucp
[0] << 8) | ucp
[1];
943 pout("Background scan results log\n");
946 if ((pl
< 16) || (num
< 16)) {
951 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
952 pout("%s\n", bms_status
[j
]);
954 pout("unknown [0x%x] background scan status value\n", j
);
955 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
956 pout(" Accumulated power on time, hours:minutes %d:%02d "
957 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
958 pout(" Number of background scans performed: %d, ",
959 (ucp
[10] << 8) + ucp
[11]);
960 pout("scan progress: %.2f%%\n",
961 (double)((ucp
[12] << 8) + ucp
[13]) * 100.0 / 65536.0);
962 pout(" Number of background medium scans performed: %d\n",
963 (ucp
[14] << 8) + ucp
[15]);
968 pout("\nBackground scan results log\n");
972 pout("\n # when lba(hex) [sk,asc,ascq] "
973 "reassign_status\n");
976 if ((pl
< 24) || (num
< 24)) {
978 pout("parameter length >= 24 expected, got %d\n", pl
);
981 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
982 pout("%4d:%02d ", (j
/ 60), (j
% 60));
983 for (m
= 0; m
< 8; ++m
)
984 pout("%02x", ucp
[16 + m
]);
985 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
986 j
= (ucp
[8] >> 4) & 0xf;
988 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
989 pout("%s\n", reassign_status
[j
]);
991 pout("Reassign status: reserved [0x%x]\n", j
);
998 pout(" >>>> log truncated, fetched %d of %d available "
999 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
1004 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1005 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1006 // and up to 2048 events (although would hope to have less). May set
1007 // FAILLOG if serious errors detected (in the future).
1009 scsiPrintSSMedia(scsi_device
* device
)
1011 int num
, err
, truncated
;
1015 if ((err
= scsiLogSense(device
, SS_MEDIA_LPAGE
, 0, gBuf
,
1016 LOG_RESP_LONG_LEN
, 0))) {
1018 pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err
));
1022 if ((gBuf
[0] & 0x3f) != SS_MEDIA_LPAGE
) {
1024 pout("Solid state media Log Sense Failed, page mismatch\n");
1028 // compute page length
1029 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
1032 pout("Solid state media Log Sense length is %d, too short\n", num
);
1036 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
1038 num
= LOG_RESP_LONG_LEN
;
1042 int pc
= (ucp
[0] << 8) | ucp
[1];
1044 int pl
= ucp
[3] + 4;
1049 pout("SS Media Percentage used endurance indicator parameter "
1050 "too short (pl=%d)\n", pl
);
1054 pout("Percentage used endurance indicator: %d%%\n", ucp
[7]);
1055 default: /* ignore other parameter codes */
1065 show_sas_phy_event_info(int peis
, unsigned int val
, unsigned thresh_val
)
1071 pout(" No event\n");
1074 pout(" Invalid word count: %u\n", val
);
1077 pout(" Running disparity error count: %u\n", val
);
1080 pout(" Loss of dword synchronization count: %u\n", val
);
1083 pout(" Phy reset problem count: %u\n", val
);
1086 pout(" Elasticity buffer overflow count: %u\n", val
);
1089 pout(" Received ERROR count: %u\n", val
);
1092 pout(" Received address frame error count: %u\n", val
);
1095 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
1098 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
1101 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
1104 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
1107 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val
);
1110 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
1113 pout(" Transmitted BREAK count: %u\n", val
);
1116 pout(" Received BREAK count: %u\n", val
);
1119 pout(" Break timeout count: %u\n", val
);
1122 pout(" Connection count: %u\n", val
);
1125 pout(" Peak transmitted pathway blocked count: %u\n",
1127 pout(" Peak value detector threshold: %u\n",
1133 pout(" Peak transmitted arbitration wait time (us): "
1136 pout(" Peak transmitted arbitration wait time (ms): "
1137 "%u\n", 33 + (u
- 0x8000));
1138 u
= thresh_val
& 0xffff;
1140 pout(" Peak value detector threshold (us): %u\n",
1143 pout(" Peak value detector threshold (ms): %u\n",
1147 pout(" Peak arbitration time (us): %u\n", val
);
1148 pout(" Peak value detector threshold: %u\n", thresh_val
);
1151 pout(" Peak connection time (us): %u\n", val
);
1152 pout(" Peak value detector threshold: %u\n", thresh_val
);
1155 pout(" Transmitted SSP frame count: %u\n", val
);
1158 pout(" Received SSP frame count: %u\n", val
);
1161 pout(" Transmitted SSP frame error count: %u\n", val
);
1164 pout(" Received SSP frame error count: %u\n", val
);
1167 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1170 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1173 pout(" Transmitted SATA frame count: %u\n", val
);
1176 pout(" Received SATA frame count: %u\n", val
);
1179 pout(" SATA flow control buffer overflow count: %u\n", val
);
1182 pout(" Transmitted SMP frame count: %u\n", val
);
1185 pout(" Received SMP frame count: %u\n", val
);
1188 pout(" Received SMP frame error count: %u\n", val
);
1196 show_sas_port_param(unsigned char * ucp
, int param_len
)
1198 int j
, m
, n
, nphys
, t
, sz
, spld_len
;
1199 unsigned char * vcp
;
1205 t
= (ucp
[0] << 8) | ucp
[1];
1206 pout("relative target port id = %d\n", t
);
1207 pout(" generation code = %d\n", ucp
[6]);
1209 pout(" number of phys = %d\n", nphys
);
1211 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1212 vcp
+= spld_len
, j
+= spld_len
) {
1213 pout(" phy identifier = %d\n", vcp
[1]);
1216 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1219 t
= ((0x70 & vcp
[4]) >> 4);
1221 case 0: snprintf(s
, sz
, "no device attached"); break;
1222 case 1: snprintf(s
, sz
, "SAS or SATA device"); break;
1223 case 2: snprintf(s
, sz
, "expander device"); break;
1224 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1225 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1227 pout(" attached device type: %s\n", s
);
1230 case 0: snprintf(s
, sz
, "unknown"); break;
1231 case 1: snprintf(s
, sz
, "power on"); break;
1232 case 2: snprintf(s
, sz
, "hard reset"); break;
1233 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1234 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1235 case 5: snprintf(s
, sz
, "mux mix up"); break;
1236 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1238 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1239 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1240 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1242 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1244 pout(" attached reason: %s\n", s
);
1245 t
= (vcp
[5] & 0xf0) >> 4;
1247 case 0: snprintf(s
, sz
, "unknown"); break;
1248 case 1: snprintf(s
, sz
, "power on"); break;
1249 case 2: snprintf(s
, sz
, "hard reset"); break;
1250 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1251 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1252 case 5: snprintf(s
, sz
, "mux mix up"); break;
1253 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1255 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1256 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1257 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1259 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1261 pout(" reason: %s\n", s
);
1264 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1266 case 1: snprintf(s
, sz
, "phy disabled"); break;
1267 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1269 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1271 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1273 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1275 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1277 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1278 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1279 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1280 case 0xb: snprintf(s
, sz
, "phy enabled; 12 Gbps"); break;
1281 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1283 pout(" negotiated logical link rate: %s\n", s
);
1284 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1285 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1286 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1287 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1288 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1289 ull
<<= 8; ull
|= vcp
[8 + n
];
1291 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1292 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1293 ull
<<= 8; ull
|= vcp
[16 + n
];
1295 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1296 pout(" attached phy identifier = %d\n", vcp
[24]);
1298 ui
= (vcp
[32] << 24) | (vcp
[33] << 16) | (vcp
[34] << 8) | vcp
[35];
1299 pout(" Invalid DWORD count = %u\n", ui
);
1300 ui
= (vcp
[36] << 24) | (vcp
[37] << 16) | (vcp
[38] << 8) | vcp
[39];
1301 pout(" Running disparity error count = %u\n", ui
);
1302 ui
= (vcp
[40] << 24) | (vcp
[41] << 16) | (vcp
[42] << 8) | vcp
[43];
1303 pout(" Loss of DWORD synchronization = %u\n", ui
);
1304 ui
= (vcp
[44] << 24) | (vcp
[45] << 16) | (vcp
[46] << 8) | vcp
[47];
1305 pout(" Phy reset problem = %u\n", ui
);
1306 if (spld_len
> 51) {
1308 unsigned char * xcp
;
1312 pout(" Phy event descriptors:\n");
1314 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1318 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1320 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1322 show_sas_phy_event_info(peis
, ui
, pvdt
);
1328 // Returns 1 if okay, 0 if non SAS descriptors
1330 show_protocol_specific_page(unsigned char * resp
, int len
)
1333 unsigned char * ucp
;
1336 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1337 int param_len
= ucp
[3] + 4;
1338 if (6 != (0xf & ucp
[4]))
1339 return 0; /* only decode SAS log page */
1341 pout("Protocol Specific port log page for SAS SSP\n");
1342 show_sas_port_param(ucp
, param_len
);
1351 // See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1352 // log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1354 scsiPrintSasPhy(scsi_device
* device
, int reset
)
1358 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1359 LOG_RESP_LONG_LEN
, 0))) {
1361 pout("scsiPrintSasPhy Log Sense Failed [%s]\n\n", scsiErrString(err
));
1365 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1367 pout("Protocol specific Log Sense Failed, page mismatch\n\n");
1371 // compute page length
1372 num
= (gBuf
[2] << 8) + gBuf
[3];
1373 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1375 pout("Only support protocol specific log page on SAS devices\n\n");
1380 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1381 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1383 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n\n",
1384 scsiErrString(err
));
1393 static const char * peripheral_dt_arr
[] = {
1409 "optical card reader"
1411 "object based storage"
1412 "automation/driver interface"
1413 "security manager device"
1414 "host managed zoned block device"
1424 "well known logical unit"
1425 "unknown or no device type"
1428 static const char * transport_proto_arr
[] = {
1429 "Fibre channel (FCP-2)",
1430 "Parallel SCSI (SPI-4)",
1432 "IEEE 1394 (SBP-2)",
1447 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1449 scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1451 char timedatetz
[DATEANDEPOCHLEN
];
1452 struct scsi_iec_mode_page iec
;
1453 int err
, iec_err
, len
, req_len
, avail_len
, scsi_version
;
1454 bool is_tape
= false;
1457 int form_factor
= 0;
1461 memset(gBuf
, 0, 96);
1463 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1465 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1466 pout("Retrying with a 64 byte Standard Inquiry\n");
1468 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1470 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1472 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1473 scsiErrString(err
));
1478 avail_len
= gBuf
[4] + 5;
1479 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1480 peri_dt
= gBuf
[0] & 0x1f;
1481 *peripheral_type
= peri_dt
;
1482 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peri_dt
) ||
1483 (SCSI_PT_MEDIUM_CHANGER
== 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
) { /* assume disk if not tape drive (or tape changer) */
1525 unsigned int lb_size
= 0;
1526 unsigned char lb_prov_resp
[8];
1528 int lb_per_pb_exp
= 0;
1529 uint64_t capacity
= scsiGetSize(device
, &lb_size
, &lb_per_pb_exp
);
1532 char cap_str
[64], si_str
[64];
1533 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1534 format_capacity(si_str
, sizeof(si_str
), capacity
);
1535 pout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1536 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u", lb_size
);
1537 pout("Logical block size: %s bytes\n", lb_str
);
1541 if (protect
|| lb_per_pb_exp
) {
1542 unsigned char rc16_12
[20] = {0, };
1544 if (0 == scsiGetProtPBInfo(device
, rc16_12
)) {
1545 lb_per_pb_exp
= rc16_12
[1] & 0xf; /* just in case */
1546 if (lb_per_pb_exp
> 0) {
1547 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u",
1548 (lb_size
* (1 << lb_per_pb_exp
)));
1549 pout("Physical block size: %s bytes\n", lb_str
);
1550 int n
= ((rc16_12
[2] & 0x3f) << 8) + rc16_12
[3];
1551 if (n
> 0) // not common so cut the clutter
1552 pout("Lowest aligned LBA: %d\n", n
);
1554 if (rc16_12
[0] & 0x1) { /* PROT_EN set */
1555 int p_type
= ((rc16_12
[0] >> 1) & 0x7);
1559 pout("Formatted with type 1 protection\n");
1562 pout("Formatted with type 2 protection\n");
1565 pout("Formatted with type 3 protection\n");
1568 pout("Formatted with unknown protection type [%d]\n",
1572 int p_i_exp
= ((rc16_12
[1] >> 4) & 0xf);
1575 pout("%d protection information intervals per "
1576 "logical block\n", (1 << p_i_exp
));
1578 /* Pick up some LB provisioning info since its available */
1579 lbpme
= !! (rc16_12
[2] & 0x80);
1580 lbprz
= !! (rc16_12
[2] & 0x40);
1583 if (0 == scsiInquiryVpd(device
, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING
,
1584 lb_prov_resp
, sizeof(lb_prov_resp
))) {
1585 int prov_type
= lb_prov_resp
[6] & 0x7;
1588 lbprz
= !! (lb_prov_resp
[5] & 0x4);
1589 switch (prov_type
) {
1591 pout("LB provisioning type: unreported, LBPME=%d, LBPRZ=%d\n",
1595 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz
);
1598 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz
);
1601 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1605 } else if (1 == lbpme
)
1606 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz
);
1608 int rpm
= scsiGetRPM(device
, modese_len
, &form_factor
, &haw_zbc
);
1613 pout("Rotation Rate: Solid State Device\n");
1614 else if ((rpm
<= 0x400) || (0xffff == rpm
))
1617 pout("Rotation Rate: %d rpm\n", rpm
);
1619 if (form_factor
> 0) {
1620 const char * cp
= NULL
;
1622 switch (form_factor
) {
1640 pout("Form Factor: %s inches\n", cp
);
1643 pout("Host aware zoned block capable\n");
1646 /* Do this here to try and detect badly conforming devices (some USB
1647 keys) that will lock up on a InquiryVpd or log sense or ... */
1648 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1649 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1650 pout(">> Terminate command early due to bad response to IEC "
1657 modese_len
= iec
.modese_len
;
1659 if (! dont_print_serial_number
) {
1660 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_DEVICE_IDENTIFICATION
,
1665 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
1667 pout("Logical Unit id: %s\n", s
);
1668 } else if (scsi_debugmode
> 0) {
1670 if (SIMPLE_ERR_BAD_RESP
== err
)
1671 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1673 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1676 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_UNIT_SERIAL_NUMBER
,
1681 gBuf
[4 + len
] = '\0';
1682 scsi_format_id_string(serial
, &gBuf
[4], len
);
1683 pout("Serial number: %s\n", serial
);
1684 } else if (scsi_debugmode
> 0) {
1686 if (SIMPLE_ERR_BAD_RESP
== err
)
1687 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1689 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1694 // print SCSI peripheral device type
1695 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1696 sizeof(peripheral_dt_arr
[0])))
1697 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1699 pout("Device type: <%d>\n", peri_dt
);
1701 // See if transport protocol is known
1703 transport
= scsiFetchTransportProtocol(device
, modese_len
);
1704 if ((transport
>= 0) && (transport
<= 0xf))
1705 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
1707 // print current time and date and timezone
1708 dateandtimezone(timedatetz
);
1709 pout("Local Time is: %s\n", timedatetz
);
1711 // See if unit accepts SCSI commmands from us
1712 if ((err
= scsiTestUnitReady(device
))) {
1713 if (SIMPLE_ERR_NOT_READY
== err
) {
1716 pout("device is NOT READY (e.g. spun down, busy)\n");
1718 pout("device is NOT READY (e.g. no tape)\n");
1720 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1722 pout("NO MEDIUM present on device\n");
1724 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1726 pout("device becoming ready (wait)\n");
1730 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1733 int returnval
= 0; // TODO: exit with FAILID if failuretest returns
1734 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1740 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
1741 if (scsi_debugmode
> 0)
1742 pout(" [%s]\n", scsiErrString(iec_err
));
1750 pout("SMART support is: Available - device has SMART capability.\n"
1751 "SMART support is: %s\n",
1752 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1753 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1754 "Temperature Warning: Enabled" :
1755 "Temperature Warning: Disabled or Not Supported");
1760 scsiSmartEnable(scsi_device
* device
)
1762 struct scsi_iec_mode_page iec
;
1765 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1767 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1768 scsiErrString(err
));
1772 modese_len
= iec
.modese_len
;
1774 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1776 pout("unable to enable Exception control and warning [%s]\n",
1777 scsiErrString(err
));
1781 /* Need to refetch 'iec' since could be modified by previous call */
1782 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1783 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1784 scsiErrString(err
));
1787 modese_len
= iec
.modese_len
;
1789 pout("Informational Exceptions (SMART) %s\n",
1790 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1791 pout("Temperature warning %s\n",
1792 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1797 scsiSmartDisable(scsi_device
* device
)
1799 struct scsi_iec_mode_page iec
;
1802 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1804 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1805 scsiErrString(err
));
1809 modese_len
= iec
.modese_len
;
1811 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1813 pout("unable to disable Exception control and warning [%s]\n",
1814 scsiErrString(err
));
1818 /* Need to refetch 'iec' since could be modified by previous call */
1819 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1820 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1821 scsiErrString(err
));
1824 modese_len
= iec
.modese_len
;
1826 pout("Informational Exceptions (SMART) %s\n",
1827 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1828 pout("Temperature warning %s\n",
1829 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1834 scsiPrintTemp(scsi_device
* device
)
1839 if (scsiGetTemp(device
, &temp
, &trip
))
1844 pout("Current Drive Temperature: %d C\n", temp
);
1846 pout("Current Drive Temperature: <not available>\n");
1849 pout("Drive Trip Temperature: %d C\n", trip
);
1854 /* Main entry point used by smartctl command. Return 0 for success */
1856 scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1858 int checkedSupportedLogPages
= 0;
1859 UINT8 peripheral_type
= 0;
1861 int res
, durationSec
;
1862 struct scsi_sense_disect sense_info
;
1866 bool any_output
= options
.drive_info
;
1868 if (supported_vpd_pages_p
) {
1869 delete supported_vpd_pages_p
;
1870 supported_vpd_pages_p
= NULL
;
1872 supported_vpd_pages_p
= new supported_vpd_pages(device
);
1874 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1879 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1882 is_disk
= (SCSI_PT_DIRECT_ACCESS
== peripheral_type
);
1883 is_tape
= ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1884 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
));
1886 short int wce
= -1, rcd
= -1;
1887 // Print read look-ahead status for disks
1888 if (options
.get_rcd
|| options
.get_wce
) {
1890 res
= scsiGetSetCache(device
, modese_len
, &wce
, &rcd
);
1891 if (options
.get_rcd
)
1892 pout("Read Cache is: %s\n",
1893 res
? "Unavailable" : // error
1894 rcd
? "Disabled" : "Enabled");
1895 if (options
.get_wce
)
1896 pout("Writeback Cache is: %s\n",
1897 res
? "Unavailable" : // error
1898 !wce
? "Disabled" : "Enabled");
1903 if (options
.drive_info
)
1906 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1907 if (options
.smart_disable
|| options
.smart_enable
||
1908 options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1909 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1911 if (options
.smart_enable
) {
1912 if (scsiSmartEnable(device
))
1913 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1917 if (options
.smart_disable
) {
1918 if (scsiSmartDisable(device
))
1919 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1923 if (options
.smart_auto_save_enable
) {
1924 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1925 pout("Enable autosave (clear GLTSD bit) failed\n");
1926 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1928 pout("Autosave enabled (GLTSD bit cleared).\n");
1932 // Enable/Disable write cache
1933 if (options
.set_wce
&& is_disk
) {
1934 short int enable
= wce
= (options
.set_wce
> 0);
1937 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1938 pout("Write cache %sable failed: %s\n", (enable
? "en" : "dis"),
1939 device
->get_errmsg());
1940 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1942 pout("Write cache %sabled\n", (enable
? "en" : "dis"));
1946 // Enable/Disable read cache
1947 if (options
.set_rcd
&& is_disk
) {
1948 short int enable
= (options
.set_rcd
> 0);
1952 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1953 pout("Read cache %sable failed: %s\n", (enable
? "en" : "dis"),
1954 device
->get_errmsg());
1955 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1957 pout("Read cache %sabled\n", (enable
? "en" : "dis"));
1961 if (options
.smart_auto_save_disable
) {
1962 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1963 pout("Disable autosave (set GLTSD bit) failed\n");
1964 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1966 pout("Autosave disabled (GLTSD bit set).\n");
1969 if (options
.smart_disable
|| options
.smart_enable
||
1970 options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1971 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
1973 // START OF READ-ONLY OPTIONS APART FROM -V and -i
1974 if (options
.smart_check_status
|| options
.smart_ss_media_log
||
1975 options
.smart_vendor_attrib
|| options
.smart_error_log
||
1976 options
.smart_selftest_log
|| options
.smart_background_log
||
1978 pout("=== START OF READ SMART DATA SECTION ===\n");
1980 if (options
.smart_check_status
) {
1981 scsiGetSupportedLogPages(device
);
1982 checkedSupportedLogPages
= 1;
1984 if (gTapeAlertsLPage
) {
1985 if (options
.drive_info
)
1986 pout("TapeAlert Supported\n");
1987 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
1988 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
1991 pout("TapeAlert Not Supported\n");
1992 } else { /* disk, cd/dvd, enclosure, etc */
1993 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
1995 returnval
|= FAILSTATUS
;
1997 returnval
|= FAILSMART
;
2003 if (is_disk
&& options
.smart_ss_media_log
) {
2004 if (! checkedSupportedLogPages
)
2005 scsiGetSupportedLogPages(device
);
2008 res
= scsiPrintSSMedia(device
);
2010 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2013 if (options
.smart_vendor_attrib
) {
2014 if (! checkedSupportedLogPages
)
2015 scsiGetSupportedLogPages(device
);
2017 scsiPrintTemp(device
);
2018 if (gStartStopLPage
)
2019 scsiGetStartStopData(device
);
2021 scsiPrintGrownDefectListLen(device
);
2022 if (gSeagateCacheLPage
)
2023 scsiPrintSeagateCacheLPage(device
);
2024 if (gSeagateFactoryLPage
)
2025 scsiPrintSeagateFactoryLPage(device
);
2029 if (options
.smart_error_log
) {
2030 if (! checkedSupportedLogPages
)
2031 scsiGetSupportedLogPages(device
);
2032 scsiPrintErrorCounterLog(device
);
2033 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
2034 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2035 "Enable Save with '-S on']\n");
2038 if (options
.smart_selftest_log
) {
2039 if (! checkedSupportedLogPages
)
2040 scsiGetSupportedLogPages(device
);
2043 res
= scsiPrintSelfTest(device
);
2045 pout("Device does not support Self Test logging\n");
2046 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2049 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2052 if (options
.smart_background_log
) {
2053 if (! checkedSupportedLogPages
)
2054 scsiGetSupportedLogPages(device
);
2056 if (gBackgroundResultsLPage
)
2057 res
= scsiPrintBackgroundResults(device
);
2059 pout("Device does not support Background scan results logging\n");
2060 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2063 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2066 if (options
.smart_default_selftest
) {
2067 if (scsiSmartDefaultSelfTest(device
))
2068 return returnval
| FAILSMART
;
2069 pout("Default Self Test Successful\n");
2072 if (options
.smart_short_cap_selftest
) {
2073 if (scsiSmartShortCapSelfTest(device
))
2074 return returnval
| FAILSMART
;
2075 pout("Short Foreground Self Test Successful\n");
2078 // check if another test is running
2079 if (options
.smart_short_selftest
|| options
.smart_extend_selftest
) {
2080 if (!scsiRequestSense(device
, &sense_info
) &&
2081 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09)) {
2082 if (!options
.smart_selftest_force
) {
2083 pout("Can't start self-test without aborting current test");
2084 if (sense_info
.progress
!= -1)
2085 pout(" (%d%% remaining)",
2086 100 - sense_info
.progress
* 100 / 65535);
2087 pout(",\nadd '-t force' option to override, or run "
2088 "'smartctl -X' to abort test.\n");
2091 scsiSmartSelfTestAbort(device
);
2094 if (options
.smart_short_selftest
) {
2095 if (scsiSmartShortSelfTest(device
))
2096 return returnval
| FAILSMART
;
2097 pout("Short Background Self Test has begun\n");
2098 pout("Use smartctl -X to abort test\n");
2101 if (options
.smart_extend_selftest
) {
2102 if (scsiSmartExtendSelfTest(device
))
2103 return returnval
| FAILSMART
;
2104 pout("Extended Background Self Test has begun\n");
2105 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
2106 modese_len
)) && (durationSec
> 0)) {
2107 time_t t
= time(NULL
);
2110 pout("Please wait %d minutes for test to complete.\n",
2112 pout("Estimated completion time: %s\n", ctime(&t
));
2114 pout("Use smartctl -X to abort test\n");
2117 if (options
.smart_extend_cap_selftest
) {
2118 if (scsiSmartExtendCapSelfTest(device
))
2119 return returnval
| FAILSMART
;
2120 pout("Extended Foreground Self Test Successful\n");
2122 if (options
.smart_selftest_abort
) {
2123 if (scsiSmartSelfTestAbort(device
))
2124 return returnval
| FAILSMART
;
2125 pout("Self Test returned without error\n");
2128 if (options
.sasphy
&& gProtocolSpecificLPage
) {
2129 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
2130 return returnval
| FAILSMART
;
2135 pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
2136 "to print SMART (and more) information\n\n");