4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
9 * Additional SCSI work:
10 * Copyright (C) 2003-9 Douglas Gilbert <dougg@torque.net>
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/
38 #include "atacmds.h" // smart_command_set
39 #include "dev_interface.h"
40 #include "scsiprint.h"
44 #define GBUF_SIZE 65535
46 const char * scsiprint_c_cvsid
= "$Id: scsiprint.cpp 2861 2009-07-24 16:47:03Z chrfranke $"
49 // control block which points to external global control variables
50 extern smartmonctrl
*con
;
52 UINT8 gBuf
[GBUF_SIZE
];
53 #define LOG_RESP_LEN 252
54 #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
55 #define LOG_RESP_TAPE_ALERT_LEN 0x144
57 /* Log pages supported */
58 static int gSmartLPage
= 0; /* Informational Exceptions log page */
59 static int gTempLPage
= 0;
60 static int gSelfTestLPage
= 0;
61 static int gStartStopLPage
= 0;
62 static int gReadECounterLPage
= 0;
63 static int gWriteECounterLPage
= 0;
64 static int gVerifyECounterLPage
= 0;
65 static int gNonMediumELPage
= 0;
66 static int gLastNErrorLPage
= 0;
67 static int gBackgroundResultsLPage
= 0;
68 static int gProtocolSpecificLPage
= 0;
69 static int gTapeAlertsLPage
= 0;
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;
79 // Compares failure type to policy in effect, and either exits or
80 // simply returns to the calling routine.
81 extern void failuretest(int type
, int returnvalue
);
83 static void scsiGetSupportedLogPages(scsi_device
* device
)
87 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
89 if (con
->reportscsiioctl
> 0)
90 pout("Log Sense for supported pages failed [%s]\n",
95 for (i
= 4; i
< gBuf
[3] + LOGPAGEHDRSIZE
; i
++) {
98 case READ_ERROR_COUNTER_LPAGE
:
99 gReadECounterLPage
= 1;
101 case WRITE_ERROR_COUNTER_LPAGE
:
102 gWriteECounterLPage
= 1;
104 case VERIFY_ERROR_COUNTER_LPAGE
:
105 gVerifyECounterLPage
= 1;
107 case LAST_N_ERROR_LPAGE
:
108 gLastNErrorLPage
= 1;
110 case NON_MEDIUM_ERROR_LPAGE
:
111 gNonMediumELPage
= 1;
113 case TEMPERATURE_LPAGE
:
116 case STARTSTOP_CYCLE_COUNTER_LPAGE
:
119 case SELFTEST_RESULTS_LPAGE
:
125 case BACKGROUND_RESULTS_LPAGE
:
126 gBackgroundResultsLPage
= 1;
128 case PROTOCOL_SPECIFIC_LPAGE
:
129 gProtocolSpecificLPage
= 1;
131 case TAPE_ALERTS_LPAGE
:
132 gTapeAlertsLPage
= 1;
134 case SEAGATE_CACHE_LPAGE
:
135 gSeagateCacheLPage
= 1;
137 case SEAGATE_FACTORY_LPAGE
:
138 gSeagateFactoryLPage
= 1;
146 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
147 (or at least something to report). */
148 static int scsiGetSmartData(scsi_device
* device
, bool attribs
)
152 UINT8 currenttemp
= 0;
158 if (scsiCheckIE(device
, gSmartLPage
, gTempLPage
, &asc
, &ascq
,
159 ¤ttemp
, &triptemp
)) {
160 /* error message already announced */
165 cp
= scsiGetIEString(asc
, ascq
);
169 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp
, asc
, ascq
);
171 } else if (gIecMPage
)
172 pout("SMART Health Status: OK\n");
174 if (attribs
&& !gTempLPage
) {
175 if (currenttemp
|| triptemp
)
178 if (255 != currenttemp
)
179 pout("Current Drive Temperature: %d C\n", currenttemp
);
181 pout("Current Drive Temperature: <not available>\n");
184 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";
194 static int scsiGetTapeAlertsData(scsi_device
* device
, int peripheral_type
)
196 unsigned short pagelength
;
197 unsigned short parametercode
;
204 if ((err
= scsiLogSense(device
, TAPE_ALERTS_LPAGE
, 0, gBuf
,
205 LOG_RESP_TAPE_ALERT_LEN
, LOG_RESP_TAPE_ALERT_LEN
))) {
206 pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err
));
210 if (gBuf
[0] != 0x2e) {
211 pout("TapeAlerts Log Sense Failed\n");
215 pagelength
= (unsigned short) gBuf
[2] << 8 | gBuf
[3];
217 for (s
=severities
; *s
; s
++) {
218 for (i
= 4; i
< pagelength
; i
+= 5) {
219 parametercode
= (unsigned short) gBuf
[i
] << 8 | gBuf
[i
+1];
222 ts
= SCSI_PT_MEDIUM_CHANGER
== peripheral_type
?
223 scsiTapeAlertsChangerDevice(parametercode
) :
224 scsiTapeAlertsTapeDevice(parametercode
);
227 pout("TapeAlert Errors (C=Critical, W=Warning, I=Informational):\n");
228 pout("[0x%02x] %s\n", parametercode
, ts
);
237 pout("TapeAlert: OK\n");
242 static void scsiGetStartStopData(scsi_device
* device
)
245 int err
, len
, k
, extra
, pc
;
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 pc
= (ucp
[0] << 8) + ucp
[1];
275 pout("Manufactured in week %.2s of year %.4s\n", ucp
+ 8,
279 /* ignore Accounting date */
283 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
285 pout("Specified cycle count over device lifetime: %u\n",
291 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
293 pout("Accumulated start-stop cycles: %u\n", u
);
298 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
300 pout("Specified load-unload count over device "
301 "lifetime: %u\n", u
);
306 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
308 pout("Accumulated load-unload cycles: %u\n", u
);
318 static void scsiPrintGrownDefectListLen(scsi_device
* device
)
320 int err
, dl_format
, dl_len
, div
;
323 if ((err
= scsiReadDefect10(device
, 0 /* req_plist */, 1 /* req_glist */,
324 4 /* bytes from index */, gBuf
, 4))) {
325 if (con
->reportscsiioctl
> 0) {
327 pout("Read defect list (10) Failed: %s\n", scsiErrString(err
));
332 if (0x8 != (gBuf
[1] & 0x18)) {
334 pout("Read defect list: asked for grown list but didn't get it\n");
339 dl_format
= (gBuf
[1] & 0x7);
341 case 0: /* short block */
344 case 3: /* long block */
345 case 4: /* bytes from index */
346 case 5: /* physical sector */
351 pout("defect list format %d unknown\n", dl_format
);
355 dl_len
= (gBuf
[2] << 8) + gBuf
[3];
357 pout("Elements in grown defect list: 0\n");
360 pout("Grown defect list length=%d bytes [unknown "
361 "number of elements]\n", dl_len
);
363 pout("Elements in grown defect list: %d\n", dl_len
/ div
);
367 static void scsiPrintSeagateCacheLPage(scsi_device
* device
)
369 int k
, j
, num
, pl
, pc
, err
, len
;
374 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
377 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err
));
381 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
383 pout("Seagate Cache Log Sense Failed, page mismatch\n");
387 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
391 pc
= (ucp
[0] << 8) | ucp
[1];
394 case 0: case 1: case 2: case 3: case 4:
397 if (con
->reportscsiioctl
> 0) {
399 pout("Vendor (Seagate) cache lpage has unexpected parameter"
408 pout("Vendor (Seagate) cache information\n");
412 pc
= (ucp
[0] << 8) | ucp
[1];
415 case 0: pout(" Blocks sent to initiator"); break;
416 case 1: pout(" Blocks received from initiator"); break;
417 case 2: pout(" Blocks read from cache and sent to initiator"); break;
418 case 3: pout(" Number of read and write commands whose size "
419 "<= segment size"); break;
420 case 4: pout(" Number of read and write commands whose size "
421 "> segment size"); break;
422 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
426 if (k
> (int)sizeof(ull
)) {
427 xp
+= (k
- (int)sizeof(ull
));
428 k
= (int)sizeof(ull
);
431 for (j
= 0; j
< k
; ++j
) {
436 pout(" = %"PRIu64
"\n", ull
);
442 static void scsiPrintSeagateFactoryLPage(scsi_device
* device
)
444 int k
, j
, num
, pl
, pc
, len
, err
, good
, bad
;
449 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
452 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err
));
456 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
458 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
462 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
468 pc
= (ucp
[0] << 8) | ucp
[1];
481 if ((good
< 2) || (bad
> 4)) { /* heuristic */
482 if (con
->reportscsiioctl
> 0) {
484 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
485 "unexpected parameters, skip\n");
490 pout("Vendor (Seagate/Hitachi) factory information\n");
494 pc
= (ucp
[0] << 8) | ucp
[1];
498 case 0: pout(" number of hours powered up");
501 case 8: pout(" number of minutes until next internal SMART test");
505 if (con
->reportscsiioctl
> 0) {
507 pout("Vendor (Seagate/Hitachi) factory lpage: "
508 "unknown parameter code [0x%x]\n", pc
);
516 if (k
> (int)sizeof(ull
)) {
517 xp
+= (k
- (int)sizeof(ull
));
518 k
= (int)sizeof(ull
);
521 for (j
= 0; j
< k
; ++j
) {
527 pout(" = %.2f\n", uint64_to_double(ull
) / 60.0 );
529 pout(" = %"PRIu64
"\n", ull
);
536 static void scsiPrintErrorCounterLog(scsi_device
* device
)
538 struct scsiErrorCounter errCounterArr
[3];
539 struct scsiErrorCounter
* ecp
;
540 struct scsiNonMediumError nme
;
541 int found
[3] = {0, 0, 0};
542 const char * pageNames
[3] = {"read: ", "write: ", "verify: "};
546 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
547 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
548 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
551 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
552 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
553 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
556 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
557 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
558 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
559 ecp
= &errCounterArr
[2];
560 for (k
= 0; k
< 7; ++k
) {
561 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
567 if (found
[0] || found
[1] || found
[2]) {
568 pout("\nError counter log:\n");
569 pout(" Errors Corrected by Total "
570 "Correction Gigabytes Total\n");
571 pout(" ECC rereads/ errors "
572 "algorithm processed uncorrected\n");
573 pout(" fast | delayed rewrites corrected "
574 "invocations [10^9 bytes] errors\n");
575 for (k
= 0; k
< 3; ++k
) {
578 ecp
= &errCounterArr
[k
];
579 pout("%s%8"PRIu64
" %8"PRIu64
" %8"PRIu64
" %8"PRIu64
" %8"PRIu64
,
580 pageNames
[k
], ecp
->counter
[0], ecp
->counter
[1],
581 ecp
->counter
[2], ecp
->counter
[3], ecp
->counter
[4]);
582 processed_gb
= uint64_to_double(ecp
->counter
[5]) / 1000000000.0;
583 pout(" %12.3f %8"PRIu64
"\n", processed_gb
, ecp
->counter
[6]);
587 pout("\nError Counter logging not supported\n");
588 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
589 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
590 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
592 pout("\nNon-medium error count: %8"PRIu64
"\n", nme
.counterPC0
);
594 pout("Track following error count [Hitachi]: %8"PRIu64
"\n",
597 pout("Positioning error count [Hitachi]: %8"PRIu64
"\n",
600 if (gLastNErrorLPage
&& (0 == scsiLogSense(device
,
601 LAST_N_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LONG_LEN
, 0))) {
603 int num
, k
, pc
, pl
, truncated
;
605 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
606 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
608 num
= LOG_RESP_LONG_LEN
;
612 pout("\nNo error events logged\n");
614 pout("\nLast n error events log page\n");
615 for (k
= num
; k
> 0; k
-= pl
, ucp
+= pl
) {
617 pout(" <<short Last n error events log page>>\n");
621 pc
= (ucp
[0] << 8) + ucp
[1];
623 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
624 pout(" Error event %d:\n", pc
);
625 pout(" [binary]:\n");
626 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
627 } else if (ucp
[2] & 0x1) {
628 pout(" Error event %d:\n", pc
);
629 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
631 if (con
->reportscsiioctl
> 0) {
632 pout(" Error event %d:\n", pc
);
633 pout(" [data counter??]:\n");
634 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
640 pout(" >>>> log truncated, fetched %d of %d available "
641 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
646 static const char * self_test_code
[] = {
657 static const char * self_test_result
[] = {
659 "Aborted (by user command)",
660 "Aborted (device reset ?) ",
661 "Unknown error, incomplete",
662 "Completed, segment failed",
663 "Failed in first segment ",
664 "Failed in second segment ",
665 "Failed in segment --> ",
673 "Self test in progress ..."
676 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
677 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
678 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
679 // FAILSMART is returned.
680 static int scsiPrintSelfTest(scsi_device
* device
)
682 int num
, k
, n
, res
, err
, durationSec
;
688 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
689 LOG_RESP_SELF_TEST_LEN
, 0))) {
691 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err
));
695 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
697 pout("Self-test Log Sense Failed, page mismatch\n");
701 // compute page length
702 num
= (gBuf
[2] << 8) + gBuf
[3];
703 // Log sense page length 0x190 bytes
706 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num
);
710 // loop through the twenty possible entries
711 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
714 // timestamp in power-on hours (or zero if test in progress)
715 n
= (ucp
[6] << 8) | ucp
[7];
717 // The spec says "all 20 bytes will be zero if no test" but
718 // DG has found otherwise. So this is a heuristic.
719 if ((0 == n
) && (0 == ucp
[4]))
722 // only print header if needed
724 pout("\nSMART Self-test log\n");
725 pout("Num Test Status segment "
726 "LifeTime LBA_first_err [SK ASC ASQ]\n");
727 pout(" Description number "
732 // print parameter code (test number) & self-test code text
733 pout("#%2d %s", (ucp
[0] << 8) | ucp
[1],
734 self_test_code
[(ucp
[4] >> 5) & 0x7]);
736 // check the self-test result nibble, using the self-test results
737 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
738 switch ((res
= ucp
[4] & 0xf)) {
740 // an unknown error occurred while the device server
741 // was processing the self-test and the device server
742 // was unable to complete the self-test
746 // the self-test completed with a failure in a test
747 // segment, and the test segment that failed is not
752 // the first segment of the self-test failed
756 // the second segment of the self-test failed
760 // another segment of the self-test failed and which
761 // test is indicated by the contents of the SELF-TEST
768 pout(" %s", self_test_result
[res
]);
770 // self-test number identifies test that failed and consists
771 // of either the number of the segment that failed during
772 // the test, or the number of the test that failed and the
773 // number of the segment in which the test was run, using a
774 // vendor-specific method of putting both numbers into a
777 pout(" %3d", (int)ucp
[5]);
781 // print time that the self-test was completed
782 if (n
==0 && res
==0xf)
783 // self-test in progress
788 // construct 8-byte integer address of first failure
789 for (i
= 0; i
< 8; i
++) {
793 // print Address of First Failure, if sensible
794 if ((~(uint64_t)0 != ull
) && (res
> 0) && (res
< 0xf)) {
797 // was hex but change to decimal to conform with ATA
798 snprintf(buff
, sizeof(buff
), "%"PRIu64
, ull
);
799 // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull);
804 // if sense key nonzero, then print it, along with
805 // additional sense code and additional sense code qualifier
807 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
812 // if header never printed, then there was no output
814 pout("No self-tests have been logged\n");
817 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
818 modese_len
)) && (durationSec
> 0)) {
819 pout("Long (extended) Self Test duration: %d seconds "
820 "[%.1f minutes]\n", durationSec
, durationSec
/ 60.0);
825 static const char * bms_status
[] = {
828 "pre-scan is active",
829 "halted due to fatal error",
830 "halted due to a vendor specific pattern of error",
831 "halted due to medium formatted without P-List",
832 "halted - vendor specific cause",
833 "halted due to temperature out of range",
834 "waiting until BMS interval timer expires", /* 8 */
837 static const char * reassign_status
[] = {
839 "Require Write or Reassign Blocks command",
840 "Successfully reassigned",
842 "Reassignment by disk failed",
843 "Recovered via rewrite in-place",
844 "Reassigned by app, has valid data",
845 "Reassigned by app, has no valid data",
846 "Unsuccessfully reassigned by app", /* 8 */
849 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
850 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
851 // and up to 2048 events (although would hope to have less). May set
852 // FAILLOG if serious errors detected (in the future).
853 static int scsiPrintBackgroundResults(scsi_device
* device
)
855 int num
, j
, m
, err
, pc
, pl
, truncated
;
861 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
862 LOG_RESP_LONG_LEN
, 0))) {
864 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err
));
868 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
870 pout("Background scan results Log Sense Failed, page mismatch\n");
874 // compute page length
875 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
878 pout("Background scan results Log Sense length is %d, no scan "
883 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
885 num
= LOG_RESP_LONG_LEN
;
889 pc
= (ucp
[0] << 8) | ucp
[1];
896 pout("\nBackground scan results log\n");
899 if ((pl
< 16) || (num
< 16)) {
904 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
905 pout("%s\n", bms_status
[j
]);
907 pout("unknown [0x%x] background scan status value\n", j
);
908 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
909 pout(" Accumulated power on time, hours:minutes %d:%02d "
910 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
911 pout(" Number of background scans performed: %d, ",
912 (ucp
[10] << 8) + ucp
[11]);
913 pout("scan progress: %.2f%%\n",
914 (double)((ucp
[12] << 8) + ucp
[13]) * 100.0 / 65536.0);
915 pout(" Number of background medium scans performed: %d\n",
916 (ucp
[14] << 8) + ucp
[15]);
921 pout("\nBackground scan results log\n");
925 pout("\n # when lba(hex) [sk,asc,ascq] "
926 "reassign_status\n");
929 if ((pl
< 24) || (num
< 24)) {
931 pout("parameter length >= 24 expected, got %d\n", pl
);
934 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
935 pout("%4d:%02d ", (j
/ 60), (j
% 60));
936 for (m
= 0; m
< 8; ++m
)
937 pout("%02x", ucp
[16 + m
]);
938 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
939 j
= (ucp
[8] >> 4) & 0xf;
941 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
942 pout("%s\n", reassign_status
[j
]);
944 pout("Reassign status: reserved [0x%x]\n", j
);
951 pout(" >>>> log truncated, fetched %d of %d available "
952 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
957 static void show_sas_phy_event_info(int peis
, unsigned int val
,
967 pout(" Invalid word count: %u\n", val
);
970 pout(" Running disparity error count: %u\n", val
);
973 pout(" Loss of dword synchronization count: %u\n", val
);
976 pout(" Phy reset problem count: %u\n", val
);
979 pout(" Elasticity buffer overflow count: %u\n", val
);
982 pout(" Received ERROR count: %u\n", val
);
985 pout(" Received address frame error count: %u\n", val
);
988 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
991 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
994 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
997 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
1000 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val
);
1003 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
1006 pout(" Transmitted BREAK count: %u\n", val
);
1009 pout(" Received BREAK count: %u\n", val
);
1012 pout(" Break timeout count: %u\n", val
);
1015 pout(" Connection count: %u\n", val
);
1018 pout(" Peak transmitted pathway blocked count: %u\n",
1020 pout(" Peak value detector threshold: %u\n",
1026 pout(" Peak transmitted arbitration wait time (us): "
1029 pout(" Peak transmitted arbitration wait time (ms): "
1030 "%u\n", 33 + (u
- 0x8000));
1031 u
= thresh_val
& 0xffff;
1033 pout(" Peak value detector threshold (us): %u\n",
1036 pout(" Peak value detector threshold (ms): %u\n",
1040 pout(" Peak arbitration time (us): %u\n", val
);
1041 pout(" Peak value detector threshold: %u\n", thresh_val
);
1044 pout(" Peak connection time (us): %u\n", val
);
1045 pout(" Peak value detector threshold: %u\n", thresh_val
);
1048 pout(" Transmitted SSP frame count: %u\n", val
);
1051 pout(" Received SSP frame count: %u\n", val
);
1054 pout(" Transmitted SSP frame error count: %u\n", val
);
1057 pout(" Received SSP frame error count: %u\n", val
);
1060 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1063 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1066 pout(" Transmitted SATA frame count: %u\n", val
);
1069 pout(" Received SATA frame count: %u\n", val
);
1072 pout(" SATA flow control buffer overflow count: %u\n", val
);
1075 pout(" Transmitted SMP frame count: %u\n", val
);
1078 pout(" Received SMP frame count: %u\n", val
);
1081 pout(" Received SMP frame error count: %u\n", val
);
1088 static void show_sas_port_param(unsigned char * ucp
, int param_len
)
1090 int j
, m
, n
, nphys
, pcb
, t
, sz
, spld_len
;
1091 unsigned char * vcp
;
1098 t
= (ucp
[0] << 8) | ucp
[1];
1099 pout("relative target port id = %d\n", t
);
1100 pout(" generation code = %d\n", ucp
[6]);
1102 pout(" number of phys = %d\n", nphys
);
1104 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1105 vcp
+= spld_len
, j
+= spld_len
) {
1106 pout(" phy identifier = %d\n", vcp
[1]);
1109 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1112 t
= ((0x70 & vcp
[4]) >> 4);
1114 case 0: snprintf(s
, sz
, "no device attached"); break;
1115 case 1: snprintf(s
, sz
, "end device"); break;
1116 case 2: snprintf(s
, sz
, "expander device"); break;
1117 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1118 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1120 pout(" attached device type: %s\n", s
);
1123 case 0: snprintf(s
, sz
, "unknown"); break;
1124 case 1: snprintf(s
, sz
, "power on"); break;
1125 case 2: snprintf(s
, sz
, "hard reset"); break;
1126 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1127 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1128 case 5: snprintf(s
, sz
, "mux mix up"); break;
1129 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1131 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1132 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1133 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1135 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1137 pout(" attached reason: %s\n", s
);
1138 t
= (vcp
[5] & 0xf0) >> 4;
1140 case 0: snprintf(s
, sz
, "unknown"); break;
1141 case 1: snprintf(s
, sz
, "power on"); break;
1142 case 2: snprintf(s
, sz
, "hard reset"); break;
1143 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1144 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1145 case 5: snprintf(s
, sz
, "mux mix up"); break;
1146 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1148 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1149 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1150 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1152 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1154 pout(" reason: %s\n", s
);
1157 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1159 case 1: snprintf(s
, sz
, "phy disabled"); break;
1160 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1162 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1164 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1166 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1168 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1170 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1171 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1172 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1173 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1175 pout(" negotiated logical link rate: %s\n", s
);
1176 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1177 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1178 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1179 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1180 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1181 ull
<<= 8; ull
|= vcp
[8 + n
];
1183 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1184 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1185 ull
<<= 8; ull
|= vcp
[16 + n
];
1187 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1188 pout(" attached phy identifier = %d\n", vcp
[24]);
1189 ui
= (vcp
[32] << 24) | (vcp
[33] << 16) | (vcp
[34] << 8) | vcp
[35];
1190 pout(" Invalid DWORD count = %u\n", ui
);
1191 ui
= (vcp
[36] << 24) | (vcp
[37] << 16) | (vcp
[38] << 8) | vcp
[39];
1192 pout(" Running disparity error count = %u\n", ui
);
1193 ui
= (vcp
[40] << 24) | (vcp
[41] << 16) | (vcp
[42] << 8) | vcp
[43];
1194 pout(" Loss of DWORD synchronization = %u\n", ui
);
1195 ui
= (vcp
[44] << 24) | (vcp
[45] << 16) | (vcp
[46] << 8) | vcp
[47];
1196 pout(" Phy reset problem = %u\n", ui
);
1197 if (spld_len
> 51) {
1199 unsigned char * xcp
;
1204 pout(" Phy event descriptors:\n");
1206 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1208 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1210 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1212 show_sas_phy_event_info(peis
, ui
, pvdt
);
1218 // Returns 1 if okay, 0 if non SAS descriptors
1219 static int show_protocol_specific_page(unsigned char * resp
, int len
)
1221 int k
, num
, param_len
;
1222 unsigned char * ucp
;
1225 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1226 param_len
= ucp
[3] + 4;
1227 if (6 != (0xf & ucp
[4]))
1228 return 0; /* only decode SAS log page */
1230 pout("Protocol Specific port log page for SAS SSP\n");
1231 show_sas_port_param(ucp
, param_len
);
1239 // See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific
1240 // log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol
1241 // Specific log page.
1242 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
1243 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
1244 // FAILSMART is returned.
1245 static int scsiPrintSasPhy(scsi_device
* device
, int reset
)
1249 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1250 LOG_RESP_LONG_LEN
, 0))) {
1252 pout("scsiPrintSasPhy Log Sense Failed [%s]\n", scsiErrString(err
));
1256 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1258 pout("Protocol specific Log Sense Failed, page mismatch\n");
1262 // compute page length
1263 num
= (gBuf
[2] << 8) + gBuf
[3];
1264 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1266 pout("Only support protocol specific log page on SAS devices\n");
1271 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1272 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1274 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n",
1275 scsiErrString(err
));
1284 static const char * peripheral_dt_arr
[] = {
1300 "optical card reader"
1303 static const char * transport_proto_arr
[] = {
1304 "Fibre channel (FCP-2)",
1305 "Parallel SCSI (SPI-4)",
1307 "IEEE 1394 (SBP-2)",
1322 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1323 static int scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1325 char manufacturer
[9];
1328 char timedatetz
[DATEANDEPOCHLEN
];
1329 struct scsi_iec_mode_page iec
;
1330 int err
, iec_err
, len
, req_len
, avail_len
, val
;
1335 memset(gBuf
, 0, 96);
1337 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1339 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1340 pout("Retrying with a 64 byte Standard Inquiry\n");
1342 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1344 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1346 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1347 scsiErrString(err
));
1352 avail_len
= gBuf
[4] + 5;
1353 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1354 peri_dt
= gBuf
[0] & 0x1f;
1355 if (peripheral_type
)
1356 *peripheral_type
= peri_dt
;
1360 pout("Short INQUIRY response, skip product id\n");
1364 memset(manufacturer
, 0, sizeof(manufacturer
));
1365 strncpy(manufacturer
, (char *)&gBuf
[8], 8);
1367 memset(product
, 0, sizeof(product
));
1368 strncpy(product
, (char *)&gBuf
[16], 16);
1370 memset(revision
, 0, sizeof(revision
));
1371 strncpy(revision
, (char *)&gBuf
[32], 4);
1372 if (all
&& (0 != strncmp(manufacturer
, "ATA", 3)))
1373 pout("Device: %s %s Version: %s\n", manufacturer
, product
, revision
);
1375 if (!*device
->get_req_type()/*no type requested*/ &&
1376 (0 == strncmp(manufacturer
, "ATA", 3))) {
1377 pout("\nProbable ATA device behind a SAT layer\n"
1378 "Try an additional '-d ata' or '-d sat' argument.\n");
1384 /* Do this here to try and detect badly conforming devices (some USB
1385 keys) that will lock up on a InquiryVpd or log sense or ... */
1386 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1387 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1388 pout(">> Terminate command early due to bad response to IEC "
1395 modese_len
= iec
.modese_len
;
1397 if (!con
->dont_print_serial
) {
1398 if (0 == (err
= scsiInquiryVpd(device
, 0x80, gBuf
, 64))) {
1399 /* should use VPD page 0x83 and fall back to this page (0x80)
1400 * if 0x83 not supported. NAA requires a lot of decoding code */
1402 gBuf
[4 + len
] = '\0';
1403 pout("Serial number: %s\n", &gBuf
[4]);
1405 else if (con
->reportscsiioctl
> 0) {
1407 if (SIMPLE_ERR_BAD_RESP
== err
)
1408 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1410 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1415 // print SCSI peripheral device type
1416 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1417 sizeof(peripheral_dt_arr
[0])))
1418 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1420 pout("Device type: <%d>\n", peri_dt
);
1422 // See if transport protocol is known
1423 val
= scsiFetchTransportProtocol(device
, modese_len
);
1424 if ((val
>= 0) && (val
<= 0xf))
1425 pout("Transport protocol: %s\n", transport_proto_arr
[val
]);
1427 // print current time and date and timezone
1428 dateandtimezone(timedatetz
);
1429 pout("Local Time is: %s\n", timedatetz
);
1431 if ((SCSI_PT_SEQUENTIAL_ACCESS
== *peripheral_type
) ||
1432 (SCSI_PT_MEDIUM_CHANGER
== *peripheral_type
))
1434 // See if unit accepts SCSI commmands from us
1435 if ((err
= scsiTestUnitReady(device
))) {
1436 if (SIMPLE_ERR_NOT_READY
== err
) {
1439 pout("device is NOT READY (e.g. spun down, busy)\n");
1441 pout("device is NOT READY (e.g. no tape)\n");
1443 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1445 pout("NO MEDIUM present on device\n");
1447 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1449 pout("device becoming ready (wait)\n");
1453 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1456 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1462 pout("Device does not support SMART");
1463 if (con
->reportscsiioctl
> 0)
1464 pout(" [%s]\n", scsiErrString(iec_err
));
1474 pout("Device supports SMART and is %s\n",
1475 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1476 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1477 "Temperature Warning Enabled" :
1478 "Temperature Warning Disabled or Not Supported");
1482 static int scsiSmartEnable(scsi_device
* device
)
1484 struct scsi_iec_mode_page iec
;
1487 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1489 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1490 scsiErrString(err
));
1494 modese_len
= iec
.modese_len
;
1496 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1498 pout("unable to enable Exception control and warning [%s]\n",
1499 scsiErrString(err
));
1503 /* Need to refetch 'iec' since could be modified by previous call */
1504 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1505 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1506 scsiErrString(err
));
1509 modese_len
= iec
.modese_len
;
1511 pout("Informational Exceptions (SMART) %s\n",
1512 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1513 pout("Temperature warning %s\n",
1514 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1518 static int scsiSmartDisable(scsi_device
* device
)
1520 struct scsi_iec_mode_page iec
;
1523 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1525 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1526 scsiErrString(err
));
1530 modese_len
= iec
.modese_len
;
1532 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1534 pout("unable to disable Exception control and warning [%s]\n",
1535 scsiErrString(err
));
1539 /* Need to refetch 'iec' since could be modified by previous call */
1540 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1541 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1542 scsiErrString(err
));
1545 modese_len
= iec
.modese_len
;
1547 pout("Informational Exceptions (SMART) %s\n",
1548 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1549 pout("Temperature warning %s\n",
1550 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1554 static void scsiPrintTemp(scsi_device
* device
)
1559 if (scsiGetTemp(device
, &temp
, &trip
))
1564 pout("Current Drive Temperature: %d C\n", temp
);
1566 pout("Current Drive Temperature: <not available>\n");
1569 pout("Drive Trip Temperature: %d C\n", trip
);
1572 /* Main entry point used by smartctl command. Return 0 for success */
1573 int scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1575 int checkedSupportedLogPages
= 0;
1576 UINT8 peripheral_type
= 0;
1578 int res
, durationSec
;
1580 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1585 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1588 if (options
.smart_enable
) {
1589 if (scsiSmartEnable(device
))
1590 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1593 if (options
.smart_disable
) {
1594 if (scsiSmartDisable(device
))
1595 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1598 if (options
.smart_auto_save_enable
) {
1599 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1600 pout("Enable autosave (clear GLTSD bit) failed\n");
1601 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1605 if (options
.smart_auto_save_disable
) {
1606 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1607 pout("Disable autosave (set GLTSD bit) failed\n");
1608 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1612 if (options
.smart_check_status
) {
1613 scsiGetSupportedLogPages(device
);
1614 checkedSupportedLogPages
= 1;
1615 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1616 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
)) { /* tape device */
1617 if (gTapeAlertsLPage
) {
1618 if (options
.drive_info
)
1619 pout("TapeAlert Supported\n");
1620 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
1621 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
1624 pout("TapeAlert Not Supported\n");
1625 } else { /* disk, cd/dvd, enclosure, etc */
1626 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
1628 returnval
|= FAILSTATUS
;
1630 returnval
|= FAILSMART
;
1634 if (options
.smart_vendor_attrib
) {
1635 if (! checkedSupportedLogPages
)
1636 scsiGetSupportedLogPages(device
);
1638 if (options
.smart_check_status
)
1640 scsiPrintTemp(device
);
1642 if (gStartStopLPage
)
1643 scsiGetStartStopData(device
);
1644 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1645 scsiPrintGrownDefectListLen(device
);
1646 if (gSeagateCacheLPage
)
1647 scsiPrintSeagateCacheLPage(device
);
1648 if (gSeagateFactoryLPage
)
1649 scsiPrintSeagateFactoryLPage(device
);
1652 if (options
.smart_error_log
) {
1653 if (! checkedSupportedLogPages
)
1654 scsiGetSupportedLogPages(device
);
1655 scsiPrintErrorCounterLog(device
);
1656 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
1657 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
1658 "Enable Save with '-S on']\n");
1660 if (options
.smart_selftest_log
) {
1661 if (! checkedSupportedLogPages
)
1662 scsiGetSupportedLogPages(device
);
1665 res
= scsiPrintSelfTest(device
);
1667 pout("Device does not support Self Test logging\n");
1668 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
1671 failuretest(OPTIONAL_CMD
, returnval
|=res
);
1673 if (options
.smart_background_log
) {
1674 if (! checkedSupportedLogPages
)
1675 scsiGetSupportedLogPages(device
);
1677 if (gBackgroundResultsLPage
)
1678 res
= scsiPrintBackgroundResults(device
);
1680 pout("Device does not support Background scan results logging\n");
1681 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
1684 failuretest(OPTIONAL_CMD
, returnval
|=res
);
1686 if (options
.smart_default_selftest
) {
1687 if (scsiSmartDefaultSelfTest(device
))
1688 return returnval
| FAILSMART
;
1689 pout("Default Self Test Successful\n");
1691 if (options
.smart_short_cap_selftest
) {
1692 if (scsiSmartShortCapSelfTest(device
))
1693 return returnval
| FAILSMART
;
1694 pout("Short Foreground Self Test Successful\n");
1696 if (options
.smart_short_selftest
) {
1697 if (scsiSmartShortSelfTest(device
))
1698 return returnval
| FAILSMART
;
1699 pout("Short Background Self Test has begun\n");
1700 pout("Use smartctl -X to abort test\n");
1702 if (options
.smart_extend_selftest
) {
1703 if (scsiSmartExtendSelfTest(device
))
1704 return returnval
| FAILSMART
;
1705 pout("Extended Background Self Test has begun\n");
1706 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
1707 modese_len
)) && (durationSec
> 0)) {
1708 time_t t
= time(NULL
);
1711 pout("Please wait %d minutes for test to complete.\n",
1713 pout("Estimated completion time: %s\n", ctime(&t
));
1715 pout("Use smartctl -X to abort test\n");
1717 if (options
.smart_extend_cap_selftest
) {
1718 if (scsiSmartExtendCapSelfTest(device
))
1719 return returnval
| FAILSMART
;
1720 pout("Extended Foreground Self Test Successful\n");
1722 if (options
.smart_selftest_abort
) {
1723 if (scsiSmartSelfTestAbort(device
))
1724 return returnval
| FAILSMART
;
1725 pout("Self Test returned without error\n");
1727 if (options
.sasphy
) {
1728 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
1729 return returnval
| FAILSMART
;