Annotation of embedaddon/smartmontools/scsiprint.cpp, revision 1.1.1.1
1.1 misho 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: ¤ttemp, &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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>