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