]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - scsiprint.cpp
import smartmontools 7.0
[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 4292 2016-04-12 23:06:59Z 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 /* 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 uint64_t ull;
1209 char s[64];
1210
1211 sz = sizeof(s);
1212 // pcb = ucp[2];
1213 t = (ucp[0] << 8) | ucp[1];
1214 pout("relative target port id = %d\n", t);
1215 pout(" generation code = %d\n", ucp[6]);
1216 nphys = ucp[7];
1217 pout(" number of phys = %d\n", nphys);
1218
1219 for (j = 0, vcp = ucp + 8; j < (param_len - 8);
1220 vcp += spld_len, j += spld_len) {
1221 pout(" phy identifier = %d\n", vcp[1]);
1222 spld_len = vcp[3];
1223 if (spld_len < 44)
1224 spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1225 else
1226 spld_len += 4;
1227 t = ((0x70 & vcp[4]) >> 4);
1228 switch (t) {
1229 case 0: snprintf(s, sz, "no device attached"); break;
1230 case 1: snprintf(s, sz, "SAS or SATA device"); break;
1231 case 2: snprintf(s, sz, "expander device"); break;
1232 case 3: snprintf(s, sz, "expander device (fanout)"); break;
1233 default: snprintf(s, sz, "reserved [%d]", t); break;
1234 }
1235 pout(" attached device type: %s\n", s);
1236 t = 0xf & vcp[4];
1237 switch (t) {
1238 case 0: snprintf(s, sz, "unknown"); break;
1239 case 1: snprintf(s, sz, "power on"); break;
1240 case 2: snprintf(s, sz, "hard reset"); break;
1241 case 3: snprintf(s, sz, "SMP phy control function"); break;
1242 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
1243 case 5: snprintf(s, sz, "mux mix up"); break;
1244 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
1245 break;
1246 case 7: snprintf(s, sz, "break timeout timer expired"); break;
1247 case 8: snprintf(s, sz, "phy test function stopped"); break;
1248 case 9: snprintf(s, sz, "expander device reduced functionality");
1249 break;
1250 default: snprintf(s, sz, "reserved [0x%x]", t); break;
1251 }
1252 pout(" attached reason: %s\n", s);
1253 t = (vcp[5] & 0xf0) >> 4;
1254 switch (t) {
1255 case 0: snprintf(s, sz, "unknown"); break;
1256 case 1: snprintf(s, sz, "power on"); break;
1257 case 2: snprintf(s, sz, "hard reset"); break;
1258 case 3: snprintf(s, sz, "SMP phy control function"); break;
1259 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
1260 case 5: snprintf(s, sz, "mux mix up"); break;
1261 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
1262 break;
1263 case 7: snprintf(s, sz, "break timeout timer expired"); break;
1264 case 8: snprintf(s, sz, "phy test function stopped"); break;
1265 case 9: snprintf(s, sz, "expander device reduced functionality");
1266 break;
1267 default: snprintf(s, sz, "reserved [0x%x]", t); break;
1268 }
1269 pout(" reason: %s\n", s);
1270 t = (0xf & vcp[5]);
1271 switch (t) {
1272 case 0: snprintf(s, sz, "phy enabled; unknown");
1273 break;
1274 case 1: snprintf(s, sz, "phy disabled"); break;
1275 case 2: snprintf(s, sz, "phy enabled; speed negotiation failed");
1276 break;
1277 case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state");
1278 break;
1279 case 4: snprintf(s, sz, "phy enabled; port selector");
1280 break;
1281 case 5: snprintf(s, sz, "phy enabled; reset in progress");
1282 break;
1283 case 6: snprintf(s, sz, "phy enabled; unsupported phy attached");
1284 break;
1285 case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
1286 case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
1287 case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
1288 case 0xb: snprintf(s, sz, "phy enabled; 12 Gbps"); break;
1289 default: snprintf(s, sz, "reserved [%d]", t); break;
1290 }
1291 pout(" negotiated logical link rate: %s\n", s);
1292 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1293 !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
1294 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1295 !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
1296 for (n = 0, ull = vcp[8]; n < 8; ++n) {
1297 ull <<= 8; ull |= vcp[8 + n];
1298 }
1299 pout(" SAS address = 0x%" PRIx64 "\n", ull);
1300 for (n = 0, ull = vcp[16]; n < 8; ++n) {
1301 ull <<= 8; ull |= vcp[16 + n];
1302 }
1303 pout(" attached SAS address = 0x%" PRIx64 "\n", ull);
1304 pout(" attached phy identifier = %d\n", vcp[24]);
1305 unsigned int ui;
1306 ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
1307 pout(" Invalid DWORD count = %u\n", ui);
1308 ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39];
1309 pout(" Running disparity error count = %u\n", ui);
1310 ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43];
1311 pout(" Loss of DWORD synchronization = %u\n", ui);
1312 ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
1313 pout(" Phy reset problem = %u\n", ui);
1314 if (spld_len > 51) {
1315 int num_ped;
1316 unsigned char * xcp;
1317
1318 num_ped = vcp[51];
1319 if (num_ped > 0)
1320 pout(" Phy event descriptors:\n");
1321 xcp = vcp + 52;
1322 for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
1323 int peis;
1324 unsigned int pvdt;
1325 peis = xcp[3];
1326 ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) |
1327 xcp[7];
1328 pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) |
1329 xcp[11];
1330 show_sas_phy_event_info(peis, ui, pvdt);
1331 }
1332 }
1333 }
1334 }
1335
1336 // Returns 1 if okay, 0 if non SAS descriptors
1337 static int
1338 show_protocol_specific_page(unsigned char * resp, int len)
1339 {
1340 int k, num;
1341 unsigned char * ucp;
1342
1343 num = len - 4;
1344 for (k = 0, ucp = resp + 4; k < num; ) {
1345 int param_len = ucp[3] + 4;
1346 if (6 != (0xf & ucp[4]))
1347 return 0; /* only decode SAS log page */
1348 if (0 == k)
1349 pout("Protocol Specific port log page for SAS SSP\n");
1350 show_sas_port_param(ucp, param_len);
1351 k += param_len;
1352 ucp += param_len;
1353 }
1354 pout("\n");
1355 return 1;
1356 }
1357
1358
1359 // See Serial Attached SCSI (SPL-3) (e.g. revision 6g) the Protocol Specific
1360 // log page [0x18]. Returns 0 if ok else FAIL* bitmask.
1361 static int
1362 scsiPrintSasPhy(scsi_device * device, int reset)
1363 {
1364 int num, err;
1365
1366 if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
1367 LOG_RESP_LONG_LEN, 0))) {
1368 print_on();
1369 pout("%s Log Sense Failed [%s]\n\n", __func__, scsiErrString(err));
1370 print_off();
1371 return FAILSMART;
1372 }
1373 if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
1374 print_on();
1375 pout("Protocol specific Log Sense Failed, page mismatch\n\n");
1376 print_off();
1377 return FAILSMART;
1378 }
1379 // compute page length
1380 num = (gBuf[2] << 8) + gBuf[3];
1381 if (1 != show_protocol_specific_page(gBuf, num + 4)) {
1382 print_on();
1383 pout("Only support protocol specific log page on SAS devices\n\n");
1384 print_off();
1385 return FAILSMART;
1386 }
1387 if (reset) {
1388 if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1389 PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) {
1390 print_on();
1391 pout("%s Log Select (reset) Failed [%s]\n\n", __func__,
1392 scsiErrString(err));
1393 print_off();
1394 return FAILSMART;
1395 }
1396 }
1397 return 0;
1398 }
1399
1400
1401 static const char * peripheral_dt_arr[32] = {
1402 "disk",
1403 "tape",
1404 "printer",
1405 "processor",
1406 "optical disk(4)",
1407 "CD/DVD",
1408 "scanner",
1409 "optical disk(7)",
1410 "medium changer",
1411 "communications",
1412 "graphics(10)",
1413 "graphics(11)",
1414 "storage array",
1415 "enclosure",
1416 "simplified disk",
1417 "optical card reader",
1418 "reserved [0x10]",
1419 "object based storage",
1420 "automation/driver interface",
1421 "security manager device",
1422 "host managed zoned block device",
1423 "reserved [0x15]",
1424 "reserved [0x16]",
1425 "reserved [0x17]",
1426 "reserved [0x18]",
1427 "reserved [0x19]",
1428 "reserved [0x1a]",
1429 "reserved [0x1b]",
1430 "reserved [0x1c]",
1431 "reserved [0x1d]",
1432 "well known logical unit",
1433 "unknown or no device type",
1434 };
1435
1436 static const char * transport_proto_arr[] = {
1437 "Fibre channel (FCP-2)",
1438 "Parallel SCSI (SPI-4)",
1439 "SSA",
1440 "IEEE 1394 (SBP-2)",
1441 "RDMA (SRP)",
1442 "iSCSI",
1443 "SAS (SPL-3)",
1444 "ADT",
1445 "ATA (ACS-2)",
1446 "UAS",
1447 "SOP",
1448 "0xb",
1449 "0xc",
1450 "0xd",
1451 "0xe",
1452 "0xf"
1453 };
1454
1455 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
1456 static int
1457 scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
1458 {
1459 char timedatetz[DATEANDEPOCHLEN];
1460 struct scsi_iec_mode_page iec;
1461 int err, iec_err, len, req_len, avail_len, scsi_version;
1462 bool is_tape = false;
1463 int peri_dt = 0;
1464 int transport = -1;
1465 int form_factor = 0;
1466 int haw_zbc = 0;
1467 int protect = 0;
1468
1469 memset(gBuf, 0, 96);
1470 req_len = 36;
1471 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
1472 print_on();
1473 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
1474 pout("Retrying with a 64 byte Standard Inquiry\n");
1475 print_off();
1476 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1477 req_len = 64;
1478 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
1479 print_on();
1480 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1481 scsiErrString(err));
1482 print_off();
1483 return 1;
1484 }
1485 }
1486 avail_len = gBuf[4] + 5;
1487 len = (avail_len < req_len) ? avail_len : req_len;
1488 peri_dt = gBuf[0] & 0x1f;
1489 *peripheral_type = peri_dt;
1490 if ((SCSI_PT_SEQUENTIAL_ACCESS == peri_dt) ||
1491 (SCSI_PT_MEDIUM_CHANGER == peri_dt))
1492 is_tape = true;
1493
1494 if (len < 36) {
1495 print_on();
1496 pout("Short INQUIRY response, skip product id\n");
1497 print_off();
1498 return 1;
1499 }
1500 // Upper bits of version bytes were used in older standards
1501 // Only interested in SPC-4 (0x6) and SPC-5 (assumed to be 0x7)
1502 scsi_version = gBuf[2] & 0x7;
1503
1504 if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) {
1505 char vendor[8+1], product[16+1], revision[4+1];
1506 scsi_format_id_string(vendor, (const unsigned char *)&gBuf[8], 8);
1507 scsi_format_id_string(product, (const unsigned char *)&gBuf[16], 16);
1508 scsi_format_id_string(revision, (const unsigned char *)&gBuf[32], 4);
1509
1510 pout("=== START OF INFORMATION SECTION ===\n");
1511 pout("Vendor: %.8s\n", vendor);
1512 pout("Product: %.16s\n", product);
1513 if (gBuf[32] >= ' ')
1514 pout("Revision: %.4s\n", revision);
1515 if (scsi_version == 0x6)
1516 pout("Compliance: SPC-4\n");
1517 else if (scsi_version == 0x7)
1518 pout("Compliance: SPC-5\n");
1519 }
1520
1521 if (!*device->get_req_type()/*no type requested*/ &&
1522 (0 == strncmp((char *)&gBuf[8], "ATA", 3))) {
1523 pout("\nProbable ATA device behind a SAT layer\n"
1524 "Try an additional '-d ata' or '-d sat' argument.\n");
1525 return 2;
1526 }
1527 if (! all)
1528 return 0;
1529
1530 protect = gBuf[5] & 0x1; /* from and including SPC-3 */
1531
1532 if (! is_tape) { /* assume disk if not tape drive (or tape changer) */
1533 unsigned int lb_size = 0;
1534 unsigned char lb_prov_resp[8];
1535 char lb_str[16];
1536 int lb_per_pb_exp = 0;
1537 uint64_t capacity = scsiGetSize(device, &lb_size, &lb_per_pb_exp);
1538
1539 if (capacity) {
1540 char cap_str[64], si_str[64];
1541 format_with_thousands_sep(cap_str, sizeof(cap_str), capacity);
1542 format_capacity(si_str, sizeof(si_str), capacity);
1543 pout("User Capacity: %s bytes [%s]\n", cap_str, si_str);
1544 snprintf(lb_str, sizeof(lb_str) - 1, "%u", lb_size);
1545 pout("Logical block size: %s bytes\n", lb_str);
1546 }
1547 int lbpme = -1;
1548 int lbprz = -1;
1549 if (protect || lb_per_pb_exp) {
1550 unsigned char rc16_12[20] = {0, };
1551
1552 if (0 == scsiGetProtPBInfo(device, rc16_12)) {
1553 lb_per_pb_exp = rc16_12[1] & 0xf; /* just in case */
1554 if (lb_per_pb_exp > 0) {
1555 snprintf(lb_str, sizeof(lb_str) - 1, "%u",
1556 (lb_size * (1 << lb_per_pb_exp)));
1557 pout("Physical block size: %s bytes\n", lb_str);
1558 int n = ((rc16_12[2] & 0x3f) << 8) + rc16_12[3];
1559 if (n > 0) // not common so cut the clutter
1560 pout("Lowest aligned LBA: %d\n", n);
1561 }
1562 if (rc16_12[0] & 0x1) { /* PROT_EN set */
1563 int p_type = ((rc16_12[0] >> 1) & 0x7);
1564
1565 switch (p_type) {
1566 case 0 :
1567 pout("Formatted with type 1 protection\n");
1568 break;
1569 case 1 :
1570 pout("Formatted with type 2 protection\n");
1571 break;
1572 case 2 :
1573 pout("Formatted with type 3 protection\n");
1574 break;
1575 default:
1576 pout("Formatted with unknown protection type [%d]\n",
1577 p_type);
1578 break;
1579 }
1580 int p_i_exp = ((rc16_12[1] >> 4) & 0xf);
1581
1582 if (p_i_exp > 0)
1583 pout("%d protection information intervals per "
1584 "logical block\n", (1 << p_i_exp));
1585 }
1586 /* Pick up some LB provisioning info since its available */
1587 lbpme = !! (rc16_12[2] & 0x80);
1588 lbprz = !! (rc16_12[2] & 0x40);
1589 }
1590 }
1591 /* Thin Provisioning VPD page renamed Logical Block Provisioning VPD
1592 * page in sbc3r25; some fields changed their meaning so that the
1593 * new page covered both thin and resource provisioned LUs. */
1594 if (0 == scsiInquiryVpd(device, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING,
1595 lb_prov_resp, sizeof(lb_prov_resp))) {
1596 int prov_type = lb_prov_resp[6] & 0x7; /* added sbc3r27 */
1597 int vpd_lbprz = ((lb_prov_resp[5] >> 2) & 0x7); /* sbc4r07 */
1598
1599 if (-1 == lbprz)
1600 lbprz = vpd_lbprz;
1601 else if ((0 == vpd_lbprz) && (1 == lbprz))
1602 ; /* vpd_lbprz introduced in sbc3r27, expanded in sbc4r07 */
1603 else
1604 lbprz = vpd_lbprz;
1605 switch (prov_type) {
1606 case 0:
1607 if (lbpme <= 0) {
1608 pout("LU is fully provisioned");
1609 if (lbprz)
1610 pout(" [LBPRZ=%d]\n", lbprz);
1611 else
1612 pout("\n");
1613 } else
1614 pout("LB provisioning type: not reported [LBPME=1, "
1615 "LBPRZ=%d]\n", lbprz);
1616 break;
1617 case 1:
1618 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz);
1619 break;
1620 case 2:
1621 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz);
1622 break;
1623 default:
1624 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1625 prov_type, lbprz);
1626 break;
1627 }
1628 } else if (1 == lbpme) {
1629 if (scsi_debugmode > 0)
1630 pout("rcap_16 sets LBPME but no LB provisioning VPD page\n");
1631 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz);
1632 }
1633
1634 int rpm = scsiGetRPM(device, modese_len, &form_factor, &haw_zbc);
1635 if (rpm >= 0) {
1636 if (0 == rpm)
1637 ; // Not reported
1638 else if (1 == rpm)
1639 pout("Rotation Rate: Solid State Device\n");
1640 else if ((rpm <= 0x400) || (0xffff == rpm))
1641 ; // Reserved
1642 else
1643 pout("Rotation Rate: %d rpm\n", rpm);
1644 }
1645 if (form_factor > 0) {
1646 const char * cp = NULL;
1647
1648 switch (form_factor) {
1649 case 1:
1650 cp = "5.25";
1651 break;
1652 case 2:
1653 cp = "3.5";
1654 break;
1655 case 3:
1656 cp = "2.5";
1657 break;
1658 case 4:
1659 cp = "1.8";
1660 break;
1661 case 5:
1662 cp = "< 1.8";
1663 break;
1664 }
1665 if (cp)
1666 pout("Form Factor: %s inches\n", cp);
1667 }
1668 if (haw_zbc > 0)
1669 pout("Host aware zoned block capable\n");
1670 }
1671
1672 /* Do this here to try and detect badly conforming devices (some USB
1673 keys) that will lock up on a InquiryVpd or log sense or ... */
1674 if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) {
1675 if (SIMPLE_ERR_BAD_RESP == iec_err) {
1676 pout(">> Terminate command early due to bad response to IEC "
1677 "mode page\n");
1678 print_off();
1679 gIecMPage = 0;
1680 return 1;
1681 }
1682 } else
1683 modese_len = iec.modese_len;
1684
1685 if (! dont_print_serial_number) {
1686 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_DEVICE_IDENTIFICATION,
1687 gBuf, 252))) {
1688 char s[256];
1689
1690 len = gBuf[3];
1691 scsi_decode_lu_dev_id(gBuf + 4, len, s, sizeof(s), &transport);
1692 if (strlen(s) > 0)
1693 pout("Logical Unit id: %s\n", s);
1694 } else if (scsi_debugmode > 0) {
1695 print_on();
1696 if (SIMPLE_ERR_BAD_RESP == err)
1697 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1698 else
1699 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
1700 print_off();
1701 }
1702 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_UNIT_SERIAL_NUMBER,
1703 gBuf, 252))) {
1704 char serial[256];
1705 len = gBuf[3];
1706
1707 gBuf[4 + len] = '\0';
1708 scsi_format_id_string(serial, &gBuf[4], len);
1709 pout("Serial number: %s\n", serial);
1710 } else if (scsi_debugmode > 0) {
1711 print_on();
1712 if (SIMPLE_ERR_BAD_RESP == err)
1713 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1714 else
1715 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
1716 print_off();
1717 }
1718 }
1719
1720 // print SCSI peripheral device type
1721 if (peri_dt < (int)(sizeof(peripheral_dt_arr) /
1722 sizeof(peripheral_dt_arr[0])))
1723 pout("Device type: %s\n", peripheral_dt_arr[peri_dt]);
1724 else
1725 pout("Device type: <%d>\n", peri_dt);
1726
1727 // See if transport protocol is known
1728 if (transport < 0)
1729 transport = scsiFetchTransportProtocol(device, modese_len);
1730 if ((transport >= 0) && (transport <= 0xf))
1731 pout("Transport protocol: %s\n", transport_proto_arr[transport]);
1732
1733 // print current time and date and timezone
1734 dateandtimezone(timedatetz);
1735 pout("Local Time is: %s\n", timedatetz);
1736
1737 // See if unit accepts SCSI commmands from us
1738 if ((err = scsiTestUnitReady(device))) {
1739 if (SIMPLE_ERR_NOT_READY == err) {
1740 print_on();
1741 if (!is_tape)
1742 pout("device is NOT READY (e.g. spun down, busy)\n");
1743 else
1744 pout("device is NOT READY (e.g. no tape)\n");
1745 print_off();
1746 } else if (SIMPLE_ERR_NO_MEDIUM == err) {
1747 print_on();
1748 if (is_tape)
1749 pout("NO tape present in drive\n");
1750 else
1751 pout("NO MEDIUM present in device\n");
1752 print_off();
1753 } else if (SIMPLE_ERR_BECOMING_READY == err) {
1754 print_on();
1755 pout("device becoming ready (wait)\n");
1756 print_off();
1757 } else {
1758 print_on();
1759 pout("device Test Unit Ready [%s]\n", scsiErrString(err));
1760 print_off();
1761 }
1762 if (! is_tape) {
1763 int returnval = 0; // TODO: exit with FAILID if failuretest returns
1764
1765 failuretest(MANDATORY_CMD, returnval|=FAILID);
1766 }
1767 }
1768
1769 if (iec_err) {
1770 if (!is_tape) {
1771 print_on();
1772 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
1773 if (scsi_debugmode > 0)
1774 pout(" [%s]\n", scsiErrString(iec_err));
1775 print_off();
1776 }
1777 gIecMPage = 0;
1778 return 0;
1779 }
1780
1781 if (!is_tape)
1782 pout("SMART support is: Available - device has SMART capability.\n"
1783 "SMART support is: %s\n",
1784 (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled");
1785 pout("%s\n", (scsi_IsWarningEnabled(&iec)) ?
1786 "Temperature Warning: Enabled" :
1787 "Temperature Warning: Disabled or Not Supported");
1788 return 0;
1789 }
1790
1791 static int
1792 scsiSmartEnable(scsi_device * device)
1793 {
1794 struct scsi_iec_mode_page iec;
1795 int err;
1796
1797 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
1798 print_on();
1799 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1800 scsiErrString(err));
1801 print_off();
1802 return 1;
1803 } else
1804 modese_len = iec.modese_len;
1805
1806 if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) {
1807 print_on();
1808 pout("unable to enable Exception control and warning [%s]\n",
1809 scsiErrString(err));
1810 print_off();
1811 return 1;
1812 }
1813 /* Need to refetch 'iec' since could be modified by previous call */
1814 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
1815 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1816 scsiErrString(err));
1817 return 1;
1818 } else
1819 modese_len = iec.modese_len;
1820
1821 pout("Informational Exceptions (SMART) %s\n",
1822 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
1823 pout("Temperature warning %s\n",
1824 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
1825 return 0;
1826 }
1827
1828 static int
1829 scsiSmartDisable(scsi_device * device)
1830 {
1831 struct scsi_iec_mode_page iec;
1832 int err;
1833
1834 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
1835 print_on();
1836 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1837 scsiErrString(err));
1838 print_off();
1839 return 1;
1840 } else
1841 modese_len = iec.modese_len;
1842
1843 if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) {
1844 print_on();
1845 pout("unable to disable Exception control and warning [%s]\n",
1846 scsiErrString(err));
1847 print_off();
1848 return 1;
1849 }
1850 /* Need to refetch 'iec' since could be modified by previous call */
1851 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
1852 pout("unable to fetch IEC (SMART) mode page [%s]\n",
1853 scsiErrString(err));
1854 return 1;
1855 } else
1856 modese_len = iec.modese_len;
1857
1858 pout("Informational Exceptions (SMART) %s\n",
1859 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
1860 pout("Temperature warning %s\n",
1861 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
1862 return 0;
1863 }
1864
1865 static void
1866 scsiPrintTemp(scsi_device * device)
1867 {
1868 UINT8 temp = 255;
1869 UINT8 trip = 255;
1870
1871 if (scsiGetTemp(device, &temp, &trip))
1872 return;
1873
1874 if (255 == temp)
1875 pout("Current Drive Temperature: <not available>\n");
1876 else
1877 pout("Current Drive Temperature: %d C\n", temp);
1878 if (255 == trip)
1879 pout("Drive Trip Temperature: <not available>\n");
1880 else
1881 pout("Drive Trip Temperature: %d C\n", trip);
1882 pout("\n");
1883 }
1884
1885 /* Main entry point used by smartctl command. Return 0 for success */
1886 int
1887 scsiPrintMain(scsi_device * device, const scsi_print_options & options)
1888 {
1889 int checkedSupportedLogPages = 0;
1890 UINT8 peripheral_type = 0;
1891 int returnval = 0;
1892 int res, durationSec;
1893 struct scsi_sense_disect sense_info;
1894 bool is_disk;
1895 bool is_tape;
1896
1897 bool any_output = options.drive_info;
1898
1899 if (supported_vpd_pages_p) {
1900 delete supported_vpd_pages_p;
1901 supported_vpd_pages_p = NULL;
1902 }
1903 supported_vpd_pages_p = new supported_vpd_pages(device);
1904
1905 res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info);
1906 if (res) {
1907 if (2 == res)
1908 return 0;
1909 else
1910 failuretest(MANDATORY_CMD, returnval |= FAILID);
1911 any_output = true;
1912 }
1913 is_disk = (SCSI_PT_DIRECT_ACCESS == peripheral_type);
1914 is_tape = ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
1915 (SCSI_PT_MEDIUM_CHANGER == peripheral_type));
1916
1917 short int wce = -1, rcd = -1;
1918 // Print read look-ahead status for disks
1919 if (options.get_rcd || options.get_wce) {
1920 if (is_disk) {
1921 res = scsiGetSetCache(device, modese_len, &wce, &rcd);
1922 if (options.get_rcd)
1923 pout("Read Cache is: %s\n",
1924 res ? "Unavailable" : // error
1925 rcd ? "Disabled" : "Enabled");
1926 if (options.get_wce)
1927 pout("Writeback Cache is: %s\n",
1928 res ? "Unavailable" : // error
1929 !wce ? "Disabled" : "Enabled");
1930 }
1931 } else
1932 any_output = true;
1933
1934 if (options.drive_info)
1935 pout("\n");
1936
1937 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1938 if (options.smart_disable || options.smart_enable ||
1939 options.smart_auto_save_disable || options.smart_auto_save_enable)
1940 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1941
1942 if (options.smart_enable) {
1943 if (scsiSmartEnable(device))
1944 failuretest(MANDATORY_CMD, returnval |= FAILSMART);
1945 any_output = true;
1946 }
1947
1948 if (options.smart_disable) {
1949 if (scsiSmartDisable(device))
1950 failuretest(MANDATORY_CMD,returnval |= FAILSMART);
1951 any_output = true;
1952 }
1953
1954 if (options.smart_auto_save_enable) {
1955 if (scsiSetControlGLTSD(device, 0, modese_len)) {
1956 pout("Enable autosave (clear GLTSD bit) failed\n");
1957 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1958 } else
1959 pout("Autosave enabled (GLTSD bit cleared).\n");
1960 any_output = true;
1961 }
1962
1963 // Enable/Disable write cache
1964 if (options.set_wce && is_disk) {
1965 short int enable = wce = (options.set_wce > 0);
1966
1967 rcd = -1;
1968 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
1969 pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"),
1970 device->get_errmsg());
1971 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1972 } else
1973 pout("Write cache %sabled\n", (enable ? "en" : "dis"));
1974 any_output = true;
1975 }
1976
1977 // Enable/Disable read cache
1978 if (options.set_rcd && is_disk) {
1979 short int enable = (options.set_rcd > 0);
1980
1981 rcd = !enable;
1982 wce = -1;
1983 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
1984 pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"),
1985 device->get_errmsg());
1986 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1987 } else
1988 pout("Read cache %sabled\n", (enable ? "en" : "dis"));
1989 any_output = true;
1990 }
1991
1992 if (options.smart_auto_save_disable) {
1993 if (scsiSetControlGLTSD(device, 1, modese_len)) {
1994 pout("Disable autosave (set GLTSD bit) failed\n");
1995 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1996 } else
1997 pout("Autosave disabled (GLTSD bit set).\n");
1998 any_output = true;
1999 }
2000 if (options.smart_disable || options.smart_enable ||
2001 options.smart_auto_save_disable || options.smart_auto_save_enable)
2002 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
2003
2004 // START OF READ-ONLY OPTIONS APART FROM -V and -i
2005 if (options.smart_check_status || options.smart_ss_media_log ||
2006 options.smart_vendor_attrib || options.smart_error_log ||
2007 options.smart_selftest_log || options.smart_background_log ||
2008 options.sasphy)
2009 pout("=== START OF READ SMART DATA SECTION ===\n");
2010
2011 if (options.smart_check_status) {
2012 scsiGetSupportedLogPages(device);
2013 checkedSupportedLogPages = 1;
2014 if (is_tape) {
2015 if (gTapeAlertsLPage) {
2016 if (options.drive_info)
2017 pout("TapeAlert Supported\n");
2018 if (-1 == scsiGetTapeAlertsData(device, peripheral_type))
2019 failuretest(OPTIONAL_CMD, returnval |= FAILSMART);
2020 }
2021 else
2022 pout("TapeAlert Not Supported\n");
2023 } else { /* disk, cd/dvd, enclosure, etc */
2024 if ((res = scsiGetSmartData(device, options.smart_vendor_attrib))) {
2025 if (-2 == res)
2026 returnval |= FAILSTATUS;
2027 else
2028 returnval |= FAILSMART;
2029 }
2030 }
2031 any_output = true;
2032 }
2033
2034 if (is_disk && options.smart_ss_media_log) {
2035 if (! checkedSupportedLogPages)
2036 scsiGetSupportedLogPages(device);
2037 res = 0;
2038 if (gSSMediaLPage)
2039 res = scsiPrintSSMedia(device);
2040 if (0 != res)
2041 failuretest(OPTIONAL_CMD, returnval|=res);
2042 any_output = true;
2043 }
2044 if (options.smart_vendor_attrib) {
2045 if (! checkedSupportedLogPages)
2046 scsiGetSupportedLogPages(device);
2047 if (gTempLPage)
2048 scsiPrintTemp(device);
2049 if (gStartStopLPage)
2050 scsiGetStartStopData(device);
2051 if (is_disk) {
2052 scsiPrintGrownDefectListLen(device);
2053 if (gSeagateCacheLPage)
2054 scsiPrintSeagateCacheLPage(device);
2055 if (gSeagateFactoryLPage)
2056 scsiPrintSeagateFactoryLPage(device);
2057 }
2058 any_output = true;
2059 }
2060 if (options.smart_error_log) {
2061 if (! checkedSupportedLogPages)
2062 scsiGetSupportedLogPages(device);
2063 scsiPrintErrorCounterLog(device);
2064 if (1 == scsiFetchControlGLTSD(device, modese_len, 1))
2065 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2066 "Enable Save with '-S on']\n");
2067 any_output = true;
2068 }
2069 if (options.smart_selftest_log) {
2070 if (! checkedSupportedLogPages)
2071 scsiGetSupportedLogPages(device);
2072 res = 0;
2073 if (gSelfTestLPage)
2074 res = scsiPrintSelfTest(device);
2075 else {
2076 pout("Device does not support Self Test logging\n");
2077 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
2078 }
2079 if (0 != res)
2080 failuretest(OPTIONAL_CMD, returnval|=res);
2081 any_output = true;
2082 }
2083 if (options.smart_background_log && is_disk) {
2084 if (! checkedSupportedLogPages)
2085 scsiGetSupportedLogPages(device);
2086 res = 0;
2087 if (gBackgroundResultsLPage)
2088 res = scsiPrintBackgroundResults(device);
2089 else {
2090 pout("Device does not support Background scan results logging\n");
2091 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
2092 }
2093 if (0 != res)
2094 failuretest(OPTIONAL_CMD, returnval|=res);
2095 any_output = true;
2096 }
2097 if (options.smart_default_selftest) {
2098 if (scsiSmartDefaultSelfTest(device))
2099 return returnval | FAILSMART;
2100 pout("Default Self Test Successful\n");
2101 any_output = true;
2102 }
2103 if (options.smart_short_cap_selftest) {
2104 if (scsiSmartShortCapSelfTest(device))
2105 return returnval | FAILSMART;
2106 pout("Short Foreground Self Test Successful\n");
2107 any_output = true;
2108 }
2109 // check if another test is running
2110 if (options.smart_short_selftest || options.smart_extend_selftest) {
2111 if (!scsiRequestSense(device, &sense_info) &&
2112 (sense_info.asc == 0x04 && sense_info.ascq == 0x09)) {
2113 if (!options.smart_selftest_force) {
2114 pout("Can't start self-test without aborting current test");
2115 if (sense_info.progress != -1)
2116 pout(" (%d%% remaining)",
2117 100 - sense_info.progress * 100 / 65535);
2118 pout(",\nadd '-t force' option to override, or run "
2119 "'smartctl -X' to abort test.\n");
2120 return -1;
2121 } else
2122 scsiSmartSelfTestAbort(device);
2123 }
2124 }
2125 if (options.smart_short_selftest) {
2126 if (scsiSmartShortSelfTest(device))
2127 return returnval | FAILSMART;
2128 pout("Short Background Self Test has begun\n");
2129 pout("Use smartctl -X to abort test\n");
2130 any_output = true;
2131 }
2132 if (options.smart_extend_selftest) {
2133 if (scsiSmartExtendSelfTest(device))
2134 return returnval | FAILSMART;
2135 pout("Extended Background Self Test has begun\n");
2136 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
2137 modese_len)) && (durationSec > 0)) {
2138 time_t t = time(NULL);
2139
2140 t += durationSec;
2141 pout("Please wait %d minutes for test to complete.\n",
2142 durationSec / 60);
2143 pout("Estimated completion time: %s\n", ctime(&t));
2144 }
2145 pout("Use smartctl -X to abort test\n");
2146 any_output = true;
2147 }
2148 if (options.smart_extend_cap_selftest) {
2149 if (scsiSmartExtendCapSelfTest(device))
2150 return returnval | FAILSMART;
2151 pout("Extended Foreground Self Test Successful\n");
2152 }
2153 if (options.smart_selftest_abort) {
2154 if (scsiSmartSelfTestAbort(device))
2155 return returnval | FAILSMART;
2156 pout("Self Test returned without error\n");
2157 any_output = true;
2158 }
2159 if (options.sasphy && gProtocolSpecificLPage) {
2160 if (scsiPrintSasPhy(device, options.sasphy_reset))
2161 return returnval | FAILSMART;
2162 any_output = true;
2163 }
2164
2165 if (!any_output)
2166 pout("SCSI device successfully opened\n\nUse 'smartctl -a' (or '-x') "
2167 "to print SMART (and more) information\n\n");
2168
2169 return returnval;
2170 }