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