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