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