Annotation of embedaddon/smartmontools/scsiprint.cpp, revision 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>