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 3441 2011-10-12 17:22:15Z 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;
79 static void scsiGetSupportedLogPages(scsi_device
* device
)
83 if ((err
= scsiLogSense(device
, SUPPORTED_LPAGES
, 0, gBuf
,
85 if (scsi_debugmode
> 0)
86 pout("Log Sense for supported pages failed [%s]\n",
91 for (i
= 4; i
< gBuf
[3] + LOGPAGEHDRSIZE
; i
++) {
94 case READ_ERROR_COUNTER_LPAGE
:
95 gReadECounterLPage
= 1;
97 case WRITE_ERROR_COUNTER_LPAGE
:
98 gWriteECounterLPage
= 1;
100 case VERIFY_ERROR_COUNTER_LPAGE
:
101 gVerifyECounterLPage
= 1;
103 case LAST_N_ERROR_LPAGE
:
104 gLastNErrorLPage
= 1;
106 case NON_MEDIUM_ERROR_LPAGE
:
107 gNonMediumELPage
= 1;
109 case TEMPERATURE_LPAGE
:
112 case STARTSTOP_CYCLE_COUNTER_LPAGE
:
115 case SELFTEST_RESULTS_LPAGE
:
121 case BACKGROUND_RESULTS_LPAGE
:
122 gBackgroundResultsLPage
= 1;
124 case PROTOCOL_SPECIFIC_LPAGE
:
125 gProtocolSpecificLPage
= 1;
127 case TAPE_ALERTS_LPAGE
:
128 gTapeAlertsLPage
= 1;
133 case SEAGATE_CACHE_LPAGE
:
134 gSeagateCacheLPage
= 1;
136 case SEAGATE_FACTORY_LPAGE
:
137 gSeagateFactoryLPage
= 1;
145 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
146 (or at least something to report). */
147 static int scsiGetSmartData(scsi_device
* device
, bool attribs
)
151 UINT8 currenttemp
= 0;
157 if (scsiCheckIE(device
, gSmartLPage
, gTempLPage
, &asc
, &ascq
,
158 ¤ttemp
, &triptemp
)) {
159 /* error message already announced */
164 cp
= scsiGetIEString(asc
, ascq
);
168 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp
, asc
, ascq
);
170 } else if (gIecMPage
)
171 pout("SMART Health Status: OK\n");
173 if (attribs
&& !gTempLPage
) {
174 if (currenttemp
|| triptemp
)
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
);
189 // Returns number of logged errors or zero if none or -1 if fetching
191 static const char * const severities
= "CWI";
193 static int scsiGetTapeAlertsData(scsi_device
* device
, int peripheral_type
)
195 unsigned short pagelength
;
196 unsigned short parametercode
;
203 if ((err
= scsiLogSense(device
, TAPE_ALERTS_LPAGE
, 0, gBuf
,
204 LOG_RESP_TAPE_ALERT_LEN
, LOG_RESP_TAPE_ALERT_LEN
))) {
205 pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err
));
209 if (gBuf
[0] != 0x2e) {
210 pout("TapeAlerts Log Sense Failed\n");
214 pagelength
= (unsigned short) gBuf
[2] << 8 | gBuf
[3];
216 for (s
=severities
; *s
; s
++) {
217 for (i
= 4; i
< pagelength
; i
+= 5) {
218 parametercode
= (unsigned short) gBuf
[i
] << 8 | gBuf
[i
+1];
221 ts
= SCSI_PT_MEDIUM_CHANGER
== peripheral_type
?
222 scsiTapeAlertsChangerDevice(parametercode
) :
223 scsiTapeAlertsTapeDevice(parametercode
);
226 pout("TapeAlert Errors (C=Critical, W=Warning, I=Informational):\n");
227 pout("[0x%02x] %s\n", parametercode
, ts
);
236 pout("TapeAlert: OK\n");
241 static void scsiGetStartStopData(scsi_device
* device
)
244 int err
, len
, k
, extra
, pc
;
247 if ((err
= scsiLogSense(device
, STARTSTOP_CYCLE_COUNTER_LPAGE
, 0, gBuf
,
250 pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err
));
254 if ((gBuf
[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE
) {
256 pout("StartStop Log Sense Failed, page mismatch\n");
260 len
= ((gBuf
[2] << 8) | gBuf
[3]);
262 for (k
= len
; k
> 0; k
-= extra
, ucp
+= extra
) {
265 pout("StartStop Log Sense Failed: short\n");
270 pc
= (ucp
[0] << 8) + ucp
[1];
274 pout("Manufactured in week %.2s of year %.4s\n", ucp
+ 8,
278 /* ignore Accounting date */
282 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
284 pout("Specified cycle count over device lifetime: %u\n",
290 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
292 pout("Accumulated start-stop cycles: %u\n", u
);
297 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
299 pout("Specified load-unload count over device "
300 "lifetime: %u\n", u
);
305 u
= (ucp
[4] << 24) | (ucp
[5] << 16) | (ucp
[6] << 8) | ucp
[7];
307 pout("Accumulated load-unload cycles: %u\n", u
);
317 static void scsiPrintGrownDefectListLen(scsi_device
* device
)
319 int err
, dl_format
, dl_len
, div
;
322 if ((err
= scsiReadDefect10(device
, 0 /* req_plist */, 1 /* req_glist */,
323 4 /* bytes from index */, gBuf
, 4))) {
324 if (scsi_debugmode
> 0) {
326 pout("Read defect list (10) Failed: %s\n", scsiErrString(err
));
331 if (0x8 != (gBuf
[1] & 0x18)) {
333 pout("Read defect list: asked for grown list but didn't get it\n");
338 dl_format
= (gBuf
[1] & 0x7);
340 case 0: /* short block */
343 case 3: /* long block */
344 case 4: /* bytes from index */
345 case 5: /* physical sector */
350 pout("defect list format %d unknown\n", dl_format
);
354 dl_len
= (gBuf
[2] << 8) + gBuf
[3];
356 pout("Elements in grown defect list: 0\n");
359 pout("Grown defect list length=%d bytes [unknown "
360 "number of elements]\n", dl_len
);
362 pout("Elements in grown defect list: %d\n", dl_len
/ div
);
366 static void scsiPrintSeagateCacheLPage(scsi_device
* device
)
368 int k
, j
, num
, pl
, pc
, err
, len
;
373 if ((err
= scsiLogSense(device
, SEAGATE_CACHE_LPAGE
, 0, gBuf
,
376 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err
));
380 if ((gBuf
[0] & 0x3f) != SEAGATE_CACHE_LPAGE
) {
382 pout("Seagate Cache Log Sense Failed, page mismatch\n");
386 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
390 pc
= (ucp
[0] << 8) | ucp
[1];
393 case 0: case 1: case 2: case 3: case 4:
396 if (scsi_debugmode
> 0) {
398 pout("Vendor (Seagate) cache lpage has unexpected parameter"
407 pout("Vendor (Seagate) cache information\n");
411 pc
= (ucp
[0] << 8) | ucp
[1];
414 case 0: pout(" Blocks sent to initiator"); break;
415 case 1: pout(" Blocks received from initiator"); break;
416 case 2: pout(" Blocks read from cache and sent to initiator"); break;
417 case 3: pout(" Number of read and write commands whose size "
418 "<= segment size"); break;
419 case 4: pout(" Number of read and write commands whose size "
420 "> segment size"); break;
421 default: pout(" Unknown Seagate parameter code [0x%x]", pc
); break;
425 if (k
> (int)sizeof(ull
)) {
426 xp
+= (k
- (int)sizeof(ull
));
427 k
= (int)sizeof(ull
);
430 for (j
= 0; j
< k
; ++j
) {
435 pout(" = %"PRIu64
"\n", ull
);
441 static void scsiPrintSeagateFactoryLPage(scsi_device
* device
)
443 int k
, j
, num
, pl
, pc
, len
, err
, good
, bad
;
448 if ((err
= scsiLogSense(device
, SEAGATE_FACTORY_LPAGE
, 0, gBuf
,
451 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err
));
455 if ((gBuf
[0] & 0x3f) != SEAGATE_FACTORY_LPAGE
) {
457 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
461 len
= ((gBuf
[2] << 8) | gBuf
[3]) + 4;
467 pc
= (ucp
[0] << 8) | ucp
[1];
480 if ((good
< 2) || (bad
> 4)) { /* heuristic */
481 if (scsi_debugmode
> 0) {
483 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
484 "unexpected parameters, skip\n");
489 pout("Vendor (Seagate/Hitachi) factory information\n");
493 pc
= (ucp
[0] << 8) | ucp
[1];
497 case 0: pout(" number of hours powered up");
500 case 8: pout(" number of minutes until next internal SMART test");
504 if (scsi_debugmode
> 0) {
506 pout("Vendor (Seagate/Hitachi) factory lpage: "
507 "unknown parameter code [0x%x]\n", pc
);
515 if (k
> (int)sizeof(ull
)) {
516 xp
+= (k
- (int)sizeof(ull
));
517 k
= (int)sizeof(ull
);
520 for (j
= 0; j
< k
; ++j
) {
526 pout(" = %.2f\n", ull
/ 60.0 );
528 pout(" = %"PRIu64
"\n", ull
);
535 static void scsiPrintErrorCounterLog(scsi_device
* device
)
537 struct scsiErrorCounter errCounterArr
[3];
538 struct scsiErrorCounter
* ecp
;
539 struct scsiNonMediumError nme
;
540 int found
[3] = {0, 0, 0};
541 const char * pageNames
[3] = {"read: ", "write: ", "verify: "};
544 if (gReadECounterLPage
&& (0 == scsiLogSense(device
,
545 READ_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
546 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[0]);
549 if (gWriteECounterLPage
&& (0 == scsiLogSense(device
,
550 WRITE_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
551 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[1]);
554 if (gVerifyECounterLPage
&& (0 == scsiLogSense(device
,
555 VERIFY_ERROR_COUNTER_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
556 scsiDecodeErrCounterPage(gBuf
, &errCounterArr
[2]);
557 ecp
= &errCounterArr
[2];
558 for (int k
= 0; k
< 7; ++k
) {
559 if (ecp
->gotPC
[k
] && ecp
->counter
[k
]) {
565 if (found
[0] || found
[1] || found
[2]) {
566 pout("\nError counter log:\n");
567 pout(" Errors Corrected by Total "
568 "Correction Gigabytes Total\n");
569 pout(" ECC rereads/ errors "
570 "algorithm processed uncorrected\n");
571 pout(" fast | delayed rewrites corrected "
572 "invocations [10^9 bytes] errors\n");
573 for (int k
= 0; k
< 3; ++k
) {
576 ecp
= &errCounterArr
[k
];
577 pout("%s%8"PRIu64
" %8"PRIu64
" %8"PRIu64
" %8"PRIu64
" %8"PRIu64
,
578 pageNames
[k
], ecp
->counter
[0], ecp
->counter
[1],
579 ecp
->counter
[2], ecp
->counter
[3], ecp
->counter
[4]);
580 processed_gb
= ecp
->counter
[5] / 1000000000.0;
581 pout(" %12.3f %8"PRIu64
"\n", processed_gb
, ecp
->counter
[6]);
585 pout("\nError Counter logging not supported\n");
586 if (gNonMediumELPage
&& (0 == scsiLogSense(device
,
587 NON_MEDIUM_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LEN
, 0))) {
588 scsiDecodeNonMediumErrPage(gBuf
, &nme
);
590 pout("\nNon-medium error count: %8"PRIu64
"\n", nme
.counterPC0
);
592 pout("Track following error count [Hitachi]: %8"PRIu64
"\n",
595 pout("Positioning error count [Hitachi]: %8"PRIu64
"\n",
598 if (gLastNErrorLPage
&& (0 == scsiLogSense(device
,
599 LAST_N_ERROR_LPAGE
, 0, gBuf
, LOG_RESP_LONG_LEN
, 0))) {
600 int num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
601 int truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
603 num
= LOG_RESP_LONG_LEN
;
604 unsigned char * ucp
= gBuf
+ 4;
607 pout("\nNo error events logged\n");
609 pout("\nLast n error events log page\n");
610 for (int k
= num
, pl
; k
> 0; k
-= pl
, ucp
+= pl
) {
612 pout(" <<short Last n error events log page>>\n");
616 int pc
= (ucp
[0] << 8) + ucp
[1];
618 if ((ucp
[2] & 0x1) && (ucp
[2] & 0x2)) {
619 pout(" Error event %d:\n", pc
);
620 pout(" [binary]:\n");
621 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
622 } else if (ucp
[2] & 0x1) {
623 pout(" Error event %d:\n", pc
);
624 pout(" %.*s\n", pl
- 4, (const char *)(ucp
+ 4));
626 if (scsi_debugmode
> 0) {
627 pout(" Error event %d:\n", pc
);
628 pout(" [data counter??]:\n");
629 dStrHex((const char *)ucp
+ 4, pl
- 4, 1);
635 pout(" >>>> log truncated, fetched %d of %d available "
636 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
641 static const char * self_test_code
[] = {
652 static const char * self_test_result
[] = {
654 "Aborted (by user command)",
655 "Aborted (device reset ?) ",
656 "Unknown error, incomplete",
657 "Completed, segment failed",
658 "Failed in first segment ",
659 "Failed in second segment ",
660 "Failed in segment --> ",
668 "Self test in progress ..."
671 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
672 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
673 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
674 // FAILSMART is returned.
675 static int scsiPrintSelfTest(scsi_device
* device
)
677 int num
, k
, n
, res
, err
, durationSec
;
683 if ((err
= scsiLogSense(device
, SELFTEST_RESULTS_LPAGE
, 0, gBuf
,
684 LOG_RESP_SELF_TEST_LEN
, 0))) {
686 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err
));
690 if ((gBuf
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
692 pout("Self-test Log Sense Failed, page mismatch\n");
696 // compute page length
697 num
= (gBuf
[2] << 8) + gBuf
[3];
698 // Log sense page length 0x190 bytes
701 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num
);
705 // loop through the twenty possible entries
706 for (k
= 0, ucp
= gBuf
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
709 // timestamp in power-on hours (or zero if test in progress)
710 n
= (ucp
[6] << 8) | ucp
[7];
712 // The spec says "all 20 bytes will be zero if no test" but
713 // DG has found otherwise. So this is a heuristic.
714 if ((0 == n
) && (0 == ucp
[4]))
717 // only print header if needed
719 pout("\nSMART Self-test log\n");
720 pout("Num Test Status segment "
721 "LifeTime LBA_first_err [SK ASC ASQ]\n");
722 pout(" Description number "
727 // print parameter code (test number) & self-test code text
728 pout("#%2d %s", (ucp
[0] << 8) | ucp
[1],
729 self_test_code
[(ucp
[4] >> 5) & 0x7]);
731 // check the self-test result nibble, using the self-test results
732 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
733 switch ((res
= ucp
[4] & 0xf)) {
735 // an unknown error occurred while the device server
736 // was processing the self-test and the device server
737 // was unable to complete the self-test
741 // the self-test completed with a failure in a test
742 // segment, and the test segment that failed is not
747 // the first segment of the self-test failed
751 // the second segment of the self-test failed
755 // another segment of the self-test failed and which
756 // test is indicated by the contents of the SELF-TEST
763 pout(" %s", self_test_result
[res
]);
765 // self-test number identifies test that failed and consists
766 // of either the number of the segment that failed during
767 // the test, or the number of the test that failed and the
768 // number of the segment in which the test was run, using a
769 // vendor-specific method of putting both numbers into a
772 pout(" %3d", (int)ucp
[5]);
776 // print time that the self-test was completed
777 if (n
==0 && res
==0xf)
778 // self-test in progress
783 // construct 8-byte integer address of first failure
784 for (i
= 0; i
< 8; i
++) {
788 // print Address of First Failure, if sensible
789 if ((~(uint64_t)0 != ull
) && (res
> 0) && (res
< 0xf)) {
792 // was hex but change to decimal to conform with ATA
793 snprintf(buff
, sizeof(buff
), "%"PRIu64
, ull
);
794 // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull);
799 // if sense key nonzero, then print it, along with
800 // additional sense code and additional sense code qualifier
802 pout(" [0x%x 0x%x 0x%x]\n", ucp
[16] & 0xf, ucp
[17], ucp
[18]);
807 // if header never printed, then there was no output
809 pout("No self-tests have been logged\n");
812 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
813 modese_len
)) && (durationSec
> 0)) {
814 pout("Long (extended) Self Test duration: %d seconds "
815 "[%.1f minutes]\n", durationSec
, durationSec
/ 60.0);
820 static const char * bms_status
[] = {
823 "pre-scan is active",
824 "halted due to fatal error",
825 "halted due to a vendor specific pattern of error",
826 "halted due to medium formatted without P-List",
827 "halted - vendor specific cause",
828 "halted due to temperature out of range",
829 "waiting until BMS interval timer expires", /* 8 */
832 static const char * reassign_status
[] = {
834 "Require Write or Reassign Blocks command",
835 "Successfully reassigned",
837 "Reassignment by disk failed",
838 "Recovered via rewrite in-place",
839 "Reassigned by app, has valid data",
840 "Reassigned by app, has no valid data",
841 "Unsuccessfully reassigned by app", /* 8 */
844 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
845 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
846 // and up to 2048 events (although would hope to have less). May set
847 // FAILLOG if serious errors detected (in the future).
848 static int scsiPrintBackgroundResults(scsi_device
* device
)
850 int num
, j
, m
, err
, pc
, pl
, truncated
;
856 if ((err
= scsiLogSense(device
, BACKGROUND_RESULTS_LPAGE
, 0, gBuf
,
857 LOG_RESP_LONG_LEN
, 0))) {
859 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err
));
863 if ((gBuf
[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE
) {
865 pout("Background scan results Log Sense Failed, page mismatch\n");
869 // compute page length
870 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
873 pout("Background scan results Log Sense length is %d, no scan "
878 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
880 num
= LOG_RESP_LONG_LEN
;
884 pc
= (ucp
[0] << 8) | ucp
[1];
891 pout("\nBackground scan results log\n");
894 if ((pl
< 16) || (num
< 16)) {
899 if (j
< (int)(sizeof(bms_status
) / sizeof(bms_status
[0])))
900 pout("%s\n", bms_status
[j
]);
902 pout("unknown [0x%x] background scan status value\n", j
);
903 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
904 pout(" Accumulated power on time, hours:minutes %d:%02d "
905 "[%d minutes]\n", (j
/ 60), (j
% 60), j
);
906 pout(" Number of background scans performed: %d, ",
907 (ucp
[10] << 8) + ucp
[11]);
908 pout("scan progress: %.2f%%\n",
909 (double)((ucp
[12] << 8) + ucp
[13]) * 100.0 / 65536.0);
910 pout(" Number of background medium scans performed: %d\n",
911 (ucp
[14] << 8) + ucp
[15]);
916 pout("\nBackground scan results log\n");
920 pout("\n # when lba(hex) [sk,asc,ascq] "
921 "reassign_status\n");
924 if ((pl
< 24) || (num
< 24)) {
926 pout("parameter length >= 24 expected, got %d\n", pl
);
929 j
= (ucp
[4] << 24) + (ucp
[5] << 16) + (ucp
[6] << 8) + ucp
[7];
930 pout("%4d:%02d ", (j
/ 60), (j
% 60));
931 for (m
= 0; m
< 8; ++m
)
932 pout("%02x", ucp
[16 + m
]);
933 pout(" [%x,%x,%x] ", ucp
[8] & 0xf, ucp
[9], ucp
[10]);
934 j
= (ucp
[8] >> 4) & 0xf;
936 (int)(sizeof(reassign_status
) / sizeof(reassign_status
[0])))
937 pout("%s\n", reassign_status
[j
]);
939 pout("Reassign status: reserved [0x%x]\n", j
);
946 pout(" >>>> log truncated, fetched %d of %d available "
947 "bytes\n", LOG_RESP_LONG_LEN
, truncated
);
951 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
952 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
953 // and up to 2048 events (although would hope to have less). May set
954 // FAILLOG if serious errors detected (in the future).
955 static int scsiPrintSSMedia(scsi_device
* device
)
957 int num
, err
, pc
, pl
, truncated
;
961 if ((err
= scsiLogSense(device
, SS_MEDIA_LPAGE
, 0, gBuf
,
962 LOG_RESP_LONG_LEN
, 0))) {
964 pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err
));
968 if ((gBuf
[0] & 0x3f) != SS_MEDIA_LPAGE
) {
970 pout("Solid state media Log Sense Failed, page mismatch\n");
974 // compute page length
975 num
= (gBuf
[2] << 8) + gBuf
[3] + 4;
978 pout("Solid state media Log Sense length is %d, too short\n", num
);
982 truncated
= (num
> LOG_RESP_LONG_LEN
) ? num
: 0;
984 num
= LOG_RESP_LONG_LEN
;
988 pc
= (ucp
[0] << 8) | ucp
[1];
995 pout("Percentage used endurance indicator too short (pl=%d)\n", pl
);
999 pout("SS Media used endurance indicator: %d%%\n", ucp
[7]);
1000 default: /* ignore other parameter codes */
1009 static void show_sas_phy_event_info(int peis
, unsigned int val
,
1010 unsigned thresh_val
)
1016 pout(" No event\n");
1019 pout(" Invalid word count: %u\n", val
);
1022 pout(" Running disparity error count: %u\n", val
);
1025 pout(" Loss of dword synchronization count: %u\n", val
);
1028 pout(" Phy reset problem count: %u\n", val
);
1031 pout(" Elasticity buffer overflow count: %u\n", val
);
1034 pout(" Received ERROR count: %u\n", val
);
1037 pout(" Received address frame error count: %u\n", val
);
1040 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val
);
1043 pout(" Received abandon-class OPEN_REJECT count: %u\n", val
);
1046 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val
);
1049 pout(" Received retry-class OPEN_REJECT count: %u\n", val
);
1052 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val
);
1055 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val
);
1058 pout(" Transmitted BREAK count: %u\n", val
);
1061 pout(" Received BREAK count: %u\n", val
);
1064 pout(" Break timeout count: %u\n", val
);
1067 pout(" Connection count: %u\n", val
);
1070 pout(" Peak transmitted pathway blocked count: %u\n",
1072 pout(" Peak value detector threshold: %u\n",
1078 pout(" Peak transmitted arbitration wait time (us): "
1081 pout(" Peak transmitted arbitration wait time (ms): "
1082 "%u\n", 33 + (u
- 0x8000));
1083 u
= thresh_val
& 0xffff;
1085 pout(" Peak value detector threshold (us): %u\n",
1088 pout(" Peak value detector threshold (ms): %u\n",
1092 pout(" Peak arbitration time (us): %u\n", val
);
1093 pout(" Peak value detector threshold: %u\n", thresh_val
);
1096 pout(" Peak connection time (us): %u\n", val
);
1097 pout(" Peak value detector threshold: %u\n", thresh_val
);
1100 pout(" Transmitted SSP frame count: %u\n", val
);
1103 pout(" Received SSP frame count: %u\n", val
);
1106 pout(" Transmitted SSP frame error count: %u\n", val
);
1109 pout(" Received SSP frame error count: %u\n", val
);
1112 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val
);
1115 pout(" Received CREDIT_BLOCKED count: %u\n", val
);
1118 pout(" Transmitted SATA frame count: %u\n", val
);
1121 pout(" Received SATA frame count: %u\n", val
);
1124 pout(" SATA flow control buffer overflow count: %u\n", val
);
1127 pout(" Transmitted SMP frame count: %u\n", val
);
1130 pout(" Received SMP frame count: %u\n", val
);
1133 pout(" Received SMP frame error count: %u\n", val
);
1140 static void show_sas_port_param(unsigned char * ucp
, int param_len
)
1142 int j
, m
, n
, nphys
, t
, sz
, spld_len
;
1143 unsigned char * vcp
;
1150 t
= (ucp
[0] << 8) | ucp
[1];
1151 pout("relative target port id = %d\n", t
);
1152 pout(" generation code = %d\n", ucp
[6]);
1154 pout(" number of phys = %d\n", nphys
);
1156 for (j
= 0, vcp
= ucp
+ 8; j
< (param_len
- 8);
1157 vcp
+= spld_len
, j
+= spld_len
) {
1158 pout(" phy identifier = %d\n", vcp
[1]);
1161 spld_len
= 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1164 t
= ((0x70 & vcp
[4]) >> 4);
1166 case 0: snprintf(s
, sz
, "no device attached"); break;
1167 case 1: snprintf(s
, sz
, "end device"); break;
1168 case 2: snprintf(s
, sz
, "expander device"); break;
1169 case 3: snprintf(s
, sz
, "expander device (fanout)"); break;
1170 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1172 pout(" attached device type: %s\n", s
);
1175 case 0: snprintf(s
, sz
, "unknown"); break;
1176 case 1: snprintf(s
, sz
, "power on"); break;
1177 case 2: snprintf(s
, sz
, "hard reset"); break;
1178 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1179 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1180 case 5: snprintf(s
, sz
, "mux mix up"); break;
1181 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1183 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1184 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1185 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1187 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1189 pout(" attached reason: %s\n", s
);
1190 t
= (vcp
[5] & 0xf0) >> 4;
1192 case 0: snprintf(s
, sz
, "unknown"); break;
1193 case 1: snprintf(s
, sz
, "power on"); break;
1194 case 2: snprintf(s
, sz
, "hard reset"); break;
1195 case 3: snprintf(s
, sz
, "SMP phy control function"); break;
1196 case 4: snprintf(s
, sz
, "loss of dword synchronization"); break;
1197 case 5: snprintf(s
, sz
, "mux mix up"); break;
1198 case 6: snprintf(s
, sz
, "I_T nexus loss timeout for STP/SATA");
1200 case 7: snprintf(s
, sz
, "break timeout timer expired"); break;
1201 case 8: snprintf(s
, sz
, "phy test function stopped"); break;
1202 case 9: snprintf(s
, sz
, "expander device reduced functionality");
1204 default: snprintf(s
, sz
, "reserved [0x%x]", t
); break;
1206 pout(" reason: %s\n", s
);
1209 case 0: snprintf(s
, sz
, "phy enabled; unknown");
1211 case 1: snprintf(s
, sz
, "phy disabled"); break;
1212 case 2: snprintf(s
, sz
, "phy enabled; speed negotiation failed");
1214 case 3: snprintf(s
, sz
, "phy enabled; SATA spinup hold state");
1216 case 4: snprintf(s
, sz
, "phy enabled; port selector");
1218 case 5: snprintf(s
, sz
, "phy enabled; reset in progress");
1220 case 6: snprintf(s
, sz
, "phy enabled; unsupported phy attached");
1222 case 8: snprintf(s
, sz
, "phy enabled; 1.5 Gbps"); break;
1223 case 9: snprintf(s
, sz
, "phy enabled; 3 Gbps"); break;
1224 case 0xa: snprintf(s
, sz
, "phy enabled; 6 Gbps"); break;
1225 default: snprintf(s
, sz
, "reserved [%d]", t
); break;
1227 pout(" negotiated logical link rate: %s\n", s
);
1228 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1229 !! (vcp
[6] & 8), !! (vcp
[6] & 4), !! (vcp
[6] & 2));
1230 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1231 !! (vcp
[7] & 8), !! (vcp
[7] & 4), !! (vcp
[7] & 2));
1232 for (n
= 0, ull
= vcp
[8]; n
< 8; ++n
) {
1233 ull
<<= 8; ull
|= vcp
[8 + n
];
1235 pout(" SAS address = 0x%" PRIx64
"\n", ull
);
1236 for (n
= 0, ull
= vcp
[16]; n
< 8; ++n
) {
1237 ull
<<= 8; ull
|= vcp
[16 + n
];
1239 pout(" attached SAS address = 0x%" PRIx64
"\n", ull
);
1240 pout(" attached phy identifier = %d\n", vcp
[24]);
1241 ui
= (vcp
[32] << 24) | (vcp
[33] << 16) | (vcp
[34] << 8) | vcp
[35];
1242 pout(" Invalid DWORD count = %u\n", ui
);
1243 ui
= (vcp
[36] << 24) | (vcp
[37] << 16) | (vcp
[38] << 8) | vcp
[39];
1244 pout(" Running disparity error count = %u\n", ui
);
1245 ui
= (vcp
[40] << 24) | (vcp
[41] << 16) | (vcp
[42] << 8) | vcp
[43];
1246 pout(" Loss of DWORD synchronization = %u\n", ui
);
1247 ui
= (vcp
[44] << 24) | (vcp
[45] << 16) | (vcp
[46] << 8) | vcp
[47];
1248 pout(" Phy reset problem = %u\n", ui
);
1249 if (spld_len
> 51) {
1251 unsigned char * xcp
;
1256 pout(" Phy event descriptors:\n");
1258 for (m
= 0; m
< (num_ped
* 12); m
+= 12, xcp
+= 12) {
1260 ui
= (xcp
[4] << 24) | (xcp
[5] << 16) | (xcp
[6] << 8) |
1262 pvdt
= (xcp
[8] << 24) | (xcp
[9] << 16) | (xcp
[10] << 8) |
1264 show_sas_phy_event_info(peis
, ui
, pvdt
);
1270 // Returns 1 if okay, 0 if non SAS descriptors
1271 static int show_protocol_specific_page(unsigned char * resp
, int len
)
1273 int k
, num
, param_len
;
1274 unsigned char * ucp
;
1277 for (k
= 0, ucp
= resp
+ 4; k
< num
; ) {
1278 param_len
= ucp
[3] + 4;
1279 if (6 != (0xf & ucp
[4]))
1280 return 0; /* only decode SAS log page */
1282 pout("Protocol Specific port log page for SAS SSP\n");
1283 show_sas_port_param(ucp
, param_len
);
1291 // See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific
1292 // log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol
1293 // Specific log page.
1294 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
1295 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
1296 // FAILSMART is returned.
1297 static int scsiPrintSasPhy(scsi_device
* device
, int reset
)
1301 if ((err
= scsiLogSense(device
, PROTOCOL_SPECIFIC_LPAGE
, 0, gBuf
,
1302 LOG_RESP_LONG_LEN
, 0))) {
1304 pout("scsiPrintSasPhy Log Sense Failed [%s]\n", scsiErrString(err
));
1308 if ((gBuf
[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE
) {
1310 pout("Protocol specific Log Sense Failed, page mismatch\n");
1314 // compute page length
1315 num
= (gBuf
[2] << 8) + gBuf
[3];
1316 if (1 != show_protocol_specific_page(gBuf
, num
+ 4)) {
1318 pout("Only support protocol specific log page on SAS devices\n");
1323 if ((err
= scsiLogSelect(device
, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1324 PROTOCOL_SPECIFIC_LPAGE
, 0, NULL
, 0))) {
1326 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n",
1327 scsiErrString(err
));
1336 static const char * peripheral_dt_arr
[] = {
1352 "optical card reader"
1355 static const char * transport_proto_arr
[] = {
1356 "Fibre channel (FCP-2)",
1357 "Parallel SCSI (SPI-4)",
1359 "IEEE 1394 (SBP-2)",
1374 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1375 static int scsiGetDriveInfo(scsi_device
* device
, UINT8
* peripheral_type
, bool all
)
1377 char timedatetz
[DATEANDEPOCHLEN
];
1378 struct scsi_iec_mode_page iec
;
1379 int err
, iec_err
, len
, req_len
, avail_len
;
1385 memset(gBuf
, 0, 96);
1387 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1389 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err
));
1390 pout("Retrying with a 64 byte Standard Inquiry\n");
1392 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1394 if ((err
= scsiStdInquiry(device
, gBuf
, req_len
))) {
1396 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1397 scsiErrString(err
));
1402 avail_len
= gBuf
[4] + 5;
1403 len
= (avail_len
< req_len
) ? avail_len
: req_len
;
1404 peri_dt
= gBuf
[0] & 0x1f;
1405 if (peripheral_type
)
1406 *peripheral_type
= peri_dt
;
1410 pout("Short INQUIRY response, skip product id\n");
1414 if (all
&& (0 != strncmp((char *)&gBuf
[8], "ATA", 3))) {
1415 pout("Vendor: %.8s\n", (char *)&gBuf
[8]);
1416 pout("Product: %.16s\n", (char *)&gBuf
[16]);
1417 if (gBuf
[32] >= ' ')
1418 pout("Revision: %.4s\n", (char *)&gBuf
[32]);
1421 if (!*device
->get_req_type()/*no type requested*/ &&
1422 (0 == strncmp((char *)&gBuf
[8], "ATA", 3))) {
1423 pout("\nProbable ATA device behind a SAT layer\n"
1424 "Try an additional '-d ata' or '-d sat' argument.\n");
1430 unsigned int lb_size
;
1434 uint64_t capacity
= scsiGetSize(device
, &lb_size
);
1437 format_with_thousands_sep(cap_str
, sizeof(cap_str
), capacity
);
1438 format_capacity(si_str
, sizeof(si_str
), capacity
);
1439 pout("User Capacity: %s bytes [%s]\n", cap_str
, si_str
);
1440 snprintf(lb_str
, sizeof(lb_str
) - 1, "%u", lb_size
);
1441 pout("Logical block size: %s bytes\n", lb_str
);
1444 /* Do this here to try and detect badly conforming devices (some USB
1445 keys) that will lock up on a InquiryVpd or log sense or ... */
1446 if ((iec_err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1447 if (SIMPLE_ERR_BAD_RESP
== iec_err
) {
1448 pout(">> Terminate command early due to bad response to IEC "
1455 modese_len
= iec
.modese_len
;
1457 if (! dont_print_serial_number
) {
1458 if (0 == (err
= scsiInquiryVpd(device
, 0x83, gBuf
, 200))) {
1462 scsi_decode_lu_dev_id(gBuf
+ 4, len
, s
, sizeof(s
), &transport
);
1464 pout("Logical Unit id: %s\n", s
);
1465 } else if (scsi_debugmode
> 0) {
1467 if (SIMPLE_ERR_BAD_RESP
== err
)
1468 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1470 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1473 if (0 == (err
= scsiInquiryVpd(device
, 0x80, gBuf
, 64))) {
1475 gBuf
[4 + len
] = '\0';
1476 pout("Serial number: %s\n", &gBuf
[4]);
1477 } else if (scsi_debugmode
> 0) {
1479 if (SIMPLE_ERR_BAD_RESP
== err
)
1480 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1482 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err
);
1487 // print SCSI peripheral device type
1488 if (peri_dt
< (int)(sizeof(peripheral_dt_arr
) /
1489 sizeof(peripheral_dt_arr
[0])))
1490 pout("Device type: %s\n", peripheral_dt_arr
[peri_dt
]);
1492 pout("Device type: <%d>\n", peri_dt
);
1494 // See if transport protocol is known
1496 transport
= scsiFetchTransportProtocol(device
, modese_len
);
1497 if ((transport
>= 0) && (transport
<= 0xf))
1498 pout("Transport protocol: %s\n", transport_proto_arr
[transport
]);
1500 // print current time and date and timezone
1501 dateandtimezone(timedatetz
);
1502 pout("Local Time is: %s\n", timedatetz
);
1504 if ((SCSI_PT_SEQUENTIAL_ACCESS
== *peripheral_type
) ||
1505 (SCSI_PT_MEDIUM_CHANGER
== *peripheral_type
))
1507 // See if unit accepts SCSI commmands from us
1508 if ((err
= scsiTestUnitReady(device
))) {
1509 if (SIMPLE_ERR_NOT_READY
== err
) {
1512 pout("device is NOT READY (e.g. spun down, busy)\n");
1514 pout("device is NOT READY (e.g. no tape)\n");
1516 } else if (SIMPLE_ERR_NO_MEDIUM
== err
) {
1518 pout("NO MEDIUM present on device\n");
1520 } else if (SIMPLE_ERR_BECOMING_READY
== err
) {
1522 pout("device becoming ready (wait)\n");
1526 pout("device Test Unit Ready [%s]\n", scsiErrString(err
));
1529 failuretest(MANDATORY_CMD
, returnval
|=FAILID
);
1535 pout("Device does not support SMART");
1536 if (scsi_debugmode
> 0)
1537 pout(" [%s]\n", scsiErrString(iec_err
));
1547 pout("Device supports SMART and is %s\n",
1548 (scsi_IsExceptionControlEnabled(&iec
)) ? "Enabled" : "Disabled");
1549 pout("%s\n", (scsi_IsWarningEnabled(&iec
)) ?
1550 "Temperature Warning Enabled" :
1551 "Temperature Warning Disabled or Not Supported");
1555 static int scsiSmartEnable(scsi_device
* device
)
1557 struct scsi_iec_mode_page iec
;
1560 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1562 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1563 scsiErrString(err
));
1567 modese_len
= iec
.modese_len
;
1569 if ((err
= scsiSetExceptionControlAndWarning(device
, 1, &iec
))) {
1571 pout("unable to enable Exception control and warning [%s]\n",
1572 scsiErrString(err
));
1576 /* Need to refetch 'iec' since could be modified by previous call */
1577 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1578 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1579 scsiErrString(err
));
1582 modese_len
= iec
.modese_len
;
1584 pout("Informational Exceptions (SMART) %s\n",
1585 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1586 pout("Temperature warning %s\n",
1587 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1591 static int scsiSmartDisable(scsi_device
* device
)
1593 struct scsi_iec_mode_page iec
;
1596 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1598 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1599 scsiErrString(err
));
1603 modese_len
= iec
.modese_len
;
1605 if ((err
= scsiSetExceptionControlAndWarning(device
, 0, &iec
))) {
1607 pout("unable to disable Exception control and warning [%s]\n",
1608 scsiErrString(err
));
1612 /* Need to refetch 'iec' since could be modified by previous call */
1613 if ((err
= scsiFetchIECmpage(device
, &iec
, modese_len
))) {
1614 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1615 scsiErrString(err
));
1618 modese_len
= iec
.modese_len
;
1620 pout("Informational Exceptions (SMART) %s\n",
1621 scsi_IsExceptionControlEnabled(&iec
) ? "enabled" : "disabled");
1622 pout("Temperature warning %s\n",
1623 scsi_IsWarningEnabled(&iec
) ? "enabled" : "disabled");
1627 static void scsiPrintTemp(scsi_device
* device
)
1632 if (scsiGetTemp(device
, &temp
, &trip
))
1637 pout("Current Drive Temperature: %d C\n", temp
);
1639 pout("Current Drive Temperature: <not available>\n");
1642 pout("Drive Trip Temperature: %d C\n", trip
);
1645 /* Main entry point used by smartctl command. Return 0 for success */
1646 int scsiPrintMain(scsi_device
* device
, const scsi_print_options
& options
)
1648 int checkedSupportedLogPages
= 0;
1649 UINT8 peripheral_type
= 0;
1651 int res
, durationSec
;
1653 bool any_output
= options
.drive_info
;
1655 res
= scsiGetDriveInfo(device
, &peripheral_type
, options
.drive_info
);
1660 failuretest(MANDATORY_CMD
, returnval
|= FAILID
);
1664 if (options
.smart_enable
) {
1665 if (scsiSmartEnable(device
))
1666 failuretest(MANDATORY_CMD
, returnval
|= FAILSMART
);
1670 if (options
.smart_disable
) {
1671 if (scsiSmartDisable(device
))
1672 failuretest(MANDATORY_CMD
,returnval
|= FAILSMART
);
1676 if (options
.smart_auto_save_enable
) {
1677 if (scsiSetControlGLTSD(device
, 0, modese_len
)) {
1678 pout("Enable autosave (clear GLTSD bit) failed\n");
1679 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1684 if (options
.smart_auto_save_disable
) {
1685 if (scsiSetControlGLTSD(device
, 1, modese_len
)) {
1686 pout("Disable autosave (set GLTSD bit) failed\n");
1687 failuretest(OPTIONAL_CMD
,returnval
|= FAILSMART
);
1692 if (options
.smart_check_status
) {
1693 scsiGetSupportedLogPages(device
);
1694 checkedSupportedLogPages
= 1;
1695 if ((SCSI_PT_SEQUENTIAL_ACCESS
== peripheral_type
) ||
1696 (SCSI_PT_MEDIUM_CHANGER
== peripheral_type
)) { /* tape device */
1697 if (gTapeAlertsLPage
) {
1698 if (options
.drive_info
)
1699 pout("TapeAlert Supported\n");
1700 if (-1 == scsiGetTapeAlertsData(device
, peripheral_type
))
1701 failuretest(OPTIONAL_CMD
, returnval
|= FAILSMART
);
1704 pout("TapeAlert Not Supported\n");
1705 } else { /* disk, cd/dvd, enclosure, etc */
1706 if ((res
= scsiGetSmartData(device
, options
.smart_vendor_attrib
))) {
1708 returnval
|= FAILSTATUS
;
1710 returnval
|= FAILSMART
;
1715 if (options
.smart_ss_media_log
) {
1716 if (! checkedSupportedLogPages
)
1717 scsiGetSupportedLogPages(device
);
1720 res
= scsiPrintSSMedia(device
);
1722 failuretest(OPTIONAL_CMD
, returnval
|=res
);
1725 if (options
.smart_vendor_attrib
) {
1726 if (! checkedSupportedLogPages
)
1727 scsiGetSupportedLogPages(device
);
1729 if (options
.smart_check_status
)
1731 scsiPrintTemp(device
);
1733 if (gStartStopLPage
)
1734 scsiGetStartStopData(device
);
1735 if (SCSI_PT_DIRECT_ACCESS
== peripheral_type
) {
1736 scsiPrintGrownDefectListLen(device
);
1737 if (gSeagateCacheLPage
)
1738 scsiPrintSeagateCacheLPage(device
);
1739 if (gSeagateFactoryLPage
)
1740 scsiPrintSeagateFactoryLPage(device
);
1744 if (options
.smart_error_log
) {
1745 if (! checkedSupportedLogPages
)
1746 scsiGetSupportedLogPages(device
);
1747 scsiPrintErrorCounterLog(device
);
1748 if (1 == scsiFetchControlGLTSD(device
, modese_len
, 1))
1749 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
1750 "Enable Save with '-S on']\n");
1753 if (options
.smart_selftest_log
) {
1754 if (! checkedSupportedLogPages
)
1755 scsiGetSupportedLogPages(device
);
1758 res
= scsiPrintSelfTest(device
);
1760 pout("Device does not support Self Test logging\n");
1761 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
1764 failuretest(OPTIONAL_CMD
, returnval
|=res
);
1767 if (options
.smart_background_log
) {
1768 if (! checkedSupportedLogPages
)
1769 scsiGetSupportedLogPages(device
);
1771 if (gBackgroundResultsLPage
)
1772 res
= scsiPrintBackgroundResults(device
);
1774 pout("Device does not support Background scan results logging\n");
1775 failuretest(OPTIONAL_CMD
, returnval
|=FAILSMART
);
1778 failuretest(OPTIONAL_CMD
, returnval
|=res
);
1781 if (options
.smart_default_selftest
) {
1782 if (scsiSmartDefaultSelfTest(device
))
1783 return returnval
| FAILSMART
;
1784 pout("Default Self Test Successful\n");
1787 if (options
.smart_short_cap_selftest
) {
1788 if (scsiSmartShortCapSelfTest(device
))
1789 return returnval
| FAILSMART
;
1790 pout("Short Foreground Self Test Successful\n");
1793 if (options
.smart_short_selftest
) {
1794 if (scsiSmartShortSelfTest(device
))
1795 return returnval
| FAILSMART
;
1796 pout("Short Background Self Test has begun\n");
1797 pout("Use smartctl -X to abort test\n");
1800 if (options
.smart_extend_selftest
) {
1801 if (scsiSmartExtendSelfTest(device
))
1802 return returnval
| FAILSMART
;
1803 pout("Extended Background Self Test has begun\n");
1804 if ((0 == scsiFetchExtendedSelfTestTime(device
, &durationSec
,
1805 modese_len
)) && (durationSec
> 0)) {
1806 time_t t
= time(NULL
);
1809 pout("Please wait %d minutes for test to complete.\n",
1811 pout("Estimated completion time: %s\n", ctime(&t
));
1813 pout("Use smartctl -X to abort test\n");
1816 if (options
.smart_extend_cap_selftest
) {
1817 if (scsiSmartExtendCapSelfTest(device
))
1818 return returnval
| FAILSMART
;
1819 pout("Extended Foreground Self Test Successful\n");
1821 if (options
.smart_selftest_abort
) {
1822 if (scsiSmartSelfTestAbort(device
))
1823 return returnval
| FAILSMART
;
1824 pout("Self Test returned without error\n");
1827 if (options
.sasphy
) {
1828 if (scsiPrintSasPhy(device
, options
.sasphy_reset
))
1829 return returnval
| FAILSMART
;
1834 pout("SCSI device successfully opened\n\n"
1835 "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");