]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - scsiprint.cpp
Stop passing arguments to dh_installinit
[mirror_smartmontools-debian.git] / scsiprint.cpp
1 /*
2 * scsiprint.cpp
3 *
4 * Home page of code is: http://www.smartmontools.org
5 *
6 * Copyright (C) 2002-11 Bruce Allen
7 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
8 * Copyright (C) 2003-15 Douglas Gilbert <dgilbert@interlog.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * You should have received a copy of the GNU General Public License
16 * (for example COPYING); if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * This code was originally developed as a Senior Thesis by Michael Cornwell
20 * at the Concurrent Systems Laboratory (now part of the Storage Systems
21 * Research Center), Jack Baskin School of Engineering, University of
22 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
23 *
24 */
25
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <errno.h>
31
32 #include "config.h"
33 #include "int64.h"
34 #include "scsicmds.h"
35 #include "atacmds.h" // smart_command_set
36 #include "dev_interface.h"
37 #include "scsiprint.h"
38 #include "smartctl.h"
39 #include "utility.h"
40
41 #define GBUF_SIZE 65535
42
43 const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 4189 2015-12-16 14:53:41Z dpgilbert $"
44 SCSIPRINT_H_CVSID;
45
46
47 UINT8 gBuf[GBUF_SIZE];
48 #define LOG_RESP_LEN 252
49 #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
50 #define LOG_RESP_TAPE_ALERT_LEN 0x144
51
52 /* Log pages supported */
53 static int gSmartLPage = 0; /* Informational Exceptions log page */
54 static int gTempLPage = 0;
55 static int gSelfTestLPage = 0;
56 static int gStartStopLPage = 0;
57 static int gReadECounterLPage = 0;
58 static int gWriteECounterLPage = 0;
59 static int gVerifyECounterLPage = 0;
60 static int gNonMediumELPage = 0;
61 static int gLastNErrorLPage = 0;
62 static int gBackgroundResultsLPage = 0;
63 static int gProtocolSpecificLPage = 0;
64 static int gTapeAlertsLPage = 0;
65 static int gSSMediaLPage = 0;
66
67 /* Vendor specific log pages */
68 static int gSeagateCacheLPage = 0;
69 static int gSeagateFactoryLPage = 0;
70
71 /* Mode pages supported */
72 static int gIecMPage = 1; /* N.B. assume it until we know otherwise */
73
74 /* Remember last successful mode sense/select command */
75 static int modese_len = 0;
76
77
78 static void
79 scsiGetSupportedLogPages(scsi_device * device)
80 {
81 int i, err;
82
83 if ((err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
84 LOG_RESP_LEN, 0))) {
85 if (scsi_debugmode > 0)
86 pout("Log Sense for supported pages failed [%s]\n",
87 scsiErrString(err));
88 return;
89 }
90
91 for (i = 4; i < gBuf[3] + LOGPAGEHDRSIZE; i++) {
92 switch (gBuf[i])
93 {
94 case READ_ERROR_COUNTER_LPAGE:
95 gReadECounterLPage = 1;
96 break;
97 case WRITE_ERROR_COUNTER_LPAGE:
98 gWriteECounterLPage = 1;
99 break;
100 case VERIFY_ERROR_COUNTER_LPAGE:
101 gVerifyECounterLPage = 1;
102 break;
103 case LAST_N_ERROR_LPAGE:
104 gLastNErrorLPage = 1;
105 break;
106 case NON_MEDIUM_ERROR_LPAGE:
107 gNonMediumELPage = 1;
108 break;
109 case TEMPERATURE_LPAGE:
110 gTempLPage = 1;
111 break;
112 case STARTSTOP_CYCLE_COUNTER_LPAGE:
113 gStartStopLPage = 1;
114 break;
115 case SELFTEST_RESULTS_LPAGE:
116 gSelfTestLPage = 1;
117 break;
118 case IE_LPAGE:
119 gSmartLPage = 1;
120 break;
121 case BACKGROUND_RESULTS_LPAGE:
122 gBackgroundResultsLPage = 1;
123 break;
124 case PROTOCOL_SPECIFIC_LPAGE:
125 gProtocolSpecificLPage = 1;
126 break;
127 case TAPE_ALERTS_LPAGE:
128 gTapeAlertsLPage = 1;
129 break;
130 case SS_MEDIA_LPAGE:
131 gSSMediaLPage = 1;
132 break;
133 case SEAGATE_CACHE_LPAGE:
134 gSeagateCacheLPage = 1;
135 break;
136 case SEAGATE_FACTORY_LPAGE:
137 gSeagateFactoryLPage = 1;
138 break;
139 default:
140 break;
141 }
142 }
143 }
144
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
148 scsiGetSmartData(scsi_device * device, bool attribs)
149 {
150 UINT8 asc;
151 UINT8 ascq;
152 UINT8 currenttemp = 0;
153 UINT8 triptemp = 0;
154 const char * cp;
155 int err = 0;
156 print_on();
157 if (scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, &ascq,
158 &currenttemp, &triptemp)) {
159 /* error message already announced */
160 print_off();
161 return -1;
162 }
163 print_off();
164 cp = scsiGetIEString(asc, ascq);
165 if (cp) {
166 err = -2;
167 print_on();
168 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq);
169 print_off();
170 } else if (gIecMPage)
171 pout("SMART Health Status: OK\n");
172
173 if (attribs && !gTempLPage) {
174 if (currenttemp) {
175 if (255 != currenttemp)
176 pout("Current Drive Temperature: %d C\n", currenttemp);
177 else
178 pout("Current Drive Temperature: <not available>\n");
179 }
180 if (triptemp)
181 pout("Drive Trip Temperature: %d C\n", triptemp);
182 }
183 pout("\n");
184 return err;
185 }
186
187
188 // Returns number of logged errors or zero if none or -1 if fetching
189 // TapeAlerts fails
190 static const char * const severities = "CWI";
191
192 static int
193 scsiGetTapeAlertsData(scsi_device * device, int peripheral_type)
194 {
195 unsigned short pagelength;
196 unsigned short parametercode;
197 int i, err;
198 const char *s;
199 const char *ts;
200 int failures = 0;
201
202 print_on();
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));
206 print_off();
207 return -1;
208 }
209 if (gBuf[0] != 0x2e) {
210 pout("TapeAlerts Log Sense Failed\n");
211 print_off();
212 return -1;
213 }
214 pagelength = (unsigned short) gBuf[2] << 8 | gBuf[3];
215
216 for (s=severities; *s; s++) {
217 for (i = 4; i < pagelength; i += 5) {
218 parametercode = (unsigned short) gBuf[i] << 8 | gBuf[i+1];
219
220 if (gBuf[i + 4]) {
221 ts = SCSI_PT_MEDIUM_CHANGER == peripheral_type ?
222 scsiTapeAlertsChangerDevice(parametercode) :
223 scsiTapeAlertsTapeDevice(parametercode);
224 if (*ts == *s) {
225 if (!failures)
226 pout("TapeAlert Errors (C=Critical, W=Warning, "
227 "I=Informational):\n");
228 pout("[0x%02x] %s\n", parametercode, ts);
229 failures += 1;
230 }
231 }
232 }
233 }
234 print_off();
235
236 if (! failures)
237 pout("TapeAlert: OK\n");
238
239 return failures;
240 }
241
242 static void
243 scsiGetStartStopData(scsi_device * device)
244 {
245 int err, len, k, extra;
246 unsigned char * ucp;
247
248 if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf,
249 LOG_RESP_LEN, 0))) {
250 print_on();
251 pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err));
252 print_off();
253 return;
254 }
255 if ((gBuf[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE) {
256 print_on();
257 pout("StartStop Log Sense Failed, page mismatch\n");
258 print_off();
259 return;
260 }
261 len = ((gBuf[2] << 8) | gBuf[3]);
262 ucp = gBuf + 4;
263 for (k = len; k > 0; k -= extra, ucp += extra) {
264 if (k < 3) {
265 print_on();
266 pout("StartStop Log Sense Failed: short\n");
267 print_off();
268 return;
269 }
270 extra = ucp[3] + 4;
271 int pc = (ucp[0] << 8) + ucp[1];
272 UINT32 u;
273 switch (pc) {
274 case 1:
275 if (10 == extra)
276 pout("Manufactured in week %.2s of year %.4s\n", ucp + 8,
277 ucp + 4);
278 break;
279 case 2:
280 /* ignore Accounting date */
281 break;
282 case 3:
283 if (extra > 7) {
284 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
285 if (0xffffffff != u)
286 pout("Specified cycle count over device lifetime: %u\n",
287 u);
288 }
289 break;
290 case 4:
291 if (extra > 7) {
292 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
293 if (0xffffffff != u)
294 pout("Accumulated start-stop cycles: %u\n", u);
295 }
296 break;
297 case 5:
298 if (extra > 7) {
299 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
300 if (0xffffffff != u)
301 pout("Specified load-unload count over device "
302 "lifetime: %u\n", u);
303 }
304 break;
305 case 6:
306 if (extra > 7) {
307 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
308 if (0xffffffff != u)
309 pout("Accumulated load-unload cycles: %u\n", u);
310 }
311 break;
312 default:
313 /* ignore */
314 break;
315 }
316 }
317 }
318
319 static void
320 scsiPrintGrownDefectListLen(scsi_device * device)
321 {
322 int err, dl_format, got_rd12;
323 unsigned int dl_len, div;
324
325 memset(gBuf, 0, 8);
326 if ((err = scsiReadDefect12(device, 0 /* req_plist */, 1 /* req_glist */,
327 4 /* format: bytes from index */,
328 0 /* addr desc index */, gBuf, 8))) {
329 if (2 == err) { /* command not supported */
330 if ((err = scsiReadDefect10(device, 0 /* req_plist */, 1 /* req_glist */,
331 4 /* format: bytes from index */, gBuf, 4))) {
332 if (scsi_debugmode > 0) {
333 print_on();
334 pout("Read defect list (10) Failed: %s\n", scsiErrString(err));
335 print_off();
336 }
337 return;
338 } else
339 got_rd12 = 0;
340 } else if (101 == err) /* Defect list not found, leave quietly */
341 return;
342 else {
343 if (scsi_debugmode > 0) {
344 print_on();
345 pout("Read defect list (12) Failed: %s\n", scsiErrString(err));
346 print_off();
347 }
348 return;
349 }
350 } else
351 got_rd12 = 1;
352
353 if (got_rd12) {
354 int generation = (gBuf[2] << 8) + gBuf[3];
355 if ((generation > 1) && (scsi_debugmode > 0)) {
356 print_on();
357 pout("Read defect list (12): generation=%d\n", generation);
358 print_off();
359 }
360 dl_len = (gBuf[4] << 24) + (gBuf[5] << 16) + (gBuf[6] << 8) + gBuf[7];
361 } else {
362 dl_len = (gBuf[2] << 8) + gBuf[3];
363 }
364 if (0x8 != (gBuf[1] & 0x18)) {
365 print_on();
366 pout("Read defect list: asked for grown list but didn't get it\n");
367 print_off();
368 return;
369 }
370 div = 0;
371 dl_format = (gBuf[1] & 0x7);
372 switch (dl_format) {
373 case 0: /* short block */
374 div = 4;
375 break;
376 case 1: /* extended bytes from index */
377 case 2: /* extended physical sector */
378 /* extended = 1; # might use in future */
379 div = 8;
380 break;
381 case 3: /* long block */
382 case 4: /* bytes from index */
383 case 5: /* physical sector */
384 div = 8;
385 break;
386 default:
387 print_on();
388 pout("defect list format %d unknown\n", dl_format);
389 print_off();
390 break;
391 }
392 if (0 == dl_len)
393 pout("Elements in grown defect list: 0\n\n");
394 else {
395 if (0 == div)
396 pout("Grown defect list length=%u bytes [unknown "
397 "number of elements]\n\n", dl_len);
398 else
399 pout("Elements in grown defect list: %u\n\n", dl_len / div);
400 }
401 }
402
403 static void
404 scsiPrintSeagateCacheLPage(scsi_device * device)
405 {
406 int num, pl, pc, err, len;
407 unsigned char * ucp;
408 uint64_t ull;
409
410 if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf,
411 LOG_RESP_LEN, 0))) {
412 print_on();
413 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err));
414 print_off();
415 return;
416 }
417 if ((gBuf[0] & 0x3f) != SEAGATE_CACHE_LPAGE) {
418 print_on();
419 pout("Seagate Cache Log Sense Failed, page mismatch\n");
420 print_off();
421 return;
422 }
423 len = ((gBuf[2] << 8) | gBuf[3]) + 4;
424 num = len - 4;
425 ucp = &gBuf[0] + 4;
426 while (num > 3) {
427 pc = (ucp[0] << 8) | ucp[1];
428 pl = ucp[3] + 4;
429 switch (pc) {
430 case 0: case 1: case 2: case 3: case 4:
431 break;
432 default:
433 if (scsi_debugmode > 0) {
434 print_on();
435 pout("Vendor (Seagate) cache lpage has unexpected parameter"
436 ", skip\n");
437 print_off();
438 }
439 return;
440 }
441 num -= pl;
442 ucp += pl;
443 }
444 pout("Vendor (Seagate) cache information\n");
445 num = len - 4;
446 ucp = &gBuf[0] + 4;
447 while (num > 3) {
448 pc = (ucp[0] << 8) | ucp[1];
449 pl = ucp[3] + 4;
450 switch (pc) {
451 case 0: pout(" Blocks sent to initiator"); break;
452 case 1: pout(" Blocks received from initiator"); break;
453 case 2: pout(" Blocks read from cache and sent to initiator"); break;
454 case 3: pout(" Number of read and write commands whose size "
455 "<= segment size"); break;
456 case 4: pout(" Number of read and write commands whose size "
457 "> segment size"); break;
458 default: pout(" Unknown Seagate parameter code [0x%x]", pc); break;
459 }
460 int k = pl - 4;
461 unsigned char * xp = ucp + 4;
462 if (k > (int)sizeof(ull)) {
463 xp += (k - (int)sizeof(ull));
464 k = (int)sizeof(ull);
465 }
466 ull = 0;
467 for (int j = 0; j < k; ++j) {
468 if (j > 0)
469 ull <<= 8;
470 ull |= xp[j];
471 }
472 pout(" = %" PRIu64 "\n", ull);
473 num -= pl;
474 ucp += pl;
475 }
476 pout("\n");
477 }
478
479 static void
480 scsiPrintSeagateFactoryLPage(scsi_device * device)
481 {
482 int num, pl, pc, len, err, good, bad;
483 unsigned char * ucp;
484 uint64_t ull;
485
486 if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf,
487 LOG_RESP_LEN, 0))) {
488 print_on();
489 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err));
490 print_off();
491 return;
492 }
493 if ((gBuf[0] & 0x3f) != SEAGATE_FACTORY_LPAGE) {
494 print_on();
495 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
496 print_off();
497 return;
498 }
499 len = ((gBuf[2] << 8) | gBuf[3]) + 4;
500 num = len - 4;
501 ucp = &gBuf[0] + 4;
502 good = 0;
503 bad = 0;
504 while (num > 3) {
505 pc = (ucp[0] << 8) | ucp[1];
506 pl = ucp[3] + 4;
507 switch (pc) {
508 case 0: case 8:
509 ++good;
510 break;
511 default:
512 ++bad;
513 break;
514 }
515 num -= pl;
516 ucp += pl;
517 }
518 if ((good < 2) || (bad > 4)) { /* heuristic */
519 if (scsi_debugmode > 0) {
520 print_on();
521 pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
522 "unexpected parameters, skip\n");
523 print_off();
524 }
525 return;
526 }
527 pout("Vendor (Seagate/Hitachi) factory information\n");
528 num = len - 4;
529 ucp = &gBuf[0] + 4;
530 while (num > 3) {
531 pc = (ucp[0] << 8) | ucp[1];
532 pl = ucp[3] + 4;
533 good = 0;
534 switch (pc) {
535 case 0: pout(" number of hours powered up");
536 good = 1;
537 break;
538 case 8: pout(" number of minutes until next internal SMART test");
539 good = 1;
540 break;
541 default:
542 if (scsi_debugmode > 0) {
543 print_on();
544 pout("Vendor (Seagate/Hitachi) factory lpage: "
545 "unknown parameter code [0x%x]\n", pc);
546 print_off();
547 }
548 break;
549 }
550 if (good) {
551 int k = pl - 4;
552 unsigned char * xp = ucp + 4;
553 if (k > (int)sizeof(ull)) {
554 xp += (k - (int)sizeof(ull));
555 k = (int)sizeof(ull);
556 }
557 ull = 0;
558 for (int j = 0; j < k; ++j) {
559 if (j > 0)
560 ull <<= 8;
561 ull |= xp[j];
562 }
563 if (0 == pc)
564 pout(" = %.2f\n", ull / 60.0 );
565 else
566 pout(" = %" PRIu64 "\n", ull);
567 }
568 num -= pl;
569 ucp += pl;
570 }
571 pout("\n");
572 }
573
574 static void
575 scsiPrintErrorCounterLog(scsi_device * device)
576 {
577 struct scsiErrorCounter errCounterArr[3];
578 struct scsiErrorCounter * ecp;
579 int found[3] = {0, 0, 0};
580
581 if (gReadECounterLPage && (0 == scsiLogSense(device,
582 READ_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
583 scsiDecodeErrCounterPage(gBuf, &errCounterArr[0]);
584 found[0] = 1;
585 }
586 if (gWriteECounterLPage && (0 == scsiLogSense(device,
587 WRITE_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
588 scsiDecodeErrCounterPage(gBuf, &errCounterArr[1]);
589 found[1] = 1;
590 }
591 if (gVerifyECounterLPage && (0 == scsiLogSense(device,
592 VERIFY_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
593 scsiDecodeErrCounterPage(gBuf, &errCounterArr[2]);
594 ecp = &errCounterArr[2];
595 for (int k = 0; k < 7; ++k) {
596 if (ecp->gotPC[k] && ecp->counter[k]) {
597 found[2] = 1;
598 break;
599 }
600 }
601 }
602 if (found[0] || found[1] || found[2]) {
603 pout("Error counter log:\n");
604 pout(" Errors Corrected by Total "
605 "Correction Gigabytes Total\n");
606 pout(" ECC rereads/ errors "
607 "algorithm processed uncorrected\n");
608 pout(" fast | delayed rewrites corrected "
609 "invocations [10^9 bytes] errors\n");
610 for (int k = 0; k < 3; ++k) {
611 if (! found[k])
612 continue;
613 ecp = &errCounterArr[k];
614 static const char * const pageNames[3] = {"read: ", "write: ", "verify: "};
615 pout("%s%8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64 " %8" PRIu64,
616 pageNames[k], ecp->counter[0], ecp->counter[1],
617 ecp->counter[2], ecp->counter[3], ecp->counter[4]);
618 double processed_gb = ecp->counter[5] / 1000000000.0;
619 pout(" %12.3f %8" PRIu64 "\n", processed_gb, ecp->counter[6]);
620 }
621 }
622 else
623 pout("Error Counter logging not supported\n");
624 if (gNonMediumELPage && (0 == scsiLogSense(device,
625 NON_MEDIUM_ERROR_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
626 struct scsiNonMediumError nme;
627 scsiDecodeNonMediumErrPage(gBuf, &nme);
628 if (nme.gotPC0)
629 pout("\nNon-medium error count: %8" PRIu64 "\n", nme.counterPC0);
630 if (nme.gotTFE_H)
631 pout("Track following error count [Hitachi]: %8" PRIu64 "\n",
632 nme.counterTFE_H);
633 if (nme.gotPE_H)
634 pout("Positioning error count [Hitachi]: %8" PRIu64 "\n",
635 nme.counterPE_H);
636 }
637 if (gLastNErrorLPage && (0 == scsiLogSense(device,
638 LAST_N_ERROR_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) {
639 int num = (gBuf[2] << 8) + gBuf[3] + 4;
640 int truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
641 if (truncated)
642 num = LOG_RESP_LONG_LEN;
643 unsigned char * ucp = gBuf + 4;
644 num -= 4;
645 if (num < 4)
646 pout("\nNo error events logged\n");
647 else {
648 pout("\nLast n error events log page\n");
649 for (int k = num, pl; k > 0; k -= pl, ucp += pl) {
650 if (k < 3) {
651 pout(" <<short Last n error events log page>>\n");
652 break;
653 }
654 pl = ucp[3] + 4;
655 int pc = (ucp[0] << 8) + ucp[1];
656 if (pl > 4) {
657 if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) {
658 pout(" Error event %d:\n", pc);
659 pout(" [binary]:\n");
660 dStrHex((const char *)ucp + 4, pl - 4, 1);
661 } else if (ucp[2] & 0x1) {
662 pout(" Error event %d:\n", pc);
663 pout(" %.*s\n", pl - 4, (const char *)(ucp + 4));
664 } else {
665 if (scsi_debugmode > 0) {
666 pout(" Error event %d:\n", pc);
667 pout(" [data counter??]:\n");
668 dStrHex((const char *)ucp + 4, pl - 4, 1);
669 }
670 }
671 }
672 }
673 if (truncated)
674 pout(" >>>> log truncated, fetched %d of %d available "
675 "bytes\n", LOG_RESP_LONG_LEN, truncated);
676 }
677 }
678 pout("\n");
679 }
680
681 static const char * self_test_code[] = {
682 "Default ",
683 "Background short",
684 "Background long ",
685 "Reserved(3) ",
686 "Abort background",
687 "Foreground short",
688 "Foreground long ",
689 "Reserved(7) "
690 };
691
692 static const char * self_test_result[] = {
693 "Completed ",
694 "Aborted (by user command)",
695 "Aborted (device reset ?) ",
696 "Unknown error, incomplete",
697 "Completed, segment failed",
698 "Failed in first segment ",
699 "Failed in second segment ",
700 "Failed in segment --> ",
701 "Reserved(8) ",
702 "Reserved(9) ",
703 "Reserved(10) ",
704 "Reserved(11) ",
705 "Reserved(12) ",
706 "Reserved(13) ",
707 "Reserved(14) ",
708 "Self test in progress ..."
709 };
710
711 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
712 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
713 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
714 // FAILSMART is returned.
715 static int
716 scsiPrintSelfTest(scsi_device * device)
717 {
718 int num, k, err, durationSec;
719 int noheader = 1;
720 int retval = 0;
721 UINT8 * ucp;
722 uint64_t ull=0;
723 struct scsi_sense_disect sense_info;
724
725 // check if test is running
726 if (!scsiRequestSense(device, &sense_info) &&
727 (sense_info.asc == 0x04 && sense_info.ascq == 0x09 &&
728 sense_info.progress != -1)) {
729 pout("Self-test execution status:\t\t%d%% of test remaining\n",
730 100 - ((sense_info.progress * 100) / 65535));
731 }
732
733 if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf,
734 LOG_RESP_SELF_TEST_LEN, 0))) {
735 print_on();
736 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err));
737 print_off();
738 return FAILSMART;
739 }
740 if ((gBuf[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
741 print_on();
742 pout("Self-test Log Sense Failed, page mismatch\n");
743 print_off();
744 return FAILSMART;
745 }
746 // compute page length
747 num = (gBuf[2] << 8) + gBuf[3];
748 // Log sense page length 0x190 bytes
749 if (num != 0x190) {
750 print_on();
751 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num);
752 print_off();
753 return FAILSMART;
754 }
755 // loop through the twenty possible entries
756 for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) {
757 int i;
758
759 // timestamp in power-on hours (or zero if test in progress)
760 int n = (ucp[6] << 8) | ucp[7];
761
762 // The spec says "all 20 bytes will be zero if no test" but
763 // DG has found otherwise. So this is a heuristic.
764 if ((0 == n) && (0 == ucp[4]))
765 break;
766
767 // only print header if needed
768 if (noheader) {
769 pout("SMART Self-test log\n");
770 pout("Num Test Status segment "
771 "LifeTime LBA_first_err [SK ASC ASQ]\n");
772 pout(" Description number "
773 "(hours)\n");
774 noheader=0;
775 }
776
777 // print parameter code (test number) & self-test code text
778 pout("#%2d %s", (ucp[0] << 8) | ucp[1],
779 self_test_code[(ucp[4] >> 5) & 0x7]);
780
781 // check the self-test result nibble, using the self-test results
782 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
783 int res;
784 switch ((res = ucp[4] & 0xf)) {
785 case 0x3:
786 // an unknown error occurred while the device server
787 // was processing the self-test and the device server
788 // was unable to complete the self-test
789 retval|=FAILSMART;
790 break;
791 case 0x4:
792 // the self-test completed with a failure in a test
793 // segment, and the test segment that failed is not
794 // known
795 retval|=FAILLOG;
796 break;
797 case 0x5:
798 // the first segment of the self-test failed
799 retval|=FAILLOG;
800 break;
801 case 0x6:
802 // the second segment of the self-test failed
803 retval|=FAILLOG;
804 break;
805 case 0x7:
806 // another segment of the self-test failed and which
807 // test is indicated by the contents of the SELF-TEST
808 // NUMBER field
809 retval|=FAILLOG;
810 break;
811 default:
812 break;
813 }
814 pout(" %s", self_test_result[res]);
815
816 // self-test number identifies test that failed and consists
817 // of either the number of the segment that failed during
818 // the test, or the number of the test that failed and the
819 // number of the segment in which the test was run, using a
820 // vendor-specific method of putting both numbers into a
821 // single byte.
822 if (ucp[5])
823 pout(" %3d", (int)ucp[5]);
824 else
825 pout(" -");
826
827 // print time that the self-test was completed
828 if (n==0 && res==0xf)
829 // self-test in progress
830 pout(" NOW");
831 else
832 pout(" %5d", n);
833
834 // construct 8-byte integer address of first failure
835 for (i = 0; i < 8; i++) {
836 ull <<= 8;
837 ull |= ucp[i+8];
838 }
839 // print Address of First Failure, if sensible
840 if ((~(uint64_t)0 != ull) && (res > 0) && (res < 0xf)) {
841 char buff[32];
842
843 // was hex but change to decimal to conform with ATA
844 snprintf(buff, sizeof(buff), "%" PRIu64, ull);
845 // snprintf(buff, sizeof(buff), "0x%" PRIx64, ull);
846 pout("%18s", buff);
847 } else
848 pout(" -");
849
850 // if sense key nonzero, then print it, along with
851 // additional sense code and additional sense code qualifier
852 if (ucp[16] & 0xf)
853 pout(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]);
854 else
855 pout(" [- - -]\n");
856 }
857
858 // if header never printed, then there was no output
859 if (noheader)
860 pout("No self-tests have been logged\n");
861 else
862 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
863 modese_len)) && (durationSec > 0)) {
864 pout("\nLong (extended) Self Test duration: %d seconds "
865 "[%.1f minutes]\n", durationSec, durationSec / 60.0);
866 }
867 pout("\n");
868 return retval;
869 }
870
871 static const char * bms_status[] = {
872 "no scans active",
873 "scan is active",
874 "pre-scan is active",
875 "halted due to fatal error",
876 "halted due to a vendor specific pattern of error",
877 "halted due to medium formatted without P-List",
878 "halted - vendor specific cause",
879 "halted due to temperature out of range",
880 "waiting until BMS interval timer expires", /* 8 */
881 };
882
883 static const char * reassign_status[] = {
884 "Reserved [0x0]",
885 "Require Write or Reassign Blocks command",
886 "Successfully reassigned",
887 "Reserved [0x3]",
888 "Reassignment by disk failed",
889 "Recovered via rewrite in-place",
890 "Reassigned by app, has valid data",
891 "Reassigned by app, has no valid data",
892 "Unsuccessfully reassigned by app", /* 8 */
893 };
894
895 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
896 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
897 // and up to 2048 events (although would hope to have less). May set
898 // FAILLOG if serious errors detected (in the future).
899 static int
900 scsiPrintBackgroundResults(scsi_device * device)
901 {
902 int num, j, m, err, truncated;
903 int noheader = 1;
904 int firstresult = 1;
905 int retval = 0;
906 UINT8 * ucp;
907
908 if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf,
909 LOG_RESP_LONG_LEN, 0))) {
910 print_on();
911 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err));
912 print_off();
913 return FAILSMART;
914 }
915 if ((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) {
916 print_on();
917 pout("Background scan results Log Sense Failed, page mismatch\n");
918 print_off();
919 return FAILSMART;
920 }
921 // compute page length
922 num = (gBuf[2] << 8) + gBuf[3] + 4;
923 if (num < 20) {
924 print_on();
925 pout("Background scan results Log Sense length is %d, no scan "
926 "status\n", num);
927 print_off();
928 return FAILSMART;
929 }
930 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
931 if (truncated)
932 num = LOG_RESP_LONG_LEN;
933 ucp = gBuf + 4;
934 num -= 4;
935 while (num > 3) {
936 int pc = (ucp[0] << 8) | ucp[1];
937 // pcb = ucp[2];
938 int pl = ucp[3] + 4;
939 switch (pc) {
940 case 0:
941 if (noheader) {
942 noheader = 0;
943 pout("Background scan results log\n");
944 }
945 pout(" Status: ");
946 if ((pl < 16) || (num < 16)) {
947 pout("\n");
948 break;
949 }
950 j = ucp[9];
951 if (j < (int)(sizeof(bms_status) / sizeof(bms_status[0])))
952 pout("%s\n", bms_status[j]);
953 else
954 pout("unknown [0x%x] background scan status value\n", j);
955 j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7];
956 pout(" Accumulated power on time, hours:minutes %d:%02d "
957 "[%d minutes]\n", (j / 60), (j % 60), j);
958 pout(" Number of background scans performed: %d, ",
959 (ucp[10] << 8) + ucp[11]);
960 pout("scan progress: %.2f%%\n",
961 (double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0);
962 pout(" Number of background medium scans performed: %d\n",
963 (ucp[14] << 8) + ucp[15]);
964 break;
965 default:
966 if (noheader) {
967 noheader = 0;
968 pout("\nBackground scan results log\n");
969 }
970 if (firstresult) {
971 firstresult = 0;
972 pout("\n # when lba(hex) [sk,asc,ascq] "
973 "reassign_status\n");
974 }
975 pout(" %3d ", pc);
976 if ((pl < 24) || (num < 24)) {
977 if (pl < 24)
978 pout("parameter length >= 24 expected, got %d\n", pl);
979 break;
980 }
981 j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7];
982 pout("%4d:%02d ", (j / 60), (j % 60));
983 for (m = 0; m < 8; ++m)
984 pout("%02x", ucp[16 + m]);
985 pout(" [%x,%x,%x] ", ucp[8] & 0xf, ucp[9], ucp[10]);
986 j = (ucp[8] >> 4) & 0xf;
987 if (j <
988 (int)(sizeof(reassign_status) / sizeof(reassign_status[0])))
989 pout("%s\n", reassign_status[j]);
990 else
991 pout("Reassign status: reserved [0x%x]\n", j);
992 break;
993 }
994 num -= pl;
995 ucp += pl;
996 }
997 if (truncated)
998 pout(" >>>> log truncated, fetched %d of %d available "
999 "bytes\n", LOG_RESP_LONG_LEN, truncated);
1000 pout("\n");
1001 return retval;
1002 }
1003
1004 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
1005 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
1006 // and up to 2048 events (although would hope to have less). May set
1007 // FAILLOG if serious errors detected (in the future).
1008 static int
1009 scsiPrintSSMedia(scsi_device * device)
1010 {
1011 int num, err, truncated;
1012 int retval = 0;
1013 UINT8 * ucp;
1014
1015 if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf,
1016 LOG_RESP_LONG_LEN, 0))) {
1017 print_on();
1018 pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err));
1019 print_off();
1020 return FAILSMART;
1021 }
1022 if ((gBuf[0] & 0x3f) != SS_MEDIA_LPAGE) {
1023 print_on();
1024 pout("Solid state media Log Sense Failed, page mismatch\n");
1025 print_off();
1026 return FAILSMART;
1027 }
1028 // compute page length
1029 num = (gBuf[2] << 8) + gBuf[3] + 4;
1030 if (num < 12) {
1031 print_on();
1032 pout("Solid state media Log Sense length is %d, too short\n", num);
1033 print_off();
1034 return FAILSMART;
1035 }
1036 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
1037 if (truncated)
1038 num = LOG_RESP_LONG_LEN;
1039 ucp = gBuf + 4;
1040 num -= 4;
1041 while (num > 3) {
1042 int pc = (ucp[0] << 8) | ucp[1];
1043 // pcb = ucp[2];
1044 int pl = ucp[3] + 4;
1045 switch (pc) {
1046 case 1:
1047 if (pl < 8) {
1048 print_on();
1049 pout("SS Media Percentage used endurance indicator parameter "
1050 "too short (pl=%d)\n", pl);
1051 print_off();
1052 return FAILSMART;
1053 }
1054 pout("Percentage used endurance indicator: %d%%\n", ucp[7]);
1055 default: /* ignore other parameter codes */
1056 break;
1057 }
1058 num -= pl;
1059 ucp += pl;
1060 }
1061 return retval;
1062 }
1063
1064 static void
1065 show_sas_phy_event_info(int peis, unsigned int val, unsigned thresh_val)
1066 {
1067 unsigned int u;
1068
1069 switch (peis) {
1070 case 0:
1071 pout(" No event\n");
1072 break;
1073 case 0x1:
1074 pout(" Invalid word count: %u\n", val);
1075 break;
1076 case 0x2:
1077 pout(" Running disparity error count: %u\n", val);
1078 break;
1079 case 0x3:
1080 pout(" Loss of dword synchronization count: %u\n", val);
1081 break;
1082 case 0x4:
1083 pout(" Phy reset problem count: %u\n", val);
1084 break;
1085 case 0x5:
1086 pout(" Elasticity buffer overflow count: %u\n", val);
1087 break;
1088 case 0x6:
1089 pout(" Received ERROR count: %u\n", val);
1090 break;
1091 case 0x20:
1092 pout(" Received address frame error count: %u\n", val);
1093 break;
1094 case 0x21:
1095 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val);
1096 break;
1097 case 0x22:
1098 pout(" Received abandon-class OPEN_REJECT count: %u\n", val);
1099 break;
1100 case 0x23:
1101 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val);
1102 break;
1103 case 0x24:
1104 pout(" Received retry-class OPEN_REJECT count: %u\n", val);
1105 break;
1106 case 0x25:
1107 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val);
1108 break;
1109 case 0x26:
1110 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val);
1111 break;
1112 case 0x27:
1113 pout(" Transmitted BREAK count: %u\n", val);
1114 break;
1115 case 0x28:
1116 pout(" Received BREAK count: %u\n", val);
1117 break;
1118 case 0x29:
1119 pout(" Break timeout count: %u\n", val);
1120 break;
1121 case 0x2a:
1122 pout(" Connection count: %u\n", val);
1123 break;
1124 case 0x2b:
1125 pout(" Peak transmitted pathway blocked count: %u\n",
1126 val & 0xff);
1127 pout(" Peak value detector threshold: %u\n",
1128 thresh_val & 0xff);
1129 break;
1130 case 0x2c:
1131 u = val & 0xffff;
1132 if (u < 0x8000)
1133 pout(" Peak transmitted arbitration wait time (us): "
1134 "%u\n", u);
1135 else
1136 pout(" Peak transmitted arbitration wait time (ms): "
1137 "%u\n", 33 + (u - 0x8000));
1138 u = thresh_val & 0xffff;
1139 if (u < 0x8000)
1140 pout(" Peak value detector threshold (us): %u\n",
1141 u);
1142 else
1143 pout(" Peak value detector threshold (ms): %u\n",
1144 33 + (u - 0x8000));
1145 break;
1146 case 0x2d:
1147 pout(" Peak arbitration time (us): %u\n", val);
1148 pout(" Peak value detector threshold: %u\n", thresh_val);
1149 break;
1150 case 0x2e:
1151 pout(" Peak connection time (us): %u\n", val);
1152 pout(" Peak value detector threshold: %u\n", thresh_val);
1153 break;
1154 case 0x40:
1155 pout(" Transmitted SSP frame count: %u\n", val);
1156 break;
1157 case 0x41:
1158 pout(" Received SSP frame count: %u\n", val);
1159 break;
1160 case 0x42:
1161 pout(" Transmitted SSP frame error count: %u\n", val);
1162 break;
1163 case 0x43:
1164 pout(" Received SSP frame error count: %u\n", val);
1165 break;
1166 case 0x44:
1167 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val);
1168 break;
1169 case 0x45:
1170 pout(" Received CREDIT_BLOCKED count: %u\n", val);
1171 break;
1172 case 0x50:
1173 pout(" Transmitted SATA frame count: %u\n", val);
1174 break;
1175 case 0x51:
1176 pout(" Received SATA frame count: %u\n", val);
1177 break;
1178 case 0x52:
1179 pout(" SATA flow control buffer overflow count: %u\n", val);
1180 break;
1181 case 0x60:
1182 pout(" Transmitted SMP frame count: %u\n", val);
1183 break;
1184 case 0x61:
1185 pout(" Received SMP frame count: %u\n", val);
1186 break;
1187 case 0x63:
1188 pout(" Received SMP frame error count: %u\n", val);
1189 break;
1190 default:
1191 break;
1192 }
1193 }
1194
1195 static void
1196 show_sas_port_param(unsigned char * ucp, int param_len)
1197 {
1198 int j, m, n, nphys, t, sz, spld_len;
1199 unsigned char * vcp;
1200 uint64_t ull;
1201 char s[64];
1202
1203 sz = sizeof(s);
1204 // pcb = ucp[2];
1205 t = (ucp[0] << 8) | ucp[1];
1206 pout("relative target port id = %d\n", t);
1207 pout(" generation code = %d\n", ucp[6]);
1208 nphys = ucp[7];
1209 pout(" number of phys = %d\n", nphys);
1210
1211 for (j = 0, vcp = ucp + 8; j < (param_len - 8);
1212 vcp += spld_len, j += spld_len) {
1213 pout(" phy identifier = %d\n", vcp[1]);
1214 spld_len = vcp[3];
1215 if (spld_len < 44)
1216 spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1217 else
1218 spld_len += 4;
1219 t = ((0x70 & vcp[4]) >> 4);
1220 switch (t) {
1221 case 0: snprintf(s, sz, "no device attached"); break;
1222 case 1: snprintf(s, sz, "SAS or SATA device"); break;
1223 case 2: snprintf(s, sz, "expander device"); break;
1224 case 3: snprintf(s, sz, "expander device (fanout)"); break;
1225 default: snprintf(s, sz, "reserved [%d]", t); break;
1226 }
1227 pout(" attached device type: %s\n", s);
1228 t = 0xf & vcp[4];
1229 switch (t) {
1230 case 0: snprintf(s, sz, "unknown"); break;
1231 case 1: snprintf(s, sz, "power on"); break;
1232 case 2: snprintf(s, sz, "hard reset"); break;
1233 case 3: snprintf(s, sz, "SMP phy control function"); break;
1234 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
1235 case 5: snprintf(s, sz, "mux mix up"); break;
1236 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
1237 break;
1238 case 7: snprintf(s, sz, "break timeout timer expired"); break;
1239 case 8: snprintf(s, sz, "phy test function stopped"); break;
1240 case 9: snprintf(s, sz, "expander device reduced functionality");
1241 break;
1242 default: snprintf(s, sz, "reserved [0x%x]", t); break;
1243 }
1244 pout(" attached reason: %s\n", s);
1245 t = (vcp[5] & 0xf0) >> 4;
1246 switch (t) {
1247 case 0: snprintf(s, sz, "unknown"); break;
1248 case 1: snprintf(s, sz, "power on"); break;
1249 case 2: snprintf(s, sz, "hard reset"); break;
1250 case 3: snprintf(s, sz, "SMP phy control function"); break;
1251 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
1252 case 5: snprintf(s, sz, "mux mix up"); break;
1253 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
1254 break;
1255 case 7: snprintf(s, sz, "break timeout timer expired"); break;
1256 case 8: snprintf(s, sz, "phy test function stopped"); break;
1257 case 9: snprintf(s, sz, "expander device reduced functionality");
1258 break;
1259 default: snprintf(s, sz, "reserved [0x%x]", t); break;
1260 }
1261 pout(" reason: %s\n", s);
1262 t = (0xf & vcp[5]);
1263 switch (t) {
1264 case 0: snprintf(s, sz, "phy enabled; unknown");
1265 break;
1266 case 1: snprintf(s, sz, "phy disabled"); break;
1267 case 2: snprintf(s, sz, "phy enabled; speed negotiation failed");
1268 break;
1269 case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state");
1270 break;
1271 case 4: snprintf(s, sz, "phy enabled; port selector");
1272 break;
1273 case 5: snprintf(s, sz, "phy enabled; reset in progress");
1274 break;
1275 case 6: snprintf(s, sz, "phy enabled; unsupported phy attached");
1276 break;
1277 case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
1278 case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
1279 case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
1280 case 0xb: snprintf(s, sz, "phy enabled; 12 Gbps"); break;
1281 default: snprintf(s, sz, "reserved [%d]", t); break;
1282 }
1283 pout(" negotiated logical link rate: %s\n", s);
1284 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1285 !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
1286 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1287 !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
1288 for (n = 0, ull = vcp[8]; n < 8; ++n) {
1289 ull <<= 8; ull |= vcp[8 + n];
1290 }
1291 pout(" SAS address = 0x%" PRIx64 "\n", ull);
1292 for (n = 0, ull = vcp[16]; n < 8; ++n) {
1293 ull <<= 8; ull |= vcp[16 + n];
1294 }
1295 pout(" attached SAS address = 0x%" PRIx64 "\n", ull);
1296 pout(" attached phy identifier = %d\n", vcp[24]);
1297 unsigned int ui;
1298 ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
1299 pout(" Invalid DWORD count = %u\n", ui);
1300 ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39];
1301 pout(" Running disparity error count = %u\n", ui);
1302 ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43];
1303 pout(" Loss of DWORD synchronization = %u\n", ui);
1304 ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
1305 pout(" Phy reset problem = %u\n", ui);
1306 if (spld_len > 51) {
1307 int num_ped;
1308 unsigned char * xcp;
1309
1310 num_ped = vcp[51];
1311 if (num_ped > 0)
1312 pout(" Phy event descriptors:\n");
1313 xcp = vcp + 52;
1314 for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
1315 int peis;
1316 unsigned int pvdt;
1317 peis = xcp[3];
1318 ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) |
1319 xcp[7];
1320 pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) |
1321 xcp[11];
1322 show_sas_phy_event_info(peis, ui, pvdt);
1323 }
1324 }
1325 }
1326 }
1327
1328 // Returns 1 if okay, 0 if non SAS descriptors
1329 static int
1330 show_protocol_specific_page(unsigned char * resp, int len)
1331 {
1332 int k, num;
1333 unsigned char * ucp;
1334
1335 num = len - 4;
1336 for (k = 0, ucp = resp + 4; k < num; ) {
1337 int param_len = ucp[3] + 4;
1338 if (6 != (0xf & ucp[4]))
1339 return 0; /* only decode SAS log page */
1340 if (0 == k)
1341 pout("Protocol Specific port log page for SAS SSP\n");
1342 show_sas_port_param(ucp, param_len);
1343 k += param_len;
1344 ucp += param_len;
1345 }
1346 pout("\n");
1347 return 1;
1348 }
1349
1350
1351 // See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1352 // log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1353 static int
1354 scsiPrintSasPhy(scsi_device * device, int reset)
1355 {
1356 int num, err;
1357
1358 if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
1359 LOG_RESP_LONG_LEN, 0))) {
1360 print_on();
1361 pout("scsiPrintSasPhy Log Sense Failed [%s]\n\n", scsiErrString(err));
1362 print_off();
1363 return FAILSMART;
1364 }
1365 if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
1366 print_on();
1367 pout("Protocol specific Log Sense Failed, page mismatch\n\n");
1368 print_off();
1369 return FAILSMART;
1370 }
1371 // compute page length
1372 num = (gBuf[2] << 8) + gBuf[3];
1373 if (1 != show_protocol_specific_page(gBuf, num + 4)) {
1374 print_on();
1375 pout("Only support protocol specific log page on SAS devices\n\n");
1376 print_off();
1377 return FAILSMART;
1378 }
1379 if (reset) {
1380 if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1381 PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) {
1382 print_on();
1383 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n\n",
1384 scsiErrString(err));
1385 print_off();
1386 return FAILSMART;
1387 }
1388 }
1389 return 0;
1390 }
1391
1392
1393 static const char * peripheral_dt_arr[] = {
1394 "disk",
1395 "tape",
1396 "printer",
1397 "processor",
1398 "optical disk(4)",
1399 "CD/DVD",
1400 "scanner",
1401 "optical disk(7)",
1402 "medium changer",
1403 "communications",
1404 "graphics(10)",
1405 "graphics(11)",
1406 "storage array",
1407 "enclosure",
1408 "simplified disk",
1409 "optical card reader"
1410 "reserved [0x10]"
1411 "object based storage"
1412 "automation/driver interface"
1413 "security manager device"
1414 "host managed zoned block device"
1415 "reserved [0x15]"
1416 "reserved [0x16]"
1417 "reserved [0x17]"
1418 "reserved [0x18]"
1419 "reserved [0x19]"
1420 "reserved [0x1a]"
1421 "reserved [0x1b]"
1422 "reserved [0x1c]"
1423 "reserved [0x1d]"
1424 "well known logical unit"
1425 "unknown or no device type"
1426 };
1427
1428 static const char * transport_proto_arr[] = {
1429 "Fibre channel (FCP-2)",
1430 "Parallel SCSI (SPI-4)",
1431 "SSA",
1432 "IEEE 1394 (SBP-2)",
1433 "RDMA (SRP)",
1434 "iSCSI",
1435 "SAS (SPL-3)",
1436 "ADT",
1437 "ATA (ACS-2)",
1438 "UAS",
1439 "SOP",
1440 "0xb",
1441 "0xc",
1442 "0xd",
1443 "0xe",
1444 "0xf"
1445 };
1446
1447 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1448 static int
1449 scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
1450 {
1451 char timedatetz[DATEANDEPOCHLEN];
1452 struct scsi_iec_mode_page iec;
1453 int err, iec_err, len, req_len, avail_len, scsi_version;
1454 bool is_tape = false;
1455 int peri_dt = 0;
1456 int transport = -1;
1457 int form_factor = 0;
1458 int haw_zbc = 0;
1459 int protect = 0;
1460
1461 memset(gBuf, 0, 96);
1462 req_len = 36;
1463 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
1464 print_on();
1465 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
1466 pout("Retrying with a 64 byte Standard Inquiry\n");
1467 print_off();
1468 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1469 req_len = 64;
1470 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
1471 print_on();
1472 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1473 scsiErrString(err));
1474 print_off();
1475 return 1;
1476 }
1477 }
1478 avail_len = gBuf[4] + 5;
1479 len = (avail_len < req_len) ? avail_len : req_len;
1480 peri_dt = gBuf[0] & 0x1f;
1481 *peripheral_type = peri_dt;
1482 if ((SCSI_PT_SEQUENTIAL_ACCESS == peri_dt) ||
1483 (SCSI_PT_MEDIUM_CHANGER == peri_dt))
1484 is_tape = true;
1485
1486 if (len < 36) {
1487 print_on();
1488 pout("Short INQUIRY response, skip product id\n");
1489 print_off();
1490 return 1;
1491 }
1492 // Upper bits of version bytes were used in older standards
1493 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
1494 scsi_version = gBuf[2] & 0x7;
1495
1496 if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) {
1497 char vendor[8+1], product[16+1], revision[4+1];
1498 scsi_format_id_string(vendor, (const unsigned char *)&gBuf[8], 8);
1499 scsi_format_id_string(product, (const unsigned char *)&gBuf[16], 16);
1500 scsi_format_id_string(revision, (const unsigned char *)&gBuf[32], 4);
1501
1502 pout("=== START OF INFORMATION SECTION ===\n");
1503 pout("Vendor: %.8s\n", vendor);
1504 pout("Product: %.16s\n", product);
1505 if (gBuf[32] >= ' ')
1506 pout("Revision: %.4s\n", revision);
1507 if (scsi_version == 0x6)
1508 pout("Compliance: SPC-4\n");
1509 else if (scsi_version == 0x7)
1510 pout("Compliance: SPC-5\n");
1511 }
1512
1513 if (!*device->get_req_type()/*no type requested*/ &&
1514 (0 == strncmp((char *)&gBuf[8], "ATA", 3))) {
1515 pout("\nProbable ATA device behind a SAT layer\n"
1516 "Try an additional '-d ata' or '-d sat' argument.\n");
1517 return 2;
1518 }
1519 if (! all)
1520 return 0;
1521
1522 protect = gBuf[5] & 0x1; /* from and including SPC-3 */
1523
1524 if (! is_tape) { /* assume disk if not tape drive (or tape changer) */
1525 unsigned int lb_size = 0;
1526 unsigned char lb_prov_resp[8];
1527 char lb_str[16];
1528 int lb_per_pb_exp = 0;
1529 uint64_t capacity = scsiGetSize(device, &lb_size, &lb_per_pb_exp);
1530
1531 if (capacity) {
1532 char cap_str[64], si_str[64];
1533 format_with_thousands_sep(cap_str, sizeof(cap_str), capacity);
1534 format_capacity(si_str, sizeof(si_str), capacity);
1535 pout("User Capacity: %s bytes [%s]\n", cap_str, si_str);
1536 snprintf(lb_str, sizeof(lb_str) - 1, "%u", lb_size);
1537 pout("Logical block size: %s bytes\n", lb_str);
1538 }
1539 int lbpme = -1;
1540 int lbprz = -1;
1541 if (protect || lb_per_pb_exp) {
1542 unsigned char rc16_12[20] = {0, };
1543
1544 if (0 == scsiGetProtPBInfo(device, rc16_12)) {
1545 lb_per_pb_exp = rc16_12[1] & 0xf; /* just in case */
1546 if (lb_per_pb_exp > 0) {
1547 snprintf(lb_str, sizeof(lb_str) - 1, "%u",
1548 (lb_size * (1 << lb_per_pb_exp)));
1549 pout("Physical block size: %s bytes\n", lb_str);
1550 int n = ((rc16_12[2] & 0x3f) << 8) + rc16_12[3];
1551 if (n > 0) // not common so cut the clutter
1552 pout("Lowest aligned LBA: %d\n", n);
1553 }
1554 if (rc16_12[0] & 0x1) { /* PROT_EN set */
1555 int p_type = ((rc16_12[0] >> 1) & 0x7);
1556
1557 switch (p_type) {
1558 case 0 :
1559 pout("Formatted with type 1 protection\n");
1560 break;
1561 case 1 :
1562 pout("Formatted with type 2 protection\n");
1563 break;
1564 case 2 :
1565 pout("Formatted with type 3 protection\n");
1566 break;
1567 default:
1568 pout("Formatted with unknown protection type [%d]\n",
1569 p_type);
1570 break;
1571 }
1572 int p_i_exp = ((rc16_12[1] >> 4) & 0xf);
1573
1574 if (p_i_exp > 0)
1575 pout("%d protection information intervals per "
1576 "logical block\n", (1 << p_i_exp));
1577 }
1578 /* Pick up some LB provisioning info since its available */
1579 lbpme = !! (rc16_12[2] & 0x80);
1580 lbprz = !! (rc16_12[2] & 0x40);
1581 }
1582 }
1583 if (0 == scsiInquiryVpd(device, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING,
1584 lb_prov_resp, sizeof(lb_prov_resp))) {
1585 int prov_type = lb_prov_resp[6] & 0x7;
1586
1587 if (-1 == lbprz)
1588 lbprz = !! (lb_prov_resp[5] & 0x4);
1589 switch (prov_type) {
1590 case 0:
1591 pout("LB provisioning type: unreported, LBPME=%d, LBPRZ=%d\n",
1592 lbpme, lbprz);
1593 break;
1594 case 1:
1595 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz);
1596 break;
1597 case 2:
1598 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz);
1599 break;
1600 default:
1601 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1602 prov_type, lbprz);
1603 break;
1604 }
1605 } else if (1 == lbpme)
1606 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz);
1607
1608 int rpm = scsiGetRPM(device, modese_len, &form_factor, &haw_zbc);
1609 if (rpm >= 0) {
1610 if (0 == rpm)
1611 ; // Not reported
1612 else if (1 == rpm)
1613 pout("Rotation Rate: Solid State Device\n");
1614 else if ((rpm <= 0x400) || (0xffff == rpm))
1615 ; // Reserved
1616 else
1617 pout("Rotation Rate: %d rpm\n", rpm);
1618 }
1619 if (form_factor > 0) {
1620 const char * cp = NULL;
1621
1622 switch (form_factor) {
1623 case 1:
1624 cp = "5.25";
1625 break;
1626 case 2:
1627 cp = "3.5";
1628 break;
1629 case 3:
1630 cp = "2.5";
1631 break;
1632 case 4:
1633 cp = "1.8";
1634 break;
1635 case 5:
1636 cp = "< 1.8";
1637 break;
1638 }
1639 if (cp)
1640 pout("Form Factor: %s inches\n", cp);
1641 }
1642 if (haw_zbc > 0)
1643 pout("Host aware zoned block capable\n");
1644 }
1645
1646 /* Do this here to try and detect badly conforming devices (some USB
1647 keys) that will lock up on a InquiryVpd or log sense or ... */
1648 if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) {
1649 if (SIMPLE_ERR_BAD_RESP == iec_err) {
1650 pout(">> Terminate command early due to bad response to IEC "
1651 "mode page\n");
1652 print_off();
1653 gIecMPage = 0;
1654 return 1;
1655 }
1656 } else
1657 modese_len = iec.modese_len;
1658
1659 if (! dont_print_serial_number) {
1660 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_DEVICE_IDENTIFICATION,
1661 gBuf, 252))) {
1662 char s[256];
1663
1664 len = gBuf[3];
1665 scsi_decode_lu_dev_id(gBuf + 4, len, s, sizeof(s), &transport);
1666 if (strlen(s) > 0)
1667 pout("Logical Unit id: %s\n", s);
1668 } else if (scsi_debugmode > 0) {
1669 print_on();
1670 if (SIMPLE_ERR_BAD_RESP == err)
1671 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1672 else
1673 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
1674 print_off();
1675 }
1676 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_UNIT_SERIAL_NUMBER,
1677 gBuf, 252))) {
1678 char serial[256];
1679 len = gBuf[3];
1680
1681 gBuf[4 + len] = '\0';
1682 scsi_format_id_string(serial, &gBuf[4], len);
1683 pout("Serial number: %s\n", serial);
1684 } else if (scsi_debugmode > 0) {
1685 print_on();
1686 if (SIMPLE_ERR_BAD_RESP == err)
1687 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1688 else
1689 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
1690 print_off();
1691 }
1692 }
1693
1694 // print SCSI peripheral device type
1695 if (peri_dt < (int)(sizeof(peripheral_dt_arr) /
1696 sizeof(peripheral_dt_arr[0])))
1697 pout("Device type: %s\n", peripheral_dt_arr[peri_dt]);
1698 else
1699 pout("Device type: <%d>\n", peri_dt);
1700
1701 // See if transport protocol is known
1702 if (transport < 0)
1703 transport = scsiFetchTransportProtocol(device, modese_len);
1704 if ((transport >= 0) && (transport <= 0xf))
1705 pout("Transport protocol: %s\n", transport_proto_arr[transport]);
1706
1707 // print current time and date and timezone
1708 dateandtimezone(timedatetz);
1709 pout("Local Time is: %s\n", timedatetz);
1710
1711 // See if unit accepts SCSI commmands from us
1712 if ((err = scsiTestUnitReady(device))) {
1713 if (SIMPLE_ERR_NOT_READY == err) {
1714 print_on();
1715 if (!is_tape)
1716 pout("device is NOT READY (e.g. spun down, busy)\n");
1717 else
1718 pout("device is NOT READY (e.g. no tape)\n");
1719 print_off();
1720 } else if (SIMPLE_ERR_NO_MEDIUM == err) {
1721 print_on();
1722 pout("NO MEDIUM present on device\n");
1723 print_off();
1724 } else if (SIMPLE_ERR_BECOMING_READY == err) {
1725 print_on();
1726 pout("device becoming ready (wait)\n");
1727 print_off();
1728 } else {
1729 print_on();
1730 pout("device Test Unit Ready [%s]\n", scsiErrString(err));
1731 print_off();
1732 }
1733 int returnval = 0; // TODO: exit with FAILID if failuretest returns
1734 failuretest(MANDATORY_CMD, returnval|=FAILID);
1735 }
1736
1737 if (iec_err) {
1738 if (!is_tape) {
1739 print_on();
1740 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
1741 if (scsi_debugmode > 0)
1742 pout(" [%s]\n", scsiErrString(iec_err));
1743 print_off();
1744 }
1745 gIecMPage = 0;
1746 return 0;
1747 }
1748
1749 if (!is_tape)
1750 pout("SMART support is: Available - device has SMART capability.\n"
1751 "SMART support is: %s\n",
1752 (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled");
1753 pout("%s\n", (scsi_IsWarningEnabled(&iec)) ?
1754 "Temperature Warning: Enabled" :
1755 "Temperature Warning: Disabled or Not Supported");
1756 return 0;
1757 }
1758
1759 static int
1760 scsiSmartEnable(scsi_device * device)
1761 {
1762 struct scsi_iec_mode_page iec;
1763 int err;
1764
1765 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
1766 print_on();
1767 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1768 scsiErrString(err));
1769 print_off();
1770 return 1;
1771 } else
1772 modese_len = iec.modese_len;
1773
1774 if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) {
1775 print_on();
1776 pout("unable to enable Exception control and warning [%s]\n",
1777 scsiErrString(err));
1778 print_off();
1779 return 1;
1780 }
1781 /* Need to refetch 'iec' since could be modified by previous call */
1782 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
1783 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1784 scsiErrString(err));
1785 return 1;
1786 } else
1787 modese_len = iec.modese_len;
1788
1789 pout("Informational Exceptions (SMART) %s\n",
1790 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
1791 pout("Temperature warning %s\n",
1792 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
1793 return 0;
1794 }
1795
1796 static int
1797 scsiSmartDisable(scsi_device * device)
1798 {
1799 struct scsi_iec_mode_page iec;
1800 int err;
1801
1802 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
1803 print_on();
1804 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1805 scsiErrString(err));
1806 print_off();
1807 return 1;
1808 } else
1809 modese_len = iec.modese_len;
1810
1811 if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) {
1812 print_on();
1813 pout("unable to disable Exception control and warning [%s]\n",
1814 scsiErrString(err));
1815 print_off();
1816 return 1;
1817 }
1818 /* Need to refetch 'iec' since could be modified by previous call */
1819 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
1820 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1821 scsiErrString(err));
1822 return 1;
1823 } else
1824 modese_len = iec.modese_len;
1825
1826 pout("Informational Exceptions (SMART) %s\n",
1827 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
1828 pout("Temperature warning %s\n",
1829 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
1830 return 0;
1831 }
1832
1833 static void
1834 scsiPrintTemp(scsi_device * device)
1835 {
1836 UINT8 temp = 0;
1837 UINT8 trip = 0;
1838
1839 if (scsiGetTemp(device, &temp, &trip))
1840 return;
1841
1842 if (temp) {
1843 if (255 != temp)
1844 pout("Current Drive Temperature: %d C\n", temp);
1845 else
1846 pout("Current Drive Temperature: <not available>\n");
1847 }
1848 if (trip)
1849 pout("Drive Trip Temperature: %d C\n", trip);
1850 if (temp || trip)
1851 pout("\n");
1852 }
1853
1854 /* Main entry point used by smartctl command. Return 0 for success */
1855 int
1856 scsiPrintMain(scsi_device * device, const scsi_print_options & options)
1857 {
1858 int checkedSupportedLogPages = 0;
1859 UINT8 peripheral_type = 0;
1860 int returnval = 0;
1861 int res, durationSec;
1862 struct scsi_sense_disect sense_info;
1863 bool is_disk;
1864 bool is_tape;
1865
1866 bool any_output = options.drive_info;
1867
1868 if (supported_vpd_pages_p) {
1869 delete supported_vpd_pages_p;
1870 supported_vpd_pages_p = NULL;
1871 }
1872 supported_vpd_pages_p = new supported_vpd_pages(device);
1873
1874 res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info);
1875 if (res) {
1876 if (2 == res)
1877 return 0;
1878 else
1879 failuretest(MANDATORY_CMD, returnval |= FAILID);
1880 any_output = true;
1881 }
1882 is_disk = (SCSI_PT_DIRECT_ACCESS == peripheral_type);
1883 is_tape = ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
1884 (SCSI_PT_MEDIUM_CHANGER == peripheral_type));
1885
1886 short int wce = -1, rcd = -1;
1887 // Print read look-ahead status for disks
1888 if (options.get_rcd || options.get_wce) {
1889 if (is_disk) {
1890 res = scsiGetSetCache(device, modese_len, &wce, &rcd);
1891 if (options.get_rcd)
1892 pout("Read Cache is: %s\n",
1893 res ? "Unavailable" : // error
1894 rcd ? "Disabled" : "Enabled");
1895 if (options.get_wce)
1896 pout("Writeback Cache is: %s\n",
1897 res ? "Unavailable" : // error
1898 !wce ? "Disabled" : "Enabled");
1899 }
1900 } else
1901 any_output = true;
1902
1903 if (options.drive_info)
1904 pout("\n");
1905
1906 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1907 if (options.smart_disable || options.smart_enable ||
1908 options.smart_auto_save_disable || options.smart_auto_save_enable)
1909 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1910
1911 if (options.smart_enable) {
1912 if (scsiSmartEnable(device))
1913 failuretest(MANDATORY_CMD, returnval |= FAILSMART);
1914 any_output = true;
1915 }
1916
1917 if (options.smart_disable) {
1918 if (scsiSmartDisable(device))
1919 failuretest(MANDATORY_CMD,returnval |= FAILSMART);
1920 any_output = true;
1921 }
1922
1923 if (options.smart_auto_save_enable) {
1924 if (scsiSetControlGLTSD(device, 0, modese_len)) {
1925 pout("Enable autosave (clear GLTSD bit) failed\n");
1926 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1927 } else
1928 pout("Autosave enabled (GLTSD bit cleared).\n");
1929 any_output = true;
1930 }
1931
1932 // Enable/Disable write cache
1933 if (options.set_wce && is_disk) {
1934 short int enable = wce = (options.set_wce > 0);
1935
1936 rcd = -1;
1937 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
1938 pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"),
1939 device->get_errmsg());
1940 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1941 } else
1942 pout("Write cache %sabled\n", (enable ? "en" : "dis"));
1943 any_output = true;
1944 }
1945
1946 // Enable/Disable read cache
1947 if (options.set_rcd && is_disk) {
1948 short int enable = (options.set_rcd > 0);
1949
1950 rcd = !enable;
1951 wce = -1;
1952 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
1953 pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"),
1954 device->get_errmsg());
1955 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1956 } else
1957 pout("Read cache %sabled\n", (enable ? "en" : "dis"));
1958 any_output = true;
1959 }
1960
1961 if (options.smart_auto_save_disable) {
1962 if (scsiSetControlGLTSD(device, 1, modese_len)) {
1963 pout("Disable autosave (set GLTSD bit) failed\n");
1964 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1965 } else
1966 pout("Autosave disabled (GLTSD bit set).\n");
1967 any_output = true;
1968 }
1969 if (options.smart_disable || options.smart_enable ||
1970 options.smart_auto_save_disable || options.smart_auto_save_enable)
1971 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
1972
1973 // START OF READ-ONLY OPTIONS APART FROM -V and -i
1974 if (options.smart_check_status || options.smart_ss_media_log ||
1975 options.smart_vendor_attrib || options.smart_error_log ||
1976 options.smart_selftest_log || options.smart_background_log ||
1977 options.sasphy)
1978 pout("=== START OF READ SMART DATA SECTION ===\n");
1979
1980 if (options.smart_check_status) {
1981 scsiGetSupportedLogPages(device);
1982 checkedSupportedLogPages = 1;
1983 if (is_tape) {
1984 if (gTapeAlertsLPage) {
1985 if (options.drive_info)
1986 pout("TapeAlert Supported\n");
1987 if (-1 == scsiGetTapeAlertsData(device, peripheral_type))
1988 failuretest(OPTIONAL_CMD, returnval |= FAILSMART);
1989 }
1990 else
1991 pout("TapeAlert Not Supported\n");
1992 } else { /* disk, cd/dvd, enclosure, etc */
1993 if ((res = scsiGetSmartData(device, options.smart_vendor_attrib))) {
1994 if (-2 == res)
1995 returnval |= FAILSTATUS;
1996 else
1997 returnval |= FAILSMART;
1998 }
1999 }
2000 any_output = true;
2001 }
2002
2003 if (is_disk && options.smart_ss_media_log) {
2004 if (! checkedSupportedLogPages)
2005 scsiGetSupportedLogPages(device);
2006 res = 0;
2007 if (gSSMediaLPage)
2008 res = scsiPrintSSMedia(device);
2009 if (0 != res)
2010 failuretest(OPTIONAL_CMD, returnval|=res);
2011 any_output = true;
2012 }
2013 if (options.smart_vendor_attrib) {
2014 if (! checkedSupportedLogPages)
2015 scsiGetSupportedLogPages(device);
2016 if (gTempLPage)
2017 scsiPrintTemp(device);
2018 if (gStartStopLPage)
2019 scsiGetStartStopData(device);
2020 if (is_disk) {
2021 scsiPrintGrownDefectListLen(device);
2022 if (gSeagateCacheLPage)
2023 scsiPrintSeagateCacheLPage(device);
2024 if (gSeagateFactoryLPage)
2025 scsiPrintSeagateFactoryLPage(device);
2026 }
2027 any_output = true;
2028 }
2029 if (options.smart_error_log) {
2030 if (! checkedSupportedLogPages)
2031 scsiGetSupportedLogPages(device);
2032 scsiPrintErrorCounterLog(device);
2033 if (1 == scsiFetchControlGLTSD(device, modese_len, 1))
2034 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2035 "Enable Save with '-S on']\n");
2036 any_output = true;
2037 }
2038 if (options.smart_selftest_log) {
2039 if (! checkedSupportedLogPages)
2040 scsiGetSupportedLogPages(device);
2041 res = 0;
2042 if (gSelfTestLPage)
2043 res = scsiPrintSelfTest(device);
2044 else {
2045 pout("Device does not support Self Test logging\n");
2046 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
2047 }
2048 if (0 != res)
2049 failuretest(OPTIONAL_CMD, returnval|=res);
2050 any_output = true;
2051 }
2052 if (options.smart_background_log) {
2053 if (! checkedSupportedLogPages)
2054 scsiGetSupportedLogPages(device);
2055 res = 0;
2056 if (gBackgroundResultsLPage)
2057 res = scsiPrintBackgroundResults(device);
2058 else {
2059 pout("Device does not support Background scan results logging\n");
2060 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
2061 }
2062 if (0 != res)
2063 failuretest(OPTIONAL_CMD, returnval|=res);
2064 any_output = true;
2065 }
2066 if (options.smart_default_selftest) {
2067 if (scsiSmartDefaultSelfTest(device))
2068 return returnval | FAILSMART;
2069 pout("Default Self Test Successful\n");
2070 any_output = true;
2071 }
2072 if (options.smart_short_cap_selftest) {
2073 if (scsiSmartShortCapSelfTest(device))
2074 return returnval | FAILSMART;
2075 pout("Short Foreground Self Test Successful\n");
2076 any_output = true;
2077 }
2078 // check if another test is running
2079 if (options.smart_short_selftest || options.smart_extend_selftest) {
2080 if (!scsiRequestSense(device, &sense_info) &&
2081 (sense_info.asc == 0x04 && sense_info.ascq == 0x09)) {
2082 if (!options.smart_selftest_force) {
2083 pout("Can't start self-test without aborting current test");
2084 if (sense_info.progress != -1)
2085 pout(" (%d%% remaining)",
2086 100 - sense_info.progress * 100 / 65535);
2087 pout(",\nadd '-t force' option to override, or run "
2088 "'smartctl -X' to abort test.\n");
2089 return -1;
2090 } else
2091 scsiSmartSelfTestAbort(device);
2092 }
2093 }
2094 if (options.smart_short_selftest) {
2095 if (scsiSmartShortSelfTest(device))
2096 return returnval | FAILSMART;
2097 pout("Short Background Self Test has begun\n");
2098 pout("Use smartctl -X to abort test\n");
2099 any_output = true;
2100 }
2101 if (options.smart_extend_selftest) {
2102 if (scsiSmartExtendSelfTest(device))
2103 return returnval | FAILSMART;
2104 pout("Extended Background Self Test has begun\n");
2105 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
2106 modese_len)) && (durationSec > 0)) {
2107 time_t t = time(NULL);
2108
2109 t += durationSec;
2110 pout("Please wait %d minutes for test to complete.\n",
2111 durationSec / 60);
2112 pout("Estimated completion time: %s\n", ctime(&t));
2113 }
2114 pout("Use smartctl -X to abort test\n");
2115 any_output = true;
2116 }
2117 if (options.smart_extend_cap_selftest) {
2118 if (scsiSmartExtendCapSelfTest(device))
2119 return returnval | FAILSMART;
2120 pout("Extended Foreground Self Test Successful\n");
2121 }
2122 if (options.smart_selftest_abort) {
2123 if (scsiSmartSelfTestAbort(device))
2124 return returnval | FAILSMART;
2125 pout("Self Test returned without error\n");
2126 any_output = true;
2127 }
2128 if (options.sasphy && gProtocolSpecificLPage) {
2129 if (scsiPrintSasPhy(device, options.sasphy_reset))
2130 return returnval | FAILSMART;
2131 any_output = true;
2132 }
2133
2134 if (!any_output)
2135 pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
2136 "to print SMART (and more) information\n\n");
2137
2138 return returnval;
2139 }