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