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