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 3807 2013-04-18 17:11:12Z chrfranke $"
49 UINT8 gBuf
[GBUF_SIZE
];
50 #define LOG_RESP_LEN 252
51 #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
52 #define LOG_RESP_TAPE_ALERT_LEN 0x144
54 /* Log pages supported */
55 static int gSmartLPage
= 0; /* Informational Exceptions log page */
56 static int gTempLPage
= 0;
57 static int gSelfTestLPage
= 0;
58 static int gStartStopLPage
= 0;
59 static int gReadECounterLPage
= 0;
60 static int gWriteECounterLPage
= 0;
61 static int gVerifyECounterLPage
= 0;
62 static int gNonMediumELPage
= 0;
63 static int gLastNErrorLPage
= 0;
64 static int gBackgroundResultsLPage
= 0;
65 static int gProtocolSpecificLPage
= 0;
66 static int gTapeAlertsLPage
= 0;
67 static int gSSMediaLPage
= 0;
69 /* Vendor specific log pages */
70 static int gSeagateCacheLPage
= 0;
71 static int gSeagateFactoryLPage
= 0;
73 /* Mode pages supported */
74 static int gIecMPage
= 1; /* N.B. assume it until we know otherwise */
76 /* Remember last successful mode sense/select command */
77 static int modese_len
= 0;
81 scsiGetSupportedLogPages(scsi_device
* device
)
85 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
87 if (scsi_debugmode
> 0)
88 pout("Log Sense for supported pages failed [%s]\n",
93 for (i
= 4; i
< gBuf
[3] + LOGPAGEHDRSIZE
; i
++) {
96 case READ_ERROR_COUNTER_LPAGE
:
97 gReadECounterLPage
= 1;
99 case WRITE_ERROR_COUNTER_LPAGE
:
100 gWriteECounterLPage
= 1;
102 case VERIFY_ERROR_COUNTER_LPAGE
:
103 gVerifyECounterLPage
= 1;
105 case LAST_N_ERROR_LPAGE
:
106 gLastNErrorLPage
= 1;
108 case NON_MEDIUM_ERROR_LPAGE
:
109 gNonMediumELPage
= 1;
111 case TEMPERATURE_LPAGE
:
114 case STARTSTOP_CYCLE_COUNTER_LPAGE
:
117 case SELFTEST_RESULTS_LPAGE
:
123 case BACKGROUND_RESULTS_LPAGE
:
124 gBackgroundResultsLPage
= 1;
126 case PROTOCOL_SPECIFIC_LPAGE
:
127 gProtocolSpecificLPage
= 1;
129 case TAPE_ALERTS_LPAGE
:
130 gTapeAlertsLPage
= 1;
135 case SEAGATE_CACHE_LPAGE
:
136 gSeagateCacheLPage
= 1;
138 case SEAGATE_FACTORY_LPAGE
:
139 gSeagateFactoryLPage
= 1;
147 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
148 (or at least something to report). */
150 scsiGetSmartData(scsi_device
* device
, bool attribs
)
154 UINT8 currenttemp
= 0;
159 if (scsiCheckIE(device
, gSmartLPage
, gTempLPage
, &asc
, &ascq
,
160 ¤ttemp
, &triptemp
)) {
161 /* error message already announced */
166 cp
= scsiGetIEString(asc
, ascq
);
170 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp
, asc
, ascq
);
172 } else if (gIecMPage
)
173 pout("SMART Health Status: OK\n");
175 if (attribs
&& !gTempLPage
) {
177 if (255 != currenttemp
)
178 pout("Current Drive Temperature: %d C\n", currenttemp
);
180 pout("Current Drive Temperature: <not available>\n");
183 pout("Drive Trip Temperature: %d C\n", triptemp
);
190 // Returns number of logged errors or zero if none or -1 if fetching
192 static const char * const severities
= "CWI";
195 scsiGetTapeAlertsData(scsi_device
* device
, int peripheral_type
)
197 unsigned short pagelength
;
198 unsigned short parametercode
;
205 if ((err
= scsiLogSense(device
, TAPE_ALERTS_LPAGE
, 0, gBuf
,
206 LOG_RESP_TAPE_ALERT_LEN
, LOG_RESP_TAPE_ALERT_LEN
))) {
207 pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err
));
211 if (gBuf
[0] != 0x2e) {
212 pout("TapeAlerts Log Sense Failed\n");
216 pagelength
= (unsigned short) gBuf
[2] << 8 | gBuf
[3];
218 for (s
=severities
; *s
; s
++) {
219 for (i
= 4; i
< pagelength
; i
+= 5) {
220 parametercode
= (unsigned short) gBuf
[i
] << 8 | gBuf
[i
+1];
223 ts
= SCSI_PT_MEDIUM_CHANGER
== peripheral_type
?
224 scsiTapeAlertsChangerDevice(parametercode
) :
225 scsiTapeAlertsTapeDevice(parametercode
);
228 pout("TapeAlert Errors (C=Critical, W=Warning, "
229 "I=Informational):\n");
230 pout("[0x%02x] %s\n", parametercode
, ts
);
239 pout("TapeAlert: OK\n");
245 scsiGetStartStopData(scsi_device
* device
)
248 int err
, len
, k
, extra
, pc
;
251 if ((err
= scsiLogSense(device
, STARTSTOP_CYCLE_COUNTER_LPAGE
, 0, gBuf
,
254 pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err
));
258 if ((gBuf
[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE
) {
260 pout("StartStop Log Sense Failed, page mismatch\n");
264 len
= ((gBuf
[2] << 8) | gBuf
[3]);
266 for (k
= len
; k
> 0; k
-= extra
, ucp
+= extra
) {
269 pout("StartStop Log Sense Failed: short\n");
274 pc
= (ucp
[0] << 8) + ucp
[1];
278 pout("Manufactured in week %.2s of year %.4s\n", ucp
+ 8,
282 /* ignore Accounting date */
286 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
288 pout("Specified cycle count over device lifetime: %u\n",
294 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
296 pout("Accumulated start-stop cycles: %u\n", u
);
301 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
303 pout("Specified load-unload count over device "
304 "lifetime: %u\n", u
);
309 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
311 pout("Accumulated load-unload cycles: %u\n", u
);
322 scsiPrintGrownDefectListLen(scsi_device
* device
)
324 int err
, dl_format
, got_rd12
, generation
;
325 unsigned int dl_len
, div
;
328 if ((err
= scsiReadDefect12(device
, 0 /* req_plist */, 1 /* req_glist */,
329 4 /* format: bytes from index */,
330 0 /* addr desc index */, gBuf
, 8))) {
331 if (2 == err
) { /* command not supported */
332 if ((err
= scsiReadDefect10(device
, 0 /* req_plist */, 1 /* req_glist */,
333 4 /* format: bytes from index */, gBuf
, 4))) {
334 if (scsi_debugmode
> 0) {
336 pout("Read defect list (10) Failed: %s\n", scsiErrString(err
));
343 if (scsi_debugmode
> 0) {
345 pout("Read defect list (12) Failed: %s\n", scsiErrString(err
));
354 generation
= (gBuf
[2] << 8) + gBuf
[3];
355 if ((generation
> 1) && (scsi_debugmode
> 0)) {
357 pout("Read defect list (12): generation=%d\n", generation
);
360 dl_len
= (gBuf
[4] << 24) + (gBuf
[5] << 16) + (gBuf
[6] << 8) + gBuf
[7];
362 dl_len
= (gBuf
[2] << 8) + gBuf
[3];
364 if (0x8 != (gBuf
[1] & 0x18)) {
366 pout("Read defect list: asked for grown list but didn't get it\n");
371 dl_format
= (gBuf
[1] & 0x7);
373 case 0: /* short block */
376 case 1: /* extended bytes from index */
377 case 2: /* extended physical sector */
378 /* extended = 1; # might use in future */
381 case 3: /* long block */
382 case 4: /* bytes from index */
383 case 5: /* physical sector */
388 pout("defect list format %d unknown\n", dl_format
);
393 pout("Elements in grown defect list: 0\n\n");
396 pout("Grown defect list length=%u bytes [unknown "
397 "number of elements]\n\n", dl_len
);
399 pout("Elements in grown defect list: %u\n\n", dl_len
/ div
);
404 scsiPrintSeagateCacheLPage(scsi_device
* device
)
406 int k
, j
, num
, pl
, pc
, err
, len
;
411 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
414 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err
));
418 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
420 pout("Seagate Cache Log Sense Failed, page mismatch\n");
424 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
428 pc
= (ucp
[0] << 8) | ucp
[1];
431 case 0: case 1: case 2: case 3: case 4:
434 if (scsi_debugmode
> 0) {
436 pout("Vendor (Seagate) cache lpage has unexpected parameter"
445 pout("Vendor (Seagate) cache information\n");
449 pc
= (ucp
[0] << 8) | ucp
[1];
452 case 0: pout(" Blocks sent to initiator"); break;
453 case 1: pout(" Blocks received from initiator"); break;
454 case 2: pout(" Blocks read from cache and sent to initiator"); break;
455 case 3: pout(" Number of read and write commands whose size "
456 "<= segment size"); break;
457 case 4: pout(" Number of read and write commands whose size "
458 "> segment size"); break;
459 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
463 if (k
> (int)sizeof(ull
)) {
464 xp
+= (k
- (int)sizeof(ull
));
465 k
= (int)sizeof(ull
);
468 for (j
= 0; j
< k
; ++j
) {
473 pout(" = %"PRIu64
"\n", ull
);
481 scsiPrintSeagateFactoryLPage(scsi_device
* device
)
483 int k
, j
, num
, pl
, pc
, len
, err
, good
, bad
;
488 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
491 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err
));
495 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
497 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
501 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
507 pc
= (ucp
[0] << 8) | ucp
[1];
520 if ((good
< 2) || (bad
> 4)) { /* heuristic */
521 if (scsi_debugmode
> 0) {
523 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
524 "unexpected parameters, skip\n");
529 pout("Vendor (Seagate/Hitachi) factory information\n");
533 pc
= (ucp
[0] << 8) | ucp
[1];
537 case 0: pout(" number of hours powered up");
540 case 8: pout(" number of minutes until next internal SMART test");
544 if (scsi_debugmode
> 0) {
546 pout("Vendor (Seagate/Hitachi) factory lpage: "
547 "unknown parameter code [0x%x]\n", pc
);
555 if (k
> (int)sizeof(ull
)) {
556 xp
+= (k
- (int)sizeof(ull
));
557 k
= (int)sizeof(ull
);
560 for (j
= 0; j
< k
; ++j
) {
566 pout(" = %.2f\n", ull
/ 60.0 );
568 pout(" = %"PRIu64
"\n", ull
);
577 scsiPrintErrorCounterLog(scsi_device
* device
)
579 struct scsiErrorCounter errCounterArr
[3];
580 struct scsiErrorCounter
* ecp
;
581 struct scsiNonMediumError nme
;
582 int found
[3] = {0, 0, 0};
583 const char * pageNames
[3] = {"read: ", "write: ", "verify: "};
586 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
587 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
588 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
591 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
592 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
593 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
596 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
597 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
598 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
599 ecp
= &errCounterArr
[2];
600 for (int k
= 0; k
< 7; ++k
) {
601 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
607 if (found
[0] || found
[1] || found
[2]) {
608 pout("Error counter log:\n");
609 pout(" Errors Corrected by Total "
610 "Correction Gigabytes Total\n");
611 pout(" ECC rereads/ errors "
612 "algorithm processed uncorrected\n");
613 pout(" fast | delayed rewrites corrected "
614 "invocations [10^9 bytes] errors\n");
615 for (int k
= 0; k
< 3; ++k
) {
618 ecp
= &errCounterArr
[k
];
619 pout("%s%8"PRIu64
" %8"PRIu64
" %8"PRIu64
" %8"PRIu64
" %8"PRIu64
,
620 pageNames
[k
], ecp
->counter
[0], ecp
->counter
[1],
621 ecp
->counter
[2], ecp
->counter
[3], ecp
->counter
[4]);
622 processed_gb
= ecp
->counter
[5] / 1000000000.0;
623 pout(" %12.3f %8"PRIu64
"\n", processed_gb
, ecp
->counter
[6]);
627 pout("Error Counter logging not supported\n");
628 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
629 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
630 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
632 pout("\nNon-medium error count: %8"PRIu64
"\n", nme
.counterPC0
);
634 pout("Track following error count [Hitachi]: %8"PRIu64
"\n",
637 pout("Positioning error count [Hitachi]: %8"PRIu64
"\n",
640 if (gLastNErrorLPage
&& (0 == scsiLogSense(device
,
641 LAST_N_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LONG_LEN
, 0))) {
642 int num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
643 int truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
645 num
= LOG_RESP_LONG_LEN
;
646 unsigned char * ucp
= gBuf
+ 4;
649 pout("\nNo error events logged\n");
651 pout("\nLast n error events log page\n");
652 for (int k
= num
, pl
; k
> 0; k
-= pl
, ucp
+= pl
) {
654 pout(" <<short Last n error events log page>>\n");
658 int pc
= (ucp
[0] << 8) + ucp
[1];
660 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
661 pout(" Error event %d:\n", pc
);
662 pout(" [binary]:\n");
663 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
664 } else if (ucp
[2] & 0x1) {
665 pout(" Error event %d:\n", pc
);
666 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
668 if (scsi_debugmode
> 0) {
669 pout(" Error event %d:\n", pc
);
670 pout(" [data counter??]:\n");
671 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
677 pout(" >>>> log truncated, fetched %d of %d available "
678 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
684 static const char * self_test_code
[] = {
695 static const char * self_test_result
[] = {
697 "Aborted (by user command)",
698 "Aborted (device reset ?) ",
699 "Unknown error, incomplete",
700 "Completed, segment failed",
701 "Failed in first segment ",
702 "Failed in second segment ",
703 "Failed in segment --> ",
711 "Self test in progress ..."
714 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
715 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
716 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
717 // FAILSMART is returned.
719 scsiPrintSelfTest(scsi_device
* device
)
721 int num
, k
, n
, res
, err
, durationSec
;
726 struct scsi_sense_disect sense_info
;
728 // check if test is running
729 if (!scsiRequestSense(device
, &sense_info
) &&
730 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09 &&
731 sense_info
.progress
!= -1)) {
732 pout("Self-test execution status:\t\t%d%% of test remaining\n",
733 100 - ((sense_info
.progress
* 100) / 65535));
736 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
737 LOG_RESP_SELF_TEST_LEN
, 0))) {
739 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err
));
743 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
745 pout("Self-test Log Sense Failed, page mismatch\n");
749 // compute page length
750 num
= (gBuf
[2] << 8) + gBuf
[3];
751 // Log sense page length 0x190 bytes
754 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num
);
758 // loop through the twenty possible entries
759 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
762 // timestamp in power-on hours (or zero if test in progress)
763 n
= (ucp
[6] << 8) | ucp
[7];
765 // The spec says "all 20 bytes will be zero if no test" but
766 // DG has found otherwise. So this is a heuristic.
767 if ((0 == n
) && (0 == ucp
[4]))
770 // only print header if needed
772 pout("SMART Self-test log\n");
773 pout("Num Test Status segment "
774 "LifeTime LBA_first_err [SK ASC ASQ]\n");
775 pout(" Description number "
780 // print parameter code (test number) & self-test code text
781 pout("#%2d %s", (ucp
[0] << 8) | ucp
[1],
782 self_test_code
[(ucp
[4] >> 5) & 0x7]);
784 // check the self-test result nibble, using the self-test results
785 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
786 switch ((res
= ucp
[4] & 0xf)) {
788 // an unknown error occurred while the device server
789 // was processing the self-test and the device server
790 // was unable to complete the self-test
794 // the self-test completed with a failure in a test
795 // segment, and the test segment that failed is not
800 // the first segment of the self-test failed
804 // the second segment of the self-test failed
808 // another segment of the self-test failed and which
809 // test is indicated by the contents of the SELF-TEST
816 pout(" %s", self_test_result
[res
]);
818 // self-test number identifies test that failed and consists
819 // of either the number of the segment that failed during
820 // the test, or the number of the test that failed and the
821 // number of the segment in which the test was run, using a
822 // vendor-specific method of putting both numbers into a
825 pout(" %3d", (int)ucp
[5]);
829 // print time that the self-test was completed
830 if (n
==0 && res
==0xf)
831 // self-test in progress
836 // construct 8-byte integer address of first failure
837 for (i
= 0; i
< 8; i
++) {
841 // print Address of First Failure, if sensible
842 if ((~(uint64_t)0 != ull
) && (res
> 0) && (res
< 0xf)) {
845 // was hex but change to decimal to conform with ATA
846 snprintf(buff
, sizeof(buff
), "%"PRIu64
, ull
);
847 // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull);
852 // if sense key nonzero, then print it, along with
853 // additional sense code and additional sense code qualifier
855 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
860 // if header never printed, then there was no output
862 pout("No self-tests have been logged\n");
864 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
865 modese_len
)) && (durationSec
> 0)) {
866 pout("Long (extended) Self Test duration: %d seconds "
867 "[%.1f minutes]\n", durationSec
, durationSec
/ 60.0);
873 static const char * bms_status
[] = {
876 "pre-scan is active",
877 "halted due to fatal error",
878 "halted due to a vendor specific pattern of error",
879 "halted due to medium formatted without P-List",
880 "halted - vendor specific cause",
881 "halted due to temperature out of range",
882 "waiting until BMS interval timer expires", /* 8 */
885 static const char * reassign_status
[] = {
887 "Require Write or Reassign Blocks command",
888 "Successfully reassigned",
890 "Reassignment by disk failed",
891 "Recovered via rewrite in-place",
892 "Reassigned by app, has valid data",
893 "Reassigned by app, has no valid data",
894 "Unsuccessfully reassigned by app", /* 8 */
897 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
898 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
899 // and up to 2048 events (although would hope to have less). May set
900 // FAILLOG if serious errors detected (in the future).
902 scsiPrintBackgroundResults(scsi_device
* device
)
904 int num
, j
, m
, err
, pc
, pl
, truncated
;
910 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
911 LOG_RESP_LONG_LEN
, 0))) {
913 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err
));
917 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
919 pout("Background scan results Log Sense Failed, page mismatch\n");
923 // compute page length
924 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
927 pout("Background scan results Log Sense length is %d, no scan "
932 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
934 num
= LOG_RESP_LONG_LEN
;
938 pc
= (ucp
[0] << 8) | ucp
[1];
945 pout("Background scan results log\n");
948 if ((pl
< 16) || (num
< 16)) {
953 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
954 pout("%s\n", bms_status
[j
]);
956 pout("unknown [0x%x] background scan status value\n", j
);
957 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
958 pout(" Accumulated power on time, hours:minutes %d:%02d "
959 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
960 pout(" Number of background scans performed: %d, ",
961 (ucp
[10] << 8) + ucp
[11]);
962 pout("scan progress: %.2f%%\n",
963 (double)((ucp
[12] << 8) + ucp
[13]) * 100.0 / 65536.0);
964 pout(" Number of background medium scans performed: %d\n",
965 (ucp
[14] << 8) + ucp
[15]);
970 pout("\nBackground scan results log\n");
974 pout("\n # when lba(hex) [sk,asc,ascq] "
975 "reassign_status\n");
978 if ((pl
< 24) || (num
< 24)) {
980 pout("parameter length >= 24 expected, got %d\n", pl
);
983 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
984 pout("%4d:%02d ", (j
/ 60), (j
% 60));
985 for (m
= 0; m
< 8; ++m
)
986 pout("%02x", ucp
[16 + m
]);
987 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
988 j
= (ucp
[8] >> 4) & 0xf;
990 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
991 pout("%s\n", reassign_status
[j
]);
993 pout("Reassign status: reserved [0x%x]\n", j
);
1000 pout(" >>>> log truncated, fetched %d of %d available "
1001 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
1006 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1007 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1008 // and up to 2048 events (although would hope to have less). May set
1009 // FAILLOG if serious errors detected (in the future).
1011 scsiPrintSSMedia(scsi_device
* device
)
1013 int num
, err
, pc
, pl
, truncated
;
1017 if ((err
= scsiLogSense(device
, SS_MEDIA_LPAGE
, 0, gBuf
,
1018 LOG_RESP_LONG_LEN
, 0))) {
1020 pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err
));
1024 if ((gBuf
[0] & 0x3f) != SS_MEDIA_LPAGE
) {
1026 pout("Solid state media Log Sense Failed, page mismatch\n");
1030 // compute page length
1031 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
1034 pout("Solid state media Log Sense length is %d, too short\n", num
);
1038 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
1040 num
= LOG_RESP_LONG_LEN
;
1044 pc
= (ucp
[0] << 8) | ucp
[1];
1051 pout("Percentage used endurance indicator too short (pl=%d)\n", pl
);
1055 pout("SS Media used endurance indicator: %d%%\n", ucp
[7]);
1056 default: /* ignore other parameter codes */
1066 show_sas_phy_event_info(int peis
, unsigned int val
, unsigned thresh_val
)
1072 pout(" No event\n");
1075 pout(" Invalid word count: %u\n", val
);
1078 pout(" Running disparity error count: %u\n", val
);
1081 pout(" Loss of dword synchronization count: %u\n", val
);
1084 pout(" Phy reset problem count: %u\n", val
);
1087 pout(" Elasticity buffer overflow count: %u\n", val
);
1090 pout(" Received ERROR count: %u\n", val
);
1093 pout(" Received address frame error count: %u\n", val
);
1096 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
1099 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
1102 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
1105 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
1108 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val
);
1111 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
1114 pout(" Transmitted BREAK count: %u\n", val
);
1117 pout(" Received BREAK count: %u\n", val
);
1120 pout(" Break timeout count: %u\n", val
);
1123 pout(" Connection count: %u\n", val
);
1126 pout(" Peak transmitted pathway blocked count: %u\n",
1128 pout(" Peak value detector threshold: %u\n",
1134 pout(" Peak transmitted arbitration wait time (us): "
1137 pout(" Peak transmitted arbitration wait time (ms): "
1138 "%u\n", 33 + (u
- 0x8000));
1139 u
= thresh_val
& 0xffff;
1141 pout(" Peak value detector threshold (us): %u\n",
1144 pout(" Peak value detector threshold (ms): %u\n",
1148 pout(" Peak arbitration time (us): %u\n", val
);
1149 pout(" Peak value detector threshold: %u\n", thresh_val
);
1152 pout(" Peak connection time (us): %u\n", val
);
1153 pout(" Peak value detector threshold: %u\n", thresh_val
);
1156 pout(" Transmitted SSP frame count: %u\n", val
);
1159 pout(" Received SSP frame count: %u\n", val
);
1162 pout(" Transmitted SSP frame error count: %u\n", val
);
1165 pout(" Received SSP frame error count: %u\n", val
);
1168 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1171 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1174 pout(" Transmitted SATA frame count: %u\n", val
);
1177 pout(" Received SATA frame count: %u\n", val
);
1180 pout(" SATA flow control buffer overflow count: %u\n", val
);
1183 pout(" Transmitted SMP frame count: %u\n", val
);
1186 pout(" Received SMP frame count: %u\n", val
);
1189 pout(" Received SMP frame error count: %u\n", val
);
1197 show_sas_port_param(unsigned char * ucp
, int param_len
)
1199 int j
, m
, n
, nphys
, t
, sz
, spld_len
;
1200 unsigned char * vcp
;
1207 t
= (ucp
[0] << 8) | ucp
[1];
1208 pout("relative target port id = %d\n", t
);
1209 pout(" generation code = %d\n", ucp
[6]);
1211 pout(" number of phys = %d\n", nphys
);
1213 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1214 vcp
+= spld_len
, j
+= spld_len
) {
1215 pout(" phy identifier = %d\n", vcp
[1]);
1218 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1221 t
= ((0x70 & vcp
[4]) >> 4);
1223 case 0: snprintf(s
, sz
, "no device attached"); break;
1224 case 1: snprintf(s
, sz
, "end device"); break;
1225 case 2: snprintf(s
, sz
, "expander device"); break;
1226 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1227 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1229 pout(" attached device type: %s\n", s
);
1232 case 0: snprintf(s
, sz
, "unknown"); break;
1233 case 1: snprintf(s
, sz
, "power on"); break;
1234 case 2: snprintf(s
, sz
, "hard reset"); break;
1235 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1236 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1237 case 5: snprintf(s
, sz
, "mux mix up"); break;
1238 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1240 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1241 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1242 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1244 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1246 pout(" attached reason: %s\n", s
);
1247 t
= (vcp
[5] & 0xf0) >> 4;
1249 case 0: snprintf(s
, sz
, "unknown"); break;
1250 case 1: snprintf(s
, sz
, "power on"); break;
1251 case 2: snprintf(s
, sz
, "hard reset"); break;
1252 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1253 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1254 case 5: snprintf(s
, sz
, "mux mix up"); break;
1255 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1257 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1258 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1259 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1261 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1263 pout(" reason: %s\n", s
);
1266 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1268 case 1: snprintf(s
, sz
, "phy disabled"); break;
1269 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1271 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1273 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1275 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1277 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1279 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1280 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1281 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1282 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1284 pout(" negotiated logical link rate: %s\n", s
);
1285 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1286 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1287 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1288 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1289 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1290 ull
<<= 8; ull
|= vcp
[8 + n
];
1292 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1293 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1294 ull
<<= 8; ull
|= vcp
[16 + n
];
1296 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1297 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
;
1313 pout(" Phy event descriptors:\n");
1315 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1317 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1319 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1321 show_sas_phy_event_info(peis
, ui
, pvdt
);
1327 // Returns 1 if okay, 0 if non SAS descriptors
1329 show_protocol_specific_page(unsigned char * resp
, int len
)
1331 int k
, num
, param_len
;
1332 unsigned char * ucp
;
1335 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1336 param_len
= ucp
[3] + 4;
1337 if (6 != (0xf & ucp
[4]))
1338 return 0; /* only decode SAS log page */
1340 pout("Protocol Specific port log page for SAS SSP\n");
1341 show_sas_port_param(ucp
, param_len
);
1350 // See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific
1351 // log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol
1352 // Specific log page.
1353 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
1354 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
1355 // FAILSMART is returned.
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"
1415 static const char * transport_proto_arr
[] = {
1416 "Fibre channel (FCP-2)",
1417 "Parallel SCSI (SPI-4)",
1419 "IEEE 1394 (SBP-2)",
1434 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1436 scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1438 char timedatetz
[DATEANDEPOCHLEN
];
1439 struct scsi_iec_mode_page iec
;
1440 int err
, iec_err
, len
, req_len
, avail_len
, n
;
1445 int form_factor
= 0;
1448 memset(gBuf
, 0, 96);
1450 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1452 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1453 pout("Retrying with a 64 byte Standard Inquiry\n");
1455 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1457 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1459 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1460 scsiErrString(err
));
1465 avail_len
= gBuf
[4] + 5;
1466 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1467 peri_dt
= gBuf
[0] & 0x1f;
1468 if (peripheral_type
)
1469 *peripheral_type
= peri_dt
;
1473 pout("Short INQUIRY response, skip product id\n");
1478 if (all
&& (0 != strncmp((char *)&gBuf
[8], "ATA", 3))) {
1479 char vendor
[8+1], product
[16+1], revision
[4+1];
1480 scsi_format_id_string(vendor
, (const unsigned char *)&gBuf
[8], 8);
1481 scsi_format_id_string(product
, (const unsigned char *)&gBuf
[16], 16);
1482 scsi_format_id_string(revision
, (const unsigned char *)&gBuf
[32], 4);
1484 pout("=== START OF INFORMATION SECTION ===\n");
1485 pout("Vendor: %.8s\n", vendor
);
1486 pout("Product: %.16s\n", product
);
1487 if (gBuf
[32] >= ' ')
1488 pout("Revision: %.4s\n", revision
);
1491 if (!*device
->get_req_type()/*no type requested*/ &&
1492 (0 == strncmp((char *)&gBuf
[8], "ATA", 3))) {
1493 pout("\nProbable ATA device behind a SAT layer\n"
1494 "Try an additional '-d ata' or '-d sat' argument.\n");
1500 protect
= gBuf
[5] & 0x1; /* from and including SPC-3 */
1502 if (! is_tape
) { /* only do this for disks */
1503 unsigned int lb_size
= 0;
1504 unsigned char lb_prov_resp
[8];
1508 int lb_per_pb_exp
= 0;
1509 uint64_t capacity
= scsiGetSize(device
, &lb_size
, &lb_per_pb_exp
);
1512 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1513 format_capacity(si_str
, sizeof(si_str
), capacity
);
1514 pout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1515 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u", lb_size
);
1516 pout("Logical block size: %s bytes\n", lb_str
);
1520 if (protect
|| lb_per_pb_exp
) {
1521 unsigned char rc16_12
[20] = {0, };
1523 if (0 == scsiGetProtPBInfo(device
, rc16_12
)) {
1524 lb_per_pb_exp
= rc16_12
[1] & 0xf; /* just in case */
1525 if (lb_per_pb_exp
> 0) {
1526 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u",
1527 (lb_size
* (1 << lb_per_pb_exp
)));
1528 pout("Physical block size: %s bytes\n", lb_str
);
1529 n
= ((rc16_12
[2] & 0x3f) << 8) + rc16_12
[3];
1530 pout("Lowest aligned LBA: %d\n", n
);
1532 if (rc16_12
[0] & 0x1) { /* PROT_EN set */
1533 int p_type
= ((rc16_12
[0] >> 1) & 0x7);
1537 pout("Formatted with type 1 protection\n");
1540 pout("Formatted with type 2 protection\n");
1543 pout("Formatted with type 3 protection\n");
1546 pout("Formatted with unknown protection type [%d]\n",
1550 int p_i_exp
= ((rc16_12
[1] >> 4) & 0xf);
1553 pout("%d protection information intervals per "
1554 "logical block\n", (1 << p_i_exp
));
1556 /* Pick up some LB provisioning info since its available */
1557 lbpme
= !! (rc16_12
[2] & 0x80);
1558 lbprz
= !! (rc16_12
[2] & 0x40);
1561 if (0 == scsiInquiryVpd(device
, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING
,
1562 lb_prov_resp
, sizeof(lb_prov_resp
))) {
1563 int prov_type
= lb_prov_resp
[6] & 0x7;
1566 lbprz
= !! (lb_prov_resp
[5] & 0x4);
1567 switch (prov_type
) {
1569 pout("Logical block provisioning type unreported, "
1570 "LBPME=%d, LBPRZ=%d\n", lbpme
, lbprz
);
1573 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz
);
1576 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz
);
1579 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1583 } else if (1 == lbpme
)
1584 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz
);
1586 int rpm
= scsiGetRPM(device
, modese_len
, &form_factor
);
1589 pout("Rotation Rate: Solid State Device\n");
1591 pout("Rotation Rate: %d rpm\n", rpm
);
1593 if (form_factor
> 0) {
1594 const char * cp
= NULL
;
1596 switch (form_factor
) {
1614 pout("Form Factor: %s inches\n", cp
);
1618 /* Do this here to try and detect badly conforming devices (some USB
1619 keys) that will lock up on a InquiryVpd or log sense or ... */
1620 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1621 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1622 pout(">> Terminate command early due to bad response to IEC "
1629 modese_len
= iec
.modese_len
;
1631 if (! dont_print_serial_number
) {
1632 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_DEVICE_IDENTIFICATION
,
1637 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
1639 pout("Logical Unit id: %s\n", s
);
1640 } else if (scsi_debugmode
> 0) {
1642 if (SIMPLE_ERR_BAD_RESP
== err
)
1643 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1645 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1648 if (0 == (err
= scsiInquiryVpd(device
, SCSI_VPD_UNIT_SERIAL_NUMBER
,
1653 gBuf
[4 + len
] = '\0';
1654 scsi_format_id_string(serial
, &gBuf
[4], len
);
1655 pout("Serial number: %s\n", serial
);
1656 } else if (scsi_debugmode
> 0) {
1658 if (SIMPLE_ERR_BAD_RESP
== err
)
1659 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1661 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1666 // print SCSI peripheral device type
1667 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1668 sizeof(peripheral_dt_arr
[0])))
1669 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1671 pout("Device type: <%d>\n", peri_dt
);
1673 // See if transport protocol is known
1675 transport
= scsiFetchTransportProtocol(device
, modese_len
);
1676 if ((transport
>= 0) && (transport
<= 0xf))
1677 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
1679 // print current time and date and timezone
1680 dateandtimezone(timedatetz
);
1681 pout("Local Time is: %s\n", timedatetz
);
1683 if ((SCSI_PT_SEQUENTIAL_ACCESS
== *peripheral_type
) ||
1684 (SCSI_PT_MEDIUM_CHANGER
== *peripheral_type
))
1686 // See if unit accepts SCSI commmands from us
1687 if ((err
= scsiTestUnitReady(device
))) {
1688 if (SIMPLE_ERR_NOT_READY
== err
) {
1691 pout("device is NOT READY (e.g. spun down, busy)\n");
1693 pout("device is NOT READY (e.g. no tape)\n");
1695 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1697 pout("NO MEDIUM present on device\n");
1699 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1701 pout("device becoming ready (wait)\n");
1705 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1708 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1714 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
1715 if (scsi_debugmode
> 0)
1716 pout(" [%s]\n", scsiErrString(iec_err
));
1724 pout("SMART support is: Available - device has SMART capability.\n"
1725 "SMART support is: %s\n",
1726 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1727 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1728 "Temperature Warning: Enabled" :
1729 "Temperature Warning: Disabled or Not Supported");
1734 scsiSmartEnable(scsi_device
* device
)
1736 struct scsi_iec_mode_page iec
;
1739 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1741 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1742 scsiErrString(err
));
1746 modese_len
= iec
.modese_len
;
1748 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1750 pout("unable to enable Exception control and warning [%s]\n",
1751 scsiErrString(err
));
1755 /* Need to refetch 'iec' since could be modified by previous call */
1756 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1757 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1758 scsiErrString(err
));
1761 modese_len
= iec
.modese_len
;
1763 pout("Informational Exceptions (SMART) %s\n",
1764 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1765 pout("Temperature warning %s\n",
1766 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1771 scsiSmartDisable(scsi_device
* device
)
1773 struct scsi_iec_mode_page iec
;
1776 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1778 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1779 scsiErrString(err
));
1783 modese_len
= iec
.modese_len
;
1785 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1787 pout("unable to disable Exception control and warning [%s]\n",
1788 scsiErrString(err
));
1792 /* Need to refetch 'iec' since could be modified by previous call */
1793 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1794 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1795 scsiErrString(err
));
1798 modese_len
= iec
.modese_len
;
1800 pout("Informational Exceptions (SMART) %s\n",
1801 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1802 pout("Temperature warning %s\n",
1803 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1808 scsiPrintTemp(scsi_device
* device
)
1813 if (scsiGetTemp(device
, &temp
, &trip
))
1818 pout("Current Drive Temperature: %d C\n", temp
);
1820 pout("Current Drive Temperature: <not available>\n");
1823 pout("Drive Trip Temperature: %d C\n", trip
);
1828 /* Main entry point used by smartctl command. Return 0 for success */
1830 scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1832 int checkedSupportedLogPages
= 0;
1833 UINT8 peripheral_type
= 0;
1835 int res
, durationSec
;
1836 struct scsi_sense_disect sense_info
;
1838 bool any_output
= options
.drive_info
;
1840 if (supported_vpd_pages_p
) {
1841 delete supported_vpd_pages_p
;
1842 supported_vpd_pages_p
= NULL
;
1844 supported_vpd_pages_p
= new supported_vpd_pages(device
);
1846 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1851 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1855 // Print read look-ahead status for disks
1856 short int wce
= -1, rcd
= -1;
1857 if (options
.get_rcd
|| options
.get_wce
) {
1858 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
)
1859 res
= scsiGetSetCache(device
, modese_len
, &wce
, &rcd
);
1861 res
= -1; // fetch for disks only
1865 if (options
.get_rcd
) {
1866 pout("Read Cache is: %s\n",
1867 res
? "Unavailable" : // error
1868 rcd
? "Disabled" : "Enabled");
1871 if (options
.get_wce
) {
1872 pout("Writeback Cache is: %s\n",
1873 res
? "Unavailable" : // error
1874 !wce
? "Disabled" : "Enabled");
1876 if (options
.drive_info
)
1879 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1880 if ( options
.smart_disable
|| options
.smart_enable
1881 || options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1882 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1884 if (options
.smart_enable
) {
1885 if (scsiSmartEnable(device
))
1886 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1890 if (options
.smart_disable
) {
1891 if (scsiSmartDisable(device
))
1892 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1896 if (options
.smart_auto_save_enable
) {
1897 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1898 pout("Enable autosave (clear GLTSD bit) failed\n");
1899 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1902 pout("Autosave enabled (GLTSD bit set).\n");
1907 // Enable/Disable write cache
1908 if (options
.set_wce
&& SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1909 short int enable
= wce
= (options
.set_wce
> 0);
1911 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1912 pout("Write cache %sable failed: %s\n", (enable
? "en" : "dis"),
1913 device
->get_errmsg());
1914 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1917 pout("Write cache %sabled\n", (enable
? "en" : "dis"));
1921 // Enable/Disable read cache
1922 if (options
.set_rcd
&& SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1923 short int enable
= (options
.set_rcd
> 0);
1926 if (scsiGetSetCache(device
, modese_len
, &wce
, &rcd
)) {
1927 pout("Read cache %sable failed: %s\n", (enable
? "en" : "dis"),
1928 device
->get_errmsg());
1929 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1932 pout("Read cache %sabled\n", (enable
? "en" : "dis"));
1936 if (options
.smart_auto_save_disable
) {
1937 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1938 pout("Disable autosave (set GLTSD bit) failed\n");
1939 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1942 pout("Autosave disabled (GLTSD bit cleared).\n");
1946 if ( options
.smart_disable
|| options
.smart_enable
1947 || options
.smart_auto_save_disable
|| options
.smart_auto_save_enable
)
1948 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
1950 // START OF READ-ONLY OPTIONS APART FROM -V and -i
1951 if ( options
.smart_check_status
|| options
.smart_ss_media_log
1952 || options
.smart_vendor_attrib
|| options
.smart_error_log
1953 || options
.smart_selftest_log
|| options
.smart_vendor_attrib
1954 || options
.smart_background_log
|| options
.sasphy
1956 pout("=== START OF READ SMART DATA SECTION ===\n");
1958 if (options
.smart_check_status
) {
1959 scsiGetSupportedLogPages(device
);
1960 checkedSupportedLogPages
= 1;
1961 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1962 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
)) { /* tape device */
1963 if (gTapeAlertsLPage
) {
1964 if (options
.drive_info
)
1965 pout("TapeAlert Supported\n");
1966 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
1967 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
1970 pout("TapeAlert Not Supported\n");
1971 } else { /* disk, cd/dvd, enclosure, etc */
1972 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
1974 returnval
|= FAILSTATUS
;
1976 returnval
|= FAILSMART
;
1982 if (options
.smart_ss_media_log
) {
1983 if (! checkedSupportedLogPages
)
1984 scsiGetSupportedLogPages(device
);
1987 res
= scsiPrintSSMedia(device
);
1989 failuretest(OPTIONAL_CMD
, returnval
|=res
);
1992 if (options
.smart_vendor_attrib
) {
1993 if (! checkedSupportedLogPages
)
1994 scsiGetSupportedLogPages(device
);
1996 scsiPrintTemp(device
);
1998 if (gStartStopLPage
)
1999 scsiGetStartStopData(device
);
2000 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
2001 scsiPrintGrownDefectListLen(device
);
2002 if (gSeagateCacheLPage
)
2003 scsiPrintSeagateCacheLPage(device
);
2004 if (gSeagateFactoryLPage
)
2005 scsiPrintSeagateFactoryLPage(device
);
2009 if (options
.smart_error_log
) {
2010 if (! checkedSupportedLogPages
)
2011 scsiGetSupportedLogPages(device
);
2012 scsiPrintErrorCounterLog(device
);
2013 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
2014 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2015 "Enable Save with '-S on']\n");
2018 if (options
.smart_selftest_log
) {
2019 if (! checkedSupportedLogPages
)
2020 scsiGetSupportedLogPages(device
);
2023 res
= scsiPrintSelfTest(device
);
2025 pout("Device does not support Self Test logging\n");
2026 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2029 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2032 if (options
.smart_background_log
) {
2033 if (! checkedSupportedLogPages
)
2034 scsiGetSupportedLogPages(device
);
2036 if (gBackgroundResultsLPage
)
2037 res
= scsiPrintBackgroundResults(device
);
2039 pout("Device does not support Background scan results logging\n");
2040 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
2043 failuretest(OPTIONAL_CMD
, returnval
|=res
);
2046 if (options
.smart_default_selftest
) {
2047 if (scsiSmartDefaultSelfTest(device
))
2048 return returnval
| FAILSMART
;
2049 pout("Default Self Test Successful\n");
2052 if (options
.smart_short_cap_selftest
) {
2053 if (scsiSmartShortCapSelfTest(device
))
2054 return returnval
| FAILSMART
;
2055 pout("Short Foreground Self Test Successful\n");
2058 // check if another test is running
2059 if (options
.smart_short_selftest
|| options
.smart_extend_selftest
) {
2060 if (!scsiRequestSense(device
, &sense_info
) &&
2061 (sense_info
.asc
== 0x04 && sense_info
.ascq
== 0x09)) {
2062 if (!options
.smart_selftest_force
) {
2063 pout("Can't start self-test without aborting current test");
2064 if (sense_info
.progress
!= -1) {
2065 pout(" (%d%% remaining)",
2066 100 - sense_info
.progress
* 100 / 65535);
2068 pout(",\nadd '-t force' option to override, or run 'smartctl -X' "
2069 "to abort test.\n");
2073 scsiSmartSelfTestAbort(device
);
2076 if (options
.smart_short_selftest
) {
2077 if (scsiSmartShortSelfTest(device
))
2078 return returnval
| FAILSMART
;
2079 pout("Short Background Self Test has begun\n");
2080 pout("Use smartctl -X to abort test\n");
2083 if (options
.smart_extend_selftest
) {
2084 if (scsiSmartExtendSelfTest(device
))
2085 return returnval
| FAILSMART
;
2086 pout("Extended Background Self Test has begun\n");
2087 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
2088 modese_len
)) && (durationSec
> 0)) {
2089 time_t t
= time(NULL
);
2092 pout("Please wait %d minutes for test to complete.\n",
2094 pout("Estimated completion time: %s\n", ctime(&t
));
2096 pout("Use smartctl -X to abort test\n");
2099 if (options
.smart_extend_cap_selftest
) {
2100 if (scsiSmartExtendCapSelfTest(device
))
2101 return returnval
| FAILSMART
;
2102 pout("Extended Foreground Self Test Successful\n");
2104 if (options
.smart_selftest_abort
) {
2105 if (scsiSmartSelfTestAbort(device
))
2106 return returnval
| FAILSMART
;
2107 pout("Self Test returned without error\n");
2110 if (options
.sasphy
) {
2111 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
2112 return returnval
| FAILSMART
;
2117 pout("SCSI device successfully opened\n\n"
2118 "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");