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