|
smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
|
00001 /* 00002 * scsiprint.cpp 00003 * 00004 * Home page of code is: http://smartmontools.sourceforge.net 00005 * 00006 * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> 00007 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> 00008 * 00009 * Additional SCSI work: 00010 * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com> 00011 * 00012 * This program is free software; you can redistribute it and/or modify 00013 * it under the terms of the GNU General Public License as published by 00014 * the Free Software Foundation; either version 2, or (at your option) 00015 * any later version. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * (for example COPYING); if not, write to the Free Software Foundation, 00019 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00020 * 00021 * This code was originally developed as a Senior Thesis by Michael Cornwell 00022 * at the Concurrent Systems Laboratory (now part of the Storage Systems 00023 * Research Center), Jack Baskin School of Engineering, University of 00024 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/ 00025 * 00026 */ 00027 00028 00029 #include <stdio.h> 00030 #include <string.h> 00031 #include <fcntl.h> 00032 #include <errno.h> 00033 00034 #include "config.h" 00035 #include "int64.h" 00036 #include "scsicmds.h" 00037 #include "atacmds.h" // smart_command_set 00038 #include "dev_interface.h" 00039 #include "scsiprint.h" 00040 #include "smartctl.h" 00041 #include "utility.h" 00042 00043 #define GBUF_SIZE 65535 00044 00045 const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 3807 2013-04-18 17:11:12Z chrfranke $" 00046 SCSIPRINT_H_CVSID; 00047 00048 00049 UINT8 gBuf[GBUF_SIZE]; 00050 #define LOG_RESP_LEN 252 00051 #define LOG_RESP_LONG_LEN ((62 * 256) + 252) 00052 #define LOG_RESP_TAPE_ALERT_LEN 0x144 00053 00054 /* Log pages supported */ 00055 static int gSmartLPage = 0; /* Informational Exceptions log page */ 00056 static int gTempLPage = 0; 00057 static int gSelfTestLPage = 0; 00058 static int gStartStopLPage = 0; 00059 static int gReadECounterLPage = 0; 00060 static int gWriteECounterLPage = 0; 00061 static int gVerifyECounterLPage = 0; 00062 static int gNonMediumELPage = 0; 00063 static int gLastNErrorLPage = 0; 00064 static int gBackgroundResultsLPage = 0; 00065 static int gProtocolSpecificLPage = 0; 00066 static int gTapeAlertsLPage = 0; 00067 static int gSSMediaLPage = 0; 00068 00069 /* Vendor specific log pages */ 00070 static int gSeagateCacheLPage = 0; 00071 static int gSeagateFactoryLPage = 0; 00072 00073 /* Mode pages supported */ 00074 static int gIecMPage = 1; /* N.B. assume it until we know otherwise */ 00075 00076 /* Remember last successful mode sense/select command */ 00077 static int modese_len = 0; 00078 00079 00080 static void 00081 scsiGetSupportedLogPages(scsi_device * device) 00082 { 00083 int i, err; 00084 00085 if ((err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf, 00086 LOG_RESP_LEN, 0))) { 00087 if (scsi_debugmode > 0) 00088 pout("Log Sense for supported pages failed [%s]\n", 00089 scsiErrString(err)); 00090 return; 00091 } 00092 00093 for (i = 4; i < gBuf[3] + LOGPAGEHDRSIZE; i++) { 00094 switch (gBuf[i]) 00095 { 00096 case READ_ERROR_COUNTER_LPAGE: 00097 gReadECounterLPage = 1; 00098 break; 00099 case WRITE_ERROR_COUNTER_LPAGE: 00100 gWriteECounterLPage = 1; 00101 break; 00102 case VERIFY_ERROR_COUNTER_LPAGE: 00103 gVerifyECounterLPage = 1; 00104 break; 00105 case LAST_N_ERROR_LPAGE: 00106 gLastNErrorLPage = 1; 00107 break; 00108 case NON_MEDIUM_ERROR_LPAGE: 00109 gNonMediumELPage = 1; 00110 break; 00111 case TEMPERATURE_LPAGE: 00112 gTempLPage = 1; 00113 break; 00114 case STARTSTOP_CYCLE_COUNTER_LPAGE: 00115 gStartStopLPage = 1; 00116 break; 00117 case SELFTEST_RESULTS_LPAGE: 00118 gSelfTestLPage = 1; 00119 break; 00120 case IE_LPAGE: 00121 gSmartLPage = 1; 00122 break; 00123 case BACKGROUND_RESULTS_LPAGE: 00124 gBackgroundResultsLPage = 1; 00125 break; 00126 case PROTOCOL_SPECIFIC_LPAGE: 00127 gProtocolSpecificLPage = 1; 00128 break; 00129 case TAPE_ALERTS_LPAGE: 00130 gTapeAlertsLPage = 1; 00131 break; 00132 case SS_MEDIA_LPAGE: 00133 gSSMediaLPage = 1; 00134 break; 00135 case SEAGATE_CACHE_LPAGE: 00136 gSeagateCacheLPage = 1; 00137 break; 00138 case SEAGATE_FACTORY_LPAGE: 00139 gSeagateFactoryLPage = 1; 00140 break; 00141 default: 00142 break; 00143 } 00144 } 00145 } 00146 00147 /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad 00148 (or at least something to report). */ 00149 static int 00150 scsiGetSmartData(scsi_device * device, bool attribs) 00151 { 00152 UINT8 asc; 00153 UINT8 ascq; 00154 UINT8 currenttemp = 0; 00155 UINT8 triptemp = 0; 00156 const char * cp; 00157 int err = 0; 00158 print_on(); 00159 if (scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, &ascq, 00160 ¤ttemp, &triptemp)) { 00161 /* error message already announced */ 00162 print_off(); 00163 return -1; 00164 } 00165 print_off(); 00166 cp = scsiGetIEString(asc, ascq); 00167 if (cp) { 00168 err = -2; 00169 print_on(); 00170 pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq); 00171 print_off(); 00172 } else if (gIecMPage) 00173 pout("SMART Health Status: OK\n"); 00174 00175 if (attribs && !gTempLPage) { 00176 if (currenttemp) { 00177 if (255 != currenttemp) 00178 pout("Current Drive Temperature: %d C\n", currenttemp); 00179 else 00180 pout("Current Drive Temperature: <not available>\n"); 00181 } 00182 if (triptemp) 00183 pout("Drive Trip Temperature: %d C\n", triptemp); 00184 } 00185 pout("\n"); 00186 return err; 00187 } 00188 00189 00190 // Returns number of logged errors or zero if none or -1 if fetching 00191 // TapeAlerts fails 00192 static const char * const severities = "CWI"; 00193 00194 static int 00195 scsiGetTapeAlertsData(scsi_device * device, int peripheral_type) 00196 { 00197 unsigned short pagelength; 00198 unsigned short parametercode; 00199 int i, err; 00200 const char *s; 00201 const char *ts; 00202 int failures = 0; 00203 00204 print_on(); 00205 if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf, 00206 LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) { 00207 pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err)); 00208 print_off(); 00209 return -1; 00210 } 00211 if (gBuf[0] != 0x2e) { 00212 pout("TapeAlerts Log Sense Failed\n"); 00213 print_off(); 00214 return -1; 00215 } 00216 pagelength = (unsigned short) gBuf[2] << 8 | gBuf[3]; 00217 00218 for (s=severities; *s; s++) { 00219 for (i = 4; i < pagelength; i += 5) { 00220 parametercode = (unsigned short) gBuf[i] << 8 | gBuf[i+1]; 00221 00222 if (gBuf[i + 4]) { 00223 ts = SCSI_PT_MEDIUM_CHANGER == peripheral_type ? 00224 scsiTapeAlertsChangerDevice(parametercode) : 00225 scsiTapeAlertsTapeDevice(parametercode); 00226 if (*ts == *s) { 00227 if (!failures) 00228 pout("TapeAlert Errors (C=Critical, W=Warning, " 00229 "I=Informational):\n"); 00230 pout("[0x%02x] %s\n", parametercode, ts); 00231 failures += 1; 00232 } 00233 } 00234 } 00235 } 00236 print_off(); 00237 00238 if (! failures) 00239 pout("TapeAlert: OK\n"); 00240 00241 return failures; 00242 } 00243 00244 static void 00245 scsiGetStartStopData(scsi_device * device) 00246 { 00247 UINT32 u; 00248 int err, len, k, extra, pc; 00249 unsigned char * ucp; 00250 00251 if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf, 00252 LOG_RESP_LEN, 0))) { 00253 print_on(); 00254 pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err)); 00255 print_off(); 00256 return; 00257 } 00258 if ((gBuf[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE) { 00259 print_on(); 00260 pout("StartStop Log Sense Failed, page mismatch\n"); 00261 print_off(); 00262 return; 00263 } 00264 len = ((gBuf[2] << 8) | gBuf[3]); 00265 ucp = gBuf + 4; 00266 for (k = len; k > 0; k -= extra, ucp += extra) { 00267 if (k < 3) { 00268 print_on(); 00269 pout("StartStop Log Sense Failed: short\n"); 00270 print_off(); 00271 return; 00272 } 00273 extra = ucp[3] + 4; 00274 pc = (ucp[0] << 8) + ucp[1]; 00275 switch (pc) { 00276 case 1: 00277 if (10 == extra) 00278 pout("Manufactured in week %.2s of year %.4s\n", ucp + 8, 00279 ucp + 4); 00280 break; 00281 case 2: 00282 /* ignore Accounting date */ 00283 break; 00284 case 3: 00285 if (extra > 7) { 00286 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; 00287 if (0xffffffff != u) 00288 pout("Specified cycle count over device lifetime: %u\n", 00289 u); 00290 } 00291 break; 00292 case 4: 00293 if (extra > 7) { 00294 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; 00295 if (0xffffffff != u) 00296 pout("Accumulated start-stop cycles: %u\n", u); 00297 } 00298 break; 00299 case 5: 00300 if (extra > 7) { 00301 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; 00302 if (0xffffffff != u) 00303 pout("Specified load-unload count over device " 00304 "lifetime: %u\n", u); 00305 } 00306 break; 00307 case 6: 00308 if (extra > 7) { 00309 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; 00310 if (0xffffffff != u) 00311 pout("Accumulated load-unload cycles: %u\n", u); 00312 } 00313 break; 00314 default: 00315 /* ignore */ 00316 break; 00317 } 00318 } 00319 } 00320 00321 static void 00322 scsiPrintGrownDefectListLen(scsi_device * device) 00323 { 00324 int err, dl_format, got_rd12, generation; 00325 unsigned int dl_len, div; 00326 00327 memset(gBuf, 0, 8); 00328 if ((err = scsiReadDefect12(device, 0 /* req_plist */, 1 /* req_glist */, 00329 4 /* format: bytes from index */, 00330 0 /* addr desc index */, gBuf, 8))) { 00331 if (2 == err) { /* command not supported */ 00332 if ((err = scsiReadDefect10(device, 0 /* req_plist */, 1 /* req_glist */, 00333 4 /* format: bytes from index */, gBuf, 4))) { 00334 if (scsi_debugmode > 0) { 00335 print_on(); 00336 pout("Read defect list (10) Failed: %s\n", scsiErrString(err)); 00337 print_off(); 00338 } 00339 return; 00340 } else 00341 got_rd12 = 0; 00342 } else { 00343 if (scsi_debugmode > 0) { 00344 print_on(); 00345 pout("Read defect list (12) Failed: %s\n", scsiErrString(err)); 00346 print_off(); 00347 } 00348 return; 00349 } 00350 } else 00351 got_rd12 = 1; 00352 00353 if (got_rd12) { 00354 generation = (gBuf[2] << 8) + gBuf[3]; 00355 if ((generation > 1) && (scsi_debugmode > 0)) { 00356 print_on(); 00357 pout("Read defect list (12): generation=%d\n", generation); 00358 print_off(); 00359 } 00360 dl_len = (gBuf[4] << 24) + (gBuf[5] << 16) + (gBuf[6] << 8) + gBuf[7]; 00361 } else { 00362 dl_len = (gBuf[2] << 8) + gBuf[3]; 00363 } 00364 if (0x8 != (gBuf[1] & 0x18)) { 00365 print_on(); 00366 pout("Read defect list: asked for grown list but didn't get it\n"); 00367 print_off(); 00368 return; 00369 } 00370 div = 0; 00371 dl_format = (gBuf[1] & 0x7); 00372 switch (dl_format) { 00373 case 0: /* short block */ 00374 div = 4; 00375 break; 00376 case 1: /* extended bytes from index */ 00377 case 2: /* extended physical sector */ 00378 /* extended = 1; # might use in future */ 00379 div = 8; 00380 break; 00381 case 3: /* long block */ 00382 case 4: /* bytes from index */ 00383 case 5: /* physical sector */ 00384 div = 8; 00385 break; 00386 default: 00387 print_on(); 00388 pout("defect list format %d unknown\n", dl_format); 00389 print_off(); 00390 break; 00391 } 00392 if (0 == dl_len) 00393 pout("Elements in grown defect list: 0\n\n"); 00394 else { 00395 if (0 == div) 00396 pout("Grown defect list length=%u bytes [unknown " 00397 "number of elements]\n\n", dl_len); 00398 else 00399 pout("Elements in grown defect list: %u\n\n", dl_len / div); 00400 } 00401 } 00402 00403 static void 00404 scsiPrintSeagateCacheLPage(scsi_device * device) 00405 { 00406 int k, j, num, pl, pc, err, len; 00407 unsigned char * ucp; 00408 unsigned char * xp; 00409 uint64_t ull; 00410 00411 if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf, 00412 LOG_RESP_LEN, 0))) { 00413 print_on(); 00414 pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err)); 00415 print_off(); 00416 return; 00417 } 00418 if ((gBuf[0] & 0x3f) != SEAGATE_CACHE_LPAGE) { 00419 print_on(); 00420 pout("Seagate Cache Log Sense Failed, page mismatch\n"); 00421 print_off(); 00422 return; 00423 } 00424 len = ((gBuf[2] << 8) | gBuf[3]) + 4; 00425 num = len - 4; 00426 ucp = &gBuf[0] + 4; 00427 while (num > 3) { 00428 pc = (ucp[0] << 8) | ucp[1]; 00429 pl = ucp[3] + 4; 00430 switch (pc) { 00431 case 0: case 1: case 2: case 3: case 4: 00432 break; 00433 default: 00434 if (scsi_debugmode > 0) { 00435 print_on(); 00436 pout("Vendor (Seagate) cache lpage has unexpected parameter" 00437 ", skip\n"); 00438 print_off(); 00439 } 00440 return; 00441 } 00442 num -= pl; 00443 ucp += pl; 00444 } 00445 pout("Vendor (Seagate) cache information\n"); 00446 num = len - 4; 00447 ucp = &gBuf[0] + 4; 00448 while (num > 3) { 00449 pc = (ucp[0] << 8) | ucp[1]; 00450 pl = ucp[3] + 4; 00451 switch (pc) { 00452 case 0: pout(" Blocks sent to initiator"); break; 00453 case 1: pout(" Blocks received from initiator"); break; 00454 case 2: pout(" Blocks read from cache and sent to initiator"); break; 00455 case 3: pout(" Number of read and write commands whose size " 00456 "<= segment size"); break; 00457 case 4: pout(" Number of read and write commands whose size " 00458 "> segment size"); break; 00459 default: pout(" Unknown Seagate parameter code [0x%x]", pc); break; 00460 } 00461 k = pl - 4; 00462 xp = ucp + 4; 00463 if (k > (int)sizeof(ull)) { 00464 xp += (k - (int)sizeof(ull)); 00465 k = (int)sizeof(ull); 00466 } 00467 ull = 0; 00468 for (j = 0; j < k; ++j) { 00469 if (j > 0) 00470 ull <<= 8; 00471 ull |= xp[j]; 00472 } 00473 pout(" = %"PRIu64"\n", ull); 00474 num -= pl; 00475 ucp += pl; 00476 } 00477 pout("\n"); 00478 } 00479 00480 static void 00481 scsiPrintSeagateFactoryLPage(scsi_device * device) 00482 { 00483 int k, j, num, pl, pc, len, err, good, bad; 00484 unsigned char * ucp; 00485 unsigned char * xp; 00486 uint64_t ull; 00487 00488 if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf, 00489 LOG_RESP_LEN, 0))) { 00490 print_on(); 00491 pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err)); 00492 print_off(); 00493 return; 00494 } 00495 if ((gBuf[0] & 0x3f) != SEAGATE_FACTORY_LPAGE) { 00496 print_on(); 00497 pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n"); 00498 print_off(); 00499 return; 00500 } 00501 len = ((gBuf[2] << 8) | gBuf[3]) + 4; 00502 num = len - 4; 00503 ucp = &gBuf[0] + 4; 00504 good = 0; 00505 bad = 0; 00506 while (num > 3) { 00507 pc = (ucp[0] << 8) | ucp[1]; 00508 pl = ucp[3] + 4; 00509 switch (pc) { 00510 case 0: case 8: 00511 ++good; 00512 break; 00513 default: 00514 ++bad; 00515 break; 00516 } 00517 num -= pl; 00518 ucp += pl; 00519 } 00520 if ((good < 2) || (bad > 4)) { /* heuristic */ 00521 if (scsi_debugmode > 0) { 00522 print_on(); 00523 pout("\nVendor (Seagate/Hitachi) factory lpage has too many " 00524 "unexpected parameters, skip\n"); 00525 print_off(); 00526 } 00527 return; 00528 } 00529 pout("Vendor (Seagate/Hitachi) factory information\n"); 00530 num = len - 4; 00531 ucp = &gBuf[0] + 4; 00532 while (num > 3) { 00533 pc = (ucp[0] << 8) | ucp[1]; 00534 pl = ucp[3] + 4; 00535 good = 0; 00536 switch (pc) { 00537 case 0: pout(" number of hours powered up"); 00538 good = 1; 00539 break; 00540 case 8: pout(" number of minutes until next internal SMART test"); 00541 good = 1; 00542 break; 00543 default: 00544 if (scsi_debugmode > 0) { 00545 print_on(); 00546 pout("Vendor (Seagate/Hitachi) factory lpage: " 00547 "unknown parameter code [0x%x]\n", pc); 00548 print_off(); 00549 } 00550 break; 00551 } 00552 if (good) { 00553 k = pl - 4; 00554 xp = ucp + 4; 00555 if (k > (int)sizeof(ull)) { 00556 xp += (k - (int)sizeof(ull)); 00557 k = (int)sizeof(ull); 00558 } 00559 ull = 0; 00560 for (j = 0; j < k; ++j) { 00561 if (j > 0) 00562 ull <<= 8; 00563 ull |= xp[j]; 00564 } 00565 if (0 == pc) 00566 pout(" = %.2f\n", ull / 60.0 ); 00567 else 00568 pout(" = %"PRIu64"\n", ull); 00569 } 00570 num -= pl; 00571 ucp += pl; 00572 } 00573 pout("\n"); 00574 } 00575 00576 static void 00577 scsiPrintErrorCounterLog(scsi_device * device) 00578 { 00579 struct scsiErrorCounter errCounterArr[3]; 00580 struct scsiErrorCounter * ecp; 00581 struct scsiNonMediumError nme; 00582 int found[3] = {0, 0, 0}; 00583 const char * pageNames[3] = {"read: ", "write: ", "verify: "}; 00584 double processed_gb; 00585 00586 if (gReadECounterLPage && (0 == scsiLogSense(device, 00587 READ_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { 00588 scsiDecodeErrCounterPage(gBuf, &errCounterArr[0]); 00589 found[0] = 1; 00590 } 00591 if (gWriteECounterLPage && (0 == scsiLogSense(device, 00592 WRITE_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { 00593 scsiDecodeErrCounterPage(gBuf, &errCounterArr[1]); 00594 found[1] = 1; 00595 } 00596 if (gVerifyECounterLPage && (0 == scsiLogSense(device, 00597 VERIFY_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { 00598 scsiDecodeErrCounterPage(gBuf, &errCounterArr[2]); 00599 ecp = &errCounterArr[2]; 00600 for (int k = 0; k < 7; ++k) { 00601 if (ecp->gotPC[k] && ecp->counter[k]) { 00602 found[2] = 1; 00603 break; 00604 } 00605 } 00606 } 00607 if (found[0] || found[1] || found[2]) { 00608 pout("Error counter log:\n"); 00609 pout(" Errors Corrected by Total " 00610 "Correction Gigabytes Total\n"); 00611 pout(" ECC rereads/ errors " 00612 "algorithm processed uncorrected\n"); 00613 pout(" fast | delayed rewrites corrected " 00614 "invocations [10^9 bytes] errors\n"); 00615 for (int k = 0; k < 3; ++k) { 00616 if (! found[k]) 00617 continue; 00618 ecp = &errCounterArr[k]; 00619 pout("%s%8"PRIu64" %8"PRIu64" %8"PRIu64" %8"PRIu64" %8"PRIu64, 00620 pageNames[k], ecp->counter[0], ecp->counter[1], 00621 ecp->counter[2], ecp->counter[3], ecp->counter[4]); 00622 processed_gb = ecp->counter[5] / 1000000000.0; 00623 pout(" %12.3f %8"PRIu64"\n", processed_gb, ecp->counter[6]); 00624 } 00625 } 00626 else 00627 pout("Error Counter logging not supported\n"); 00628 if (gNonMediumELPage && (0 == scsiLogSense(device, 00629 NON_MEDIUM_ERROR_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { 00630 scsiDecodeNonMediumErrPage(gBuf, &nme); 00631 if (nme.gotPC0) 00632 pout("\nNon-medium error count: %8"PRIu64"\n", nme.counterPC0); 00633 if (nme.gotTFE_H) 00634 pout("Track following error count [Hitachi]: %8"PRIu64"\n", 00635 nme.counterTFE_H); 00636 if (nme.gotPE_H) 00637 pout("Positioning error count [Hitachi]: %8"PRIu64"\n", 00638 nme.counterPE_H); 00639 } 00640 if (gLastNErrorLPage && (0 == scsiLogSense(device, 00641 LAST_N_ERROR_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) { 00642 int num = (gBuf[2] << 8) + gBuf[3] + 4; 00643 int truncated = (num > LOG_RESP_LONG_LEN) ? num : 0; 00644 if (truncated) 00645 num = LOG_RESP_LONG_LEN; 00646 unsigned char * ucp = gBuf + 4; 00647 num -= 4; 00648 if (num < 4) 00649 pout("\nNo error events logged\n"); 00650 else { 00651 pout("\nLast n error events log page\n"); 00652 for (int k = num, pl; k > 0; k -= pl, ucp += pl) { 00653 if (k < 3) { 00654 pout(" <<short Last n error events log page>>\n"); 00655 break; 00656 } 00657 pl = ucp[3] + 4; 00658 int pc = (ucp[0] << 8) + ucp[1]; 00659 if (pl > 4) { 00660 if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) { 00661 pout(" Error event %d:\n", pc); 00662 pout(" [binary]:\n"); 00663 dStrHex((const char *)ucp + 4, pl - 4, 1); 00664 } else if (ucp[2] & 0x1) { 00665 pout(" Error event %d:\n", pc); 00666 pout(" %.*s\n", pl - 4, (const char *)(ucp + 4)); 00667 } else { 00668 if (scsi_debugmode > 0) { 00669 pout(" Error event %d:\n", pc); 00670 pout(" [data counter??]:\n"); 00671 dStrHex((const char *)ucp + 4, pl - 4, 1); 00672 } 00673 } 00674 } 00675 } 00676 if (truncated) 00677 pout(" >>>> log truncated, fetched %d of %d available " 00678 "bytes\n", LOG_RESP_LONG_LEN, truncated); 00679 } 00680 } 00681 pout("\n"); 00682 } 00683 00684 static const char * self_test_code[] = { 00685 "Default ", 00686 "Background short", 00687 "Background long ", 00688 "Reserved(3) ", 00689 "Abort background", 00690 "Foreground short", 00691 "Foreground long ", 00692 "Reserved(7) " 00693 }; 00694 00695 static const char * self_test_result[] = { 00696 "Completed ", 00697 "Aborted (by user command)", 00698 "Aborted (device reset ?) ", 00699 "Unknown error, incomplete", 00700 "Completed, segment failed", 00701 "Failed in first segment ", 00702 "Failed in second segment ", 00703 "Failed in segment --> ", 00704 "Reserved(8) ", 00705 "Reserved(9) ", 00706 "Reserved(10) ", 00707 "Reserved(11) ", 00708 "Reserved(12) ", 00709 "Reserved(13) ", 00710 "Reserved(14) ", 00711 "Self test in progress ..." 00712 }; 00713 00714 // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 . 00715 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent 00716 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or 00717 // FAILSMART is returned. 00718 static int 00719 scsiPrintSelfTest(scsi_device * device) 00720 { 00721 int num, k, n, res, err, durationSec; 00722 int noheader = 1; 00723 int retval = 0; 00724 UINT8 * ucp; 00725 uint64_t ull=0; 00726 struct scsi_sense_disect sense_info; 00727 00728 // check if test is running 00729 if (!scsiRequestSense(device, &sense_info) && 00730 (sense_info.asc == 0x04 && sense_info.ascq == 0x09 && 00731 sense_info.progress != -1)) { 00732 pout("Self-test execution status:\t\t%d%% of test remaining\n", 00733 100 - ((sense_info.progress * 100) / 65535)); 00734 } 00735 00736 if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf, 00737 LOG_RESP_SELF_TEST_LEN, 0))) { 00738 print_on(); 00739 pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err)); 00740 print_off(); 00741 return FAILSMART; 00742 } 00743 if ((gBuf[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) { 00744 print_on(); 00745 pout("Self-test Log Sense Failed, page mismatch\n"); 00746 print_off(); 00747 return FAILSMART; 00748 } 00749 // compute page length 00750 num = (gBuf[2] << 8) + gBuf[3]; 00751 // Log sense page length 0x190 bytes 00752 if (num != 0x190) { 00753 print_on(); 00754 pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num); 00755 print_off(); 00756 return FAILSMART; 00757 } 00758 // loop through the twenty possible entries 00759 for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) { 00760 int i; 00761 00762 // timestamp in power-on hours (or zero if test in progress) 00763 n = (ucp[6] << 8) | ucp[7]; 00764 00765 // The spec says "all 20 bytes will be zero if no test" but 00766 // DG has found otherwise. So this is a heuristic. 00767 if ((0 == n) && (0 == ucp[4])) 00768 break; 00769 00770 // only print header if needed 00771 if (noheader) { 00772 pout("SMART Self-test log\n"); 00773 pout("Num Test Status segment " 00774 "LifeTime LBA_first_err [SK ASC ASQ]\n"); 00775 pout(" Description number " 00776 "(hours)\n"); 00777 noheader=0; 00778 } 00779 00780 // print parameter code (test number) & self-test code text 00781 pout("#%2d %s", (ucp[0] << 8) | ucp[1], 00782 self_test_code[(ucp[4] >> 5) & 0x7]); 00783 00784 // check the self-test result nibble, using the self-test results 00785 // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10: 00786 switch ((res = ucp[4] & 0xf)) { 00787 case 0x3: 00788 // an unknown error occurred while the device server 00789 // was processing the self-test and the device server 00790 // was unable to complete the self-test 00791 retval|=FAILSMART; 00792 break; 00793 case 0x4: 00794 // the self-test completed with a failure in a test 00795 // segment, and the test segment that failed is not 00796 // known 00797 retval|=FAILLOG; 00798 break; 00799 case 0x5: 00800 // the first segment of the self-test failed 00801 retval|=FAILLOG; 00802 break; 00803 case 0x6: 00804 // the second segment of the self-test failed 00805 retval|=FAILLOG; 00806 break; 00807 case 0x7: 00808 // another segment of the self-test failed and which 00809 // test is indicated by the contents of the SELF-TEST 00810 // NUMBER field 00811 retval|=FAILLOG; 00812 break; 00813 default: 00814 break; 00815 } 00816 pout(" %s", self_test_result[res]); 00817 00818 // self-test number identifies test that failed and consists 00819 // of either the number of the segment that failed during 00820 // the test, or the number of the test that failed and the 00821 // number of the segment in which the test was run, using a 00822 // vendor-specific method of putting both numbers into a 00823 // single byte. 00824 if (ucp[5]) 00825 pout(" %3d", (int)ucp[5]); 00826 else 00827 pout(" -"); 00828 00829 // print time that the self-test was completed 00830 if (n==0 && res==0xf) 00831 // self-test in progress 00832 pout(" NOW"); 00833 else 00834 pout(" %5d", n); 00835 00836 // construct 8-byte integer address of first failure 00837 for (i = 0; i < 8; i++) { 00838 ull <<= 8; 00839 ull |= ucp[i+8]; 00840 } 00841 // print Address of First Failure, if sensible 00842 if ((~(uint64_t)0 != ull) && (res > 0) && (res < 0xf)) { 00843 char buff[32]; 00844 00845 // was hex but change to decimal to conform with ATA 00846 snprintf(buff, sizeof(buff), "%"PRIu64, ull); 00847 // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull); 00848 pout("%18s", buff); 00849 } else 00850 pout(" -"); 00851 00852 // if sense key nonzero, then print it, along with 00853 // additional sense code and additional sense code qualifier 00854 if (ucp[16] & 0xf) 00855 pout(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]); 00856 else 00857 pout(" [- - -]\n"); 00858 } 00859 00860 // if header never printed, then there was no output 00861 if (noheader) 00862 pout("No self-tests have been logged\n"); 00863 else 00864 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec, 00865 modese_len)) && (durationSec > 0)) { 00866 pout("Long (extended) Self Test duration: %d seconds " 00867 "[%.1f minutes]\n", durationSec, durationSec / 60.0); 00868 } 00869 pout("\n"); 00870 return retval; 00871 } 00872 00873 static const char * bms_status[] = { 00874 "no scans active", 00875 "scan is active", 00876 "pre-scan is active", 00877 "halted due to fatal error", 00878 "halted due to a vendor specific pattern of error", 00879 "halted due to medium formatted without P-List", 00880 "halted - vendor specific cause", 00881 "halted due to temperature out of range", 00882 "waiting until BMS interval timer expires", /* 8 */ 00883 }; 00884 00885 static const char * reassign_status[] = { 00886 "Reserved [0x0]", 00887 "Require Write or Reassign Blocks command", 00888 "Successfully reassigned", 00889 "Reserved [0x3]", 00890 "Reassignment by disk failed", 00891 "Recovered via rewrite in-place", 00892 "Reassigned by app, has valid data", 00893 "Reassigned by app, has no valid data", 00894 "Unsuccessfully reassigned by app", /* 8 */ 00895 }; 00896 00897 // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 . 00898 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry 00899 // and up to 2048 events (although would hope to have less). May set 00900 // FAILLOG if serious errors detected (in the future). 00901 static int 00902 scsiPrintBackgroundResults(scsi_device * device) 00903 { 00904 int num, j, m, err, pc, pl, truncated; 00905 int noheader = 1; 00906 int firstresult = 1; 00907 int retval = 0; 00908 UINT8 * ucp; 00909 00910 if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf, 00911 LOG_RESP_LONG_LEN, 0))) { 00912 print_on(); 00913 pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err)); 00914 print_off(); 00915 return FAILSMART; 00916 } 00917 if ((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) { 00918 print_on(); 00919 pout("Background scan results Log Sense Failed, page mismatch\n"); 00920 print_off(); 00921 return FAILSMART; 00922 } 00923 // compute page length 00924 num = (gBuf[2] << 8) + gBuf[3] + 4; 00925 if (num < 20) { 00926 print_on(); 00927 pout("Background scan results Log Sense length is %d, no scan " 00928 "status\n", num); 00929 print_off(); 00930 return FAILSMART; 00931 } 00932 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0; 00933 if (truncated) 00934 num = LOG_RESP_LONG_LEN; 00935 ucp = gBuf + 4; 00936 num -= 4; 00937 while (num > 3) { 00938 pc = (ucp[0] << 8) | ucp[1]; 00939 // pcb = ucp[2]; 00940 pl = ucp[3] + 4; 00941 switch (pc) { 00942 case 0: 00943 if (noheader) { 00944 noheader = 0; 00945 pout("Background scan results log\n"); 00946 } 00947 pout(" Status: "); 00948 if ((pl < 16) || (num < 16)) { 00949 pout("\n"); 00950 break; 00951 } 00952 j = ucp[9]; 00953 if (j < (int)(sizeof(bms_status) / sizeof(bms_status[0]))) 00954 pout("%s\n", bms_status[j]); 00955 else 00956 pout("unknown [0x%x] background scan status value\n", j); 00957 j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; 00958 pout(" Accumulated power on time, hours:minutes %d:%02d " 00959 "[%d minutes]\n", (j / 60), (j % 60), j); 00960 pout(" Number of background scans performed: %d, ", 00961 (ucp[10] << 8) + ucp[11]); 00962 pout("scan progress: %.2f%%\n", 00963 (double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0); 00964 pout(" Number of background medium scans performed: %d\n", 00965 (ucp[14] << 8) + ucp[15]); 00966 break; 00967 default: 00968 if (noheader) { 00969 noheader = 0; 00970 pout("\nBackground scan results log\n"); 00971 } 00972 if (firstresult) { 00973 firstresult = 0; 00974 pout("\n # when lba(hex) [sk,asc,ascq] " 00975 "reassign_status\n"); 00976 } 00977 pout(" %3d ", pc); 00978 if ((pl < 24) || (num < 24)) { 00979 if (pl < 24) 00980 pout("parameter length >= 24 expected, got %d\n", pl); 00981 break; 00982 } 00983 j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; 00984 pout("%4d:%02d ", (j / 60), (j % 60)); 00985 for (m = 0; m < 8; ++m) 00986 pout("%02x", ucp[16 + m]); 00987 pout(" [%x,%x,%x] ", ucp[8] & 0xf, ucp[9], ucp[10]); 00988 j = (ucp[8] >> 4) & 0xf; 00989 if (j < 00990 (int)(sizeof(reassign_status) / sizeof(reassign_status[0]))) 00991 pout("%s\n", reassign_status[j]); 00992 else 00993 pout("Reassign status: reserved [0x%x]\n", j); 00994 break; 00995 } 00996 num -= pl; 00997 ucp += pl; 00998 } 00999 if (truncated) 01000 pout(" >>>> log truncated, fetched %d of %d available " 01001 "bytes\n", LOG_RESP_LONG_LEN, truncated); 01002 pout("\n"); 01003 return retval; 01004 } 01005 01006 // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 . 01007 // Returns 0 if ok else FAIL* bitmask. Note can have a status entry 01008 // and up to 2048 events (although would hope to have less). May set 01009 // FAILLOG if serious errors detected (in the future). 01010 static int 01011 scsiPrintSSMedia(scsi_device * device) 01012 { 01013 int num, err, pc, pl, truncated; 01014 int retval = 0; 01015 UINT8 * ucp; 01016 01017 if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf, 01018 LOG_RESP_LONG_LEN, 0))) { 01019 print_on(); 01020 pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err)); 01021 print_off(); 01022 return FAILSMART; 01023 } 01024 if ((gBuf[0] & 0x3f) != SS_MEDIA_LPAGE) { 01025 print_on(); 01026 pout("Solid state media Log Sense Failed, page mismatch\n"); 01027 print_off(); 01028 return FAILSMART; 01029 } 01030 // compute page length 01031 num = (gBuf[2] << 8) + gBuf[3] + 4; 01032 if (num < 12) { 01033 print_on(); 01034 pout("Solid state media Log Sense length is %d, too short\n", num); 01035 print_off(); 01036 return FAILSMART; 01037 } 01038 truncated = (num > LOG_RESP_LONG_LEN) ? num : 0; 01039 if (truncated) 01040 num = LOG_RESP_LONG_LEN; 01041 ucp = gBuf + 4; 01042 num -= 4; 01043 while (num > 3) { 01044 pc = (ucp[0] << 8) | ucp[1]; 01045 // pcb = ucp[2]; 01046 pl = ucp[3] + 4; 01047 switch (pc) { 01048 case 1: 01049 if (pl < 8) { 01050 print_on(); 01051 pout("Percentage used endurance indicator too short (pl=%d)\n", pl); 01052 print_off(); 01053 return FAILSMART; 01054 } 01055 pout("SS Media used endurance indicator: %d%%\n", ucp[7]); 01056 default: /* ignore other parameter codes */ 01057 break; 01058 } 01059 num -= pl; 01060 ucp += pl; 01061 } 01062 return retval; 01063 } 01064 01065 static void 01066 show_sas_phy_event_info(int peis, unsigned int val, unsigned thresh_val) 01067 { 01068 unsigned int u; 01069 01070 switch (peis) { 01071 case 0: 01072 pout(" No event\n"); 01073 break; 01074 case 0x1: 01075 pout(" Invalid word count: %u\n", val); 01076 break; 01077 case 0x2: 01078 pout(" Running disparity error count: %u\n", val); 01079 break; 01080 case 0x3: 01081 pout(" Loss of dword synchronization count: %u\n", val); 01082 break; 01083 case 0x4: 01084 pout(" Phy reset problem count: %u\n", val); 01085 break; 01086 case 0x5: 01087 pout(" Elasticity buffer overflow count: %u\n", val); 01088 break; 01089 case 0x6: 01090 pout(" Received ERROR count: %u\n", val); 01091 break; 01092 case 0x20: 01093 pout(" Received address frame error count: %u\n", val); 01094 break; 01095 case 0x21: 01096 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val); 01097 break; 01098 case 0x22: 01099 pout(" Received abandon-class OPEN_REJECT count: %u\n", val); 01100 break; 01101 case 0x23: 01102 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val); 01103 break; 01104 case 0x24: 01105 pout(" Received retry-class OPEN_REJECT count: %u\n", val); 01106 break; 01107 case 0x25: 01108 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val); 01109 break; 01110 case 0x26: 01111 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val); 01112 break; 01113 case 0x27: 01114 pout(" Transmitted BREAK count: %u\n", val); 01115 break; 01116 case 0x28: 01117 pout(" Received BREAK count: %u\n", val); 01118 break; 01119 case 0x29: 01120 pout(" Break timeout count: %u\n", val); 01121 break; 01122 case 0x2a: 01123 pout(" Connection count: %u\n", val); 01124 break; 01125 case 0x2b: 01126 pout(" Peak transmitted pathway blocked count: %u\n", 01127 val & 0xff); 01128 pout(" Peak value detector threshold: %u\n", 01129 thresh_val & 0xff); 01130 break; 01131 case 0x2c: 01132 u = val & 0xffff; 01133 if (u < 0x8000) 01134 pout(" Peak transmitted arbitration wait time (us): " 01135 "%u\n", u); 01136 else 01137 pout(" Peak transmitted arbitration wait time (ms): " 01138 "%u\n", 33 + (u - 0x8000)); 01139 u = thresh_val & 0xffff; 01140 if (u < 0x8000) 01141 pout(" Peak value detector threshold (us): %u\n", 01142 u); 01143 else 01144 pout(" Peak value detector threshold (ms): %u\n", 01145 33 + (u - 0x8000)); 01146 break; 01147 case 0x2d: 01148 pout(" Peak arbitration time (us): %u\n", val); 01149 pout(" Peak value detector threshold: %u\n", thresh_val); 01150 break; 01151 case 0x2e: 01152 pout(" Peak connection time (us): %u\n", val); 01153 pout(" Peak value detector threshold: %u\n", thresh_val); 01154 break; 01155 case 0x40: 01156 pout(" Transmitted SSP frame count: %u\n", val); 01157 break; 01158 case 0x41: 01159 pout(" Received SSP frame count: %u\n", val); 01160 break; 01161 case 0x42: 01162 pout(" Transmitted SSP frame error count: %u\n", val); 01163 break; 01164 case 0x43: 01165 pout(" Received SSP frame error count: %u\n", val); 01166 break; 01167 case 0x44: 01168 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val); 01169 break; 01170 case 0x45: 01171 pout(" Received CREDIT_BLOCKED count: %u\n", val); 01172 break; 01173 case 0x50: 01174 pout(" Transmitted SATA frame count: %u\n", val); 01175 break; 01176 case 0x51: 01177 pout(" Received SATA frame count: %u\n", val); 01178 break; 01179 case 0x52: 01180 pout(" SATA flow control buffer overflow count: %u\n", val); 01181 break; 01182 case 0x60: 01183 pout(" Transmitted SMP frame count: %u\n", val); 01184 break; 01185 case 0x61: 01186 pout(" Received SMP frame count: %u\n", val); 01187 break; 01188 case 0x63: 01189 pout(" Received SMP frame error count: %u\n", val); 01190 break; 01191 default: 01192 break; 01193 } 01194 } 01195 01196 static void 01197 show_sas_port_param(unsigned char * ucp, int param_len) 01198 { 01199 int j, m, n, nphys, t, sz, spld_len; 01200 unsigned char * vcp; 01201 uint64_t ull; 01202 unsigned int ui; 01203 char s[64]; 01204 01205 sz = sizeof(s); 01206 // pcb = ucp[2]; 01207 t = (ucp[0] << 8) | ucp[1]; 01208 pout("relative target port id = %d\n", t); 01209 pout(" generation code = %d\n", ucp[6]); 01210 nphys = ucp[7]; 01211 pout(" number of phys = %d\n", nphys); 01212 01213 for (j = 0, vcp = ucp + 8; j < (param_len - 8); 01214 vcp += spld_len, j += spld_len) { 01215 pout(" phy identifier = %d\n", vcp[1]); 01216 spld_len = vcp[3]; 01217 if (spld_len < 44) 01218 spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */ 01219 else 01220 spld_len += 4; 01221 t = ((0x70 & vcp[4]) >> 4); 01222 switch (t) { 01223 case 0: snprintf(s, sz, "no device attached"); break; 01224 case 1: snprintf(s, sz, "end device"); break; 01225 case 2: snprintf(s, sz, "expander device"); break; 01226 case 3: snprintf(s, sz, "expander device (fanout)"); break; 01227 default: snprintf(s, sz, "reserved [%d]", t); break; 01228 } 01229 pout(" attached device type: %s\n", s); 01230 t = 0xf & vcp[4]; 01231 switch (t) { 01232 case 0: snprintf(s, sz, "unknown"); break; 01233 case 1: snprintf(s, sz, "power on"); break; 01234 case 2: snprintf(s, sz, "hard reset"); break; 01235 case 3: snprintf(s, sz, "SMP phy control function"); break; 01236 case 4: snprintf(s, sz, "loss of dword synchronization"); break; 01237 case 5: snprintf(s, sz, "mux mix up"); break; 01238 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA"); 01239 break; 01240 case 7: snprintf(s, sz, "break timeout timer expired"); break; 01241 case 8: snprintf(s, sz, "phy test function stopped"); break; 01242 case 9: snprintf(s, sz, "expander device reduced functionality"); 01243 break; 01244 default: snprintf(s, sz, "reserved [0x%x]", t); break; 01245 } 01246 pout(" attached reason: %s\n", s); 01247 t = (vcp[5] & 0xf0) >> 4; 01248 switch (t) { 01249 case 0: snprintf(s, sz, "unknown"); break; 01250 case 1: snprintf(s, sz, "power on"); break; 01251 case 2: snprintf(s, sz, "hard reset"); break; 01252 case 3: snprintf(s, sz, "SMP phy control function"); break; 01253 case 4: snprintf(s, sz, "loss of dword synchronization"); break; 01254 case 5: snprintf(s, sz, "mux mix up"); break; 01255 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA"); 01256 break; 01257 case 7: snprintf(s, sz, "break timeout timer expired"); break; 01258 case 8: snprintf(s, sz, "phy test function stopped"); break; 01259 case 9: snprintf(s, sz, "expander device reduced functionality"); 01260 break; 01261 default: snprintf(s, sz, "reserved [0x%x]", t); break; 01262 } 01263 pout(" reason: %s\n", s); 01264 t = (0xf & vcp[5]); 01265 switch (t) { 01266 case 0: snprintf(s, sz, "phy enabled; unknown"); 01267 break; 01268 case 1: snprintf(s, sz, "phy disabled"); break; 01269 case 2: snprintf(s, sz, "phy enabled; speed negotiation failed"); 01270 break; 01271 case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state"); 01272 break; 01273 case 4: snprintf(s, sz, "phy enabled; port selector"); 01274 break; 01275 case 5: snprintf(s, sz, "phy enabled; reset in progress"); 01276 break; 01277 case 6: snprintf(s, sz, "phy enabled; unsupported phy attached"); 01278 break; 01279 case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break; 01280 case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break; 01281 case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break; 01282 default: snprintf(s, sz, "reserved [%d]", t); break; 01283 } 01284 pout(" negotiated logical link rate: %s\n", s); 01285 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n", 01286 !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2)); 01287 pout(" attached target port: ssp=%d stp=%d smp=%d\n", 01288 !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2)); 01289 for (n = 0, ull = vcp[8]; n < 8; ++n) { 01290 ull <<= 8; ull |= vcp[8 + n]; 01291 } 01292 pout(" SAS address = 0x%" PRIx64 "\n", ull); 01293 for (n = 0, ull = vcp[16]; n < 8; ++n) { 01294 ull <<= 8; ull |= vcp[16 + n]; 01295 } 01296 pout(" attached SAS address = 0x%" PRIx64 "\n", ull); 01297 pout(" attached phy identifier = %d\n", vcp[24]); 01298 ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35]; 01299 pout(" Invalid DWORD count = %u\n", ui); 01300 ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39]; 01301 pout(" Running disparity error count = %u\n", ui); 01302 ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43]; 01303 pout(" Loss of DWORD synchronization = %u\n", ui); 01304 ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47]; 01305 pout(" Phy reset problem = %u\n", ui); 01306 if (spld_len > 51) { 01307 int num_ped, peis; 01308 unsigned char * xcp; 01309 unsigned int pvdt; 01310 01311 num_ped = vcp[51]; 01312 if (num_ped > 0) 01313 pout(" Phy event descriptors:\n"); 01314 xcp = vcp + 52; 01315 for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) { 01316 peis = xcp[3]; 01317 ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) | 01318 xcp[7]; 01319 pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) | 01320 xcp[11]; 01321 show_sas_phy_event_info(peis, ui, pvdt); 01322 } 01323 } 01324 } 01325 } 01326 01327 // Returns 1 if okay, 0 if non SAS descriptors 01328 static int 01329 show_protocol_specific_page(unsigned char * resp, int len) 01330 { 01331 int k, num, param_len; 01332 unsigned char * ucp; 01333 01334 num = len - 4; 01335 for (k = 0, ucp = resp + 4; k < num; ) { 01336 param_len = ucp[3] + 4; 01337 if (6 != (0xf & ucp[4])) 01338 return 0; /* only decode SAS log page */ 01339 if (0 == k) 01340 pout("Protocol Specific port log page for SAS SSP\n"); 01341 show_sas_port_param(ucp, param_len); 01342 k += param_len; 01343 ucp += param_len; 01344 } 01345 pout("\n"); 01346 return 1; 01347 } 01348 01349 01350 // See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific 01351 // log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol 01352 // Specific log page. 01353 // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent 01354 // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or 01355 // FAILSMART is returned. 01356 static int 01357 scsiPrintSasPhy(scsi_device * device, int reset) 01358 { 01359 int num, err; 01360 01361 if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf, 01362 LOG_RESP_LONG_LEN, 0))) { 01363 print_on(); 01364 pout("scsiPrintSasPhy Log Sense Failed [%s]\n\n", scsiErrString(err)); 01365 print_off(); 01366 return FAILSMART; 01367 } 01368 if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) { 01369 print_on(); 01370 pout("Protocol specific Log Sense Failed, page mismatch\n\n"); 01371 print_off(); 01372 return FAILSMART; 01373 } 01374 // compute page length 01375 num = (gBuf[2] << 8) + gBuf[3]; 01376 if (1 != show_protocol_specific_page(gBuf, num + 4)) { 01377 print_on(); 01378 pout("Only support protocol specific log page on SAS devices\n\n"); 01379 print_off(); 01380 return FAILSMART; 01381 } 01382 if (reset) { 01383 if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */, 01384 PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) { 01385 print_on(); 01386 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n\n", 01387 scsiErrString(err)); 01388 print_off(); 01389 return FAILSMART; 01390 } 01391 } 01392 return 0; 01393 } 01394 01395 01396 static const char * peripheral_dt_arr[] = { 01397 "disk", 01398 "tape", 01399 "printer", 01400 "processor", 01401 "optical disk(4)", 01402 "CD/DVD", 01403 "scanner", 01404 "optical disk(7)", 01405 "medium changer", 01406 "communications", 01407 "graphics(10)", 01408 "graphics(11)", 01409 "storage array", 01410 "enclosure", 01411 "simplified disk", 01412 "optical card reader" 01413 }; 01414 01415 static const char * transport_proto_arr[] = { 01416 "Fibre channel (FCP-2)", 01417 "Parallel SCSI (SPI-4)", 01418 "SSA", 01419 "IEEE 1394 (SBP-2)", 01420 "RDMA (SRP)", 01421 "iSCSI", 01422 "SAS", 01423 "ADT", 01424 "0x8", 01425 "0x9", 01426 "0xa", 01427 "0xb", 01428 "0xc", 01429 "0xd", 01430 "0xe", 01431 "0xf" 01432 }; 01433 01434 /* Returns 0 on success, 1 on general error and 2 for early, clean exit */ 01435 static int 01436 scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all) 01437 { 01438 char timedatetz[DATEANDEPOCHLEN]; 01439 struct scsi_iec_mode_page iec; 01440 int err, iec_err, len, req_len, avail_len, n; 01441 int is_tape = 0; 01442 int peri_dt = 0; 01443 int returnval = 0; 01444 int transport = -1; 01445 int form_factor = 0; 01446 int protect = 0; 01447 01448 memset(gBuf, 0, 96); 01449 req_len = 36; 01450 if ((err = scsiStdInquiry(device, gBuf, req_len))) { 01451 print_on(); 01452 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err)); 01453 pout("Retrying with a 64 byte Standard Inquiry\n"); 01454 print_off(); 01455 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */ 01456 req_len = 64; 01457 if ((err = scsiStdInquiry(device, gBuf, req_len))) { 01458 print_on(); 01459 pout("Standard Inquiry (64 bytes) failed [%s]\n", 01460 scsiErrString(err)); 01461 print_off(); 01462 return 1; 01463 } 01464 } 01465 avail_len = gBuf[4] + 5; 01466 len = (avail_len < req_len) ? avail_len : req_len; 01467 peri_dt = gBuf[0] & 0x1f; 01468 if (peripheral_type) 01469 *peripheral_type = peri_dt; 01470 01471 if (len < 36) { 01472 print_on(); 01473 pout("Short INQUIRY response, skip product id\n"); 01474 print_off(); 01475 return 1; 01476 } 01477 01478 if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) { 01479 char vendor[8+1], product[16+1], revision[4+1]; 01480 scsi_format_id_string(vendor, (const unsigned char *)&gBuf[8], 8); 01481 scsi_format_id_string(product, (const unsigned char *)&gBuf[16], 16); 01482 scsi_format_id_string(revision, (const unsigned char *)&gBuf[32], 4); 01483 01484 pout("=== START OF INFORMATION SECTION ===\n"); 01485 pout("Vendor: %.8s\n", vendor); 01486 pout("Product: %.16s\n", product); 01487 if (gBuf[32] >= ' ') 01488 pout("Revision: %.4s\n", revision); 01489 } 01490 01491 if (!*device->get_req_type()/*no type requested*/ && 01492 (0 == strncmp((char *)&gBuf[8], "ATA", 3))) { 01493 pout("\nProbable ATA device behind a SAT layer\n" 01494 "Try an additional '-d ata' or '-d sat' argument.\n"); 01495 return 2; 01496 } 01497 if (! all) 01498 return 0; 01499 01500 protect = gBuf[5] & 0x1; /* from and including SPC-3 */ 01501 01502 if (! is_tape) { /* only do this for disks */ 01503 unsigned int lb_size = 0; 01504 unsigned char lb_prov_resp[8]; 01505 char cap_str[64]; 01506 char si_str[64]; 01507 char lb_str[16]; 01508 int lb_per_pb_exp = 0; 01509 uint64_t capacity = scsiGetSize(device, &lb_size, &lb_per_pb_exp); 01510 01511 if (capacity) { 01512 format_with_thousands_sep(cap_str, sizeof(cap_str), capacity); 01513 format_capacity(si_str, sizeof(si_str), capacity); 01514 pout("User Capacity: %s bytes [%s]\n", cap_str, si_str); 01515 snprintf(lb_str, sizeof(lb_str) - 1, "%u", lb_size); 01516 pout("Logical block size: %s bytes\n", lb_str); 01517 } 01518 int lbpme = -1; 01519 int lbprz = -1; 01520 if (protect || lb_per_pb_exp) { 01521 unsigned char rc16_12[20] = {0, }; 01522 01523 if (0 == scsiGetProtPBInfo(device, rc16_12)) { 01524 lb_per_pb_exp = rc16_12[1] & 0xf; /* just in case */ 01525 if (lb_per_pb_exp > 0) { 01526 snprintf(lb_str, sizeof(lb_str) - 1, "%u", 01527 (lb_size * (1 << lb_per_pb_exp))); 01528 pout("Physical block size: %s bytes\n", lb_str); 01529 n = ((rc16_12[2] & 0x3f) << 8) + rc16_12[3]; 01530 pout("Lowest aligned LBA: %d\n", n); 01531 } 01532 if (rc16_12[0] & 0x1) { /* PROT_EN set */ 01533 int p_type = ((rc16_12[0] >> 1) & 0x7); 01534 01535 switch (p_type) { 01536 case 0 : 01537 pout("Formatted with type 1 protection\n"); 01538 break; 01539 case 1 : 01540 pout("Formatted with type 2 protection\n"); 01541 break; 01542 case 2 : 01543 pout("Formatted with type 3 protection\n"); 01544 break; 01545 default: 01546 pout("Formatted with unknown protection type [%d]\n", 01547 p_type); 01548 break; 01549 } 01550 int p_i_exp = ((rc16_12[1] >> 4) & 0xf); 01551 01552 if (p_i_exp > 0) 01553 pout("%d protection information intervals per " 01554 "logical block\n", (1 << p_i_exp)); 01555 } 01556 /* Pick up some LB provisioning info since its available */ 01557 lbpme = !! (rc16_12[2] & 0x80); 01558 lbprz = !! (rc16_12[2] & 0x40); 01559 } 01560 } 01561 if (0 == scsiInquiryVpd(device, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING, 01562 lb_prov_resp, sizeof(lb_prov_resp))) { 01563 int prov_type = lb_prov_resp[6] & 0x7; 01564 01565 if (-1 == lbprz) 01566 lbprz = !! (lb_prov_resp[5] & 0x4); 01567 switch (prov_type) { 01568 case 0: 01569 pout("Logical block provisioning type unreported, " 01570 "LBPME=%d, LBPRZ=%d\n", lbpme, lbprz); 01571 break; 01572 case 1: 01573 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz); 01574 break; 01575 case 2: 01576 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz); 01577 break; 01578 default: 01579 pout("LU provisioning type reserved [%d], LBPRZ=%d\n", 01580 prov_type, lbprz); 01581 break; 01582 } 01583 } else if (1 == lbpme) 01584 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz); 01585 01586 int rpm = scsiGetRPM(device, modese_len, &form_factor); 01587 if (rpm > 0) { 01588 if (1 == rpm) 01589 pout("Rotation Rate: Solid State Device\n"); 01590 else 01591 pout("Rotation Rate: %d rpm\n", rpm); 01592 } 01593 if (form_factor > 0) { 01594 const char * cp = NULL; 01595 01596 switch (form_factor) { 01597 case 1: 01598 cp = "5.25"; 01599 break; 01600 case 2: 01601 cp = "3.5"; 01602 break; 01603 case 3: 01604 cp = "2.5"; 01605 break; 01606 case 4: 01607 cp = "1.8"; 01608 break; 01609 case 5: 01610 cp = "< 1.8"; 01611 break; 01612 } 01613 if (cp) 01614 pout("Form Factor: %s inches\n", cp); 01615 } 01616 } 01617 01618 /* Do this here to try and detect badly conforming devices (some USB 01619 keys) that will lock up on a InquiryVpd or log sense or ... */ 01620 if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) { 01621 if (SIMPLE_ERR_BAD_RESP == iec_err) { 01622 pout(">> Terminate command early due to bad response to IEC " 01623 "mode page\n"); 01624 print_off(); 01625 gIecMPage = 0; 01626 return 1; 01627 } 01628 } else 01629 modese_len = iec.modese_len; 01630 01631 if (! dont_print_serial_number) { 01632 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_DEVICE_IDENTIFICATION, 01633 gBuf, 252))) { 01634 char s[256]; 01635 01636 len = gBuf[3]; 01637 scsi_decode_lu_dev_id(gBuf + 4, len, s, sizeof(s), &transport); 01638 if (strlen(s) > 0) 01639 pout("Logical Unit id: %s\n", s); 01640 } else if (scsi_debugmode > 0) { 01641 print_on(); 01642 if (SIMPLE_ERR_BAD_RESP == err) 01643 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n"); 01644 else 01645 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err); 01646 print_off(); 01647 } 01648 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_UNIT_SERIAL_NUMBER, 01649 gBuf, 252))) { 01650 char serial[256]; 01651 len = gBuf[3]; 01652 01653 gBuf[4 + len] = '\0'; 01654 scsi_format_id_string(serial, &gBuf[4], len); 01655 pout("Serial number: %s\n", serial); 01656 } else if (scsi_debugmode > 0) { 01657 print_on(); 01658 if (SIMPLE_ERR_BAD_RESP == err) 01659 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n"); 01660 else 01661 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err); 01662 print_off(); 01663 } 01664 } 01665 01666 // print SCSI peripheral device type 01667 if (peri_dt < (int)(sizeof(peripheral_dt_arr) / 01668 sizeof(peripheral_dt_arr[0]))) 01669 pout("Device type: %s\n", peripheral_dt_arr[peri_dt]); 01670 else 01671 pout("Device type: <%d>\n", peri_dt); 01672 01673 // See if transport protocol is known 01674 if (transport < 0) 01675 transport = scsiFetchTransportProtocol(device, modese_len); 01676 if ((transport >= 0) && (transport <= 0xf)) 01677 pout("Transport protocol: %s\n", transport_proto_arr[transport]); 01678 01679 // print current time and date and timezone 01680 dateandtimezone(timedatetz); 01681 pout("Local Time is: %s\n", timedatetz); 01682 01683 if ((SCSI_PT_SEQUENTIAL_ACCESS == *peripheral_type) || 01684 (SCSI_PT_MEDIUM_CHANGER == *peripheral_type)) 01685 is_tape = 1; 01686 // See if unit accepts SCSI commmands from us 01687 if ((err = scsiTestUnitReady(device))) { 01688 if (SIMPLE_ERR_NOT_READY == err) { 01689 print_on(); 01690 if (!is_tape) 01691 pout("device is NOT READY (e.g. spun down, busy)\n"); 01692 else 01693 pout("device is NOT READY (e.g. no tape)\n"); 01694 print_off(); 01695 } else if (SIMPLE_ERR_NO_MEDIUM == err) { 01696 print_on(); 01697 pout("NO MEDIUM present on device\n"); 01698 print_off(); 01699 } else if (SIMPLE_ERR_BECOMING_READY == err) { 01700 print_on(); 01701 pout("device becoming ready (wait)\n"); 01702 print_off(); 01703 } else { 01704 print_on(); 01705 pout("device Test Unit Ready [%s]\n", scsiErrString(err)); 01706 print_off(); 01707 } 01708 failuretest(MANDATORY_CMD, returnval|=FAILID); 01709 } 01710 01711 if (iec_err) { 01712 if (!is_tape) { 01713 print_on(); 01714 pout("SMART support is: Unavailable - device lacks SMART capability.\n"); 01715 if (scsi_debugmode > 0) 01716 pout(" [%s]\n", scsiErrString(iec_err)); 01717 print_off(); 01718 } 01719 gIecMPage = 0; 01720 return 0; 01721 } 01722 01723 if (!is_tape) 01724 pout("SMART support is: Available - device has SMART capability.\n" 01725 "SMART support is: %s\n", 01726 (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled"); 01727 pout("%s\n", (scsi_IsWarningEnabled(&iec)) ? 01728 "Temperature Warning: Enabled" : 01729 "Temperature Warning: Disabled or Not Supported"); 01730 return 0; 01731 } 01732 01733 static int 01734 scsiSmartEnable(scsi_device * device) 01735 { 01736 struct scsi_iec_mode_page iec; 01737 int err; 01738 01739 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { 01740 print_on(); 01741 pout("unable to fetch IEC (SMART) mode page [%s]\n", 01742 scsiErrString(err)); 01743 print_off(); 01744 return 1; 01745 } else 01746 modese_len = iec.modese_len; 01747 01748 if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) { 01749 print_on(); 01750 pout("unable to enable Exception control and warning [%s]\n", 01751 scsiErrString(err)); 01752 print_off(); 01753 return 1; 01754 } 01755 /* Need to refetch 'iec' since could be modified by previous call */ 01756 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { 01757 pout("unable to fetch IEC (SMART) mode page [%s]\n", 01758 scsiErrString(err)); 01759 return 1; 01760 } else 01761 modese_len = iec.modese_len; 01762 01763 pout("Informational Exceptions (SMART) %s\n", 01764 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled"); 01765 pout("Temperature warning %s\n", 01766 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled"); 01767 return 0; 01768 } 01769 01770 static int 01771 scsiSmartDisable(scsi_device * device) 01772 { 01773 struct scsi_iec_mode_page iec; 01774 int err; 01775 01776 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { 01777 print_on(); 01778 pout("unable to fetch IEC (SMART) mode page [%s]\n", 01779 scsiErrString(err)); 01780 print_off(); 01781 return 1; 01782 } else 01783 modese_len = iec.modese_len; 01784 01785 if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) { 01786 print_on(); 01787 pout("unable to disable Exception control and warning [%s]\n", 01788 scsiErrString(err)); 01789 print_off(); 01790 return 1; 01791 } 01792 /* Need to refetch 'iec' since could be modified by previous call */ 01793 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { 01794 pout("unable to fetch IEC (SMART) mode page [%s]\n", 01795 scsiErrString(err)); 01796 return 1; 01797 } else 01798 modese_len = iec.modese_len; 01799 01800 pout("Informational Exceptions (SMART) %s\n", 01801 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled"); 01802 pout("Temperature warning %s\n", 01803 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled"); 01804 return 0; 01805 } 01806 01807 static void 01808 scsiPrintTemp(scsi_device * device) 01809 { 01810 UINT8 temp = 0; 01811 UINT8 trip = 0; 01812 01813 if (scsiGetTemp(device, &temp, &trip)) 01814 return; 01815 01816 if (temp) { 01817 if (255 != temp) 01818 pout("Current Drive Temperature: %d C\n", temp); 01819 else 01820 pout("Current Drive Temperature: <not available>\n"); 01821 } 01822 if (trip) 01823 pout("Drive Trip Temperature: %d C\n", trip); 01824 if (temp || trip) 01825 pout("\n"); 01826 } 01827 01828 /* Main entry point used by smartctl command. Return 0 for success */ 01829 int 01830 scsiPrintMain(scsi_device * device, const scsi_print_options & options) 01831 { 01832 int checkedSupportedLogPages = 0; 01833 UINT8 peripheral_type = 0; 01834 int returnval = 0; 01835 int res, durationSec; 01836 struct scsi_sense_disect sense_info; 01837 01838 bool any_output = options.drive_info; 01839 01840 if (supported_vpd_pages_p) { 01841 delete supported_vpd_pages_p; 01842 supported_vpd_pages_p = NULL; 01843 } 01844 supported_vpd_pages_p = new supported_vpd_pages(device); 01845 01846 res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info); 01847 if (res) { 01848 if (2 == res) 01849 return 0; 01850 else 01851 failuretest(MANDATORY_CMD, returnval |= FAILID); 01852 any_output = true; 01853 } 01854 01855 // Print read look-ahead status for disks 01856 short int wce = -1, rcd = -1; 01857 if (options.get_rcd || options.get_wce) { 01858 if (SCSI_PT_DIRECT_ACCESS == peripheral_type) 01859 res = scsiGetSetCache(device, modese_len, &wce, &rcd); 01860 else 01861 res = -1; // fetch for disks only 01862 any_output = true; 01863 } 01864 01865 if (options.get_rcd) { 01866 pout("Read Cache is: %s\n", 01867 res ? "Unavailable" : // error 01868 rcd ? "Disabled" : "Enabled"); 01869 } 01870 01871 if (options.get_wce) { 01872 pout("Writeback Cache is: %s\n", 01873 res ? "Unavailable" : // error 01874 !wce ? "Disabled" : "Enabled"); 01875 } 01876 if (options.drive_info) 01877 pout("\n"); 01878 01879 // START OF THE ENABLE/DISABLE SECTION OF THE CODE 01880 if ( options.smart_disable || options.smart_enable 01881 || options.smart_auto_save_disable || options.smart_auto_save_enable) 01882 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); 01883 01884 if (options.smart_enable) { 01885 if (scsiSmartEnable(device)) 01886 failuretest(MANDATORY_CMD, returnval |= FAILSMART); 01887 any_output = true; 01888 } 01889 01890 if (options.smart_disable) { 01891 if (scsiSmartDisable(device)) 01892 failuretest(MANDATORY_CMD,returnval |= FAILSMART); 01893 any_output = true; 01894 } 01895 01896 if (options.smart_auto_save_enable) { 01897 if (scsiSetControlGLTSD(device, 0, modese_len)) { 01898 pout("Enable autosave (clear GLTSD bit) failed\n"); 01899 failuretest(OPTIONAL_CMD,returnval |= FAILSMART); 01900 } 01901 else { 01902 pout("Autosave enabled (GLTSD bit set).\n"); 01903 } 01904 any_output = true; 01905 } 01906 01907 // Enable/Disable write cache 01908 if (options.set_wce && SCSI_PT_DIRECT_ACCESS == peripheral_type) { 01909 short int enable = wce = (options.set_wce > 0); 01910 rcd = -1; 01911 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) { 01912 pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"), 01913 device->get_errmsg()); 01914 failuretest(OPTIONAL_CMD,returnval |= FAILSMART); 01915 } 01916 else 01917 pout("Write cache %sabled\n", (enable ? "en" : "dis")); 01918 any_output = true; 01919 } 01920 01921 // Enable/Disable read cache 01922 if (options.set_rcd && SCSI_PT_DIRECT_ACCESS == peripheral_type) { 01923 short int enable = (options.set_rcd > 0); 01924 rcd = !enable; 01925 wce = -1; 01926 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) { 01927 pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"), 01928 device->get_errmsg()); 01929 failuretest(OPTIONAL_CMD,returnval |= FAILSMART); 01930 } 01931 else 01932 pout("Read cache %sabled\n", (enable ? "en" : "dis")); 01933 any_output = true; 01934 } 01935 01936 if (options.smart_auto_save_disable) { 01937 if (scsiSetControlGLTSD(device, 1, modese_len)) { 01938 pout("Disable autosave (set GLTSD bit) failed\n"); 01939 failuretest(OPTIONAL_CMD,returnval |= FAILSMART); 01940 } 01941 else { 01942 pout("Autosave disabled (GLTSD bit cleared).\n"); 01943 } 01944 any_output = true; 01945 } 01946 if ( options.smart_disable || options.smart_enable 01947 || options.smart_auto_save_disable || options.smart_auto_save_enable) 01948 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE 01949 01950 // START OF READ-ONLY OPTIONS APART FROM -V and -i 01951 if ( options.smart_check_status || options.smart_ss_media_log 01952 || options.smart_vendor_attrib || options.smart_error_log 01953 || options.smart_selftest_log || options.smart_vendor_attrib 01954 || options.smart_background_log || options.sasphy 01955 ) 01956 pout("=== START OF READ SMART DATA SECTION ===\n"); 01957 01958 if (options.smart_check_status) { 01959 scsiGetSupportedLogPages(device); 01960 checkedSupportedLogPages = 1; 01961 if ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) || 01962 (SCSI_PT_MEDIUM_CHANGER == peripheral_type)) { /* tape device */ 01963 if (gTapeAlertsLPage) { 01964 if (options.drive_info) 01965 pout("TapeAlert Supported\n"); 01966 if (-1 == scsiGetTapeAlertsData(device, peripheral_type)) 01967 failuretest(OPTIONAL_CMD, returnval |= FAILSMART); 01968 } 01969 else 01970 pout("TapeAlert Not Supported\n"); 01971 } else { /* disk, cd/dvd, enclosure, etc */ 01972 if ((res = scsiGetSmartData(device, options.smart_vendor_attrib))) { 01973 if (-2 == res) 01974 returnval |= FAILSTATUS; 01975 else 01976 returnval |= FAILSMART; 01977 } 01978 } 01979 any_output = true; 01980 } 01981 01982 if (options.smart_ss_media_log) { 01983 if (! checkedSupportedLogPages) 01984 scsiGetSupportedLogPages(device); 01985 res = 0; 01986 if (gSSMediaLPage) 01987 res = scsiPrintSSMedia(device); 01988 if (0 != res) 01989 failuretest(OPTIONAL_CMD, returnval|=res); 01990 any_output = true; 01991 } 01992 if (options.smart_vendor_attrib) { 01993 if (! checkedSupportedLogPages) 01994 scsiGetSupportedLogPages(device); 01995 if (gTempLPage) { 01996 scsiPrintTemp(device); 01997 } 01998 if (gStartStopLPage) 01999 scsiGetStartStopData(device); 02000 if (SCSI_PT_DIRECT_ACCESS == peripheral_type) { 02001 scsiPrintGrownDefectListLen(device); 02002 if (gSeagateCacheLPage) 02003 scsiPrintSeagateCacheLPage(device); 02004 if (gSeagateFactoryLPage) 02005 scsiPrintSeagateFactoryLPage(device); 02006 } 02007 any_output = true; 02008 } 02009 if (options.smart_error_log) { 02010 if (! checkedSupportedLogPages) 02011 scsiGetSupportedLogPages(device); 02012 scsiPrintErrorCounterLog(device); 02013 if (1 == scsiFetchControlGLTSD(device, modese_len, 1)) 02014 pout("\n[GLTSD (Global Logging Target Save Disable) set. " 02015 "Enable Save with '-S on']\n"); 02016 any_output = true; 02017 } 02018 if (options.smart_selftest_log) { 02019 if (! checkedSupportedLogPages) 02020 scsiGetSupportedLogPages(device); 02021 res = 0; 02022 if (gSelfTestLPage) 02023 res = scsiPrintSelfTest(device); 02024 else { 02025 pout("Device does not support Self Test logging\n"); 02026 failuretest(OPTIONAL_CMD, returnval|=FAILSMART); 02027 } 02028 if (0 != res) 02029 failuretest(OPTIONAL_CMD, returnval|=res); 02030 any_output = true; 02031 } 02032 if (options.smart_background_log) { 02033 if (! checkedSupportedLogPages) 02034 scsiGetSupportedLogPages(device); 02035 res = 0; 02036 if (gBackgroundResultsLPage) 02037 res = scsiPrintBackgroundResults(device); 02038 else { 02039 pout("Device does not support Background scan results logging\n"); 02040 failuretest(OPTIONAL_CMD, returnval|=FAILSMART); 02041 } 02042 if (0 != res) 02043 failuretest(OPTIONAL_CMD, returnval|=res); 02044 any_output = true; 02045 } 02046 if (options.smart_default_selftest) { 02047 if (scsiSmartDefaultSelfTest(device)) 02048 return returnval | FAILSMART; 02049 pout("Default Self Test Successful\n"); 02050 any_output = true; 02051 } 02052 if (options.smart_short_cap_selftest) { 02053 if (scsiSmartShortCapSelfTest(device)) 02054 return returnval | FAILSMART; 02055 pout("Short Foreground Self Test Successful\n"); 02056 any_output = true; 02057 } 02058 // check if another test is running 02059 if (options.smart_short_selftest || options.smart_extend_selftest) { 02060 if (!scsiRequestSense(device, &sense_info) && 02061 (sense_info.asc == 0x04 && sense_info.ascq == 0x09)) { 02062 if (!options.smart_selftest_force) { 02063 pout("Can't start self-test without aborting current test"); 02064 if (sense_info.progress != -1) { 02065 pout(" (%d%% remaining)", 02066 100 - sense_info.progress * 100 / 65535); 02067 } 02068 pout(",\nadd '-t force' option to override, or run 'smartctl -X' " 02069 "to abort test.\n"); 02070 return -1; 02071 } 02072 else 02073 scsiSmartSelfTestAbort(device); 02074 } 02075 } 02076 if (options.smart_short_selftest) { 02077 if (scsiSmartShortSelfTest(device)) 02078 return returnval | FAILSMART; 02079 pout("Short Background Self Test has begun\n"); 02080 pout("Use smartctl -X to abort test\n"); 02081 any_output = true; 02082 } 02083 if (options.smart_extend_selftest) { 02084 if (scsiSmartExtendSelfTest(device)) 02085 return returnval | FAILSMART; 02086 pout("Extended Background Self Test has begun\n"); 02087 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec, 02088 modese_len)) && (durationSec > 0)) { 02089 time_t t = time(NULL); 02090 02091 t += durationSec; 02092 pout("Please wait %d minutes for test to complete.\n", 02093 durationSec / 60); 02094 pout("Estimated completion time: %s\n", ctime(&t)); 02095 } 02096 pout("Use smartctl -X to abort test\n"); 02097 any_output = true; 02098 } 02099 if (options.smart_extend_cap_selftest) { 02100 if (scsiSmartExtendCapSelfTest(device)) 02101 return returnval | FAILSMART; 02102 pout("Extended Foreground Self Test Successful\n"); 02103 } 02104 if (options.smart_selftest_abort) { 02105 if (scsiSmartSelfTestAbort(device)) 02106 return returnval | FAILSMART; 02107 pout("Self Test returned without error\n"); 02108 any_output = true; 02109 } 02110 if (options.sasphy) { 02111 if (scsiPrintSasPhy(device, options.sasphy_reset)) 02112 return returnval | FAILSMART; 02113 any_output = true; 02114 } 02115 02116 if (!any_output) 02117 pout("SCSI device successfully opened\n\n" 02118 "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n"); 02119 02120 return returnval; 02121 }
1.7.4