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