]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - scsiprint.cpp
Imported Upstream version 6.1+svn3812
[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
ee38a438 45const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 3807 2013-04-18 17:11:12Z chrfranke $"
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 }
473 pout(" = %"PRIu64"\n", ull);
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
GG
567 else
568 pout(" = %"PRIu64"\n", ull);
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];
ee38a438
GI
619 pout("%s%8"PRIu64" %8"PRIu64" %8"PRIu64" %8"PRIu64" %8"PRIu64,
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;
832b75ed
GG
623 pout(" %12.3f %8"PRIu64"\n", processed_gb, ecp->counter[6]);
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)
632 pout("\nNon-medium error count: %8"PRIu64"\n", nme.counterPC0);
633 if (nme.gotTFE_H)
634 pout("Track following error count [Hitachi]: %8"PRIu64"\n",
635 nme.counterTFE_H);
636 if (nme.gotPE_H)
637 pout("Positioning error count [Hitachi]: %8"PRIu64"\n",
638 nme.counterPE_H);
639 }
640 if (gLastNErrorLPage && (0 == scsiLogSense(device,
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
846 snprintf(buff, sizeof(buff), "%"PRIu64, ull);
847 // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull);
848 pout("%18s", buff);
849 } else
850 pout(" -");
851
852 // if sense key nonzero, then print it, along with
853 // additional sense code and additional sense code qualifier
854 if (ucp[16] & 0xf)
855 pout(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]);
856 else
857 pout(" [- - -]\n");
858 }
859
860 // if header never printed, then there was no output
861 if (noheader)
862 pout("No self-tests have been logged\n");
863 else
2127e193 864 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
832b75ed
GG
865 modese_len)) && (durationSec > 0)) {
866 pout("Long (extended) Self Test duration: %d seconds "
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
GI
1050 print_on();
1051 pout("Percentage used endurance indicator too short (pl=%d)\n", pl);
1052 print_off();
1053 return FAILSMART;
ee38a438 1054 }
d008864d 1055 pout("SS Media used endurance indicator: %d%%\n", ucp[7]);
ee38a438 1056 default: /* ignore other parameter codes */
d008864d
GI
1057 break;
1058 }
1059 num -= pl;
1060 ucp += pl;
1061 }
1062 return retval;
1063}
2127e193 1064
ee38a438
GI
1065static void
1066show_sas_phy_event_info(int peis, unsigned int val, unsigned thresh_val)
2127e193
GI
1067{
1068 unsigned int u;
1069
1070 switch (peis) {
1071 case 0:
1072 pout(" No event\n");
1073 break;
1074 case 0x1:
1075 pout(" Invalid word count: %u\n", val);
1076 break;
1077 case 0x2:
1078 pout(" Running disparity error count: %u\n", val);
1079 break;
1080 case 0x3:
1081 pout(" Loss of dword synchronization count: %u\n", val);
1082 break;
1083 case 0x4:
1084 pout(" Phy reset problem count: %u\n", val);
1085 break;
1086 case 0x5:
1087 pout(" Elasticity buffer overflow count: %u\n", val);
1088 break;
1089 case 0x6:
1090 pout(" Received ERROR count: %u\n", val);
1091 break;
1092 case 0x20:
1093 pout(" Received address frame error count: %u\n", val);
1094 break;
1095 case 0x21:
1096 pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val);
1097 break;
1098 case 0x22:
1099 pout(" Received abandon-class OPEN_REJECT count: %u\n", val);
1100 break;
1101 case 0x23:
1102 pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val);
1103 break;
1104 case 0x24:
1105 pout(" Received retry-class OPEN_REJECT count: %u\n", val);
1106 break;
1107 case 0x25:
1108 pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val);
1109 break;
1110 case 0x26:
1111 pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val);
1112 break;
1113 case 0x27:
1114 pout(" Transmitted BREAK count: %u\n", val);
1115 break;
1116 case 0x28:
1117 pout(" Received BREAK count: %u\n", val);
1118 break;
1119 case 0x29:
1120 pout(" Break timeout count: %u\n", val);
1121 break;
1122 case 0x2a:
1123 pout(" Connection count: %u\n", val);
1124 break;
1125 case 0x2b:
1126 pout(" Peak transmitted pathway blocked count: %u\n",
1127 val & 0xff);
1128 pout(" Peak value detector threshold: %u\n",
1129 thresh_val & 0xff);
1130 break;
1131 case 0x2c:
1132 u = val & 0xffff;
1133 if (u < 0x8000)
1134 pout(" Peak transmitted arbitration wait time (us): "
1135 "%u\n", u);
1136 else
1137 pout(" Peak transmitted arbitration wait time (ms): "
1138 "%u\n", 33 + (u - 0x8000));
1139 u = thresh_val & 0xffff;
1140 if (u < 0x8000)
1141 pout(" Peak value detector threshold (us): %u\n",
1142 u);
1143 else
1144 pout(" Peak value detector threshold (ms): %u\n",
1145 33 + (u - 0x8000));
1146 break;
1147 case 0x2d:
1148 pout(" Peak arbitration time (us): %u\n", val);
1149 pout(" Peak value detector threshold: %u\n", thresh_val);
1150 break;
1151 case 0x2e:
1152 pout(" Peak connection time (us): %u\n", val);
1153 pout(" Peak value detector threshold: %u\n", thresh_val);
1154 break;
1155 case 0x40:
1156 pout(" Transmitted SSP frame count: %u\n", val);
1157 break;
1158 case 0x41:
1159 pout(" Received SSP frame count: %u\n", val);
1160 break;
1161 case 0x42:
1162 pout(" Transmitted SSP frame error count: %u\n", val);
1163 break;
1164 case 0x43:
1165 pout(" Received SSP frame error count: %u\n", val);
1166 break;
1167 case 0x44:
1168 pout(" Transmitted CREDIT_BLOCKED count: %u\n", val);
1169 break;
1170 case 0x45:
1171 pout(" Received CREDIT_BLOCKED count: %u\n", val);
1172 break;
1173 case 0x50:
1174 pout(" Transmitted SATA frame count: %u\n", val);
1175 break;
1176 case 0x51:
1177 pout(" Received SATA frame count: %u\n", val);
1178 break;
1179 case 0x52:
1180 pout(" SATA flow control buffer overflow count: %u\n", val);
1181 break;
1182 case 0x60:
1183 pout(" Transmitted SMP frame count: %u\n", val);
1184 break;
1185 case 0x61:
1186 pout(" Received SMP frame count: %u\n", val);
1187 break;
1188 case 0x63:
1189 pout(" Received SMP frame error count: %u\n", val);
1190 break;
1191 default:
1192 break;
1193 }
1194}
1195
ee38a438
GI
1196static void
1197show_sas_port_param(unsigned char * ucp, int param_len)
2127e193 1198{
d008864d 1199 int j, m, n, nphys, t, sz, spld_len;
2127e193
GI
1200 unsigned char * vcp;
1201 uint64_t ull;
1202 unsigned int ui;
1203 char s[64];
1204
1205 sz = sizeof(s);
d008864d 1206 // pcb = ucp[2];
2127e193
GI
1207 t = (ucp[0] << 8) | ucp[1];
1208 pout("relative target port id = %d\n", t);
1209 pout(" generation code = %d\n", ucp[6]);
1210 nphys = ucp[7];
1211 pout(" number of phys = %d\n", nphys);
1212
1213 for (j = 0, vcp = ucp + 8; j < (param_len - 8);
1214 vcp += spld_len, j += spld_len) {
1215 pout(" phy identifier = %d\n", vcp[1]);
1216 spld_len = vcp[3];
1217 if (spld_len < 44)
1218 spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */
1219 else
1220 spld_len += 4;
1221 t = ((0x70 & vcp[4]) >> 4);
1222 switch (t) {
1223 case 0: snprintf(s, sz, "no device attached"); break;
1224 case 1: snprintf(s, sz, "end device"); break;
1225 case 2: snprintf(s, sz, "expander device"); break;
1226 case 3: snprintf(s, sz, "expander device (fanout)"); break;
1227 default: snprintf(s, sz, "reserved [%d]", t); break;
1228 }
1229 pout(" attached device type: %s\n", s);
1230 t = 0xf & vcp[4];
1231 switch (t) {
1232 case 0: snprintf(s, sz, "unknown"); break;
1233 case 1: snprintf(s, sz, "power on"); break;
1234 case 2: snprintf(s, sz, "hard reset"); break;
1235 case 3: snprintf(s, sz, "SMP phy control function"); break;
1236 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
1237 case 5: snprintf(s, sz, "mux mix up"); break;
1238 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
1239 break;
1240 case 7: snprintf(s, sz, "break timeout timer expired"); break;
1241 case 8: snprintf(s, sz, "phy test function stopped"); break;
1242 case 9: snprintf(s, sz, "expander device reduced functionality");
1243 break;
1244 default: snprintf(s, sz, "reserved [0x%x]", t); break;
1245 }
1246 pout(" attached reason: %s\n", s);
1247 t = (vcp[5] & 0xf0) >> 4;
1248 switch (t) {
1249 case 0: snprintf(s, sz, "unknown"); break;
1250 case 1: snprintf(s, sz, "power on"); break;
1251 case 2: snprintf(s, sz, "hard reset"); break;
1252 case 3: snprintf(s, sz, "SMP phy control function"); break;
1253 case 4: snprintf(s, sz, "loss of dword synchronization"); break;
1254 case 5: snprintf(s, sz, "mux mix up"); break;
1255 case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
1256 break;
1257 case 7: snprintf(s, sz, "break timeout timer expired"); break;
1258 case 8: snprintf(s, sz, "phy test function stopped"); break;
1259 case 9: snprintf(s, sz, "expander device reduced functionality");
1260 break;
1261 default: snprintf(s, sz, "reserved [0x%x]", t); break;
1262 }
1263 pout(" reason: %s\n", s);
1264 t = (0xf & vcp[5]);
1265 switch (t) {
1266 case 0: snprintf(s, sz, "phy enabled; unknown");
1267 break;
1268 case 1: snprintf(s, sz, "phy disabled"); break;
1269 case 2: snprintf(s, sz, "phy enabled; speed negotiation failed");
1270 break;
1271 case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state");
1272 break;
1273 case 4: snprintf(s, sz, "phy enabled; port selector");
1274 break;
1275 case 5: snprintf(s, sz, "phy enabled; reset in progress");
1276 break;
1277 case 6: snprintf(s, sz, "phy enabled; unsupported phy attached");
1278 break;
1279 case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
1280 case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
1281 case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
1282 default: snprintf(s, sz, "reserved [%d]", t); break;
1283 }
1284 pout(" negotiated logical link rate: %s\n", s);
1285 pout(" attached initiator port: ssp=%d stp=%d smp=%d\n",
1286 !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
1287 pout(" attached target port: ssp=%d stp=%d smp=%d\n",
1288 !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
1289 for (n = 0, ull = vcp[8]; n < 8; ++n) {
1290 ull <<= 8; ull |= vcp[8 + n];
1291 }
1292 pout(" SAS address = 0x%" PRIx64 "\n", ull);
1293 for (n = 0, ull = vcp[16]; n < 8; ++n) {
1294 ull <<= 8; ull |= vcp[16 + n];
1295 }
1296 pout(" attached SAS address = 0x%" PRIx64 "\n", ull);
1297 pout(" attached phy identifier = %d\n", vcp[24]);
1298 ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
1299 pout(" Invalid DWORD count = %u\n", ui);
1300 ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39];
1301 pout(" Running disparity error count = %u\n", ui);
1302 ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43];
1303 pout(" Loss of DWORD synchronization = %u\n", ui);
1304 ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
1305 pout(" Phy reset problem = %u\n", ui);
1306 if (spld_len > 51) {
1307 int num_ped, peis;
1308 unsigned char * xcp;
1309 unsigned int pvdt;
1310
1311 num_ped = vcp[51];
1312 if (num_ped > 0)
1313 pout(" Phy event descriptors:\n");
1314 xcp = vcp + 52;
1315 for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
1316 peis = xcp[3];
1317 ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) |
1318 xcp[7];
1319 pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) |
1320 xcp[11];
1321 show_sas_phy_event_info(peis, ui, pvdt);
1322 }
1323 }
1324 }
1325}
1326
1327// Returns 1 if okay, 0 if non SAS descriptors
ee38a438
GI
1328static int
1329show_protocol_specific_page(unsigned char * resp, int len)
2127e193
GI
1330{
1331 int k, num, param_len;
1332 unsigned char * ucp;
1333
1334 num = len - 4;
1335 for (k = 0, ucp = resp + 4; k < num; ) {
1336 param_len = ucp[3] + 4;
1337 if (6 != (0xf & ucp[4]))
1338 return 0; /* only decode SAS log page */
1339 if (0 == k)
1340 pout("Protocol Specific port log page for SAS SSP\n");
1341 show_sas_port_param(ucp, param_len);
1342 k += param_len;
1343 ucp += param_len;
1344 }
ee38a438 1345 pout("\n");
2127e193
GI
1346 return 1;
1347}
1348
1349
1350// See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific
1351// log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol
1352// Specific log page.
1353// Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
1354// 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
1355// FAILSMART is returned.
ee38a438
GI
1356static int
1357scsiPrintSasPhy(scsi_device * device, int reset)
2127e193
GI
1358{
1359 int num, err;
1360
1361 if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
1362 LOG_RESP_LONG_LEN, 0))) {
cfbba5b9 1363 print_on();
ee38a438 1364 pout("scsiPrintSasPhy Log Sense Failed [%s]\n\n", scsiErrString(err));
cfbba5b9 1365 print_off();
2127e193
GI
1366 return FAILSMART;
1367 }
1368 if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
cfbba5b9 1369 print_on();
ee38a438 1370 pout("Protocol specific Log Sense Failed, page mismatch\n\n");
cfbba5b9 1371 print_off();
2127e193
GI
1372 return FAILSMART;
1373 }
1374 // compute page length
1375 num = (gBuf[2] << 8) + gBuf[3];
1376 if (1 != show_protocol_specific_page(gBuf, num + 4)) {
cfbba5b9 1377 print_on();
ee38a438 1378 pout("Only support protocol specific log page on SAS devices\n\n");
cfbba5b9 1379 print_off();
2127e193
GI
1380 return FAILSMART;
1381 }
1382 if (reset) {
1383 if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
1384 PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) {
cfbba5b9 1385 print_on();
ee38a438 1386 pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n\n",
2127e193 1387 scsiErrString(err));
cfbba5b9 1388 print_off();
2127e193
GI
1389 return FAILSMART;
1390 }
1391 }
1392 return 0;
1393}
1394
1395
832b75ed
GG
1396static const char * peripheral_dt_arr[] = {
1397 "disk",
1398 "tape",
1399 "printer",
1400 "processor",
1401 "optical disk(4)",
1402 "CD/DVD",
1403 "scanner",
1404 "optical disk(7)",
1405 "medium changer",
1406 "communications",
1407 "graphics(10)",
1408 "graphics(11)",
1409 "storage array",
1410 "enclosure",
1411 "simplified disk",
1412 "optical card reader"
1413};
1414
1415static const char * transport_proto_arr[] = {
1416 "Fibre channel (FCP-2)",
1417 "Parallel SCSI (SPI-4)",
1418 "SSA",
1419 "IEEE 1394 (SBP-2)",
1420 "RDMA (SRP)",
1421 "iSCSI",
1422 "SAS",
1423 "ADT",
1424 "0x8",
1425 "0x9",
1426 "0xa",
1427 "0xb",
1428 "0xc",
1429 "0xd",
1430 "0xe",
1431 "0xf"
1432};
1433
1434/* Returns 0 on success, 1 on general error and 2 for early, clean exit */
ee38a438
GI
1435static int
1436scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
832b75ed 1437{
832b75ed
GG
1438 char timedatetz[DATEANDEPOCHLEN];
1439 struct scsi_iec_mode_page iec;
ee38a438 1440 int err, iec_err, len, req_len, avail_len, n;
832b75ed
GG
1441 int is_tape = 0;
1442 int peri_dt = 0;
a7e8ffec
GI
1443 int returnval = 0;
1444 int transport = -1;
ee38a438
GI
1445 int form_factor = 0;
1446 int protect = 0;
1447
832b75ed
GG
1448 memset(gBuf, 0, 96);
1449 req_len = 36;
1450 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
cfbba5b9 1451 print_on();
832b75ed
GG
1452 pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
1453 pout("Retrying with a 64 byte Standard Inquiry\n");
cfbba5b9 1454 print_off();
832b75ed
GG
1455 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
1456 req_len = 64;
1457 if ((err = scsiStdInquiry(device, gBuf, req_len))) {
cfbba5b9 1458 print_on();
832b75ed
GG
1459 pout("Standard Inquiry (64 bytes) failed [%s]\n",
1460 scsiErrString(err));
cfbba5b9 1461 print_off();
832b75ed
GG
1462 return 1;
1463 }
1464 }
1465 avail_len = gBuf[4] + 5;
1466 len = (avail_len < req_len) ? avail_len : req_len;
1467 peri_dt = gBuf[0] & 0x1f;
1468 if (peripheral_type)
1469 *peripheral_type = peri_dt;
832b75ed
GG
1470
1471 if (len < 36) {
cfbba5b9 1472 print_on();
832b75ed 1473 pout("Short INQUIRY response, skip product id\n");
cfbba5b9 1474 print_off();
832b75ed
GG
1475 return 1;
1476 }
ee38a438 1477
a7e8ffec 1478 if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) {
ee38a438
GI
1479 char vendor[8+1], product[16+1], revision[4+1];
1480 scsi_format_id_string(vendor, (const unsigned char *)&gBuf[8], 8);
1481 scsi_format_id_string(product, (const unsigned char *)&gBuf[16], 16);
1482 scsi_format_id_string(revision, (const unsigned char *)&gBuf[32], 4);
1483
1484 pout("=== START OF INFORMATION SECTION ===\n");
1485 pout("Vendor: %.8s\n", vendor);
1486 pout("Product: %.16s\n", product);
1487 if (gBuf[32] >= ' ')
1488 pout("Revision: %.4s\n", revision);
a7e8ffec 1489 }
832b75ed 1490
2127e193 1491 if (!*device->get_req_type()/*no type requested*/ &&
a7e8ffec 1492 (0 == strncmp((char *)&gBuf[8], "ATA", 3))) {
9ebc753d
GG
1493 pout("\nProbable ATA device behind a SAT layer\n"
1494 "Try an additional '-d ata' or '-d sat' argument.\n");
1495 return 2;
832b75ed 1496 }
4d59bff9
GG
1497 if (! all)
1498 return 0;
832b75ed 1499
ee38a438
GI
1500 protect = gBuf[5] & 0x1; /* from and including SPC-3 */
1501
1502 if (! is_tape) { /* only do this for disks */
1503 unsigned int lb_size = 0;
1504 unsigned char lb_prov_resp[8];
1505 char cap_str[64];
1506 char si_str[64];
1507 char lb_str[16];
1508 int lb_per_pb_exp = 0;
1509 uint64_t capacity = scsiGetSize(device, &lb_size, &lb_per_pb_exp);
1510
1511 if (capacity) {
1512 format_with_thousands_sep(cap_str, sizeof(cap_str), capacity);
1513 format_capacity(si_str, sizeof(si_str), capacity);
1514 pout("User Capacity: %s bytes [%s]\n", cap_str, si_str);
1515 snprintf(lb_str, sizeof(lb_str) - 1, "%u", lb_size);
1516 pout("Logical block size: %s bytes\n", lb_str);
1517 }
1518 int lbpme = -1;
1519 int lbprz = -1;
1520 if (protect || lb_per_pb_exp) {
1521 unsigned char rc16_12[20] = {0, };
1522
1523 if (0 == scsiGetProtPBInfo(device, rc16_12)) {
1524 lb_per_pb_exp = rc16_12[1] & 0xf; /* just in case */
1525 if (lb_per_pb_exp > 0) {
1526 snprintf(lb_str, sizeof(lb_str) - 1, "%u",
1527 (lb_size * (1 << lb_per_pb_exp)));
1528 pout("Physical block size: %s bytes\n", lb_str);
1529 n = ((rc16_12[2] & 0x3f) << 8) + rc16_12[3];
1530 pout("Lowest aligned LBA: %d\n", n);
1531 }
1532 if (rc16_12[0] & 0x1) { /* PROT_EN set */
1533 int p_type = ((rc16_12[0] >> 1) & 0x7);
1534
1535 switch (p_type) {
1536 case 0 :
1537 pout("Formatted with type 1 protection\n");
1538 break;
1539 case 1 :
1540 pout("Formatted with type 2 protection\n");
1541 break;
1542 case 2 :
1543 pout("Formatted with type 3 protection\n");
1544 break;
1545 default:
1546 pout("Formatted with unknown protection type [%d]\n",
1547 p_type);
1548 break;
1549 }
1550 int p_i_exp = ((rc16_12[1] >> 4) & 0xf);
1551
1552 if (p_i_exp > 0)
1553 pout("%d protection information intervals per "
1554 "logical block\n", (1 << p_i_exp));
1555 }
1556 /* Pick up some LB provisioning info since its available */
1557 lbpme = !! (rc16_12[2] & 0x80);
1558 lbprz = !! (rc16_12[2] & 0x40);
1559 }
1560 }
1561 if (0 == scsiInquiryVpd(device, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING,
1562 lb_prov_resp, sizeof(lb_prov_resp))) {
1563 int prov_type = lb_prov_resp[6] & 0x7;
1564
1565 if (-1 == lbprz)
1566 lbprz = !! (lb_prov_resp[5] & 0x4);
1567 switch (prov_type) {
1568 case 0:
1569 pout("Logical block provisioning type unreported, "
1570 "LBPME=%d, LBPRZ=%d\n", lbpme, lbprz);
1571 break;
1572 case 1:
1573 pout("LU is resource provisioned, LBPRZ=%d\n", lbprz);
1574 break;
1575 case 2:
1576 pout("LU is thin provisioned, LBPRZ=%d\n", lbprz);
1577 break;
1578 default:
1579 pout("LU provisioning type reserved [%d], LBPRZ=%d\n",
1580 prov_type, lbprz);
1581 break;
1582 }
1583 } else if (1 == lbpme)
1584 pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz);
a7e8ffec 1585
ee38a438
GI
1586 int rpm = scsiGetRPM(device, modese_len, &form_factor);
1587 if (rpm > 0) {
1588 if (1 == rpm)
1589 pout("Rotation Rate: Solid State Device\n");
1590 else
1591 pout("Rotation Rate: %d rpm\n", rpm);
1592 }
1593 if (form_factor > 0) {
1594 const char * cp = NULL;
1595
1596 switch (form_factor) {
1597 case 1:
1598 cp = "5.25";
1599 break;
1600 case 2:
1601 cp = "3.5";
1602 break;
1603 case 3:
1604 cp = "2.5";
1605 break;
1606 case 4:
1607 cp = "1.8";
1608 break;
1609 case 5:
1610 cp = "< 1.8";
1611 break;
1612 }
1613 if (cp)
1614 pout("Form Factor: %s inches\n", cp);
1615 }
a7e8ffec
GI
1616 }
1617
832b75ed
GG
1618 /* Do this here to try and detect badly conforming devices (some USB
1619 keys) that will lock up on a InquiryVpd or log sense or ... */
1620 if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) {
1621 if (SIMPLE_ERR_BAD_RESP == iec_err) {
1622 pout(">> Terminate command early due to bad response to IEC "
1623 "mode page\n");
cfbba5b9 1624 print_off();
832b75ed
GG
1625 gIecMPage = 0;
1626 return 1;
1627 }
1628 } else
1629 modese_len = iec.modese_len;
1630
a7e8ffec 1631 if (! dont_print_serial_number) {
ee38a438
GI
1632 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_DEVICE_IDENTIFICATION,
1633 gBuf, 252))) {
1634 char s[256];
a7e8ffec 1635
a37e7145 1636 len = gBuf[3];
ee38a438
GI
1637 scsi_decode_lu_dev_id(gBuf + 4, len, s, sizeof(s), &transport);
1638 if (strlen(s) > 0)
a7e8ffec
GI
1639 pout("Logical Unit id: %s\n", s);
1640 } else if (scsi_debugmode > 0) {
1641 print_on();
1642 if (SIMPLE_ERR_BAD_RESP == err)
1643 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1644 else
1645 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
1646 print_off();
a37e7145 1647 }
ee38a438
GI
1648 if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_UNIT_SERIAL_NUMBER,
1649 gBuf, 252))) {
1650 char serial[256];
a7e8ffec 1651 len = gBuf[3];
ee38a438 1652
a7e8ffec 1653 gBuf[4 + len] = '\0';
ee38a438
GI
1654 scsi_format_id_string(serial, &gBuf[4], len);
1655 pout("Serial number: %s\n", serial);
a7e8ffec 1656 } else if (scsi_debugmode > 0) {
cfbba5b9 1657 print_on();
a37e7145
GG
1658 if (SIMPLE_ERR_BAD_RESP == err)
1659 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
1660 else
1661 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
cfbba5b9 1662 print_off();
a37e7145 1663 }
832b75ed
GG
1664 }
1665
1666 // print SCSI peripheral device type
ee38a438 1667 if (peri_dt < (int)(sizeof(peripheral_dt_arr) /
832b75ed 1668 sizeof(peripheral_dt_arr[0])))
a7e8ffec 1669 pout("Device type: %s\n", peripheral_dt_arr[peri_dt]);
832b75ed 1670 else
a7e8ffec 1671 pout("Device type: <%d>\n", peri_dt);
832b75ed
GG
1672
1673 // See if transport protocol is known
a7e8ffec
GI
1674 if (transport < 0)
1675 transport = scsiFetchTransportProtocol(device, modese_len);
1676 if ((transport >= 0) && (transport <= 0xf))
1677 pout("Transport protocol: %s\n", transport_proto_arr[transport]);
832b75ed
GG
1678
1679 // print current time and date and timezone
1680 dateandtimezone(timedatetz);
a7e8ffec 1681 pout("Local Time is: %s\n", timedatetz);
832b75ed
GG
1682
1683 if ((SCSI_PT_SEQUENTIAL_ACCESS == *peripheral_type) ||
1684 (SCSI_PT_MEDIUM_CHANGER == *peripheral_type))
1685 is_tape = 1;
1686 // See if unit accepts SCSI commmands from us
1687 if ((err = scsiTestUnitReady(device))) {
1688 if (SIMPLE_ERR_NOT_READY == err) {
cfbba5b9 1689 print_on();
832b75ed
GG
1690 if (!is_tape)
1691 pout("device is NOT READY (e.g. spun down, busy)\n");
1692 else
1693 pout("device is NOT READY (e.g. no tape)\n");
cfbba5b9 1694 print_off();
832b75ed 1695 } else if (SIMPLE_ERR_NO_MEDIUM == err) {
cfbba5b9 1696 print_on();
832b75ed 1697 pout("NO MEDIUM present on device\n");
cfbba5b9 1698 print_off();
832b75ed 1699 } else if (SIMPLE_ERR_BECOMING_READY == err) {
cfbba5b9 1700 print_on();
832b75ed 1701 pout("device becoming ready (wait)\n");
cfbba5b9 1702 print_off();
832b75ed 1703 } else {
cfbba5b9 1704 print_on();
832b75ed 1705 pout("device Test Unit Ready [%s]\n", scsiErrString(err));
cfbba5b9 1706 print_off();
832b75ed
GG
1707 }
1708 failuretest(MANDATORY_CMD, returnval|=FAILID);
1709 }
ee38a438 1710
832b75ed
GG
1711 if (iec_err) {
1712 if (!is_tape) {
cfbba5b9 1713 print_on();
ee38a438 1714 pout("SMART support is: Unavailable - device lacks SMART capability.\n");
cfbba5b9 1715 if (scsi_debugmode > 0)
832b75ed 1716 pout(" [%s]\n", scsiErrString(iec_err));
cfbba5b9 1717 print_off();
832b75ed
GG
1718 }
1719 gIecMPage = 0;
1720 return 0;
1721 }
1722
1723 if (!is_tape)
ee38a438
GI
1724 pout("SMART support is: Available - device has SMART capability.\n"
1725 "SMART support is: %s\n",
832b75ed 1726 (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled");
ee38a438
GI
1727 pout("%s\n", (scsi_IsWarningEnabled(&iec)) ?
1728 "Temperature Warning: Enabled" :
1729 "Temperature Warning: Disabled or Not Supported");
832b75ed
GG
1730 return 0;
1731}
1732
ee38a438
GI
1733static int
1734scsiSmartEnable(scsi_device * device)
832b75ed
GG
1735{
1736 struct scsi_iec_mode_page iec;
1737 int err;
1738
1739 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
cfbba5b9 1740 print_on();
ee38a438 1741 pout("unable to fetch IEC (SMART) mode page [%s]\n",
832b75ed 1742 scsiErrString(err));
cfbba5b9 1743 print_off();
832b75ed
GG
1744 return 1;
1745 } else
1746 modese_len = iec.modese_len;
1747
1748 if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) {
cfbba5b9 1749 print_on();
832b75ed
GG
1750 pout("unable to enable Exception control and warning [%s]\n",
1751 scsiErrString(err));
cfbba5b9 1752 print_off();
832b75ed
GG
1753 return 1;
1754 }
1755 /* Need to refetch 'iec' since could be modified by previous call */
1756 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
ee38a438 1757 pout("unable to fetch IEC (SMART) mode page [%s]\n",
832b75ed
GG
1758 scsiErrString(err));
1759 return 1;
1760 } else
1761 modese_len = iec.modese_len;
1762
1763 pout("Informational Exceptions (SMART) %s\n",
1764 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
1765 pout("Temperature warning %s\n",
1766 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
1767 return 0;
1768}
ee38a438
GI
1769
1770static int
1771scsiSmartDisable(scsi_device * device)
832b75ed
GG
1772{
1773 struct scsi_iec_mode_page iec;
1774 int err;
1775
1776 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
cfbba5b9 1777 print_on();
ee38a438 1778 pout("unable to fetch IEC (SMART) mode page [%s]\n",
832b75ed 1779 scsiErrString(err));
cfbba5b9 1780 print_off();
832b75ed
GG
1781 return 1;
1782 } else
1783 modese_len = iec.modese_len;
1784
1785 if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) {
cfbba5b9 1786 print_on();
832b75ed
GG
1787 pout("unable to disable Exception control and warning [%s]\n",
1788 scsiErrString(err));
cfbba5b9 1789 print_off();
832b75ed
GG
1790 return 1;
1791 }
1792 /* Need to refetch 'iec' since could be modified by previous call */
1793 if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
ee38a438 1794 pout("unable to fetch IEC (SMART) mode page [%s]\n",
832b75ed
GG
1795 scsiErrString(err));
1796 return 1;
1797 } else
1798 modese_len = iec.modese_len;
1799
1800 pout("Informational Exceptions (SMART) %s\n",
1801 scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
1802 pout("Temperature warning %s\n",
1803 scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
1804 return 0;
1805}
1806
ee38a438
GI
1807static void
1808scsiPrintTemp(scsi_device * device)
832b75ed
GG
1809{
1810 UINT8 temp = 0;
1811 UINT8 trip = 0;
1812
1813 if (scsiGetTemp(device, &temp, &trip))
1814 return;
ee38a438 1815
832b75ed
GG
1816 if (temp) {
1817 if (255 != temp)
1818 pout("Current Drive Temperature: %d C\n", temp);
1819 else
1820 pout("Current Drive Temperature: <not available>\n");
1821 }
1822 if (trip)
1823 pout("Drive Trip Temperature: %d C\n", trip);
ee38a438
GI
1824 if (temp || trip)
1825 pout("\n");
832b75ed
GG
1826}
1827
1828/* Main entry point used by smartctl command. Return 0 for success */
ee38a438
GI
1829int
1830scsiPrintMain(scsi_device * device, const scsi_print_options & options)
832b75ed
GG
1831{
1832 int checkedSupportedLogPages = 0;
1833 UINT8 peripheral_type = 0;
1834 int returnval = 0;
1835 int res, durationSec;
ee38a438 1836 struct scsi_sense_disect sense_info;
832b75ed 1837
cfbba5b9
GI
1838 bool any_output = options.drive_info;
1839
ee38a438
GI
1840 if (supported_vpd_pages_p) {
1841 delete supported_vpd_pages_p;
1842 supported_vpd_pages_p = NULL;
1843 }
1844 supported_vpd_pages_p = new supported_vpd_pages(device);
1845
2127e193 1846 res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info);
832b75ed
GG
1847 if (res) {
1848 if (2 == res)
1849 return 0;
1850 else
1851 failuretest(MANDATORY_CMD, returnval |= FAILID);
ee38a438 1852 any_output = true;
832b75ed
GG
1853 }
1854
ee38a438
GI
1855 // Print read look-ahead status for disks
1856 short int wce = -1, rcd = -1;
1857 if (options.get_rcd || options.get_wce) {
1858 if (SCSI_PT_DIRECT_ACCESS == peripheral_type)
1859 res = scsiGetSetCache(device, modese_len, &wce, &rcd);
1860 else
1861 res = -1; // fetch for disks only
1862 any_output = true;
1863 }
1864
1865 if (options.get_rcd) {
1866 pout("Read Cache is: %s\n",
1867 res ? "Unavailable" : // error
1868 rcd ? "Disabled" : "Enabled");
1869 }
1870
1871 if (options.get_wce) {
1872 pout("Writeback Cache is: %s\n",
1873 res ? "Unavailable" : // error
1874 !wce ? "Disabled" : "Enabled");
1875 }
1876 if (options.drive_info)
1877 pout("\n");
1878
1879 // START OF THE ENABLE/DISABLE SECTION OF THE CODE
1880 if ( options.smart_disable || options.smart_enable
1881 || options.smart_auto_save_disable || options.smart_auto_save_enable)
1882 pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
1883
2127e193
GI
1884 if (options.smart_enable) {
1885 if (scsiSmartEnable(device))
832b75ed 1886 failuretest(MANDATORY_CMD, returnval |= FAILSMART);
ee38a438 1887 any_output = true;
832b75ed
GG
1888 }
1889
2127e193
GI
1890 if (options.smart_disable) {
1891 if (scsiSmartDisable(device))
832b75ed 1892 failuretest(MANDATORY_CMD,returnval |= FAILSMART);
ee38a438 1893 any_output = true;
832b75ed 1894 }
ee38a438 1895
2127e193
GI
1896 if (options.smart_auto_save_enable) {
1897 if (scsiSetControlGLTSD(device, 0, modese_len)) {
832b75ed
GG
1898 pout("Enable autosave (clear GLTSD bit) failed\n");
1899 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1900 }
ee38a438
GI
1901 else {
1902 pout("Autosave enabled (GLTSD bit set).\n");
1903 }
1904 any_output = true;
1905 }
1906
1907 // Enable/Disable write cache
1908 if (options.set_wce && SCSI_PT_DIRECT_ACCESS == peripheral_type) {
1909 short int enable = wce = (options.set_wce > 0);
1910 rcd = -1;
1911 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
1912 pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"),
1913 device->get_errmsg());
1914 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1915 }
1916 else
1917 pout("Write cache %sabled\n", (enable ? "en" : "dis"));
1918 any_output = true;
1919 }
1920
1921 // Enable/Disable read cache
1922 if (options.set_rcd && SCSI_PT_DIRECT_ACCESS == peripheral_type) {
1923 short int enable = (options.set_rcd > 0);
1924 rcd = !enable;
1925 wce = -1;
1926 if (scsiGetSetCache(device, modese_len, &wce, &rcd)) {
1927 pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"),
1928 device->get_errmsg());
1929 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1930 }
1931 else
1932 pout("Read cache %sabled\n", (enable ? "en" : "dis"));
cfbba5b9 1933 any_output = true;
832b75ed 1934 }
ee38a438 1935
2127e193
GI
1936 if (options.smart_auto_save_disable) {
1937 if (scsiSetControlGLTSD(device, 1, modese_len)) {
832b75ed
GG
1938 pout("Disable autosave (set GLTSD bit) failed\n");
1939 failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
1940 }
ee38a438
GI
1941 else {
1942 pout("Autosave disabled (GLTSD bit cleared).\n");
1943 }
cfbba5b9 1944 any_output = true;
832b75ed 1945 }
ee38a438
GI
1946 if ( options.smart_disable || options.smart_enable
1947 || options.smart_auto_save_disable || options.smart_auto_save_enable)
1948 pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE
1949
1950 // START OF READ-ONLY OPTIONS APART FROM -V and -i
1951 if ( options.smart_check_status || options.smart_ss_media_log
1952 || options.smart_vendor_attrib || options.smart_error_log
1953 || options.smart_selftest_log || options.smart_vendor_attrib
1954 || options.smart_background_log || options.sasphy
1955 )
1956 pout("=== START OF READ SMART DATA SECTION ===\n");
1957
2127e193
GI
1958 if (options.smart_check_status) {
1959 scsiGetSupportedLogPages(device);
832b75ed
GG
1960 checkedSupportedLogPages = 1;
1961 if ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
1962 (SCSI_PT_MEDIUM_CHANGER == peripheral_type)) { /* tape device */
1963 if (gTapeAlertsLPage) {
2127e193 1964 if (options.drive_info)
832b75ed 1965 pout("TapeAlert Supported\n");
2127e193 1966 if (-1 == scsiGetTapeAlertsData(device, peripheral_type))
832b75ed
GG
1967 failuretest(OPTIONAL_CMD, returnval |= FAILSMART);
1968 }
1969 else
1970 pout("TapeAlert Not Supported\n");
1971 } else { /* disk, cd/dvd, enclosure, etc */
2127e193 1972 if ((res = scsiGetSmartData(device, options.smart_vendor_attrib))) {
832b75ed
GG
1973 if (-2 == res)
1974 returnval |= FAILSTATUS;
1975 else
1976 returnval |= FAILSMART;
1977 }
1978 }
cfbba5b9 1979 any_output = true;
ee38a438
GI
1980 }
1981
d008864d
GI
1982 if (options.smart_ss_media_log) {
1983 if (! checkedSupportedLogPages)
1984 scsiGetSupportedLogPages(device);
1985 res = 0;
1986 if (gSSMediaLPage)
1987 res = scsiPrintSSMedia(device);
1988 if (0 != res)
1989 failuretest(OPTIONAL_CMD, returnval|=res);
1990 any_output = true;
1991 }
2127e193 1992 if (options.smart_vendor_attrib) {
832b75ed 1993 if (! checkedSupportedLogPages)
2127e193 1994 scsiGetSupportedLogPages(device);
832b75ed 1995 if (gTempLPage) {
2127e193 1996 scsiPrintTemp(device);
832b75ed
GG
1997 }
1998 if (gStartStopLPage)
2127e193 1999 scsiGetStartStopData(device);
832b75ed 2000 if (SCSI_PT_DIRECT_ACCESS == peripheral_type) {
2127e193 2001 scsiPrintGrownDefectListLen(device);
832b75ed 2002 if (gSeagateCacheLPage)
2127e193 2003 scsiPrintSeagateCacheLPage(device);
832b75ed 2004 if (gSeagateFactoryLPage)
2127e193 2005 scsiPrintSeagateFactoryLPage(device);
832b75ed 2006 }
cfbba5b9 2007 any_output = true;
832b75ed 2008 }
2127e193 2009 if (options.smart_error_log) {
832b75ed 2010 if (! checkedSupportedLogPages)
2127e193
GI
2011 scsiGetSupportedLogPages(device);
2012 scsiPrintErrorCounterLog(device);
2013 if (1 == scsiFetchControlGLTSD(device, modese_len, 1))
832b75ed
GG
2014 pout("\n[GLTSD (Global Logging Target Save Disable) set. "
2015 "Enable Save with '-S on']\n");
cfbba5b9 2016 any_output = true;
832b75ed 2017 }
2127e193 2018 if (options.smart_selftest_log) {
832b75ed 2019 if (! checkedSupportedLogPages)
2127e193 2020 scsiGetSupportedLogPages(device);
832b75ed
GG
2021 res = 0;
2022 if (gSelfTestLPage)
2127e193 2023 res = scsiPrintSelfTest(device);
832b75ed
GG
2024 else {
2025 pout("Device does not support Self Test logging\n");
2026 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
2027 }
2028 if (0 != res)
2029 failuretest(OPTIONAL_CMD, returnval|=res);
cfbba5b9 2030 any_output = true;
832b75ed 2031 }
2127e193 2032 if (options.smart_background_log) {
4d59bff9 2033 if (! checkedSupportedLogPages)
2127e193 2034 scsiGetSupportedLogPages(device);
4d59bff9
GG
2035 res = 0;
2036 if (gBackgroundResultsLPage)
2127e193 2037 res = scsiPrintBackgroundResults(device);
4d59bff9
GG
2038 else {
2039 pout("Device does not support Background scan results logging\n");
2040 failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
2041 }
2042 if (0 != res)
2043 failuretest(OPTIONAL_CMD, returnval|=res);
cfbba5b9 2044 any_output = true;
4d59bff9 2045 }
2127e193
GI
2046 if (options.smart_default_selftest) {
2047 if (scsiSmartDefaultSelfTest(device))
832b75ed
GG
2048 return returnval | FAILSMART;
2049 pout("Default Self Test Successful\n");
cfbba5b9 2050 any_output = true;
832b75ed 2051 }
2127e193
GI
2052 if (options.smart_short_cap_selftest) {
2053 if (scsiSmartShortCapSelfTest(device))
832b75ed
GG
2054 return returnval | FAILSMART;
2055 pout("Short Foreground Self Test Successful\n");
cfbba5b9 2056 any_output = true;
832b75ed 2057 }
ee38a438
GI
2058 // check if another test is running
2059 if (options.smart_short_selftest || options.smart_extend_selftest) {
2060 if (!scsiRequestSense(device, &sense_info) &&
2061 (sense_info.asc == 0x04 && sense_info.ascq == 0x09)) {
2062 if (!options.smart_selftest_force) {
2063 pout("Can't start self-test without aborting current test");
2064 if (sense_info.progress != -1) {
2065 pout(" (%d%% remaining)",
2066 100 - sense_info.progress * 100 / 65535);
2067 }
2068 pout(",\nadd '-t force' option to override, or run 'smartctl -X' "
2069 "to abort test.\n");
2070 return -1;
2071 }
2072 else
2073 scsiSmartSelfTestAbort(device);
2074 }
2075 }
2127e193
GI
2076 if (options.smart_short_selftest) {
2077 if (scsiSmartShortSelfTest(device))
832b75ed
GG
2078 return returnval | FAILSMART;
2079 pout("Short Background Self Test has begun\n");
2080 pout("Use smartctl -X to abort test\n");
cfbba5b9 2081 any_output = true;
832b75ed 2082 }
2127e193
GI
2083 if (options.smart_extend_selftest) {
2084 if (scsiSmartExtendSelfTest(device))
832b75ed
GG
2085 return returnval | FAILSMART;
2086 pout("Extended Background Self Test has begun\n");
2127e193 2087 if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
832b75ed
GG
2088 modese_len)) && (durationSec > 0)) {
2089 time_t t = time(NULL);
2090
2091 t += durationSec;
ee38a438 2092 pout("Please wait %d minutes for test to complete.\n",
832b75ed
GG
2093 durationSec / 60);
2094 pout("Estimated completion time: %s\n", ctime(&t));
2095 }
ee38a438 2096 pout("Use smartctl -X to abort test\n");
cfbba5b9 2097 any_output = true;
832b75ed 2098 }
2127e193
GI
2099 if (options.smart_extend_cap_selftest) {
2100 if (scsiSmartExtendCapSelfTest(device))
832b75ed
GG
2101 return returnval | FAILSMART;
2102 pout("Extended Foreground Self Test Successful\n");
2103 }
2127e193
GI
2104 if (options.smart_selftest_abort) {
2105 if (scsiSmartSelfTestAbort(device))
832b75ed
GG
2106 return returnval | FAILSMART;
2107 pout("Self Test returned without error\n");
cfbba5b9 2108 any_output = true;
ee38a438 2109 }
2127e193
GI
2110 if (options.sasphy) {
2111 if (scsiPrintSasPhy(device, options.sasphy_reset))
2112 return returnval | FAILSMART;
cfbba5b9 2113 any_output = true;
ee38a438 2114 }
cfbba5b9
GI
2115
2116 if (!any_output)
2117 pout("SCSI device successfully opened\n\n"
2118 "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
2119
832b75ed
GG
2120 return returnval;
2121}