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-10 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
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 3307 2011-03-31 14:54:58Z dpgilbert $"
49 UINT8 gBuf
[GBUF_SIZE
];
50 #define LOG_RESP_LEN 252
51 #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
52 #define LOG_RESP_TAPE_ALERT_LEN 0x144
54 /* Log pages supported */
55 static int gSmartLPage
= 0; /* Informational Exceptions log page */
56 static int gTempLPage
= 0;
57 static int gSelfTestLPage
= 0;
58 static int gStartStopLPage
= 0;
59 static int gReadECounterLPage
= 0;
60 static int gWriteECounterLPage
= 0;
61 static int gVerifyECounterLPage
= 0;
62 static int gNonMediumELPage
= 0;
63 static int gLastNErrorLPage
= 0;
64 static int gBackgroundResultsLPage
= 0;
65 static int gProtocolSpecificLPage
= 0;
66 static int gTapeAlertsLPage
= 0;
67 static int gSeagateCacheLPage
= 0;
68 static int gSeagateFactoryLPage
= 0;
70 /* Mode pages supported */
71 static int gIecMPage
= 1; /* N.B. assume it until we know otherwise */
73 /* Remember last successful mode sense/select command */
74 static int modese_len
= 0;
76 static void scsiGetSupportedLogPages(scsi_device
* device
)
80 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
82 if (scsi_debugmode
> 0)
83 pout("Log Sense for supported pages failed [%s]\n",
88 for (i
= 4; i
< gBuf
[3] + LOGPAGEHDRSIZE
; i
++) {
91 case READ_ERROR_COUNTER_LPAGE
:
92 gReadECounterLPage
= 1;
94 case WRITE_ERROR_COUNTER_LPAGE
:
95 gWriteECounterLPage
= 1;
97 case VERIFY_ERROR_COUNTER_LPAGE
:
98 gVerifyECounterLPage
= 1;
100 case LAST_N_ERROR_LPAGE
:
101 gLastNErrorLPage
= 1;
103 case NON_MEDIUM_ERROR_LPAGE
:
104 gNonMediumELPage
= 1;
106 case TEMPERATURE_LPAGE
:
109 case STARTSTOP_CYCLE_COUNTER_LPAGE
:
112 case SELFTEST_RESULTS_LPAGE
:
118 case BACKGROUND_RESULTS_LPAGE
:
119 gBackgroundResultsLPage
= 1;
121 case PROTOCOL_SPECIFIC_LPAGE
:
122 gProtocolSpecificLPage
= 1;
124 case TAPE_ALERTS_LPAGE
:
125 gTapeAlertsLPage
= 1;
127 case SEAGATE_CACHE_LPAGE
:
128 gSeagateCacheLPage
= 1;
130 case SEAGATE_FACTORY_LPAGE
:
131 gSeagateFactoryLPage
= 1;
139 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
140 (or at least something to report). */
141 static int scsiGetSmartData(scsi_device
* device
, bool attribs
)
145 UINT8 currenttemp
= 0;
151 if (scsiCheckIE(device
, gSmartLPage
, gTempLPage
, &asc
, &ascq
,
152 ¤ttemp
, &triptemp
)) {
153 /* error message already announced */
158 cp
= scsiGetIEString(asc
, ascq
);
162 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp
, asc
, ascq
);
164 } else if (gIecMPage
)
165 pout("SMART Health Status: OK\n");
167 if (attribs
&& !gTempLPage
) {
168 if (currenttemp
|| triptemp
)
171 if (255 != currenttemp
)
172 pout("Current Drive Temperature: %d C\n", currenttemp
);
174 pout("Current Drive Temperature: <not available>\n");
177 pout("Drive Trip Temperature: %d C\n", triptemp
);
183 // Returns number of logged errors or zero if none or -1 if fetching
185 static const char * const severities
= "CWI";
187 static int scsiGetTapeAlertsData(scsi_device
* device
, int peripheral_type
)
189 unsigned short pagelength
;
190 unsigned short parametercode
;
197 if ((err
= scsiLogSense(device
, TAPE_ALERTS_LPAGE
, 0, gBuf
,
198 LOG_RESP_TAPE_ALERT_LEN
, LOG_RESP_TAPE_ALERT_LEN
))) {
199 pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err
));
203 if (gBuf
[0] != 0x2e) {
204 pout("TapeAlerts Log Sense Failed\n");
208 pagelength
= (unsigned short) gBuf
[2] << 8 | gBuf
[3];
210 for (s
=severities
; *s
; s
++) {
211 for (i
= 4; i
< pagelength
; i
+= 5) {
212 parametercode
= (unsigned short) gBuf
[i
] << 8 | gBuf
[i
+1];
215 ts
= SCSI_PT_MEDIUM_CHANGER
== peripheral_type
?
216 scsiTapeAlertsChangerDevice(parametercode
) :
217 scsiTapeAlertsTapeDevice(parametercode
);
220 pout("TapeAlert Errors (C=Critical, W=Warning, I=Informational):\n");
221 pout("[0x%02x] %s\n", parametercode
, ts
);
230 pout("TapeAlert: OK\n");
235 static void scsiGetStartStopData(scsi_device
* device
)
238 int err
, len
, k
, extra
, pc
;
241 if ((err
= scsiLogSense(device
, STARTSTOP_CYCLE_COUNTER_LPAGE
, 0, gBuf
,
244 pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err
));
248 if ((gBuf
[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE
) {
250 pout("StartStop Log Sense Failed, page mismatch\n");
254 len
= ((gBuf
[2] << 8) | gBuf
[3]);
256 for (k
= len
; k
> 0; k
-= extra
, ucp
+= extra
) {
259 pout("StartStop Log Sense Failed: short\n");
264 pc
= (ucp
[0] << 8) + ucp
[1];
268 pout("Manufactured in week %.2s of year %.4s\n", ucp
+ 8,
272 /* ignore Accounting date */
276 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
278 pout("Specified cycle count over device lifetime: %u\n",
284 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
286 pout("Accumulated start-stop cycles: %u\n", u
);
291 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
293 pout("Specified load-unload count over device "
294 "lifetime: %u\n", u
);
299 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
301 pout("Accumulated load-unload cycles: %u\n", u
);
311 static void scsiPrintGrownDefectListLen(scsi_device
* device
)
313 int err
, dl_format
, dl_len
, div
;
316 if ((err
= scsiReadDefect10(device
, 0 /* req_plist */, 1 /* req_glist */,
317 4 /* bytes from index */, gBuf
, 4))) {
318 if (scsi_debugmode
> 0) {
320 pout("Read defect list (10) Failed: %s\n", scsiErrString(err
));
325 if (0x8 != (gBuf
[1] & 0x18)) {
327 pout("Read defect list: asked for grown list but didn't get it\n");
332 dl_format
= (gBuf
[1] & 0x7);
334 case 0: /* short block */
337 case 3: /* long block */
338 case 4: /* bytes from index */
339 case 5: /* physical sector */
344 pout("defect list format %d unknown\n", dl_format
);
348 dl_len
= (gBuf
[2] << 8) + gBuf
[3];
350 pout("Elements in grown defect list: 0\n");
353 pout("Grown defect list length=%d bytes [unknown "
354 "number of elements]\n", dl_len
);
356 pout("Elements in grown defect list: %d\n", dl_len
/ div
);
360 static void scsiPrintSeagateCacheLPage(scsi_device
* device
)
362 int k
, j
, num
, pl
, pc
, err
, len
;
367 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
370 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err
));
374 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
376 pout("Seagate Cache Log Sense Failed, page mismatch\n");
380 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
384 pc
= (ucp
[0] << 8) | ucp
[1];
387 case 0: case 1: case 2: case 3: case 4:
390 if (scsi_debugmode
> 0) {
392 pout("Vendor (Seagate) cache lpage has unexpected parameter"
401 pout("Vendor (Seagate) cache information\n");
405 pc
= (ucp
[0] << 8) | ucp
[1];
408 case 0: pout(" Blocks sent to initiator"); break;
409 case 1: pout(" Blocks received from initiator"); break;
410 case 2: pout(" Blocks read from cache and sent to initiator"); break;
411 case 3: pout(" Number of read and write commands whose size "
412 "<= segment size"); break;
413 case 4: pout(" Number of read and write commands whose size "
414 "> segment size"); break;
415 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
419 if (k
> (int)sizeof(ull
)) {
420 xp
+= (k
- (int)sizeof(ull
));
421 k
= (int)sizeof(ull
);
424 for (j
= 0; j
< k
; ++j
) {
429 pout(" = %"PRIu64
"\n", ull
);
435 static void scsiPrintSeagateFactoryLPage(scsi_device
* device
)
437 int k
, j
, num
, pl
, pc
, len
, err
, good
, bad
;
442 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
445 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err
));
449 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
451 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
455 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
461 pc
= (ucp
[0] << 8) | ucp
[1];
474 if ((good
< 2) || (bad
> 4)) { /* heuristic */
475 if (scsi_debugmode
> 0) {
477 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
478 "unexpected parameters, skip\n");
483 pout("Vendor (Seagate/Hitachi) factory information\n");
487 pc
= (ucp
[0] << 8) | ucp
[1];
491 case 0: pout(" number of hours powered up");
494 case 8: pout(" number of minutes until next internal SMART test");
498 if (scsi_debugmode
> 0) {
500 pout("Vendor (Seagate/Hitachi) factory lpage: "
501 "unknown parameter code [0x%x]\n", pc
);
509 if (k
> (int)sizeof(ull
)) {
510 xp
+= (k
- (int)sizeof(ull
));
511 k
= (int)sizeof(ull
);
514 for (j
= 0; j
< k
; ++j
) {
520 pout(" = %.2f\n", uint64_to_double(ull
) / 60.0 );
522 pout(" = %"PRIu64
"\n", ull
);
529 static void scsiPrintErrorCounterLog(scsi_device
* device
)
531 struct scsiErrorCounter errCounterArr
[3];
532 struct scsiErrorCounter
* ecp
;
533 struct scsiNonMediumError nme
;
534 int found
[3] = {0, 0, 0};
535 const char * pageNames
[3] = {"read: ", "write: ", "verify: "};
538 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
539 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
540 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
543 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
544 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
545 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
548 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
549 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
550 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
551 ecp
= &errCounterArr
[2];
552 for (int k
= 0; k
< 7; ++k
) {
553 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
559 if (found
[0] || found
[1] || found
[2]) {
560 pout("\nError counter log:\n");
561 pout(" Errors Corrected by Total "
562 "Correction Gigabytes Total\n");
563 pout(" ECC rereads/ errors "
564 "algorithm processed uncorrected\n");
565 pout(" fast | delayed rewrites corrected "
566 "invocations [10^9 bytes] errors\n");
567 for (int k
= 0; k
< 3; ++k
) {
570 ecp
= &errCounterArr
[k
];
571 pout("%s%8"PRIu64
" %8"PRIu64
" %8"PRIu64
" %8"PRIu64
" %8"PRIu64
,
572 pageNames
[k
], ecp
->counter
[0], ecp
->counter
[1],
573 ecp
->counter
[2], ecp
->counter
[3], ecp
->counter
[4]);
574 processed_gb
= uint64_to_double(ecp
->counter
[5]) / 1000000000.0;
575 pout(" %12.3f %8"PRIu64
"\n", processed_gb
, ecp
->counter
[6]);
579 pout("\nError Counter logging not supported\n");
580 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
581 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
582 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
584 pout("\nNon-medium error count: %8"PRIu64
"\n", nme
.counterPC0
);
586 pout("Track following error count [Hitachi]: %8"PRIu64
"\n",
589 pout("Positioning error count [Hitachi]: %8"PRIu64
"\n",
592 if (gLastNErrorLPage
&& (0 == scsiLogSense(device
,
593 LAST_N_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LONG_LEN
, 0))) {
594 int num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
595 int truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
597 num
= LOG_RESP_LONG_LEN
;
598 unsigned char * ucp
= gBuf
+ 4;
601 pout("\nNo error events logged\n");
603 pout("\nLast n error events log page\n");
604 for (int k
= num
, pl
; k
> 0; k
-= pl
, ucp
+= pl
) {
606 pout(" <<short Last n error events log page>>\n");
610 int pc
= (ucp
[0] << 8) + ucp
[1];
612 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
613 pout(" Error event %d:\n", pc
);
614 pout(" [binary]:\n");
615 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
616 } else if (ucp
[2] & 0x1) {
617 pout(" Error event %d:\n", pc
);
618 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
620 if (scsi_debugmode
> 0) {
621 pout(" Error event %d:\n", pc
);
622 pout(" [data counter??]:\n");
623 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
629 pout(" >>>> log truncated, fetched %d of %d available "
630 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
635 static const char * self_test_code
[] = {
646 static const char * self_test_result
[] = {
648 "Aborted (by user command)",
649 "Aborted (device reset ?) ",
650 "Unknown error, incomplete",
651 "Completed, segment failed",
652 "Failed in first segment ",
653 "Failed in second segment ",
654 "Failed in segment --> ",
662 "Self test in progress ..."
665 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
666 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
667 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
668 // FAILSMART is returned.
669 static int scsiPrintSelfTest(scsi_device
* device
)
671 int num
, k
, n
, res
, err
, durationSec
;
677 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
678 LOG_RESP_SELF_TEST_LEN
, 0))) {
680 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err
));
684 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
686 pout("Self-test Log Sense Failed, page mismatch\n");
690 // compute page length
691 num
= (gBuf
[2] << 8) + gBuf
[3];
692 // Log sense page length 0x190 bytes
695 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num
);
699 // loop through the twenty possible entries
700 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
703 // timestamp in power-on hours (or zero if test in progress)
704 n
= (ucp
[6] << 8) | ucp
[7];
706 // The spec says "all 20 bytes will be zero if no test" but
707 // DG has found otherwise. So this is a heuristic.
708 if ((0 == n
) && (0 == ucp
[4]))
711 // only print header if needed
713 pout("\nSMART Self-test log\n");
714 pout("Num Test Status segment "
715 "LifeTime LBA_first_err [SK ASC ASQ]\n");
716 pout(" Description number "
721 // print parameter code (test number) & self-test code text
722 pout("#%2d %s", (ucp
[0] << 8) | ucp
[1],
723 self_test_code
[(ucp
[4] >> 5) & 0x7]);
725 // check the self-test result nibble, using the self-test results
726 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
727 switch ((res
= ucp
[4] & 0xf)) {
729 // an unknown error occurred while the device server
730 // was processing the self-test and the device server
731 // was unable to complete the self-test
735 // the self-test completed with a failure in a test
736 // segment, and the test segment that failed is not
741 // the first segment of the self-test failed
745 // the second segment of the self-test failed
749 // another segment of the self-test failed and which
750 // test is indicated by the contents of the SELF-TEST
757 pout(" %s", self_test_result
[res
]);
759 // self-test number identifies test that failed and consists
760 // of either the number of the segment that failed during
761 // the test, or the number of the test that failed and the
762 // number of the segment in which the test was run, using a
763 // vendor-specific method of putting both numbers into a
766 pout(" %3d", (int)ucp
[5]);
770 // print time that the self-test was completed
771 if (n
==0 && res
==0xf)
772 // self-test in progress
777 // construct 8-byte integer address of first failure
778 for (i
= 0; i
< 8; i
++) {
782 // print Address of First Failure, if sensible
783 if ((~(uint64_t)0 != ull
) && (res
> 0) && (res
< 0xf)) {
786 // was hex but change to decimal to conform with ATA
787 snprintf(buff
, sizeof(buff
), "%"PRIu64
, ull
);
788 // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull);
793 // if sense key nonzero, then print it, along with
794 // additional sense code and additional sense code qualifier
796 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
801 // if header never printed, then there was no output
803 pout("No self-tests have been logged\n");
806 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
807 modese_len
)) && (durationSec
> 0)) {
808 pout("Long (extended) Self Test duration: %d seconds "
809 "[%.1f minutes]\n", durationSec
, durationSec
/ 60.0);
814 static const char * bms_status
[] = {
817 "pre-scan is active",
818 "halted due to fatal error",
819 "halted due to a vendor specific pattern of error",
820 "halted due to medium formatted without P-List",
821 "halted - vendor specific cause",
822 "halted due to temperature out of range",
823 "waiting until BMS interval timer expires", /* 8 */
826 static const char * reassign_status
[] = {
828 "Require Write or Reassign Blocks command",
829 "Successfully reassigned",
831 "Reassignment by disk failed",
832 "Recovered via rewrite in-place",
833 "Reassigned by app, has valid data",
834 "Reassigned by app, has no valid data",
835 "Unsuccessfully reassigned by app", /* 8 */
838 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
839 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
840 // and up to 2048 events (although would hope to have less). May set
841 // FAILLOG if serious errors detected (in the future).
842 static int scsiPrintBackgroundResults(scsi_device
* device
)
844 int num
, j
, m
, err
, pc
, pl
, truncated
;
850 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
851 LOG_RESP_LONG_LEN
, 0))) {
853 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err
));
857 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
859 pout("Background scan results Log Sense Failed, page mismatch\n");
863 // compute page length
864 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
867 pout("Background scan results Log Sense length is %d, no scan "
872 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
874 num
= LOG_RESP_LONG_LEN
;
878 pc
= (ucp
[0] << 8) | ucp
[1];
885 pout("\nBackground scan results log\n");
888 if ((pl
< 16) || (num
< 16)) {
893 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
894 pout("%s\n", bms_status
[j
]);
896 pout("unknown [0x%x] background scan status value\n", j
);
897 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
898 pout(" Accumulated power on time, hours:minutes %d:%02d "
899 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
900 pout(" Number of background scans performed: %d, ",
901 (ucp
[10] << 8) + ucp
[11]);
902 pout("scan progress: %.2f%%\n",
903 (double)((ucp
[12] << 8) + ucp
[13]) * 100.0 / 65536.0);
904 pout(" Number of background medium scans performed: %d\n",
905 (ucp
[14] << 8) + ucp
[15]);
910 pout("\nBackground scan results log\n");
914 pout("\n # when lba(hex) [sk,asc,ascq] "
915 "reassign_status\n");
918 if ((pl
< 24) || (num
< 24)) {
920 pout("parameter length >= 24 expected, got %d\n", pl
);
923 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
924 pout("%4d:%02d ", (j
/ 60), (j
% 60));
925 for (m
= 0; m
< 8; ++m
)
926 pout("%02x", ucp
[16 + m
]);
927 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
928 j
= (ucp
[8] >> 4) & 0xf;
930 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
931 pout("%s\n", reassign_status
[j
]);
933 pout("Reassign status: reserved [0x%x]\n", j
);
940 pout(" >>>> log truncated, fetched %d of %d available "
941 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
946 static void show_sas_phy_event_info(int peis
, unsigned int val
,
956 pout(" Invalid word count: %u\n", val
);
959 pout(" Running disparity error count: %u\n", val
);
962 pout(" Loss of dword synchronization count: %u\n", val
);
965 pout(" Phy reset problem count: %u\n", val
);
968 pout(" Elasticity buffer overflow count: %u\n", val
);
971 pout(" Received ERROR count: %u\n", val
);
974 pout(" Received address frame error count: %u\n", val
);
977 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
980 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
983 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
986 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
989 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val
);
992 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
995 pout(" Transmitted BREAK count: %u\n", val
);
998 pout(" Received BREAK count: %u\n", val
);
1001 pout(" Break timeout count: %u\n", val
);
1004 pout(" Connection count: %u\n", val
);
1007 pout(" Peak transmitted pathway blocked count: %u\n",
1009 pout(" Peak value detector threshold: %u\n",
1015 pout(" Peak transmitted arbitration wait time (us): "
1018 pout(" Peak transmitted arbitration wait time (ms): "
1019 "%u\n", 33 + (u
- 0x8000));
1020 u
= thresh_val
& 0xffff;
1022 pout(" Peak value detector threshold (us): %u\n",
1025 pout(" Peak value detector threshold (ms): %u\n",
1029 pout(" Peak arbitration time (us): %u\n", val
);
1030 pout(" Peak value detector threshold: %u\n", thresh_val
);
1033 pout(" Peak connection time (us): %u\n", val
);
1034 pout(" Peak value detector threshold: %u\n", thresh_val
);
1037 pout(" Transmitted SSP frame count: %u\n", val
);
1040 pout(" Received SSP frame count: %u\n", val
);
1043 pout(" Transmitted SSP frame error count: %u\n", val
);
1046 pout(" Received SSP frame error count: %u\n", val
);
1049 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1052 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1055 pout(" Transmitted SATA frame count: %u\n", val
);
1058 pout(" Received SATA frame count: %u\n", val
);
1061 pout(" SATA flow control buffer overflow count: %u\n", val
);
1064 pout(" Transmitted SMP frame count: %u\n", val
);
1067 pout(" Received SMP frame count: %u\n", val
);
1070 pout(" Received SMP frame error count: %u\n", val
);
1077 static void show_sas_port_param(unsigned char * ucp
, int param_len
)
1079 int j
, m
, n
, nphys
, pcb
, t
, sz
, spld_len
;
1080 unsigned char * vcp
;
1087 t
= (ucp
[0] << 8) | ucp
[1];
1088 pout("relative target port id = %d\n", t
);
1089 pout(" generation code = %d\n", ucp
[6]);
1091 pout(" number of phys = %d\n", nphys
);
1093 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1094 vcp
+= spld_len
, j
+= spld_len
) {
1095 pout(" phy identifier = %d\n", vcp
[1]);
1098 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1101 t
= ((0x70 & vcp
[4]) >> 4);
1103 case 0: snprintf(s
, sz
, "no device attached"); break;
1104 case 1: snprintf(s
, sz
, "end device"); break;
1105 case 2: snprintf(s
, sz
, "expander device"); break;
1106 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1107 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1109 pout(" attached device type: %s\n", s
);
1112 case 0: snprintf(s
, sz
, "unknown"); break;
1113 case 1: snprintf(s
, sz
, "power on"); break;
1114 case 2: snprintf(s
, sz
, "hard reset"); break;
1115 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1116 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1117 case 5: snprintf(s
, sz
, "mux mix up"); break;
1118 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1120 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1121 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1122 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1124 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1126 pout(" attached reason: %s\n", s
);
1127 t
= (vcp
[5] & 0xf0) >> 4;
1129 case 0: snprintf(s
, sz
, "unknown"); break;
1130 case 1: snprintf(s
, sz
, "power on"); break;
1131 case 2: snprintf(s
, sz
, "hard reset"); break;
1132 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1133 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1134 case 5: snprintf(s
, sz
, "mux mix up"); break;
1135 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1137 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1138 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1139 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1141 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1143 pout(" reason: %s\n", s
);
1146 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1148 case 1: snprintf(s
, sz
, "phy disabled"); break;
1149 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1151 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1153 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1155 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1157 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1159 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1160 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1161 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1162 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1164 pout(" negotiated logical link rate: %s\n", s
);
1165 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1166 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1167 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1168 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1169 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1170 ull
<<= 8; ull
|= vcp
[8 + n
];
1172 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1173 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1174 ull
<<= 8; ull
|= vcp
[16 + n
];
1176 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1177 pout(" attached phy identifier = %d\n", vcp
[24]);
1178 ui
= (vcp
[32] << 24) | (vcp
[33] << 16) | (vcp
[34] << 8) | vcp
[35];
1179 pout(" Invalid DWORD count = %u\n", ui
);
1180 ui
= (vcp
[36] << 24) | (vcp
[37] << 16) | (vcp
[38] << 8) | vcp
[39];
1181 pout(" Running disparity error count = %u\n", ui
);
1182 ui
= (vcp
[40] << 24) | (vcp
[41] << 16) | (vcp
[42] << 8) | vcp
[43];
1183 pout(" Loss of DWORD synchronization = %u\n", ui
);
1184 ui
= (vcp
[44] << 24) | (vcp
[45] << 16) | (vcp
[46] << 8) | vcp
[47];
1185 pout(" Phy reset problem = %u\n", ui
);
1186 if (spld_len
> 51) {
1188 unsigned char * xcp
;
1193 pout(" Phy event descriptors:\n");
1195 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1197 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1199 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1201 show_sas_phy_event_info(peis
, ui
, pvdt
);
1207 // Returns 1 if okay, 0 if non SAS descriptors
1208 static int show_protocol_specific_page(unsigned char * resp
, int len
)
1210 int k
, num
, param_len
;
1211 unsigned char * ucp
;
1214 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1215 param_len
= ucp
[3] + 4;
1216 if (6 != (0xf & ucp
[4]))
1217 return 0; /* only decode SAS log page */
1219 pout("Protocol Specific port log page for SAS SSP\n");
1220 show_sas_port_param(ucp
, param_len
);
1228 // See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific
1229 // log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol
1230 // Specific log page.
1231 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
1232 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
1233 // FAILSMART is returned.
1234 static int scsiPrintSasPhy(scsi_device
* device
, int reset
)
1238 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1239 LOG_RESP_LONG_LEN
, 0))) {
1241 pout("scsiPrintSasPhy Log Sense Failed [%s]\n", scsiErrString(err
));
1245 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1247 pout("Protocol specific Log Sense Failed, page mismatch\n");
1251 // compute page length
1252 num
= (gBuf
[2] << 8) + gBuf
[3];
1253 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1255 pout("Only support protocol specific log page on SAS devices\n");
1260 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1261 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1263 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n",
1264 scsiErrString(err
));
1273 static const char * peripheral_dt_arr
[] = {
1289 "optical card reader"
1292 static const char * transport_proto_arr
[] = {
1293 "Fibre channel (FCP-2)",
1294 "Parallel SCSI (SPI-4)",
1296 "IEEE 1394 (SBP-2)",
1311 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1312 static int scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1314 char timedatetz
[DATEANDEPOCHLEN
];
1315 struct scsi_iec_mode_page iec
;
1316 int err
, iec_err
, len
, req_len
, avail_len
;
1322 memset(gBuf
, 0, 96);
1324 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1326 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1327 pout("Retrying with a 64 byte Standard Inquiry\n");
1329 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1331 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1333 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1334 scsiErrString(err
));
1339 avail_len
= gBuf
[4] + 5;
1340 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1341 peri_dt
= gBuf
[0] & 0x1f;
1342 if (peripheral_type
)
1343 *peripheral_type
= peri_dt
;
1347 pout("Short INQUIRY response, skip product id\n");
1351 if (all
&& (0 != strncmp((char *)&gBuf
[8], "ATA", 3))) {
1352 pout("Vendor: %.8s\n", (char *)&gBuf
[8]);
1353 pout("Product: %.16s\n", (char *)&gBuf
[16]);
1354 if (gBuf
[32] >= ' ')
1355 pout("Revision: %.4s\n", (char *)&gBuf
[32]);
1358 if (!*device
->get_req_type()/*no type requested*/ &&
1359 (0 == strncmp((char *)&gBuf
[8], "ATA", 3))) {
1360 pout("\nProbable ATA device behind a SAT layer\n"
1361 "Try an additional '-d ata' or '-d sat' argument.\n");
1367 unsigned int lb_size
;
1371 uint64_t capacity
= scsiGetSize(device
, &lb_size
);
1374 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1375 format_capacity(si_str
, sizeof(si_str
), capacity
);
1376 pout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1377 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u", lb_size
);
1378 pout("Logical block size: %s bytes\n", lb_str
);
1381 /* Do this here to try and detect badly conforming devices (some USB
1382 keys) that will lock up on a InquiryVpd or log sense or ... */
1383 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1384 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1385 pout(">> Terminate command early due to bad response to IEC "
1392 modese_len
= iec
.modese_len
;
1394 if (! dont_print_serial_number
) {
1395 if (0 == (err
= scsiInquiryVpd(device
, 0x83, gBuf
, 200))) {
1399 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
1401 pout("Logical Unit id: %s\n", s
);
1402 } else if (scsi_debugmode
> 0) {
1404 if (SIMPLE_ERR_BAD_RESP
== err
)
1405 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1407 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1410 if (0 == (err
= scsiInquiryVpd(device
, 0x80, gBuf
, 64))) {
1412 gBuf
[4 + len
] = '\0';
1413 pout("Serial number: %s\n", &gBuf
[4]);
1414 } else if (scsi_debugmode
> 0) {
1416 if (SIMPLE_ERR_BAD_RESP
== err
)
1417 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1419 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1424 // print SCSI peripheral device type
1425 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1426 sizeof(peripheral_dt_arr
[0])))
1427 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1429 pout("Device type: <%d>\n", peri_dt
);
1431 // See if transport protocol is known
1433 transport
= scsiFetchTransportProtocol(device
, modese_len
);
1434 if ((transport
>= 0) && (transport
<= 0xf))
1435 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
1437 // print current time and date and timezone
1438 dateandtimezone(timedatetz
);
1439 pout("Local Time is: %s\n", timedatetz
);
1441 if ((SCSI_PT_SEQUENTIAL_ACCESS
== *peripheral_type
) ||
1442 (SCSI_PT_MEDIUM_CHANGER
== *peripheral_type
))
1444 // See if unit accepts SCSI commmands from us
1445 if ((err
= scsiTestUnitReady(device
))) {
1446 if (SIMPLE_ERR_NOT_READY
== err
) {
1449 pout("device is NOT READY (e.g. spun down, busy)\n");
1451 pout("device is NOT READY (e.g. no tape)\n");
1453 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1455 pout("NO MEDIUM present on device\n");
1457 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1459 pout("device becoming ready (wait)\n");
1463 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1466 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1472 pout("Device does not support SMART");
1473 if (scsi_debugmode
> 0)
1474 pout(" [%s]\n", scsiErrString(iec_err
));
1484 pout("Device supports SMART and is %s\n",
1485 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1486 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1487 "Temperature Warning Enabled" :
1488 "Temperature Warning Disabled or Not Supported");
1492 static int scsiSmartEnable(scsi_device
* device
)
1494 struct scsi_iec_mode_page iec
;
1497 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1499 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1500 scsiErrString(err
));
1504 modese_len
= iec
.modese_len
;
1506 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1508 pout("unable to enable Exception control and warning [%s]\n",
1509 scsiErrString(err
));
1513 /* Need to refetch 'iec' since could be modified by previous call */
1514 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1515 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1516 scsiErrString(err
));
1519 modese_len
= iec
.modese_len
;
1521 pout("Informational Exceptions (SMART) %s\n",
1522 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1523 pout("Temperature warning %s\n",
1524 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1528 static int scsiSmartDisable(scsi_device
* device
)
1530 struct scsi_iec_mode_page iec
;
1533 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1535 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1536 scsiErrString(err
));
1540 modese_len
= iec
.modese_len
;
1542 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1544 pout("unable to disable Exception control and warning [%s]\n",
1545 scsiErrString(err
));
1549 /* Need to refetch 'iec' since could be modified by previous call */
1550 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1551 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1552 scsiErrString(err
));
1555 modese_len
= iec
.modese_len
;
1557 pout("Informational Exceptions (SMART) %s\n",
1558 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1559 pout("Temperature warning %s\n",
1560 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1564 static void scsiPrintTemp(scsi_device
* device
)
1569 if (scsiGetTemp(device
, &temp
, &trip
))
1574 pout("Current Drive Temperature: %d C\n", temp
);
1576 pout("Current Drive Temperature: <not available>\n");
1579 pout("Drive Trip Temperature: %d C\n", trip
);
1582 /* Main entry point used by smartctl command. Return 0 for success */
1583 int scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1585 int checkedSupportedLogPages
= 0;
1586 UINT8 peripheral_type
= 0;
1588 int res
, durationSec
;
1590 bool any_output
= options
.drive_info
;
1592 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1597 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1601 if (options
.smart_enable
) {
1602 if (scsiSmartEnable(device
))
1603 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1607 if (options
.smart_disable
) {
1608 if (scsiSmartDisable(device
))
1609 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1613 if (options
.smart_auto_save_enable
) {
1614 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1615 pout("Enable autosave (clear GLTSD bit) failed\n");
1616 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1621 if (options
.smart_auto_save_disable
) {
1622 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1623 pout("Disable autosave (set GLTSD bit) failed\n");
1624 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1629 if (options
.smart_check_status
) {
1630 scsiGetSupportedLogPages(device
);
1631 checkedSupportedLogPages
= 1;
1632 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1633 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
)) { /* tape device */
1634 if (gTapeAlertsLPage
) {
1635 if (options
.drive_info
)
1636 pout("TapeAlert Supported\n");
1637 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
1638 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
1641 pout("TapeAlert Not Supported\n");
1642 } else { /* disk, cd/dvd, enclosure, etc */
1643 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
1645 returnval
|= FAILSTATUS
;
1647 returnval
|= FAILSMART
;
1652 if (options
.smart_vendor_attrib
) {
1653 if (! checkedSupportedLogPages
)
1654 scsiGetSupportedLogPages(device
);
1656 if (options
.smart_check_status
)
1658 scsiPrintTemp(device
);
1660 if (gStartStopLPage
)
1661 scsiGetStartStopData(device
);
1662 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1663 scsiPrintGrownDefectListLen(device
);
1664 if (gSeagateCacheLPage
)
1665 scsiPrintSeagateCacheLPage(device
);
1666 if (gSeagateFactoryLPage
)
1667 scsiPrintSeagateFactoryLPage(device
);
1671 if (options
.smart_error_log
) {
1672 if (! checkedSupportedLogPages
)
1673 scsiGetSupportedLogPages(device
);
1674 scsiPrintErrorCounterLog(device
);
1675 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
1676 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
1677 "Enable Save with '-S on']\n");
1680 if (options
.smart_selftest_log
) {
1681 if (! checkedSupportedLogPages
)
1682 scsiGetSupportedLogPages(device
);
1685 res
= scsiPrintSelfTest(device
);
1687 pout("Device does not support Self Test logging\n");
1688 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
1691 failuretest(OPTIONAL_CMD
, returnval
|=res
);
1694 if (options
.smart_background_log
) {
1695 if (! checkedSupportedLogPages
)
1696 scsiGetSupportedLogPages(device
);
1698 if (gBackgroundResultsLPage
)
1699 res
= scsiPrintBackgroundResults(device
);
1701 pout("Device does not support Background scan results logging\n");
1702 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
1705 failuretest(OPTIONAL_CMD
, returnval
|=res
);
1708 if (options
.smart_default_selftest
) {
1709 if (scsiSmartDefaultSelfTest(device
))
1710 return returnval
| FAILSMART
;
1711 pout("Default Self Test Successful\n");
1714 if (options
.smart_short_cap_selftest
) {
1715 if (scsiSmartShortCapSelfTest(device
))
1716 return returnval
| FAILSMART
;
1717 pout("Short Foreground Self Test Successful\n");
1720 if (options
.smart_short_selftest
) {
1721 if (scsiSmartShortSelfTest(device
))
1722 return returnval
| FAILSMART
;
1723 pout("Short Background Self Test has begun\n");
1724 pout("Use smartctl -X to abort test\n");
1727 if (options
.smart_extend_selftest
) {
1728 if (scsiSmartExtendSelfTest(device
))
1729 return returnval
| FAILSMART
;
1730 pout("Extended Background Self Test has begun\n");
1731 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
1732 modese_len
)) && (durationSec
> 0)) {
1733 time_t t
= time(NULL
);
1736 pout("Please wait %d minutes for test to complete.\n",
1738 pout("Estimated completion time: %s\n", ctime(&t
));
1740 pout("Use smartctl -X to abort test\n");
1743 if (options
.smart_extend_cap_selftest
) {
1744 if (scsiSmartExtendCapSelfTest(device
))
1745 return returnval
| FAILSMART
;
1746 pout("Extended Foreground Self Test Successful\n");
1748 if (options
.smart_selftest_abort
) {
1749 if (scsiSmartSelfTestAbort(device
))
1750 return returnval
| FAILSMART
;
1751 pout("Self Test returned without error\n");
1754 if (options
.sasphy
) {
1755 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
1756 return returnval
| FAILSMART
;
1761 pout("SCSI device successfully opened\n\n"
1762 "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");