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