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