smartmontools SVN Rev 5611
Utility to control and monitor storage systems with "S.M.A.R.T."
scsicmds.cpp
Go to the documentation of this file.
1/*
2 * scsicmds.cpp
3 *
4 * Home page of code is: https://www.smartmontools.org
5 *
6 * Copyright (C) 2002-8 Bruce Allen
7 * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
8 * Copyright (C) 2003-2023 Douglas Gilbert <dgilbert@interlog.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 *
12 *
13 * In the SCSI world "SMART" is a dead or withdrawn standard. In recent
14 * SCSI standards (since SCSI-3) it goes under the awkward name of
15 * "Informational Exceptions" ["IE" or "IEC" (with the "C" for "control")].
16 * The relevant information is spread around several SCSI draft
17 * standards available at http://www.t10.org . Reference is made in the
18 * code to the following acronyms:
19 * - SAM [SCSI Architectural model, versions 2 or 3]
20 * - SPC [SCSI Primary commands, versions 2 or 3]
21 * - SBC [SCSI Block commands, versions 2]
22 *
23 * Some SCSI disk vendors have snippets of "SMART" information in their
24 * product manuals.
25 */
26
27#include <stdio.h>
28#include <string.h>
29#include <errno.h>
30#include <ctype.h>
31
32#include "config.h"
33
34#include "scsicmds.h"
35#include "dev_interface.h"
36#include "utility.h"
37#include "sg_unaligned.h"
38
39const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 5470 2023-03-21 19:47:46Z dpgilbert $"
41
42static const char * logSenStr = "Log Sense";
43
44// Print SCSI debug messages?
45unsigned char scsi_debugmode = 0;
46
48
49#define RSOC_RESP_SZ 4096
50#define RSOC_ALL_CMDS_CTDP_0 8
51#define RSOC_ALL_CMDS_CTDP_1 20
52#define RSOC_1_CMD_CTDP_0 36
53
54// Check if LOG SENSE cdb supports changing the Subpage Code field
57{
58 int r_len = 0;
59 int err;
60 uint8_t rsoc_1cmd_rsp[RSOC_1_CMD_CTDP_0] = {};
61 uint8_t * rp = rsoc_1cmd_rsp;
62
63 err = scsiRSOCcmd(device, false /*rctd */ , 1 /* '1 cmd' format */,
64 LOG_SENSE, 0, rp, RSOC_1_CMD_CTDP_0, r_len);
65 if (err) {
67 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
68 return SC_NO_SUPPORT;
69 }
70 if (r_len < 8) {
72 pout("%s response to short [%d]\n", __func__, r_len);
73 return SC_NO_SUPPORT;
74 }
75 /* check the "subpage code" field in LOG SENSE cdb usage data */
76 return rp[7] ? SC_SUPPORT : SC_NO_SUPPORT; /* 4 + ls_cdb_byte3 */
77}
78
79bool
81{
82 bool res = true;
83 int k, err, cd_len, bump;
84 int r_len = 0;
85 uint8_t * rp = (uint8_t *)calloc(sizeof(uint8_t), RSOC_RESP_SZ);
86 const uint8_t * last_rp;
87 uint8_t * cmdp;
88 static const int max_bytes_of_cmds = RSOC_RESP_SZ - 4;
89
90 if (nullptr == rp)
91 return false;
92 rsoc_queried = true;
93 /* request 'all commands' format: 4 bytes header, 20 bytes per command */
94 err = scsiRSOCcmd(this, false /* rctd */, 0 /* 'all' format */, 0, 0,
95 rp, RSOC_RESP_SZ, r_len);
96 if (err) {
99 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
100 res = false;
101 goto fini;
102 }
103 if (r_len < 4) {
104 pout("%s response too short\n", __func__);
105 res = false;
106 goto fini;
107 }
109 cd_len = sg_get_unaligned_be32(rp + 0);
110 if (cd_len > max_bytes_of_cmds) {
111 if (scsi_debugmode)
112 pout("%s: truncate %d byte response to %d bytes\n", __func__,
113 cd_len, max_bytes_of_cmds);
114 cd_len = max_bytes_of_cmds;
115 }
116 last_rp = rp + cd_len;
122
123 for (k = 0, cmdp = rp + 4; cmdp < last_rp; ++k, cmdp += bump) {
124 bool sa_valid = !! (0x1 & cmdp[5]);
125 bool ctdp = !! (0x2 & cmdp[5]);
126 uint8_t opcode = cmdp[0];
127 uint16_t sa;
128
130 sa = sa_valid ? sg_get_unaligned_be16(cmdp + 2) : 0;
131
132 switch (opcode) {
133 case LOG_SENSE:
136 break;
137 case READ_DEFECT_10:
139 break;
140 case READ_DEFECT_12:
142 break;
144 if (sa_valid && (SAI_READ_CAPACITY_16 == sa))
146 break;
147 default:
148 break;
149 }
150 }
151 if (scsi_debugmode > 3) {
152 pout("%s: decoded %d supported commands\n", __func__, k);
153 pout(" LOG SENSE %ssupported\n",
154 (SC_SUPPORT == logsense_sup) ? "" : "not ");
155 pout(" LOG SENSE subpage code %ssupported\n",
156 (SC_SUPPORT == logsense_spc_sup) ? "" : "not ");
157 pout(" READ DEFECT 10 %ssupported\n",
158 (SC_SUPPORT == rdefect10_sup) ? "" : "not ");
159 pout(" READ DEFECT 12 %ssupported\n",
160 (SC_SUPPORT == rdefect12_sup) ? "" : "not ");
161 pout(" READ CAPACITY 16 %ssupported\n",
162 (SC_SUPPORT == rcap16_sup) ? "" : "not ");
163 }
164
165fini:
166 free(rp);
167 return res;
168}
169
170/* May track more in the future */
173 uint16_t sa, bool for_lsense_spc) const
174{
176
177 switch (opcode) {
178 case LOG_SENSE: /* checking if LOG SENSE _subpages_ supported */
179 scs = for_lsense_spc ? logsense_spc_sup : logsense_sup;
180 break;
181 case READ_DEFECT_10:
182 scs = rdefect10_sup;
183 break;
184 case READ_DEFECT_12:
185 scs = rdefect12_sup;
186 break;
188 if (sa_valid && (SAI_READ_CAPACITY_16 == sa))
189 scs = rcap16_sup;
190 break;
192 if (sa_valid && (MI_REP_SUP_OPCODES == sa))
193 scs = rsoc_sup;
194 break;
195 default:
196 break;
197 }
198 return scs;
199}
200
202{
203 unsigned char b[0xfc] = {}; /* pre SPC-3 INQUIRY max response size */
204
205 if (device && (0 == scsiInquiryVpd(device, SCSI_VPD_SUPPORTED_VPD_PAGES,
206 b, sizeof(b)))) {
208 int n = sizeof(pages);
209 if (num_valid > n)
210 num_valid = n;
211 memcpy(pages, b + 4, num_valid);
212 }
213}
214
215bool
217{
218 /* Supported VPD pages numbers start at offset 4 and should be in
219 * ascending order but don't assume that. */
220 for (int k = 0; k < num_valid; ++k) {
221 if (vpd_page_num == pages[k])
222 return true;
223 }
224 return false;
225}
226
227/* Simple ASCII printable (does not use locale), includes space and excludes
228 * DEL (0x7f). Note all UTF-8 encoding apart from <= 0x7f have top bit set. */
229static inline int
230my_isprint(uint8_t ch)
231{
232 return ((ch >= ' ') && (ch < 0x7f));
233}
234
235static int
237{
238 int n = strlen(b);
239
240 while ((n > 0) && (' ' == b[n - 1]))
241 b[--n] = '\0';
242 return n;
243}
244
245/* Read binary starting at 'up' for 'len' bytes and output as ASCII
246 * hexadecimal to the passed function 'out'. See dStrHex() below for more. */
247static void
248dStrHexHelper(const uint8_t * up, int len, int no_ascii,
249 void (*out)(const char * s, void * ctx), void * ctx = nullptr)
250{
251 static const int line_len = 80;
252 static const int cpstart = 60; // offset of start of ASCII rendering
253 uint8_t c;
254 char buff[line_len + 2]; // room for trailing null
255 int a = 0;
256 int bpstart = 5;
257 int cpos = cpstart;
258 int bpos = bpstart;
259 int i, k, blen;
260 char e[line_len + 4];
261 static const int elen = sizeof(e);
262
263 if (len <= 0)
264 return;
265 blen = (int)sizeof(buff);
266 memset(buff, ' ', line_len);
267 buff[line_len] = '\0';
268 if (no_ascii < 0) {
269 bpstart = 0;
270 bpos = bpstart;
271 for (k = 0; k < len; k++) {
272 c = *up++;
273 if (bpos == (bpstart + (8 * 3)))
274 bpos++;
275 snprintf(&buff[bpos], blen - bpos, "%.2x", (int)(uint8_t)c);
276 buff[bpos + 2] = ' ';
277 if ((k > 0) && (0 == ((k + 1) % 16))) {
278 trimTrailingSpaces(buff);
279 if (no_ascii)
280 snprintf(e, elen, "%s\n", buff);
281 else
282 snprintf(e, elen, "%.76s\n", buff);
283 out(e, ctx);
284 bpos = bpstart;
285 memset(buff, ' ', line_len);
286 } else
287 bpos += 3;
288 }
289 if (bpos > bpstart) {
290 buff[bpos + 2] = '\0';
291 trimTrailingSpaces(buff);
292 snprintf(e, elen, "%s\n", buff);
293 out(e, ctx);
294 }
295 return;
296 }
297 /* no_ascii>=0, start each line with address (offset) */
298 k = snprintf(buff + 1, blen - 1, "%.2x", a);
299 buff[k + 1] = ' ';
300
301 for (i = 0; i < len; i++) {
302 c = *up++;
303 bpos += 3;
304 if (bpos == (bpstart + (9 * 3)))
305 bpos++;
306 snprintf(&buff[bpos], blen - bpos, "%.2x", (int)(uint8_t)c);
307 buff[bpos + 2] = ' ';
308 if (no_ascii)
309 buff[cpos++] = ' ';
310 else {
311 if (! my_isprint(c))
312 c = '.';
313 buff[cpos++] = c;
314 }
315 if (cpos > (cpstart + 15)) {
316 if (no_ascii)
317 trimTrailingSpaces(buff);
318 if (no_ascii)
319 snprintf(e, elen, "%s\n", buff);
320 else
321 snprintf(e, elen, "%.76s\n", buff);
322 out(e, ctx);
323 bpos = bpstart;
324 cpos = cpstart;
325 a += 16;
326 memset(buff, ' ', line_len);
327 k = snprintf(buff + 1, blen - 1, "%.2x", a);
328 buff[k + 1] = ' ';
329 }
330 }
331 if (cpos > cpstart) {
332 buff[cpos] = '\0';
333 if (no_ascii)
334 trimTrailingSpaces(buff);
335 snprintf(e, elen, "%s\n", buff);
336 out(e, ctx);
337 }
338}
339
340/* Read binary starting at 'up' for 'len' bytes and output as ASCII
341 * hexadecimal into file pointer (fp). If fp is nullptr, then send to
342 * pout(). See dStrHex() below for more. */
343void
344dStrHexFp(const uint8_t * up, int len, int no_ascii, FILE * fp)
345{
346 /* N.B. Use of lamba requires C++11 or later. */
347 if ((nullptr == up) || (len < 1))
348 return;
349 else if (fp)
350 dStrHexHelper(up, len, no_ascii,
351 [](const char * s, void * ctx)
352 { fputs(s, reinterpret_cast<FILE *>(ctx)); },
353 fp);
354 else
355 dStrHexHelper(up, len, no_ascii,
356 [](const char * s, void *){ pout("%s", s); });
357}
358
359/* Read binary starting at 'up' for 'len' bytes and output as ASCII
360 * hexadecimal into pout(). 16 bytes per line are output with an
361 * additional space between 8th and 9th byte on each line (for readability).
362 * 'no_ascii' selects one of 3 output format types:
363 * > 0 each line has address then up to 16 ASCII-hex bytes
364 * = 0 in addition, the bytes are rendered in ASCII to the right
365 * of each line, non-printable characters shown as '.'
366 * < 0 only the ASCII-hex bytes are listed (i.e. without address) */
367void
368dStrHex(const uint8_t * up, int len, int no_ascii)
369{
370 /* N.B. Use of lamba requires C++11 or later. */
371 dStrHexHelper(up, len, no_ascii,
372 [](const char * s, void *){ pout("%s", s); });
373}
374
375/* This is a heuristic that takes into account the command bytes and length
376 * to decide whether the presented unstructured sequence of bytes could be
377 * a SCSI command. If so it returns true otherwise false. Vendor specific
378 * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
379 * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
380 * only SCSI commands considered above 16 bytes of length are the Variable
381 * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
382 * Both have an inbuilt length field which can be cross checked with clen.
383 * No NVMe commands (64 bytes long plus some extra added by some OSes) have
384 * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
385 * structures that are sent across the wire. The FIS register structure is
386 * used to move a command from a SATA host to device, but the ATA 'command'
387 * is not the first byte. So it is harder to say what will happen if a
388 * FIS structure is presented as a SCSI command, hopefully there is a low
389 * probability this function will yield true in that case. */
390bool
391is_scsi_cdb(const uint8_t * cdbp, int clen)
392{
393 if (clen < 6)
394 return false;
395 uint8_t opcode = cdbp[0];
396 uint8_t top3bits = opcode >> 5;
397 if (0x3 == top3bits) { /* Opcodes 0x60 to 0x7f */
398 int ilen, sa;
399 if ((clen < 12) || (clen % 4))
400 return false; /* must be modulo 4 and 12 or more bytes */
401 switch (opcode) {
402 case 0x7e: /* Extended cdb (XCDB) */
403 ilen = 4 + sg_get_unaligned_be16(cdbp + 2);
404 return (ilen == clen);
405 case 0x7f: /* Variable Length cdb */
406 ilen = 8 + cdbp[7];
407 sa = sg_get_unaligned_be16(cdbp + 8);
408 /* service action (sa) 0x0 is reserved */
409 return ((ilen == clen) && sa);
410 default:
411 return false;
412 }
413 } else if (clen <= 16) {
414 switch (clen) {
415 case 6:
416 if (top3bits > 0x5) /* vendor */
417 return true;
418 return (0x0 == top3bits); /* 6 byte cdb */
419 case 10:
420 if (top3bits > 0x5) /* vendor */
421 return true;
422 return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */
423 case 16:
424 if (top3bits > 0x5) /* vendor */
425 return true;
426 return (0x4 == top3bits); /* 16 byte cdb */
427 case 12:
428 if (top3bits > 0x5) /* vendor */
429 return true;
430 return (0x5 == top3bits); /* 12 byte cdb */
431 default:
432 return false;
433 }
434 }
435 /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or
436 * opcode > 0x7f). */
437 return false;
438}
439
442 scsi_sa_b1b4n5, /* for cdb byte 1, bit 4, number 5 bits */
444};
445
447 uint8_t cdb0;
449};
450
451static struct scsi_sa_var_map sa_var_a[] = {
452 {0x3b, scsi_sa_b1b4n5}, /* Write buffer modes_s */
453 {0x3c, scsi_sa_b1b4n5}, /* Read buffer(10) modes_s */
454 {0x48, scsi_sa_b1b4n5}, /* Sanitize sa_s */
455 {0x5e, scsi_sa_b1b4n5}, /* Persistent reserve in sa_s */
456 {0x5f, scsi_sa_b1b4n5}, /* Persistent reserve out sa_s */
457 {0x7f, scsi_sa_b8b7n16}, /* Variable length commands */
458 {0x83, scsi_sa_b1b4n5}, /* Extended copy out/cmd sa_s */
459 {0x84, scsi_sa_b1b4n5}, /* Extended copy in sa_s */
460 {0x8c, scsi_sa_b1b4n5}, /* Read attribute sa_s */
461 {0x9b, scsi_sa_b1b4n5}, /* Read buffer(16) modes_s */
462 {0x9e, scsi_sa_b1b4n5}, /* Service action in (16) */
463 {0x9f, scsi_sa_b1b4n5}, /* Service action out (16) */
464 {0xa3, scsi_sa_b1b4n5}, /* Maintenance in */
465 {0xa4, scsi_sa_b1b4n5}, /* Maintenance out */
466 {0xa9, scsi_sa_b1b4n5}, /* Service action out (12) */
467 {0xab, scsi_sa_b1b4n5}, /* Service action in (12) */
468};
469
471 uint8_t opcode;
472 bool sa_valid; /* Service action (next field) valid */
473 uint16_t sa;
474 const char * name;
475};
476
477/* Array assumed to be sorted by opcode then service action (sa) */
479 /* in ascending opcode order */
480 {TEST_UNIT_READY, false, 0, "test unit ready"}, /* 0x00 */
481 {REQUEST_SENSE, false, 0, "request sense"}, /* 0x03 */
482 {INQUIRY, false, 0, "inquiry"}, /* 0x12 */
483 {MODE_SELECT_6, false, 0, "mode select(6)"}, /* 0x15 */
484 {MODE_SENSE_6, false, 0, "mode sense(6)"}, /* 0x1a */
485 {START_STOP_UNIT, false, 0, "start stop unit"}, /* 0x1b */
486 {RECEIVE_DIAGNOSTIC, false, 0, "receive diagnostic"}, /* 0x1c */
487 {SEND_DIAGNOSTIC, false, 0, "send diagnostic"}, /* 0x1d */
488 {READ_CAPACITY_10, false, 0, "read capacity(10)"}, /* 0x25 */
489 {READ_DEFECT_10, false, 0, "read defect list(10)"}, /* 0x37 */
490 {LOG_SELECT, false, 0, "log select"}, /* 0x4c */
491 {LOG_SENSE, false, 0, "log sense"}, /* 0x4d */
492 {MODE_SELECT_10, false, 0, "mode select(10)"}, /* 0x55 */
493 {MODE_SENSE_10, false, 0, "mode sense(10)"}, /* 0x5a */
494 {SAT_ATA_PASSTHROUGH_16, false, 0, "ata pass-through(16)"}, /* 0x85 */
495 {SERVICE_ACTION_IN_16, true, SAI_READ_CAPACITY_16, "read capacity(16)"},
496 /* 0x9e,0x10 */
498 "get physical element status"}, /* 0x9e,0x17 */
499 {REPORT_LUNS, false, 0, "report luns"}, /* 0xa0 */
500 {SAT_ATA_PASSTHROUGH_12, false, 0, "ata pass-through(12)"}, /* 0xa1 */
502 "report supported operation codes"}, /* 0xa3,0xc */
503 {READ_DEFECT_12, false, 0, "read defect list(12)"}, /* 0xb7 */
504};
505
506static const char * vendor_specific = "<vendor specific>";
507
508/* Need to expand to take service action into account. For commands
509 * of interest the service action is in the 2nd command byte */
510const char *
511scsi_get_opcode_name(const uint8_t * cdbp)
512{
513 uint8_t opcode = cdbp[0];
514 uint8_t cdb0;
515 enum scsi_sa_t sa_var = scsi_sa_none;
516 bool sa_valid = false;
517 uint16_t sa = 0;
518 int k;
519 static const int sa_var_len = sizeof(sa_var_a) /
520 sizeof(sa_var_a[0]);
521 static const int len = sizeof(opcode_name_arr) /
522 sizeof(opcode_name_arr[0]);
523
524 if (opcode >= 0xc0)
525 return vendor_specific;
526 for (k = 0; k < sa_var_len; ++k) {
527 cdb0 = sa_var_a[k].cdb0;
528 if (opcode == cdb0) {
529 sa_var = sa_var_a[k].sa_var;
530 break;
531 }
532 if (opcode < cdb0)
533 break;
534 }
535 switch (sa_var) {
536 case scsi_sa_none:
537 break;
538 case scsi_sa_b1b4n5:
539 sa_valid = true;
540 sa = cdbp[1] & 0x1f;
541 break;
542 case scsi_sa_b8b7n16:
543 sa_valid = true;
544 sa = sg_get_unaligned_be16(cdbp + 8);
545 break;
546 }
547 for (k = 0; k < len; ++k) {
548 struct scsi_opcode_name * onp = &opcode_name_arr[k];
549
550 if (opcode == onp->opcode) {
551 if ((! sa_valid) && (! onp->sa_valid))
552 return onp->name;
553 if (sa_valid && onp->sa_valid) {
554 if (sa == onp->sa)
555 return onp->name;
556 }
557 /* should not see sa_valid and ! onp->sa_valid (or vice versa) */
558 } else if (opcode < onp->opcode)
559 return nullptr;
560 }
561 return nullptr;
562}
563
564void
565scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,
566 struct scsi_sense_disect * out)
567{
568 memset(out, 0, sizeof(struct scsi_sense_disect));
570 int resp_code = (io_buf->sensep[0] & 0x7f);
571 out->resp_code = resp_code;
572 if (resp_code >= 0x72) {
573 out->sense_key = (io_buf->sensep[1] & 0xf);
574 out->asc = io_buf->sensep[2];
575 out->ascq = io_buf->sensep[3];
576 } else if (resp_code >= 0x70) {
577 out->sense_key = (io_buf->sensep[2] & 0xf);
578 if (io_buf->resp_sense_len > 13) {
579 out->asc = io_buf->sensep[12];
580 out->ascq = io_buf->sensep[13];
581 }
582 }
583 }
584}
585
586int
588{
589 switch (sinfo->sense_key) {
590 case SCSI_SK_NO_SENSE:
593 return SIMPLE_NO_ERROR;
595 if (SCSI_ASC_NO_MEDIUM == sinfo->asc)
597 else if (SCSI_ASC_NOT_READY == sinfo->asc) {
598 if (0x1 == sinfo->ascq)
600 else
602 } else
608 if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc)
610 else if (SCSI_ASC_INVALID_FIELD == sinfo->asc)
612 else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc)
614 else
615 return SIMPLE_ERR_BAD_PARAM; /* all other illegal request */
624 default:
625 return SIMPLE_ERR_UNKNOWN;
626 }
627}
628
629const char *
630scsiErrString(int scsiErr)
631{
632 if (scsiErr < 0)
633 return strerror(-scsiErr);
634 switch (scsiErr) {
635 case SIMPLE_NO_ERROR:
636 return "no error";
638 return "device not ready";
640 return "unsupported scsi opcode";
642 return "unsupported field in scsi command";
644 return "badly formed scsi parameters";
646 return "scsi response fails sanity test";
648 return "no medium present";
650 return "device will be ready soon";
652 return "unit attention reported, try again";
654 return "medium or hardware error (serious)";
656 return "unknown error (unexpected sense key)";
658 return "aborted command";
660 return "data protection error";
662 return "miscompare";
663 default:
664 return "unknown error";
665 }
666}
667
668static const char * sense_key_desc[] = {
669 "No Sense", /* Filemark, ILI and/or EOM; progress
670 indication (during FORMAT); power
671 condition sensing (REQUEST SENSE) */
672 "Recovered Error", /* The last command completed successfully
673 but used error correction */
674 "Not Ready", /* The addressed target is not ready */
675 "Medium Error", /* Data error detected on the medium */
676 "Hardware Error", /* Controller or device failure */
677 "Illegal Request",
678 "Unit Attention", /* Removable medium was changed, or
679 the target has been reset */
680 "Data Protect", /* Access to the data is blocked */
681 "Blank Check", /* Reached unexpected written or unwritten
682 region of the medium */
683 "Vendor specific(9)", /* Vendor specific */
684 "Copy Aborted", /* COPY or COMPARE was aborted */
685 "Aborted Command", /* The target aborted the command */
686 "Equal", /* SEARCH DATA found data equal (obsolete) */
687 "Volume Overflow", /* Medium full with data to be written */
688 "Miscompare", /* Source data and data on the medium
689 do not agree */
690 "Completed" /* may occur for successful cmd (spc4r23) */
691};
692
693/* Yield string associated with sense_key value. Returns 'buff'. */
694char *
695scsi_get_sense_key_str(int sense_key, int buff_len, char * buff)
696{
697 if (1 == buff_len) {
698 buff[0] = '\0';
699 return buff;
700 }
701 if ((sense_key >= 0) && (sense_key < 16))
702 snprintf(buff, buff_len, "%s", sense_key_desc[sense_key]);
703 else
704 snprintf(buff, buff_len, "invalid value: 0x%x", sense_key);
705 return buff;
706}
707
708/* Iterates to next designation descriptor in the device identification
709 * VPD page. The 'initial_desig_desc' should point to start of first
710 * descriptor with 'page_len' being the number of valid bytes in that
711 * and following descriptors. To start, 'off' should point to a negative
712 * value, thereafter it should point to the value yielded by the previous
713 * call. If 0 returned then 'initial_desig_desc + *off' should be a valid
714 * descriptor; returns -1 if normal end condition and -2 for an abnormal
715 * termination. Matches association, designator_type and/or code_set when
716 * any of those values are greater than or equal to zero. */
717int
718scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len,
719 int * off, int m_assoc, int m_desig_type, int m_code_set)
720{
721 const unsigned char * ucp;
722 int k;
723
724 for (k = *off, ucp = initial_desig_desc ; (k + 3) < page_len; ) {
725 k = (k < 0) ? 0 : (k + ucp[k + 3] + 4);
726 if ((k + 4) > page_len)
727 break;
728 int c_set = (ucp[k] & 0xf);
729 if ((m_code_set >= 0) && (m_code_set != c_set))
730 continue;
731 int assoc = ((ucp[k + 1] >> 4) & 0x3);
732 if ((m_assoc >= 0) && (m_assoc != assoc))
733 continue;
734 int desig_type = (ucp[k + 1] & 0xf);
735 if ((m_desig_type >= 0) && (m_desig_type != desig_type))
736 continue;
737 *off = k;
738 return 0;
739 }
740 return (k == page_len) ? -1 : -2;
741}
742
743/* Decode VPD page 0x83 logical unit designator into a string. If both
744 * numeric address and SCSI name string present, prefer the former.
745 * Returns 0 on success, -1 on error with error string in s. */
746int
747scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
748 int * transport)
749{
750 if (transport)
751 *transport = -1;
752 if (slen < 32) {
753 if (slen > 0)
754 s[0] = '\0';
755 return -1;
756 }
757
758 s[0] = '\0';
759 int si = 0;
760 int have_scsi_ns = 0;
761 int off = -1;
762 int u;
763 while ((u = scsi_vpd_dev_id_iter(b, blen, &off, -1, -1, -1)) == 0) {
764 const unsigned char * ucp = b + off;
765 int i_len = ucp[3];
766 if ((off + i_len + 4) > blen) {
767 snprintf(s+si, slen-si, "error: designator length");
768 return -1;
769 }
770 int assoc = ((ucp[1] >> 4) & 0x3);
771 if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0))
772 *transport = (ucp[0] >> 4) & 0xf;
773 if (0 != assoc)
774 continue;
775 const unsigned char * ip = ucp + 4;
776 int c_set = (ucp[0] & 0xf);
777 int desig_type = (ucp[1] & 0xf);
778
779 int naa;
780 switch (desig_type) {
781 case 0: /* vendor specific */
782 case 1: /* T10 vendor identification */
783 break;
784 case 2: /* EUI-64 based */
785 if ((8 != i_len) && (12 != i_len) && (16 != i_len)) {
786 snprintf(s+si, slen-si, "error: EUI-64 length");
787 return -1;
788 }
789 if (have_scsi_ns)
790 si = 0;
791 si += snprintf(s+si, slen-si, "0x");
792 for (int m = 0; m < i_len; ++m)
793 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
794 break;
795 case 3: /* NAA */
796 if (1 != c_set) {
797 snprintf(s+si, slen-si, "error: NAA bad code_set");
798 return -1;
799 }
800 naa = (ip[0] >> 4) & 0xff;
801 if ((naa < 2) || (naa > 6) || (4 == naa)) {
802 snprintf(s+si, slen-si, "error: unexpected NAA");
803 return -1;
804 }
805 if (have_scsi_ns)
806 si = 0;
807 if (2 == naa) { /* NAA IEEE Extended */
808 if (8 != i_len) {
809 snprintf(s+si, slen-si, "error: NAA 2 length");
810 return -1;
811 }
812 si += snprintf(s+si, slen-si, "0x");
813 for (int m = 0; m < 8; ++m)
814 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
815 } else if ((3 == naa ) || (5 == naa)) {
816 /* NAA=3 Locally assigned; NAA=5 IEEE Registered */
817 if (8 != i_len) {
818 snprintf(s+si, slen-si, "error: NAA 3 or 5 length");
819 return -1;
820 }
821 si += snprintf(s+si, slen-si, "0x");
822 for (int m = 0; m < 8; ++m)
823 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
824 } else if (6 == naa) { /* NAA IEEE Registered extended */
825 if (16 != i_len) {
826 snprintf(s+si, slen-si, "error: NAA 6 length");
827 return -1;
828 }
829 si += snprintf(s+si, slen-si, "0x");
830 for (int m = 0; m < 16; ++m)
831 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
832 }
833 break;
834 case 4: /* Relative target port */
835 case 5: /* (primary) Target port group */
836 case 6: /* Logical unit group */
837 case 7: /* MD5 logical unit identifier */
838 break;
839 case 8: /* SCSI name string */
840 if (3 != c_set) {
841 snprintf(s+si, slen-si, "error: SCSI name string");
842 return -1;
843 }
844 /* does %s print out UTF-8 ok?? */
845 if (si == 0) {
846 si += snprintf(s+si, slen-si, "%s", (const char *)ip);
847 ++have_scsi_ns;
848 }
849 break;
850 default: /* reserved */
851 break;
852 }
853 }
854 if (-2 == u) {
855 snprintf(s+si, slen-si, "error: bad structure");
856 return -1;
857 }
858 return 0;
859}
860
861/* Sends LOG SENSE command. Returns 0 if ok, 1 if device NOT READY, 2 if
862 * command not supported, 3 if field (within command) not supported or
863 * returns negated errno. SPC-3 sections 6.6 and 7.2 (rec 22a).
864 * N.B. Sets PC==1 to fetch "current cumulative" log pages.
865 * If known_resp_len > 0 then a single fetch is done for this response
866 * length. If known_resp_len == 0 then twin fetches are performed, the
867 * first to deduce the response length, then send the same command again
868 * requesting the deduced response length. This protects certain fragile
869 * HBAs. The twin fetch technique should not be used with the TapeAlert
870 * log page since it clears its state flags after each fetch. If
871 * known_resp_len < 0 then does single fetch for BufLen bytes. */
872int
873scsiLogSense(scsi_device * device, int pagenum, int subpagenum, uint8_t *pBuf,
874 int bufLen, int known_resp_len)
875{
876 int pageLen;
877 struct scsi_cmnd_io io_hdr = {};
878 struct scsi_sense_disect sinfo;
879 uint8_t cdb[10] = {};
880 uint8_t sense[32];
881
882 if (known_resp_len > bufLen)
883 return -EIO;
884 if (known_resp_len > 0)
885 pageLen = known_resp_len;
886 else if (known_resp_len < 0)
887 pageLen = bufLen;
888 else { /* 0 == known_resp_len */
889 /* Twin fetch strategy: first fetch to find response length */
890 pageLen = 4;
891 if (pageLen > bufLen)
892 return -EIO;
893 else
894 memset(pBuf, 0, pageLen);
895
897 io_hdr.dxfer_len = pageLen;
898 io_hdr.dxferp = pBuf;
899 cdb[0] = LOG_SENSE;
900 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
901 cdb[3] = subpagenum; /* 0 for no sub-page */
902 sg_put_unaligned_be16(pageLen, cdb + 7);
903 io_hdr.cmnd = cdb;
904 io_hdr.cmnd_len = sizeof(cdb);
905 io_hdr.sensep = sense;
906 io_hdr.max_sense_len = sizeof(sense);
908
909 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
910 return -device->get_errno();
911 int res;
912 if ((res = scsiSimpleSenseFilter(&sinfo)))
913 return res;
914 /* sanity check on response */
915 if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum))
916 return SIMPLE_ERR_BAD_RESP;
917 uint16_t u = sg_get_unaligned_be16(pBuf + 2);
918 if (0 == u)
919 return SIMPLE_ERR_BAD_RESP;
920 pageLen = u + 4;
921 /* some SCSI HBA don't like "odd" length transfers */
922 if (pageLen % 2)
923 pageLen += 1;
924 if (pageLen > bufLen)
925 pageLen = bufLen;
926 }
927 memset(pBuf, 0, 4);
928 memset(&io_hdr, 0, sizeof(io_hdr));
929 memset(cdb, 0, sizeof(cdb));
931 io_hdr.dxfer_len = pageLen;
932 io_hdr.dxferp = pBuf;
933 cdb[0] = LOG_SENSE;
934 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
935 cdb[3] = subpagenum;
936 sg_put_unaligned_be16(pageLen, cdb + 7);
937 io_hdr.cmnd = cdb;
938 io_hdr.cmnd_len = sizeof(cdb);
939 io_hdr.sensep = sense;
940 io_hdr.max_sense_len = sizeof(sense);
942
943 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
944 return -device->get_errno();
945 int status = scsiSimpleSenseFilter(&sinfo);
946 if (0 != status)
947 return status;
948 /* sanity check on response */
949 if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum))
950 return SIMPLE_ERR_BAD_RESP;
951 if (0 == sg_get_unaligned_be16(pBuf + 2))
952 return SIMPLE_ERR_BAD_RESP;
953 return 0;
954}
955
956/* Sends a LOG SELECT command. Can be used to set log page values
957 * or reset one log page (or all of them) to its defaults (typically zero).
958 * Returns 0 if ok, 1 if NOT READY, 2 if command not supported, * 3 if
959 * field in command not supported, * 4 if bad parameter to command or
960 * returns negated errno. SPC-4 sections 6.5 and 7.2 (rev 20) */
961int
962scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum,
963 int subpagenum, uint8_t *pBuf, int bufLen)
964{
965 struct scsi_cmnd_io io_hdr = {};
966 struct scsi_sense_disect sinfo;
967 uint8_t cdb[10] = {};
968 uint8_t sense[32];
969
970 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
971 io_hdr.dxfer_len = bufLen;
972 io_hdr.dxferp = pBuf;
973 cdb[0] = LOG_SELECT;
974 cdb[1] = (pcr ? 2 : 0) | (sp ? 1 : 0);
975 cdb[2] = ((pc << 6) & 0xc0) | (pagenum & 0x3f);
976 cdb[3] = (subpagenum & 0xff);
977 sg_put_unaligned_be16(bufLen, cdb + 7);
978 io_hdr.cmnd = cdb;
979 io_hdr.cmnd_len = sizeof(cdb);
980 io_hdr.sensep = sense;
981 io_hdr.max_sense_len = sizeof(sense);
983
984 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
985 return -device->get_errno();
986 return scsiSimpleSenseFilter(&sinfo);
987}
988
989/* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY,
990 * 2 if command not supported (then MODE SENSE(10) should be supported),
991 * 3 if field in command not supported or returns negated errno.
992 * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */
993int
994scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
995 uint8_t *pBuf, int bufLen)
996{
997 struct scsi_cmnd_io io_hdr = {};
998 struct scsi_sense_disect sinfo;
999 uint8_t cdb[6] = {};
1000 uint8_t sense[32];
1001
1002 if ((bufLen < 0) || (bufLen > 255))
1003 return -EINVAL;
1005 io_hdr.dxfer_len = bufLen;
1006 io_hdr.dxferp = pBuf;
1007 cdb[0] = MODE_SENSE_6;
1008 cdb[2] = (pc << 6) | (pagenum & 0x3f);
1009 cdb[3] = subpagenum;
1010 cdb[4] = bufLen;
1011 io_hdr.cmnd = cdb;
1012 io_hdr.cmnd_len = sizeof(cdb);
1013 io_hdr.sensep = sense;
1014 io_hdr.max_sense_len = sizeof(sense);
1016
1017 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1018 return -device->get_errno();
1019 int status = scsiSimpleSenseFilter(&sinfo);
1020 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
1021 int offset;
1022
1023 offset = scsiModePageOffset(pBuf, bufLen, 0);
1024 if (offset < 0)
1025 return SIMPLE_ERR_BAD_RESP;
1026 else if (pagenum != (pBuf[offset] & 0x3f))
1027 return SIMPLE_ERR_BAD_RESP;
1028 }
1029 return status;
1030}
1031
1032/* Sends a 6 byte MODE SELECT command. Assumes given pBuf is the response
1033 * from a corresponding 6 byte MODE SENSE command. Such a response should
1034 * have a 4 byte header followed by 0 or more 8 byte block descriptors
1035 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 if NOT READY,
1036 * 2 if command not supported (then MODE SELECT(10) may be supported),
1037 * 3 if field in command not supported, 4 if bad parameter to command
1038 * or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */
1039int
1040scsiModeSelect(scsi_device * device, int sp, uint8_t *pBuf, int bufLen)
1041{
1042 struct scsi_cmnd_io io_hdr = {};
1043 struct scsi_sense_disect sinfo;
1044 uint8_t cdb[6] = {};
1045 uint8_t sense[32];
1046 int pg_offset, pg_len, hdr_plus_1_pg;
1047
1048 pg_offset = 4 + pBuf[3];
1049 if (pg_offset + 2 >= bufLen)
1050 return -EINVAL;
1051 pg_len = pBuf[pg_offset + 1] + 2;
1052 hdr_plus_1_pg = pg_offset + pg_len;
1053 if (hdr_plus_1_pg > bufLen)
1054 return -EINVAL;
1055 pBuf[0] = 0; /* Length of returned mode sense data reserved for SELECT */
1056 pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
1057 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
1058 io_hdr.dxfer_len = hdr_plus_1_pg;
1059 io_hdr.dxferp = pBuf;
1060 cdb[0] = MODE_SELECT_6;
1061 cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
1062 cdb[4] = hdr_plus_1_pg; /* make sure only one page sent */
1063 io_hdr.cmnd = cdb;
1064 io_hdr.cmnd_len = sizeof(cdb);
1065 io_hdr.sensep = sense;
1066 io_hdr.max_sense_len = sizeof(sense);
1068
1069 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1070 return -device->get_errno();
1071 return scsiSimpleSenseFilter(&sinfo);
1072}
1073
1074/* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command
1075 * not supported (then MODE SENSE(6) might be supported), 3 if field in
1076 * command not supported or returns negated errno.
1077 * SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */
1078int
1079scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
1080 uint8_t *pBuf, int bufLen)
1081{
1082 struct scsi_cmnd_io io_hdr = {};
1083 struct scsi_sense_disect sinfo;
1084 uint8_t cdb[10] = {};
1085 uint8_t sense[32];
1086
1088 io_hdr.dxfer_len = bufLen;
1089 io_hdr.dxferp = pBuf;
1090 cdb[0] = MODE_SENSE_10;
1091 cdb[2] = (pc << 6) | (pagenum & 0x3f);
1092 cdb[3] = subpagenum;
1093 sg_put_unaligned_be16(bufLen, cdb + 7);
1094 io_hdr.cmnd = cdb;
1095 io_hdr.cmnd_len = sizeof(cdb);
1096 io_hdr.sensep = sense;
1097 io_hdr.max_sense_len = sizeof(sense);
1099
1100 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1101 return -device->get_errno();
1102 int status = scsiSimpleSenseFilter(&sinfo);
1103 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
1104 int offset;
1105
1106 offset = scsiModePageOffset(pBuf, bufLen, 1);
1107 if (offset < 0)
1108 return SIMPLE_ERR_BAD_RESP;
1109 else if (pagenum != (pBuf[offset] & 0x3f))
1110 return SIMPLE_ERR_BAD_RESP;
1111 }
1112 return status;
1113}
1114
1115/* Sends a 10 byte MODE SELECT command. Assumes given pBuf is the response
1116 * from a corresponding 10 byte MODE SENSE command. Such a response should
1117 * have a 8 byte header followed by 0 or more 8 byte block descriptors
1118 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if
1119 * command not supported (then MODE SELECT(6) may be supported), 3 if field
1120 * in command not supported, 4 if bad parameter to command or returns
1121 * negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */
1122int
1123scsiModeSelect10(scsi_device * device, int sp, uint8_t *pBuf, int bufLen)
1124{
1125 struct scsi_cmnd_io io_hdr = {};
1126 struct scsi_sense_disect sinfo;
1127 uint8_t cdb[10] = {};
1128 uint8_t sense[32];
1129 int pg_offset, pg_len, hdr_plus_1_pg;
1130
1131 pg_offset = 8 + sg_get_unaligned_be16(pBuf + 6);
1132 if (pg_offset + 2 >= bufLen)
1133 return -EINVAL;
1134 pg_len = pBuf[pg_offset + 1] + 2;
1135 hdr_plus_1_pg = pg_offset + pg_len;
1136 if (hdr_plus_1_pg > bufLen)
1137 return -EINVAL;
1138 pBuf[0] = 0;
1139 pBuf[1] = 0; /* Length of returned mode sense data reserved for SELECT */
1140 pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
1141 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
1142 io_hdr.dxfer_len = hdr_plus_1_pg;
1143 io_hdr.dxferp = pBuf;
1144 cdb[0] = MODE_SELECT_10;
1145 cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
1146 /* make sure only one page sent */
1147 sg_put_unaligned_be16(hdr_plus_1_pg, cdb + 7);
1148 io_hdr.cmnd = cdb;
1149 io_hdr.cmnd_len = sizeof(cdb);
1150 io_hdr.sensep = sense;
1151 io_hdr.max_sense_len = sizeof(sense);
1153
1154 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1155 return -device->get_errno();
1156 return scsiSimpleSenseFilter(&sinfo);
1157}
1158
1159/* Standard INQUIRY returns 0 for ok, anything else is a major problem.
1160 * bufLen should be 36 for unsafe devices (like USB mass storage stuff)
1161 * otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */
1162int
1163scsiStdInquiry(scsi_device * device, uint8_t *pBuf, int bufLen)
1164{
1165 struct scsi_sense_disect sinfo;
1166 struct scsi_cmnd_io io_hdr = {};
1167 int res;
1168 uint8_t cdb[6] = {};
1169 uint8_t sense[32];
1170
1171 if ((bufLen < 0) || (bufLen > 1023))
1172 return -EINVAL;
1173 if (bufLen >= 36) /* normal case */
1174 memset(pBuf, 0, 36);
1176 io_hdr.dxfer_len = bufLen;
1177 io_hdr.dxferp = pBuf;
1178 cdb[0] = INQUIRY;
1179 sg_put_unaligned_be16(bufLen, cdb + 3);
1180 io_hdr.cmnd = cdb;
1181 io_hdr.cmnd_len = sizeof(cdb);
1182 io_hdr.sensep = sense;
1183 io_hdr.max_sense_len = sizeof(sense);
1185
1186 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1187 return -device->get_errno();
1188 res = scsiSimpleSenseFilter(&sinfo);
1189 if ((SIMPLE_NO_ERROR == res) && (! device->is_spc4_or_higher())) {
1190 if (((bufLen - io_hdr.resid) >= 36) &&
1191 (pBuf[2] >= 6) && /* VERSION field >= SPC-4 */
1192 ((pBuf[3] & 0xf) == 2)) { /* RESPONSE DATA field == 2 */
1193 uint8_t pdt = pBuf[0] & 0x1f;
1194
1195 if ((SCSI_PT_DIRECT_ACCESS == pdt) ||
1196 (SCSI_PT_HOST_MANAGED == pdt) ||
1197 (SCSI_PT_SEQUENTIAL_ACCESS == pdt) ||
1198 (SCSI_PT_MEDIUM_CHANGER == pdt))
1199 device->set_spc4_or_higher();
1200 }
1201 }
1202 return res;
1203}
1204
1205/* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY
1206 * (unlikely), 2 if command not supported, 3 if field in command not
1207 * supported, 5 if response indicates that EVPD bit ignored or returns
1208 * negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */
1209int
1210scsiInquiryVpd(scsi_device * device, int vpd_page, uint8_t *pBuf, int bufLen)
1211{
1212 struct scsi_cmnd_io io_hdr = {};
1213 struct scsi_sense_disect sinfo;
1214 uint8_t cdb[6] = {};
1215 uint8_t sense[32];
1216 int res;
1217
1218 /* Assume SCSI_VPD_SUPPORTED_VPD_PAGES is first VPD page fetched */
1219 if ((SCSI_VPD_SUPPORTED_VPD_PAGES != vpd_page) &&
1221 (! supported_vpd_pages_p->is_supported(vpd_page)))
1222 return 3;
1223
1224 if ((bufLen < 0) || (bufLen > 1023))
1225 return -EINVAL;
1226try_again:
1227 if (bufLen > 1)
1228 pBuf[1] = 0x0;
1230 io_hdr.dxfer_len = bufLen;
1231 io_hdr.dxferp = pBuf;
1232 cdb[0] = INQUIRY;
1233 cdb[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */
1234 cdb[2] = vpd_page;
1235 sg_put_unaligned_be16(bufLen, cdb + 3);
1236 io_hdr.cmnd = cdb;
1237 io_hdr.cmnd_len = sizeof(cdb);
1238 io_hdr.sensep = sense;
1239 io_hdr.max_sense_len = sizeof(sense);
1241
1242 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1243 return -device->get_errno();
1244 if ((SCSI_STATUS_CHECK_CONDITION == io_hdr.scsi_status) &&
1246 (SCSI_ASC_INVALID_FIELD == sinfo.asc) &&
1247 (cdb[3] > 0)) {
1248 bufLen &= 0xff; /* make sure cdb[3] is 0 next time around */
1249 goto try_again;
1250 }
1251
1252 if ((res = scsiSimpleSenseFilter(&sinfo)))
1253 return res;
1254 /* Guard against devices that ignore EVPD bit and do standard INQUIRY */
1255 if (bufLen > 1) {
1256 if (vpd_page == pBuf[1]) {
1257 if ((0x80 == vpd_page) && (bufLen > 2) && (0x0 != pBuf[2]))
1258 return SIMPLE_ERR_BAD_RESP;
1259 } else
1260 return SIMPLE_ERR_BAD_RESP;
1261 }
1262 return 0;
1263}
1264
1265/* REQUEST SENSE command. Returns 0 if ok, anything else major problem.
1266 * SPC-3 section 6.27 (rev 22a) */
1267int
1268scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
1269{
1270 struct scsi_cmnd_io io_hdr = {};
1271 uint8_t cdb[6] = {};
1272 uint8_t sense[32];
1273 uint8_t buff[18] = {};
1274 bool ok;
1275 static const int sz_buff = sizeof(buff);
1276
1278 io_hdr.dxfer_len = sz_buff;
1279 io_hdr.dxferp = buff;
1280 cdb[0] = REQUEST_SENSE;
1281 cdb[4] = sz_buff;
1282 io_hdr.cmnd = cdb;
1283 io_hdr.cmnd_len = sizeof(cdb);
1284 io_hdr.sensep = sense;
1285 io_hdr.max_sense_len = sizeof(sense);
1287
1288 if (sense_info)
1289 ok = scsi_pass_through_yield_sense(device, &io_hdr, *sense_info);
1290 else {
1291 scsi_sense_disect dummy_sense;
1292 ok = scsi_pass_through_yield_sense(device, &io_hdr, dummy_sense);
1293 }
1294 if (! ok)
1295 return -device->get_errno();
1296 if (sense_info) {
1297 uint8_t resp_code = buff[0] & 0x7f;
1298 sense_info->resp_code = resp_code;
1299 sense_info->sense_key = buff[2] & 0xf;
1300 sense_info->asc = 0;
1301 sense_info->ascq = 0;
1302 if ((0x70 == resp_code) || (0x71 == resp_code)) {
1303 int len = buff[7] + 8;
1304 if (len > 13) {
1305 sense_info->asc = buff[12];
1306 sense_info->ascq = buff[13];
1307 }
1308 }
1309 // fill progress indicator, if available
1310 sense_info->progress = -1;
1311 switch (resp_code) {
1312 const unsigned char * ucp;
1313 int sk, sk_pr;
1314 case 0x70:
1315 case 0x71:
1316 sk = (buff[2] & 0xf);
1317 if (! ((SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk))) {
1318 break;
1319 }
1320 if (buff[15] & 0x80) { /* SKSV bit set */
1321 sense_info->progress = sg_get_unaligned_be16(buff + 16);
1322 break;
1323 } else {
1324 break;
1325 }
1326 case 0x72:
1327 case 0x73:
1328 /* sense key specific progress (0x2) or progress descriptor (0xa) */
1329 sk = (buff[1] & 0xf);
1330 sk_pr = (SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk);
1331 if (sk_pr && ((ucp = sg_scsi_sense_desc_find(buff, sz_buff, 2))) &&
1332 (0x6 == ucp[1]) && (0x80 & ucp[4])) {
1333 sense_info->progress = sg_get_unaligned_be16(ucp + 5);
1334 break;
1335 } else if (((ucp = sg_scsi_sense_desc_find(buff, sz_buff, 0xa))) &&
1336 ((0x6 == ucp[1]))) {
1337 sense_info->progress = sg_get_unaligned_be16(ucp + 6);
1338 break;
1339 } else
1340 break;
1341 default:
1342 return 0;
1343 }
1344 }
1345 return 0;
1346}
1347
1348/* Send Start Stop Unit command with power_condition setting and
1349 * Power condition command. Returns 0 if ok, anything else major problem.
1350 * If power_cond is 0, treat as SSU(START) as that is better than
1351 * SSU(STOP) which would be the case if byte 4 of the cdb was zero.
1352 * Ref: SBC-4 revision 22, section 4.20 SSU and power conditions.
1353 *
1354 * SCSI_POW_COND_ACTIVE 0x1
1355 * SCSI_POW_COND_IDLE 0x2
1356 * SCSI_POW_COND_STANDBY 0x3
1357 *
1358 */
1359
1360int
1361scsiSetPowerCondition(scsi_device * device, int power_cond, int pcond_modifier)
1362{
1363 struct scsi_cmnd_io io_hdr = {};
1364 struct scsi_sense_disect sinfo;
1365 uint8_t cdb[6] = {};
1366 uint8_t sense[32];
1367
1368 io_hdr.dxfer_dir = DXFER_NONE;
1369 cdb[0] = START_STOP_UNIT;
1370 /* IMMED bit (cdb[1] = 0x1) not set, therefore will wait */
1371 if (power_cond > 0) {
1372 cdb[3] = pcond_modifier & 0xf;
1373 cdb[4] = power_cond << 4;
1374 } else
1375 cdb[4] = 0x1; /* START */
1376 io_hdr.cmnd = cdb;
1377 io_hdr.cmnd_len = sizeof(cdb);
1378 io_hdr.sensep = sense;
1379 io_hdr.max_sense_len = sizeof(sense);
1381
1382 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1383 return -device->get_errno();
1384
1385 return scsiSimpleSenseFilter(&sinfo);
1386}
1387
1388/* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command
1389 * not supported, 3 if field in command not supported or returns negated
1390 * errno. SPC-3 section 6.28 (rev 22a) */
1391int
1392scsiSendDiagnostic(scsi_device * device, int functioncode, uint8_t *pBuf,
1393 int bufLen)
1394{
1395 struct scsi_cmnd_io io_hdr = {};
1396 struct scsi_sense_disect sinfo;
1397 uint8_t cdb[6] = {};
1398 uint8_t sense[32];
1399
1400 io_hdr.dxfer_dir = bufLen ? DXFER_TO_DEVICE: DXFER_NONE;
1401 io_hdr.dxfer_len = bufLen;
1402 io_hdr.dxferp = pBuf;
1403 cdb[0] = SEND_DIAGNOSTIC;
1404 if (SCSI_DIAG_DEF_SELF_TEST == functioncode)
1405 cdb[1] = 0x4; /* SelfTest bit */
1406 else if (SCSI_DIAG_NO_SELF_TEST != functioncode)
1407 cdb[1] = (functioncode & 0x7) << 5; /* SelfTest _code_ */
1408 else /* SCSI_DIAG_NO_SELF_TEST == functioncode */
1409 cdb[1] = 0x10; /* PF bit */
1410 sg_put_unaligned_be16(bufLen, cdb + 3);
1411 io_hdr.cmnd = cdb;
1412 io_hdr.cmnd_len = sizeof(cdb);
1413 io_hdr.sensep = sense;
1414 io_hdr.max_sense_len = sizeof(sense);
1415 /* worst case is an extended foreground self test on a big disk */
1417
1418 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1419 return -device->get_errno();
1420 return scsiSimpleSenseFilter(&sinfo);
1421}
1422
1423/* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */
1424static int
1426{
1427 struct scsi_cmnd_io io_hdr = {};
1428 bool ok;
1429 uint8_t cdb[6] = {};
1430 uint8_t sense[32];
1431
1432 io_hdr.dxfer_dir = DXFER_NONE;
1433 io_hdr.dxfer_len = 0;
1434 io_hdr.dxferp = nullptr;
1435 cdb[0] = TEST_UNIT_READY;
1436 io_hdr.cmnd = cdb;
1437 io_hdr.cmnd_len = sizeof(cdb);
1438 io_hdr.sensep = sense;
1439 io_hdr.max_sense_len = sizeof(sense);
1441
1442 if (sinfop)
1443 ok = scsi_pass_through_yield_sense(device, &io_hdr, *sinfop);
1444 else {
1445 struct scsi_sense_disect dummy_si;
1446 ok = scsi_pass_through_yield_sense(device, &io_hdr, dummy_si);
1447 }
1448 if (! ok)
1449 return -device->get_errno();
1450 return 0;
1451}
1452
1453/* Returns 0 for device responds and media ready, 1 for device responds and
1454 media not ready, or returns a negated errno value */
1455int
1457{
1458 struct scsi_sense_disect sinfo;
1459 int status;
1460
1461 status = _testunitready(device, &sinfo);
1462 if (0 != status)
1463 return status;
1464 return scsiSimpleSenseFilter(&sinfo);
1465}
1466
1467/* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
1468 * command not supported, 3 if field in command not supported, 101 if
1469 * defect list not found (e.g. SSD may not have defect list) or returns
1470 * negated errno. SBC-2 section 5.12 (rev 16) */
1471int
1472scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
1473 int dl_format, uint8_t *pBuf, int bufLen)
1474{
1475 struct scsi_cmnd_io io_hdr = {};
1476 struct scsi_sense_disect sinfo;
1477 uint8_t cdb[10] = {};
1478 uint8_t sense[32];
1479
1481 io_hdr.dxfer_len = bufLen;
1482 io_hdr.dxferp = pBuf;
1483 cdb[0] = READ_DEFECT_10;
1484 cdb[2] = (unsigned char)(((req_plist << 4) & 0x10) |
1485 ((req_glist << 3) & 0x8) | (dl_format & 0x7));
1486 sg_put_unaligned_be16(bufLen, cdb + 7);
1487 io_hdr.cmnd = cdb;
1488 io_hdr.cmnd_len = sizeof(cdb);
1489 io_hdr.sensep = sense;
1490 io_hdr.max_sense_len = sizeof(sense);
1492
1493 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1494 return -device->get_errno();
1495 /* Look for "(Primary|Grown) defect list not found" */
1496 if ((sinfo.resp_code >= 0x70) && (0x1c == sinfo.asc))
1497 return 101;
1498 return scsiSimpleSenseFilter(&sinfo);
1499}
1500
1501/* READ DEFECT (12) command. Returns 0 if ok, 1 if NOT READY, 2 if
1502 * command not supported, 3 if field in command not supported, 101 if
1503 * defect list not found (e.g. SSD may not have defect list) or returns
1504 * negated errno. SBC-3 section 5.18 (rev 35; vale Mark Evans) */
1505int
1506scsiReadDefect12(scsi_device * device, int req_plist, int req_glist,
1507 int dl_format, int addrDescIndex, uint8_t *pBuf, int bufLen)
1508{
1509 struct scsi_cmnd_io io_hdr = {};
1510 struct scsi_sense_disect sinfo;
1511 uint8_t cdb[12] = {};
1512 uint8_t sense[32];
1513
1515 io_hdr.dxfer_len = bufLen;
1516 io_hdr.dxferp = pBuf;
1517 cdb[0] = READ_DEFECT_12;
1518 cdb[1] = (unsigned char)(((req_plist << 4) & 0x10) |
1519 ((req_glist << 3) & 0x8) | (dl_format & 0x7));
1520 sg_put_unaligned_be32(addrDescIndex, cdb + 2);
1521 sg_put_unaligned_be32(bufLen, cdb + 6);
1522 io_hdr.cmnd = cdb;
1523 io_hdr.cmnd_len = sizeof(cdb);
1524 io_hdr.sensep = sense;
1525 io_hdr.max_sense_len = sizeof(sense);
1527
1528 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1529 return -device->get_errno();
1530 /* Look for "(Primary|Grown) defect list not found" */
1531 if ((sinfo.resp_code >= 0x70) && (0x1c == sinfo.asc))
1532 return 101;
1533 return scsiSimpleSenseFilter(&sinfo);
1534}
1535
1536/* Call scsi_pass_through, and retry only if a UNIT_ATTENTION (UA) is raised.
1537 * When false returned, the caller should invoke device->get_error().
1538 * When true returned, the caller should check sinfo.
1539 * All SCSI commands can receive pending Unit Attentions, apart from:
1540 * INQUIRY, REPORT LUNS, REQUEST SENSE and NOTIFY DATA TRANSFER DEVICE
1541 * (ADC-3 spec). The first three are the important ones. */
1542bool
1544 /* OUT param */ scsi_sense_disect & sinfo)
1545{
1546 int k;
1547 uint32_t opcode = (iop->cmnd_len > 0) ? iop->cmnd[0] : 0xffff;
1548
1549 if (scsi_debugmode > 2) {
1550 bool dout = false;
1551 const char * ddir = "none";
1552 const char * np;
1553
1554 if (iop->dxfer_len > 0) {
1555 dout = (DXFER_TO_DEVICE == iop->dxfer_dir);
1556 ddir = dout ? "out" : "in";
1557 }
1558 np = scsi_get_opcode_name(iop->cmnd);
1559 pout(" [%s: ", np ? np : "<unknown opcode>");
1560 pout("SCSI opcode=0x%x, CDB length=%u, data length=0x%u, data "
1561 "dir=%s]\n", opcode, (unsigned int)iop->cmnd_len,
1562 (unsigned int)iop->dxfer_len, ddir);
1563 if (dout && (scsi_debugmode > 3)) /* output hex without address */
1564 dStrHexFp(iop->dxferp, iop->dxfer_len, -1, nullptr);
1565 }
1566
1567 if (! device->scsi_pass_through(iop))
1568 return false; // this will be missing device, timeout, etc
1569
1570 if (scsi_debugmode > 3) {
1571 unsigned int req_len = iop->dxfer_len;
1572 unsigned int act_len;
1573
1574 if ((req_len > 0) && (DXFER_FROM_DEVICE == iop->dxfer_dir) &&
1575 (iop->resid >= 0) && (req_len >= (unsigned int)iop->resid)) {
1576 act_len = req_len - (unsigned int)iop->resid;
1577 pout(" [data-in buffer: req_len=%u, resid=%d, gives %u "
1578 "bytes]\n", req_len, iop->resid, act_len);
1579 dStrHexFp(iop->dxferp, act_len, -1, nullptr);
1580 }
1581 }
1582 scsi_do_sense_disect(iop, &sinfo);
1583
1584 switch (opcode) {
1585 case INQUIRY:
1586 case REPORT_LUNS:
1587 case REQUEST_SENSE:
1588 return true; /* in these cases, it shouldn't be a UA */
1589 default:
1590 break; /* continue on for all other SCSI commands to check for UA */
1591 }
1592
1593 /* There can be multiple UAs pending, allow for three */
1594 for (k = 0; (k < 3) && (SCSI_SK_UNIT_ATTENTION == sinfo.sense_key); ++k) {
1595 if (scsi_debugmode > 0)
1596 pout("%s Unit Attention %d: asc/ascq=0x%x,0x%x, retrying\n",
1597 __func__, k + 1, sinfo.asc, sinfo.ascq);
1598 if (! device->scsi_pass_through(iop))
1599 return false;
1600 scsi_do_sense_disect(iop, &sinfo);
1601 }
1602 return true;
1603}
1604
1605/* READ CAPACITY (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
1606 * command not supported, 3 if field in command not supported or returns
1607 * negated errno. SBC-3 section 5.15 (rev 26) */
1608int
1609scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap,
1610 unsigned int * lb_sizep)
1611{
1612 int res;
1613 struct scsi_cmnd_io io_hdr = {};
1614 struct scsi_sense_disect sinfo;
1615 uint8_t cdb[10] = {};
1616 uint8_t sense[32];
1617 uint8_t resp[8] = {};
1618
1620 io_hdr.dxfer_len = sizeof(resp);
1621 io_hdr.dxferp = resp;
1622 cdb[0] = READ_CAPACITY_10;
1623 io_hdr.cmnd = cdb;
1624 io_hdr.cmnd_len = sizeof(cdb);
1625 io_hdr.sensep = sense;
1626 io_hdr.max_sense_len = sizeof(sense);
1628
1629 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1630 return -device->get_errno();
1631 res = scsiSimpleSenseFilter(&sinfo);
1632 if (res)
1633 return res;
1634 if (last_lbap)
1635 *last_lbap = sg_get_unaligned_be32(resp + 0);
1636 if (lb_sizep)
1637 *lb_sizep = sg_get_unaligned_be32(resp + 4);
1638 return 0;
1639}
1640
1641/* READ CAPACITY (16) command. The bufLen argument should be 32. Returns 0
1642 * if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command
1643 * not supported or returns negated errno. SBC-3 section 5.16 (rev 26) */
1644int
1645scsiReadCapacity16(scsi_device * device, uint8_t *pBuf, int bufLen)
1646{
1647 struct scsi_cmnd_io io_hdr = {};
1648 struct scsi_sense_disect sinfo;
1649 uint8_t cdb[16] = {};
1650 uint8_t sense[32];
1651
1653 io_hdr.dxfer_len = bufLen;
1654 io_hdr.dxferp = pBuf;
1657 sg_put_unaligned_be32(bufLen, cdb + 10);
1658 io_hdr.cmnd = cdb;
1659 io_hdr.cmnd_len = sizeof(cdb);
1660 io_hdr.sensep = sense;
1661 io_hdr.max_sense_len = sizeof(sense);
1663
1664 if (!scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1665 return -device->get_errno();
1666 return scsiSimpleSenseFilter(&sinfo);
1667}
1668
1669/* REPORT SUPPORTED OPERATION CODES [RSOC] command. If SIMPLE_NO_ERROR is
1670 * returned then the response length is written to rspLen. */
1671int
1672scsiRSOCcmd(scsi_device * device, bool rctd, uint8_t rep_opt, uint8_t opcode,
1673 uint16_t serv_act, uint8_t *pBuf, int bufLen, int & rspLen)
1674{
1675 struct scsi_cmnd_io io_hdr = {};
1676 struct scsi_sense_disect sinfo;
1677 int res;
1678 uint8_t cdb[12] = {};
1679 uint8_t sense[32];
1680
1682 io_hdr.dxfer_len = bufLen;
1683 io_hdr.dxferp = pBuf;
1686 if (rctd)
1687 cdb[2] |= 0x80;
1688 if (rep_opt > 0)
1689 cdb[2] |= (0x7 & rep_opt);
1690 cdb[3] = opcode;
1691 sg_put_unaligned_be16(serv_act, cdb + 4);
1692 sg_put_unaligned_be32(bufLen, cdb + 6);
1693 io_hdr.cmnd = cdb;
1694 io_hdr.cmnd_len = sizeof(cdb);
1695 io_hdr.sensep = sense;
1696 io_hdr.max_sense_len = sizeof(sense);
1698
1699 if (!scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1700 return -device->get_errno();
1701 res = scsiSimpleSenseFilter(&sinfo);
1702 if (SIMPLE_NO_ERROR == res)
1703 rspLen = bufLen - io_hdr.resid;
1704 return res;
1705}
1706
1707/* Return number of bytes of storage in 'device' or 0 if error. If
1708 * successful and lb_sizep is not nullptr then the logical block size in bytes
1709 * is written to the location pointed to by lb_sizep. If the 'Logical Blocks
1710 * per Physical Block Exponent' pointer (lb_per_pb_expp,) is non-null then
1711 * the value is written. If 'Protection information Intervals Exponent'*/
1712uint64_t
1713scsiGetSize(scsi_device * device, bool avoid_rcap16,
1714 struct scsi_readcap_resp * srrp)
1715{
1716 bool try_16 = false;
1717 bool try_12 = false;
1718 unsigned int last_lba = 0, lb_size = 0;
1719 int res;
1720 uint64_t ret_val = 0;
1721 uint8_t rc16resp[32];
1722
1723 if (avoid_rcap16) {
1724 res = scsiReadCapacity10(device, &last_lba, &lb_size);
1725 if (res) {
1726 if (scsi_debugmode)
1727 pout("%s: READ CAPACITY(10) failed, res=%d\n", __func__, res);
1728 try_16 = true;
1729 } else { /* rcap10 succeeded */
1730 if (0xffffffff == last_lba) {
1731 /* so number of blocks needs > 32 bits to represent */
1732 try_16 = true;
1733 device->set_rcap16_first();
1734 } else {
1735 ret_val = last_lba + 1;
1736 if (srrp) {
1737 memset(srrp, 0, sizeof(*srrp));
1738 srrp->num_lblocks = ret_val;
1739 srrp->lb_size = lb_size;
1740 }
1741 }
1742 }
1743 } else if (SC_SUPPORT ==
1746 try_16 = true;
1747
1748 if (try_16 || (! avoid_rcap16)) {
1749 res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp));
1750 if (res) {
1751 if (scsi_debugmode)
1752 pout("%s: READ CAPACITY(16) failed, res=%d\n", __func__, res);
1753 if (try_16) /* so already tried rcap10 */
1754 return 0;
1755 try_12 = true;
1756 } else { /* rcap16 succeeded */
1757 ret_val = sg_get_unaligned_be64(rc16resp + 0) + 1;
1758 lb_size = sg_get_unaligned_be32(rc16resp + 8);
1759 if (srrp) { /* writes to all fields */
1760 srrp->num_lblocks = ret_val;
1761 srrp->lb_size = lb_size;
1762 bool prot_en = !!(0x1 & rc16resp[12]);
1763 uint8_t p_type = ((rc16resp[12] >> 1) & 0x7);
1764 srrp->prot_type = prot_en ? (1 + p_type) : 0;
1765 srrp->p_i_exp = ((rc16resp[13] >> 4) & 0xf);
1766 srrp->lb_p_pb_exp = (rc16resp[13] & 0xf);
1767 srrp->lbpme = !!(0x80 & rc16resp[14]);
1768 srrp->lbprz = !!(0x40 & rc16resp[14]);
1769 srrp->l_a_lba = sg_get_unaligned_be16(rc16resp + 14) & 0x3fff;
1770 }
1771 }
1772 }
1773 if (try_12) { /* case where only rcap16 has been tried and failed */
1774 res = scsiReadCapacity10(device, &last_lba, &lb_size);
1775 if (res) {
1776 if (scsi_debugmode)
1777 pout("%s: 2nd READ CAPACITY(10) failed, res=%d\n", __func__,
1778 res);
1779 return 0;
1780 } else { /* rcap10 succeeded */
1781 ret_val = (uint64_t)last_lba + 1;
1782 if (srrp) {
1783 memset(srrp, 0, sizeof(*srrp));
1784 srrp->num_lblocks = ret_val;
1785 srrp->lb_size = lb_size;
1786 }
1787 }
1788 }
1789 return (ret_val * lb_size);
1790}
1791
1792/* Offset into mode sense (6 or 10 byte) response that actual mode page
1793 * starts at (relative to resp[0]). Returns -1 if problem */
1794int
1795scsiModePageOffset(const uint8_t * resp, int len, int modese_len)
1796{
1797 int offset = -1;
1798
1799 if (resp) {
1800 int resp_len, bd_len;
1801 if (10 == modese_len) {
1802 resp_len = sg_get_unaligned_be16(resp + 0) + 2;
1803 bd_len = sg_get_unaligned_be16(resp + 6);
1804 offset = bd_len + 8;
1805 } else {
1806 resp_len = resp[0] + 1;
1807 bd_len = resp[3];
1808 offset = bd_len + 4;
1809 }
1810 if ((offset + 2) > len) {
1811 pout("scsiModePageOffset: raw_curr too small, offset=%d "
1812 "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len);
1813 offset = -1;
1814 } else if ((offset + 2) > resp_len) {
1815 if ((resp_len > 2) || scsi_debugmode)
1816 pout("scsiModePageOffset: response length too short, "
1817 "resp_len=%d offset=%d bd_len=%d\n", resp_len,
1818 offset, bd_len);
1819 offset = -1;
1820 }
1821 }
1822 return offset;
1823}
1824
1825/* IEC mode page byte 2 bit masks */
1826#define DEXCPT_ENABLE 0x08
1827#define EWASC_ENABLE 0x10
1828#define DEXCPT_DISABLE 0xf7
1829#define EWASC_DISABLE 0xef
1830#define TEST_DISABLE 0xfb
1831
1832/* Fetches the Informational Exceptions Control mode page. First tries
1833 * the 6 byte MODE SENSE command and if that fails with an illegal opcode
1834 * tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive
1835 * number if a known error (see SIMPLE_ERR_ ...) or a negative errno
1836 * value. */
1837int
1839 int modese_len)
1840{
1841 int err = 0;
1842
1843 memset(iecp, 0, sizeof(*iecp));
1844 iecp->modese_len = modese_len;
1845 iecp->requestedCurrent = 1;
1846 if (iecp->modese_len <= 6) {
1849 iecp->raw_curr, sizeof(iecp->raw_curr)))) {
1850 if (SIMPLE_ERR_BAD_OPCODE == err)
1851 iecp->modese_len = 10;
1852 else {
1853 iecp->modese_len = 0;
1854 return err;
1855 }
1856 } else if (0 == iecp->modese_len)
1857 iecp->modese_len = 6;
1858 }
1859 if (10 == iecp->modese_len) {
1862 iecp->raw_curr, sizeof(iecp->raw_curr));
1863 if (err) {
1864 iecp->modese_len = 0;
1865 return err;
1866 }
1867 }
1868 iecp->gotCurrent = 1;
1869 iecp->requestedChangeable = 1;
1870 if (10 == iecp->modese_len)
1873 iecp->raw_chg, sizeof(iecp->raw_chg));
1874 else if (6 == iecp->modese_len)
1877 iecp->raw_chg, sizeof(iecp->raw_chg));
1878 if (err)
1879 return err;
1880 iecp->gotChangeable = 1;
1881 return 0;
1882}
1883
1884int
1886{
1887 if (iecp && iecp->gotCurrent) {
1888 int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1889 iecp->modese_len);
1890 if (offset >= 0)
1891 return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1892 else
1893 return 0;
1894 } else
1895 return 0;
1896}
1897
1898int
1900{
1901 if (iecp && iecp->gotCurrent) {
1902 int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1903 iecp->modese_len);
1904 if (offset >= 0)
1905 return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0;
1906 else
1907 return 0;
1908 } else
1909 return 0;
1910}
1911
1912/* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */
1913#define SCSI_IEC_MP_BYTE2_ENABLED 0x10
1914#define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4
1915/* exception/warning via an unrequested REQUEST SENSE command */
1916#define SCSI_IEC_MP_MRIE 6
1917#define SCSI_IEC_MP_INTERVAL_T 0
1918#define SCSI_IEC_MP_REPORT_COUNT 1
1919
1920/* Try to set (or clear) both Exception Control and Warning in the IE
1921 * mode page subject to the "changeable" mask. The object pointed to
1922 * by iecp is (possibly) inaccurate after this call, therefore
1923 * scsiFetchIECmpage() should be called again if the IEC mode page
1924 * is to be re-examined.
1925 * When -r ioctl is invoked 3 or more time on 'smartctl -s on ...'
1926 * then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */
1927int
1929 const struct scsi_iec_mode_page *iecp)
1930{
1931 int offset, resp_len;
1932 int err = 0;
1933 uint8_t rout[SCSI_IECMP_RAW_LEN];
1934
1935 if ((! iecp) || (! iecp->gotCurrent))
1936 return -EINVAL;
1937 offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1938 iecp->modese_len);
1939 if (offset < 0)
1940 return -EINVAL;
1941 memcpy(rout, iecp->raw_curr, SCSI_IECMP_RAW_LEN);
1942 /* mask out DPOFUA device specific (disk) parameter bit */
1943 if (10 == iecp->modese_len) {
1944 resp_len = sg_get_unaligned_be16(rout + 0) + 2;
1945 rout[3] &= 0xef;
1946 } else {
1947 resp_len = rout[0] + 1;
1948 rout[2] &= 0xef;
1949 }
1950 int sp = !! (rout[offset] & 0x80); /* PS bit becomes 'SELECT's SP bit */
1951 if (enabled) {
1952 rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
1953 if (scsi_debugmode > 2)
1954 rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK;
1955 rout[offset + 3] = SCSI_IEC_MP_MRIE;
1958 if (iecp->gotChangeable) {
1959 uint8_t chg2 = iecp->raw_chg[offset + 2];
1960
1961 rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) :
1962 iecp->raw_curr[offset + 2];
1963 for (int k = 3; k < 12; ++k) {
1964 if (0 == iecp->raw_chg[offset + k])
1965 rout[offset + k] = iecp->raw_curr[offset + k];
1966 }
1967 }
1968 if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) {
1969 if (scsi_debugmode > 0)
1970 pout("scsiSetExceptionControlAndWarning: already enabled\n");
1971 return 0;
1972 }
1973 } else { /* disabling Exception Control and (temperature) Warnings */
1974 int eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1975 int wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0;
1976 if ((! eCEnabled) && (! wEnabled)) {
1977 if (scsi_debugmode > 0)
1978 pout("scsiSetExceptionControlAndWarning: already disabled\n");
1979 return 0; /* nothing to do, leave other setting alone */
1980 }
1981 if (wEnabled)
1982 rout[offset + 2] &= EWASC_DISABLE;
1983 if (eCEnabled) {
1984 if (iecp->gotChangeable &&
1985 (iecp->raw_chg[offset + 2] & DEXCPT_ENABLE))
1986 rout[offset + 2] |= DEXCPT_ENABLE;
1987 rout[offset + 2] &= TEST_DISABLE; /* clear TEST bit for spec */
1988 }
1989 }
1990 if (10 == iecp->modese_len)
1991 err = scsiModeSelect10(device, sp, rout, resp_len);
1992 else if (6 == iecp->modese_len)
1993 err = scsiModeSelect(device, sp, rout, resp_len);
1994 return err;
1995}
1996
1997int
1998scsiGetTemp(scsi_device * device, uint8_t *currenttemp, uint8_t *triptemp)
1999{
2000 uint8_t tBuf[252] = {};
2001 int err;
2002
2003 if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 0, tBuf,
2004 sizeof(tBuf), 0))) {
2005 *currenttemp = 0;
2006 *triptemp = 0;
2007 pout("%s for temperature failed [%s]\n", logSenStr,
2008 scsiErrString(err));
2009 return err;
2010 }
2011 *currenttemp = tBuf[9];
2012 *triptemp = tBuf[15];
2013 return 0;
2014}
2015
2016/* Informational Exception conditions specified by spc6r06.pdf seem to be
2017 * associated with ASC values 0xb (warnings) and 0x5d (impending failures).
2018 * The asc/accq value 0x5d,0xff is reported in response to setting the TEST
2019 * bit in the Informationl Exception Control mode page. */
2020
2021/* Read informational exception log page or Request Sense response.
2022 * Fetching asc/ascq code potentially flagging an exception or warning.
2023 * Returns 0 if ok, else error number. A current temperature of 255
2024 * (Celsius) implies that the temperature not available. */
2025int
2026scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
2027 uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp,
2028 uint8_t *triptemp)
2029{
2030 uint8_t tBuf[252] = {};
2031 struct scsi_sense_disect sense_info;
2032 int err;
2033 uint8_t currTemp, trTemp;
2034
2035 memset(&sense_info, 0, sizeof(sense_info));
2036 *asc = 0;
2037 *ascq = 0;
2038 *currenttemp = 0;
2039 *triptemp = 0;
2040 if (hasIELogPage) {
2041 if ((err = scsiLogSense(device, IE_LPAGE, 0, tBuf,
2042 sizeof(tBuf), 0))) {
2043 pout("%s failed, IE page [%s]\n", logSenStr, scsiErrString(err));
2044 return err;
2045 }
2046 // pull out page size from response, don't forget to add 4
2047 unsigned short pagesize = sg_get_unaligned_be16(tBuf + 2) + 4;
2048 if ((pagesize < 4) || tBuf[4] || tBuf[5]) {
2049 pout("%s failed, IE page, bad parameter code or length\n",
2050 logSenStr);
2051 return SIMPLE_ERR_BAD_PARAM;
2052 }
2053 if (tBuf[7] > 1) {
2054 sense_info.asc = tBuf[8];
2055 sense_info.ascq = tBuf[9];
2056 if (! hasTempLogPage) {
2057 if (tBuf[7] > 2)
2058 *currenttemp = tBuf[10];
2059 if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */
2060 *triptemp = tBuf[11];
2061 }
2062 }
2063 }
2064 if (0 == sense_info.asc) {
2065 /* ties in with MRIE field of 6 in IEC mode page (0x1c) */
2066 if ((err = scsiRequestSense(device, &sense_info))) {
2067 pout("Request Sense failed, [%s]\n", scsiErrString(err));
2068 return err;
2069 }
2070 }
2071 *asc = sense_info.asc;
2072 *ascq = sense_info.ascq;
2073 if (hasTempLogPage) {
2074 if (0 == scsiGetTemp(device, &currTemp, &trTemp)) {
2075 *currenttemp = currTemp;
2076 *triptemp = trTemp;
2077 }
2078 }
2079 return 0;
2080}
2081
2082// The first character (W, C, I) tells the severity
2083static const char * TapeAlertsMessageTable[]= {
2084 " ",
2085 /* 0x01 */
2086 "W: The tape drive is having problems reading data. No data has been "
2087 "lost,\n"
2088 " but there has been a reduction in the performance of the tape.",
2089 /* 0x02 */
2090 "W: The tape drive is having problems writing data. No data has been "
2091 "lost,\n"
2092 " but there has been a reduction in the capacity of the tape.",
2093 /* 0x03 */
2094 "W: The operation has stopped because an error has occurred while "
2095 "reading\n"
2096 " or writing data that the drive cannot correct.",
2097 /* 0x04 */
2098 "C: Your data is at risk:\n"
2099 " 1. Copy any data you require from this tape. \n"
2100 " 2. Do not use this tape again.\n"
2101 " 3. Restart the operation with a different tape.",
2102 /* 0x05 */
2103 "C: The tape is damaged or the drive is faulty. Call the tape drive\n"
2104 " supplier helpline.",
2105 /* 0x06 */
2106 "C: The tape is from a faulty batch or the tape drive is faulty:\n"
2107 " 1. Use a good tape to test the drive.\n"
2108 " 2. If problem persists, call the tape drive supplier helpline.",
2109 /* 0x07 */
2110 "W: The tape cartridge has reached the end of its calculated useful "
2111 "life:\n"
2112 " 1. Copy data you need to another tape.\n"
2113 " 2. Discard the old tape.",
2114 /* 0x08 */
2115 "W: The tape cartridge is not data-grade. Any data you back up to the "
2116 "tape\n"
2117 " is at risk. Replace the cartridge with a data-grade tape.",
2118 /* 0x09 */
2119 "C: You are trying to write to a write-protected cartridge. Remove the\n"
2120 " write-protection or use another tape.",
2121 /* 0x0a */
2122 "I: You cannot eject the cartridge because the tape drive is in use. "
2123 "Wait\n"
2124 " until the operation is complete before ejecting the cartridge.",
2125 /* 0x0b */
2126 "I: The tape in the drive is a cleaning cartridge.",
2127 /* 0x0c */
2128 "I: You have tried to load a cartridge of a type which is not supported\n"
2129 " by this drive.",
2130 /* 0x0d */
2131 "C: The operation has failed because the tape in the drive has "
2132 "experienced\n"
2133 " a mechanical failure:\n"
2134 " 1. Discard the old tape.\n"
2135 " 2. Restart the operation with a different tape.",
2136 /* 0x0e */
2137 "C: The operation has failed because the tape in the drive has "
2138 "experienced\n"
2139 " a mechanical failure:\n"
2140 " 1. Do not attempt to extract the tape cartridge\n"
2141 " 2. Call the tape drive supplier helpline.",
2142 /* 0x0f */
2143 "W: The memory in the tape cartridge has failed, which reduces\n"
2144 " performance. Do not use the cartridge for further write "
2145 "operations.",
2146 /* 0x10 */
2147 "C: The operation has failed because the tape cartridge was manually\n"
2148 " de-mounted while the tape drive was actively writing or reading.",
2149 /* 0x11 */
2150 "W: You have loaded a cartridge of a type that is read-only in this "
2151 "drive.\n"
2152 " The cartridge will appear as write-protected.",
2153 /* 0x12 */
2154 "W: The tape directory on the tape cartridge has been corrupted. File\n"
2155 " search performance will be degraded. The tape directory can be "
2156 "rebuilt\n"
2157 " by reading all the data on the cartridge.",
2158 /* 0x13 */
2159 "I: The tape cartridge is nearing the end of its calculated life. It is\n"
2160 " recommended that you:\n"
2161 " 1. Use another tape cartridge for your next backup.\n"
2162 " 2. Store this tape in a safe place in case you need to restore "
2163 " data from it.",
2164 /* 0x14 */
2165 "C: The tape drive needs cleaning:\n"
2166 " 1. If the operation has stopped, eject the tape and clean the "
2167 "drive.\n"
2168 " 2. If the operation has not stopped, wait for it to finish and "
2169 "then\n"
2170 " clean the drive.\n"
2171 " Check the tape drive users manual for device specific cleaning "
2172 "instructions.",
2173 /* 0x15 */
2174 "W: The tape drive is due for routine cleaning:\n"
2175 " 1. Wait for the current operation to finish.\n"
2176 " 2. The use a cleaning cartridge.\n"
2177 " Check the tape drive users manual for device specific cleaning "
2178 "instructions.",
2179 /* 0x16 */
2180 "C: The last cleaning cartridge used in the tape drive has worn out:\n"
2181 " 1. Discard the worn out cleaning cartridge.\n"
2182 " 2. Wait for the current operation to finish.\n"
2183 " 3. Then use a new cleaning cartridge.",
2184 /* 0x17 */
2185 "C: The last cleaning cartridge used in the tape drive was an invalid\n"
2186 " type:\n"
2187 " 1. Do not use this cleaning cartridge in this drive.\n"
2188 " 2. Wait for the current operation to finish.\n"
2189 " 3. Then use a new cleaning cartridge.",
2190 /* 0x18 */
2191 "W: The tape drive has requested a retention operation",
2192 /* 0x19 */
2193 "W: A redundant interface port on the tape drive has failed",
2194 /* 0x1a */
2195 "W: A tape drive cooling fan has failed",
2196 /* 0x1b */
2197 "W: A redundant power supply has failed inside the tape drive enclosure.\n"
2198 " Check the enclosure users manual for instructions on replacing "
2199 "the\n"
2200 " failed power supply.",
2201 /* 0x1c */
2202 "W: The tape drive power consumption is outside the specified range.",
2203 /* 0x1d */
2204 "W: Preventive maintenance of the tape drive is required. Check the tape\n"
2205 " drive users manual for device specific preventive maintenance\n"
2206 " tasks or call the tape drive supplier helpline.",
2207 /* 0x1e */
2208 "C: The tape drive has a hardware fault:\n"
2209 " 1. Eject the tape or magazine.\n"
2210 " 2. Reset the drive.\n"
2211 " 3. Restart the operation.",
2212 /* 0x1f */
2213 "C: The tape drive has a hardware fault:\n"
2214 " 1. Turn the tape drive off and then on again.\n"
2215 " 2. Restart the operation.\n"
2216 " 3. If the problem persists, call the tape drive supplier helpline.",
2217 /* 0x20 */
2218 "W: The tape drive has a problem with the application client interface:\n"
2219 " 1. Check the cables and cable connections.\n"
2220 " 2. Restart the operation.",
2221 /* 0x21 */
2222 "C: The operation has failed:\n"
2223 " 1. Eject the tape or magazine.\n"
2224 " 2. Insert the tape or magazine again.\n"
2225 " 3. Restart the operation.",
2226 /* 0x22 */
2227 "W: The firmware download has failed because you have tried to use the\n"
2228 " incorrect firmware for this tape drive. Obtain the correct\n"
2229 " firmware and try again.",
2230 /* 0x23 */
2231 "W: Environmental conditions inside the tape drive are outside the\n"
2232 " specified humidity range.",
2233 /* 0x24 */
2234 "W: Environmental conditions inside the tape drive are outside the\n"
2235 " specified temperature range.",
2236 /* 0x25 */
2237 "W: The voltage supply to the tape drive is outside the specified range.",
2238 /* 0x26 */
2239 "C: A hardware failure of the tape drive is predicted. Call the tape\n"
2240 " drive supplier helpline.",
2241 /* 0x27 */
2242 "W: The tape drive may have a hardware fault. Run extended diagnostics to\n"
2243 " verify and diagnose the problem. Check the tape drive users manual "
2244 "for\n"
2245 " device specific instructions on running extended diagnostic tests.",
2246 /* 0x28 */
2247 "C: The changer mechanism is having difficulty communicating with the "
2248 "tape\n"
2249 " drive:\n"
2250 " 1. Turn the autoloader off then on.\n"
2251 " 2. Restart the operation.\n"
2252 " 3. If problem persists, call the tape drive supplier helpline.",
2253 /* 0x29 */
2254 "C: A tape has been left in the autoloader by a previous hardware fault:\n"
2255 " 1. Insert an empty magazine to clear the fault.\n"
2256 " 2. If the fault does not clear, turn the autoloader off and then\n"
2257 " on again.\n"
2258 " 3. If the problem persists, call the tape drive supplier helpline.",
2259 /* 0x2a */
2260 "W: There is a problem with the autoloader mechanism.",
2261 /* 0x2b */
2262 "C: The operation has failed because the autoloader door is open:\n"
2263 " 1. Clear any obstructions from the autoloader door.\n"
2264 " 2. Eject the magazine and then insert it again.\n"
2265 " 3. If the fault does not clear, turn the autoloader off and then\n"
2266 " on again.\n"
2267 " 4. If the problem persists, call the tape drive supplier helpline.",
2268 /* 0x2c */
2269 "C: The autoloader has a hardware fault:\n"
2270 " 1. Turn the autoloader off and then on again.\n"
2271 " 2. Restart the operation.\n"
2272 " 3. If the problem persists, call the tape drive supplier helpline.\n"
2273 " Check the autoloader users manual for device specific instructions\n"
2274 " on turning the device power on and off.",
2275 /* 0x2d */
2276 "C: The autoloader cannot operate without the magazine,\n"
2277 " 1. Insert the magazine into the autoloader.\n"
2278 " 2. Restart the operation.",
2279 /* 0x2e */
2280 "W: A hardware failure of the changer mechanism is predicted. Call the\n"
2281 " tape drive supplier helpline.",
2282 /* 0x2f */
2283 "I: Reserved.",
2284 /* 0x30 */
2285 "I: Reserved.",
2286 /* 0x31 */
2287 "I: Reserved.",
2288 /* 0x32 */
2289 "W: Media statistics have been lost at some time in the past",
2290 /* 0x33 */
2291 "W: The tape directory on the tape cartridge just unloaded has been\n"
2292 " corrupted. File search performance will be degraded. The tape\n"
2293 " directory can be rebuilt by reading all the data.",
2294 /* 0x34 */
2295 "C: The tape just unloaded could not write its system area successfully:\n"
2296 " 1. Copy data to another tape cartridge.\n"
2297 " 2. Discard the old cartridge.",
2298 /* 0x35 */
2299 "C: The tape system are could not be read successfully at load time:\n"
2300 " 1. Copy data to another tape cartridge.\n",
2301 /* 0x36 */
2302 "C: The start or data could not be found on the tape:\n"
2303 " 1. Check you are using the correct format tape.\n"
2304 " 2. Discard the tape or return the tape to your supplier",
2305 /* 0x37 */
2306 "C: The operation has failed because the media cannot be loaded\n"
2307 " and threaded.\n"
2308 " 1. Remove the cartridge, inspect it as specified in the product\n"
2309 " manual, and retry the operation.\n"
2310 " 2. If the problem persists, call the tape drive supplier help "
2311 "line.",
2312 /* 0x38 */
2313 "C: The operation has failed because the medium cannot be unloaded:\n"
2314 " 1. Do not attempt to extract the tape cartridge.\n"
2315 " 2. Call the tape driver supplier help line.",
2316 /* 0x39 */
2317 "C: The tape drive has a problem with the automation interface:\n"
2318 " 1. Check the power to the automation system.\n"
2319 " 2. Check the cables and cable connections.\n"
2320 " 3. Call the supplier help line if problem persists.",
2321 /* 0x3a */
2322 "W: The tape drive has reset itself due to a detected firmware\n"
2323 " fault. If problem persists, call the supplier help line.",
2324 };
2325
2326const char *
2327scsiTapeAlertsTapeDevice(unsigned short code)
2328{
2329 static const int num = sizeof(TapeAlertsMessageTable) /
2330 sizeof(TapeAlertsMessageTable[0]);
2331
2332 return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert";
2333}
2334
2335// The first character (W, C, I) tells the severity
2336static const char * ChangerTapeAlertsMessageTable[]= {
2337 " ",
2338 /* 0x01 */
2339 "C: The library mechanism is having difficulty communicating with the\n"
2340 " drive:\n"
2341 " 1. Turn the library off then on.\n"
2342 " 2. Restart the operation.\n"
2343 " 3. If the problem persists, call the library supplier help line.",
2344 /* 0x02 */
2345 "W: There is a problem with the library mechanism. If problem persists,\n"
2346 " call the library supplier help line.",
2347 /* 0x03 */
2348 "C: The library has a hardware fault:\n"
2349 " 1. Reset the library.\n"
2350 " 2. Restart the operation.\n"
2351 " Check the library users manual for device specific instructions on "
2352 "resetting\n"
2353 " the device.",
2354 /* 0x04 */
2355 "C: The library has a hardware fault:\n"
2356 " 1. Turn the library off then on again.\n"
2357 " 2. Restart the operation.\n"
2358 " 3. If the problem persists, call the library supplier help line.\n"
2359 " Check the library users manual for device specific instructions on "
2360 "turning the\n"
2361 " device power on and off.",
2362 /* 0x05 */
2363 "W: The library mechanism may have a hardware fault.\n"
2364 " Run extended diagnostics to verify and diagnose the problem. "
2365 "Check the library\n"
2366 " users manual for device specific instructions on running extended "
2367 "diagnostic\n"
2368 " tests.",
2369 /* 0x06 */
2370 "C: The library has a problem with the host interface:\n"
2371 " 1. Check the cables and connections.\n"
2372 " 2. Restart the operation.",
2373 /* 0x07 */
2374 "W: A hardware failure of the library is predicted. Call the library\n"
2375 " supplier help line.",
2376 /* 0x08 */
2377 "W: Preventive maintenance of the library is required.\n"
2378 " Check the library users manual for device specific preventative "
2379 "maintenance\n"
2380 " tasks, or call your library supplier help line.",
2381 /* 0x09 */
2382 "C: General environmental conditions inside the library are outside the\n"
2383 " specified humidity range.",
2384 /* 0x0a */
2385 "C: General environmental conditions inside the library are outside the\n"
2386 " specified temperature range.",
2387 /* 0x0b */
2388 "C: The voltage supply to the library is outside the specified range.\n"
2389 " There is a potential problem with the power supply or failure of\n"
2390 " a redundant power supply.",
2391 /* 0x0c */
2392 "C: A cartridge has been left inside the library by a previous hardware\n"
2393 " fault:\n"
2394 " 1. Insert an empty magazine to clear the fault.\n"
2395 " 2. If the fault does not clear, turn the library off and then on "
2396 "again.\n"
2397 " 3. If the problem persists, call the library supplier help line.",
2398 /* 0x0d */
2399 "W: There is a potential problem with the drive ejecting cartridges or\n"
2400 " with the library mechanism picking a cartridge from a slot.\n"
2401 " 1. No action needs to be taken at this time.\n"
2402 " 2. If the problem persists, call the library supplier help line.",
2403 /* 0x0e */
2404 "W: There is a potential problem with the library mechanism placing a\n"
2405 " cartridge into a slot.\n"
2406 " 1. No action needs to be taken at this time.\n"
2407 " 2. If the problem persists, call the library supplier help line.",
2408 /* 0x0f */
2409 "W: There is a potential problem with the drive or the library mechanism\n"
2410 " loading cartridges, or an incompatible cartridge.",
2411 /* 0x10 */
2412 "C: The library has failed because the door is open:\n"
2413 " 1. Clear any obstructions from the library door.\n"
2414 " 2. Close the library door.\n"
2415 " 3. If the problem persists, call the library supplier help line.",
2416 /* 0x11 */
2417 "C: There is a mechanical problem with the library media import/export\n"
2418 " mailslot.",
2419 /* 0x12 */
2420 "C: The library cannot operate without the magazine.\n"
2421 " 1. Insert the magazine into the library.\n"
2422 " 2. Restart the operation.",
2423 /* 0x13 */
2424 "W: Library security has been compromised.",
2425 /* 0x14 */
2426 "I: The library security mode has been changed.\n"
2427 " The library has either been put into secure mode, or the library "
2428 "has exited\n"
2429 " the secure mode.\n"
2430 " This is for information purposes only. No action is required.",
2431 /* 0x15 */
2432 "I: The library has been manually turned offline and is unavailable for "
2433 "use.",
2434 /* 0x16 */
2435 "I: A drive inside the library has been taken offline.\n"
2436 " This is for information purposes only. No action is required.",
2437 /* 0x17 */
2438 "W: There is a potential problem with the bar code label or the scanner\n"
2439 " hardware in the library mechanism.\n"
2440 " 1. No action needs to be taken at this time.\n"
2441 " 2. If the problem persists, call the library supplier help line.",
2442 /* 0x18 */
2443 "C: The library has detected an inconsistency in its inventory.\n"
2444 " 1. Redo the library inventory to correct inconsistency.\n"
2445 " 2. Restart the operation.\n"
2446 " Check the applications users manual or the hardware users manual "
2447 "for\n"
2448 " specific instructions on redoing the library inventory.",
2449 /* 0x19 */
2450 "W: A library operation has been attempted that is invalid at this time.",
2451 /* 0x1a */
2452 "W: A redundant interface port on the library has failed.",
2453 /* 0x1b */
2454 "W: A library cooling fan has failed.",
2455 /* 0x1c */
2456 "W: A redundant power supply has failed inside the library. Check the\n"
2457 " library users manual for instructions on replacing the failed "
2458 "power supply.",
2459 /* 0x1d */
2460 "W: The library power consumption is outside the specified range.",
2461 /* 0x1e */
2462 "C: A failure has occurred in the cartridge pass-through mechanism "
2463 "between\n"
2464 " two library modules.",
2465 /* 0x1f */
2466 "C: A cartridge has been left in the pass-through mechanism from a\n"
2467 " previous hardware fault. Check the library users guide for "
2468 "instructions on\n"
2469 " clearing this fault.",
2470 /* 0x20 */
2471 "I: The library was unable to read the bar code on a cartridge.",
2472};
2473
2474const char *
2476{
2477 static const int num = sizeof(ChangerTapeAlertsMessageTable) /
2479
2480 return (code < num) ? ChangerTapeAlertsMessageTable[code] :
2481 "Unknown Alert";
2482}
2483
2484int
2486{
2487 int res;
2488
2489 res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, nullptr, 0);
2490 if (res)
2491 pout("Default self test failed [%s]\n", scsiErrString(res));
2492 return res;
2493}
2494
2495int
2497{
2498 int res;
2499
2500 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, nullptr, 0);
2501 if (res)
2502 pout("Short offline self test failed [%s]\n", scsiErrString(res));
2503 return res;
2504}
2505
2506int
2508{
2509 int res;
2510
2511 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, nullptr, 0);
2512 if (res)
2513 pout("Long (extended) offline self test failed [%s]\n",
2514 scsiErrString(res));
2515 return res;
2516}
2517
2518int
2520{
2521 int res;
2522
2523 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, nullptr, 0);
2524 if (res)
2525 pout("Short foreground self test failed [%s]\n", scsiErrString(res));
2526 return res;
2527}
2528
2529int
2531{
2532 int res;
2533
2534 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, nullptr, 0);
2535 if (res)
2536 pout("Long (extended) foreground self test failed [%s]\n",
2537 scsiErrString(res));
2538 return res;
2539}
2540
2541int
2543{
2544 int res;
2545
2546 res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, nullptr, 0);
2547 if (res)
2548 pout("Abort self test failed [%s]\n", scsiErrString(res));
2549 return res;
2550}
2551
2552/* Returns 0 and the expected duration of an extended self test (in seconds)
2553 if successful; any other return value indicates a failure. */
2554int
2555scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
2556 int modese_len)
2557{
2558 int err, offset;
2559 uint8_t buff[64] = {};
2560
2561 if (modese_len <= 6) {
2562 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2564 buff, sizeof(buff)))) {
2565 if (SIMPLE_ERR_BAD_OPCODE == err)
2566 modese_len = 10;
2567 else
2568 return err;
2569 } else if (0 == modese_len)
2570 modese_len = 6;
2571 }
2572 if (10 == modese_len) {
2573 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2575 buff, sizeof(buff));
2576 if (err)
2577 return err;
2578 }
2579 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2580 if (offset < 0)
2581 return -EINVAL;
2582 if (buff[offset + 1] >= 0xa) {
2583 int res = sg_get_unaligned_be16(buff + offset + 10);
2584
2585 if (res < 0xffff) {
2586 *durationSec = res;
2587 return 0;
2588 }
2589 /* The value 0xffff (all bits set in 16 bit field) indicates that
2590 * the Extended Inquiry VPD page should be consulted, it has a
2591 * similarly named 16 bit field, but the unit is minutes. */
2592 uint8_t b[64];
2593
2595 b, sizeof(b))) &&
2596 ((sg_get_unaligned_be16(b + 2)) > 11)) {
2597 res = sg_get_unaligned_be16(b + 10);
2598 *durationSec = res * 60; /* VPD field is in minutes */
2599 return 0;
2600 } else
2601 return -EINVAL;
2602 } else
2603 return -EINVAL;
2604}
2605
2606void
2607scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp,
2608 int allocLen)
2609{
2610 memset(ecp, 0, sizeof(*ecp));
2611 int num = sg_get_unaligned_be16(resp + 2);
2612 unsigned char * ucp = &resp[0] + 4;
2613
2614 /* allocLen is length of whole log page including 4 byte log page header */
2615 num = num < allocLen - 4 ? num : allocLen - 4;
2616 while (num >= 4) { /* header of each parameter takes 4 bytes */
2617 int pc = sg_get_unaligned_be16(ucp + 0);
2618 int pl = ucp[3] + 4;
2619 uint64_t * ullp;
2620
2621 if (num < pl) /* remaining length less than a complete parameter */
2622 break;
2623 switch (pc) {
2624 case 0:
2625 case 1:
2626 case 2:
2627 case 3:
2628 case 4:
2629 case 5:
2630 case 6:
2631 ecp->gotPC[pc] = 1;
2632 ullp = &ecp->counter[pc];
2633 break;
2634 default:
2635 ecp->gotExtraPC = 1;
2636 ullp = &ecp->counter[7];
2637 break;
2638 }
2639 int k = pl - 4;
2640 unsigned char * xp = ucp + 4;
2641 if (k > (int)sizeof(*ullp)) {
2642 xp += (k - sizeof(*ullp));
2643 k = sizeof(*ullp);
2644 }
2645 *ullp = sg_get_unaligned_be(k, xp);
2646 num -= pl;
2647 ucp += pl;
2648 }
2649}
2650
2651void
2652scsiDecodeNonMediumErrPage(unsigned char *resp,
2653 struct scsiNonMediumError *nmep,
2654 int allocLen)
2655{
2656 memset(nmep, 0, sizeof(*nmep));
2657 int num = sg_get_unaligned_be16(resp + 2);
2658 unsigned char * ucp = &resp[0] + 4;
2659 static int szof = sizeof(nmep->counterPC0);
2660
2661 /* allocLen is length of whole log page including 4 byte log page header */
2662 num = num < allocLen - 4 ? num : allocLen - 4;
2663 while (num >= 4) { /* header of each parameter takes 4 bytes */
2664 int pc = sg_get_unaligned_be16(ucp + 0);
2665 int pl = ucp[3] + 4;
2666 int k;
2667 unsigned char * xp;
2668
2669 if (num < pl) /* remaining length less than a complete parameter */
2670 break;
2671 switch (pc) {
2672 case 0:
2673 nmep->gotPC0 = 1;
2674 k = pl - 4;
2675 xp = ucp + 4;
2676 if (k > szof) {
2677 xp += (k - szof);
2678 k = szof;
2679 }
2680 nmep->counterPC0 = sg_get_unaligned_be(k, xp + 0);
2681 break;
2682 case 0x8009:
2683 nmep->gotTFE_H = 1;
2684 k = pl - 4;
2685 xp = ucp + 4;
2686 if (k > szof) {
2687 xp += (k - szof);
2688 k = szof;
2689 }
2690 nmep->counterTFE_H = sg_get_unaligned_be(k, xp + 0);
2691 break;
2692 case 0x8015:
2693 nmep->gotPE_H = 1;
2694 k = pl - 4;
2695 xp = ucp + 4;
2696 if (k > szof) {
2697 xp += (k - szof);
2698 k = szof;
2699 }
2700 nmep->counterPE_H = sg_get_unaligned_be(k, xp + 0);
2701 break;
2702 default:
2703 nmep->gotExtraPC = 1;
2704 break;
2705 }
2706 num -= pl;
2707 ucp += pl;
2708 }
2709}
2710
2711/* Counts number of failed self-tests. Also encodes the poweron_hour
2712 of the most recent failed self-test. Return value is negative if
2713 this function has a problem (typically -1), otherwise the bottom 8
2714 bits are the number of failed self tests and the 16 bits above that
2715 are the poweron hour of the most recent failure. Note: aborted self
2716 tests (typically by the user) and self tests in progress are not
2717 considered failures. See Working Draft SCSI Primary Commands - 3
2718 (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
2719int
2721{
2722 int num, k, err, fails, fail_hour;
2723 uint8_t * ucp;
2724 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2725
2726 if ((err = scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2728 if (noisy)
2729 pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err));
2730 return -1;
2731 }
2732 if ((resp[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
2733 if (noisy)
2734 pout("Self-test %s Failed, page mismatch\n", logSenStr);
2735 return -1;
2736 }
2737 // compute page length
2738 num = sg_get_unaligned_be16(resp + 2);
2739 // Log sense page length 0x190 bytes
2740 if (num != 0x190) {
2741 if (noisy)
2742 pout("Self-test %s length is 0x%x not 0x190 bytes\n", logSenStr,
2743 num);
2744 return -1;
2745 }
2746 fails = 0;
2747 fail_hour = 0;
2748 // loop through the twenty possible entries
2749 for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) {
2750
2751 // timestamp in power-on hours (or zero if test in progress)
2752 int n = sg_get_unaligned_be16(ucp + 6);
2753
2754 // The spec says "all 20 bytes will be zero if no test" but
2755 // DG has found otherwise. So this is a heuristic.
2756 if ((0 == n) && (0 == ucp[4]))
2757 break;
2758 int res = ucp[4] & 0xf;
2759 if ((res > 2) && (res < 8)) {
2760 fails++;
2761 if (1 == fails)
2762 fail_hour = sg_get_unaligned_be16(ucp + 6);
2763 }
2764 }
2765 return (fail_hour << 8) + fails;
2766}
2767
2768/* Returns 0 if able to read self test log page; then outputs 1 into
2769 *inProgress if self test still in progress, else outputs 0. */
2770int
2772{
2773 int num;
2774 uint8_t * ucp;
2775 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2776
2777 if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2779 return -1;
2780 if (resp[0] != SELFTEST_RESULTS_LPAGE)
2781 return -1;
2782 // compute page length
2783 num = sg_get_unaligned_be16(resp + 2);
2784 // Log sense page length 0x190 bytes
2785 if (num != 0x190) {
2786 return -1;
2787 }
2788 ucp = resp + 4;
2789 if (inProgress)
2790 *inProgress = (0xf == (ucp[4] & 0xf)) ? 1 : 0;
2791 return 0;
2792}
2793
2794/* Returns a negative value if failed to fetch Control mode page or it was
2795 malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD
2796 bit is set. Examines default mode page when current==0 else examines
2797 current mode page. */
2798int
2800{
2801 int err, offset;
2802 uint8_t buff[64] = {};
2803 int pc = current ? MPAGE_CONTROL_CURRENT : MPAGE_CONTROL_DEFAULT;
2804
2805 if (modese_len <= 6) {
2806 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, pc,
2807 buff, sizeof(buff)))) {
2808 if (SIMPLE_ERR_BAD_OPCODE == err)
2809 modese_len = 10;
2810 else
2811 return -EINVAL;
2812 } else if (0 == modese_len)
2813 modese_len = 6;
2814 }
2815 if (10 == modese_len) {
2816 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, pc,
2817 buff, sizeof(buff));
2818 if (err)
2819 return -EINVAL;
2820 }
2821 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2822 if ((offset >= 0) && (buff[offset + 1] >= 0xa))
2823 return (buff[offset + 2] & 2) ? 1 : 0;
2824 return -EINVAL;
2825}
2826
2827/* Returns a negative value on error, 0 if unknown and 1 if SSD,
2828 * otherwise the positive returned value is the speed in rpm. First checks
2829 * the Block Device Characteristics VPD page and if that fails it tries the
2830 * RIGID_DISK_DRIVE_GEOMETRY_PAGE mode page.
2831 * In SBC-4 the 2 bit ZONED field in this VPD page is written to *haw_zbcp
2832 * if haw_zbcp is non-nullptr. In SBC-5 the ZONED field is now obsolete,
2833 * the Zoned block device characteristics VPD page should be used instead. */
2834
2835int
2836scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp,
2837 int * haw_zbcp)
2838{
2839 int err, offset;
2840 uint8_t buff[64] = {};
2841 int pc = MPAGE_CONTROL_DEFAULT;
2842
2844 buff, sizeof(buff))) &&
2845 ((sg_get_unaligned_be16(buff + 2)) > 2)) {
2846 int speed = sg_get_unaligned_be16(buff + 4);
2847 if (form_factorp)
2848 *form_factorp = buff[7] & 0xf;
2849 if (haw_zbcp)
2850 *haw_zbcp = (buff[8] >> 4) & 0x3;
2851 return speed;
2852 }
2853 if (form_factorp)
2854 *form_factorp = 0;
2855 if (haw_zbcp)
2856 *haw_zbcp = 0;
2857 if (modese_len <= 6) {
2858 if ((err = scsiModeSense(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc,
2859 buff, sizeof(buff)))) {
2860 if (SIMPLE_ERR_BAD_OPCODE == err)
2861 modese_len = 10;
2862 else
2863 return -EINVAL;
2864 } else if (0 == modese_len)
2865 modese_len = 6;
2866 }
2867 if (10 == modese_len) {
2869 buff, sizeof(buff));
2870 if (err)
2871 return -EINVAL;
2872 }
2873 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2874 return sg_get_unaligned_be16(buff + offset + 20);
2875}
2876
2877/* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value,
2878 0 - clear bit, 1 - set bit */
2879
2880int
2881scsiGetSetCache(scsi_device * device, int modese_len, short int * wcep,
2882 short int * rcdp)
2883{
2884 int err, offset, resp_len, sp;
2885 uint8_t buff[64] = {};
2886 uint8_t ch_buff[64];
2887 short set_wce = *wcep;
2888 short set_rcd = *rcdp;
2889
2890 if (modese_len <= 6) {
2892 buff, sizeof(buff));
2893 if (err) {
2894 if (SIMPLE_ERR_BAD_OPCODE == err)
2895 modese_len = 10;
2896 else {
2897 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2898 return -EINVAL;
2899 }
2900 } else if (0 == modese_len)
2901 modese_len = 6;
2902 }
2903
2904 if (10 == modese_len) {
2906 buff, sizeof(buff));
2907 if (err) {
2908 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2909 return -EINVAL;
2910 }
2911 }
2912 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2913 if ((offset < 0) || (buff[offset + 1] < 0xa)) {
2914 device->set_err(EINVAL, "Bad response");
2915 return SIMPLE_ERR_BAD_RESP;
2916 }
2917
2918 *wcep = ((buff[offset + 2] & 0x04) != 0);
2919 *rcdp = ((buff[offset + 2] & 0x01) != 0);
2920
2921 if((*wcep == set_wce || set_wce == -1)
2922 && ((*rcdp == set_rcd) || set_rcd == -1))
2923 return 0; // no changes needed or nothing to set
2924
2925 if (modese_len == 6)
2926 err = scsiModeSense(device, CACHING_PAGE, 0,
2928 ch_buff, sizeof(ch_buff));
2929 else
2930 err = scsiModeSense10(device, CACHING_PAGE, 0,
2932 ch_buff, sizeof(ch_buff));
2933 if (err) {
2934 device->set_err(EINVAL, "WCE/RCD bits not changeable");
2935 return err;
2936 }
2937
2938 // set WCE bit
2939 if(set_wce >= 0 && *wcep != set_wce) {
2940 if (0 == (ch_buff[offset + 2] & 0x04)) {
2941 device->set_err(EINVAL, "WCE bit not changeable");
2942 return 1;
2943 }
2944 if(set_wce)
2945 buff[offset + 2] |= 0x04; // set bit
2946 else
2947 buff[offset + 2] &= 0xfb; // clear bit
2948 }
2949 // set RCD bit
2950 if(set_rcd >= 0 && *rcdp != set_rcd) {
2951 if (0 == (ch_buff[offset + 2] & 0x01)) {
2952 device->set_err(EINVAL, "RCD bit not changeable");
2953 return 1;
2954 }
2955 if(set_rcd)
2956 buff[offset + 2] |= 0x01; // set bit
2957 else
2958 buff[offset + 2] &= 0xfe; // clear bit
2959 }
2960
2961 /* mask out DPOFUA device specific (disk) parameter bit */
2962 if (10 == modese_len) {
2963 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
2964 buff[3] &= 0xef;
2965 } else {
2966 resp_len = buff[0] + 1;
2967 buff[2] &= 0xef;
2968 }
2969 sp = 0; /* Do not change saved values */
2970 if (10 == modese_len)
2971 err = scsiModeSelect10(device, sp, buff, resp_len);
2972 else if (6 == modese_len)
2973 err = scsiModeSelect(device, sp, buff, resp_len);
2974 if(err)
2975 device->set_err(EINVAL, "MODE SELECT command failed");
2976 return err;
2977}
2978
2979
2980/* Attempts to set or clear GLTSD bit in Control mode page. If enabled is
2981 0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if
2982 successful, negative if low level error, > 0 if higher level error (e.g.
2983 SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */
2984int
2985scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len)
2986{
2987 int err, offset, resp_len, sp;
2988 uint8_t buff[64] = {};
2989 uint8_t ch_buff[64];
2990
2991 if (modese_len <= 6) {
2992 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2994 buff, sizeof(buff)))) {
2995 if (SIMPLE_ERR_BAD_OPCODE == err)
2996 modese_len = 10;
2997 else
2998 return err;
2999 } else if (0 == modese_len)
3000 modese_len = 6;
3001 }
3002 if (10 == modese_len) {
3003 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
3005 buff, sizeof(buff));
3006 if (err)
3007 return err;
3008 }
3009 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
3010 if ((offset < 0) || (buff[offset + 1] < 0xa))
3011 return SIMPLE_ERR_BAD_RESP;
3012
3013 if (enabled)
3014 enabled = 2;
3015 if (enabled == (buff[offset + 2] & 2))
3016 return 0; /* GLTSD already in wanted state so nothing to do */
3017
3018 if (modese_len == 6)
3019 err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
3021 ch_buff, sizeof(ch_buff));
3022 else
3023 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
3025 ch_buff, sizeof(ch_buff));
3026 if (err)
3027 return err;
3028 if (0 == (ch_buff[offset + 2] & 2))
3029 return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not changeable */
3030
3031 /* mask out DPOFUA device specific (disk) parameter bit */
3032 if (10 == modese_len) {
3033 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
3034 buff[3] &= 0xef;
3035 } else {
3036 resp_len = buff[0] + 1;
3037 buff[2] &= 0xef;
3038 }
3039 sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
3040 if (enabled)
3041 buff[offset + 2] |= 0x2; /* set GLTSD bit */
3042 else
3043 buff[offset + 2] &= 0xfd; /* clear GLTSD bit */
3044 if (10 == modese_len)
3045 err = scsiModeSelect10(device, sp, buff, resp_len);
3046 else if (6 == modese_len)
3047 err = scsiModeSelect(device, sp, buff, resp_len);
3048 return err;
3049}
3050
3051/* Returns a negative value if failed to fetch Protocol specific port mode
3052 page or it was malformed. Returns transport protocol identifier when
3053 value >= 0 . */
3054int
3056{
3057 int err, offset;
3058 uint8_t buff[64] {};
3059
3060 if (modese_len <= 6) {
3061 if ((err = scsiModeSense(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0,
3063 buff, sizeof(buff)))) {
3064 if (SIMPLE_ERR_BAD_OPCODE == err)
3065 modese_len = 10;
3066 else
3067 return -EINVAL;
3068 } else if (0 == modese_len)
3069 modese_len = 6;
3070 }
3071 if (10 == modese_len) {
3074 buff, sizeof(buff));
3075 if (err)
3076 return -EINVAL;
3077 }
3078 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
3079 if ((offset >= 0) && (buff[offset + 1] > 1)) {
3080 if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */
3081 (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f)))
3082 return (buff[offset + 2] & 0xf);
3083 }
3084 return -EINVAL;
3085}
3086
3087const unsigned char *
3088sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len,
3089 int desc_type)
3090{
3091 int add_sen_len;
3092 const unsigned char * descp;
3093
3094 if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
3095 return nullptr;
3096 if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
3097 return nullptr;
3098 add_sen_len = (add_sen_len < (sense_len - 8)) ?
3099 add_sen_len : (sense_len - 8);
3100 descp = &sensep[8];
3101 for (int desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
3102 descp += desc_len;
3103 int add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
3104 desc_len = add_len + 2;
3105 if (descp[0] == desc_type)
3106 return descp;
3107 if (add_len < 0) /* short descriptor ?? */
3108 break;
3109 }
3110 return nullptr;
3111}
3112
3113// Convenience function for formatting strings from SCSI identify
3114void
3115scsi_format_id_string(char * out, const uint8_t * in, int n)
3116{
3117 char tmp[65];
3118 n = n > 64 ? 64 : n;
3119 strncpy(tmp, (const char *)in, n);
3120 tmp[n] = '\0';
3121
3122 // Find the first non-space character (maybe none).
3123 int first = -1;
3124 int i;
3125 for (i = 0; tmp[i]; i++)
3126 if (!isspace((int)tmp[i])) {
3127 first = i;
3128 break;
3129 }
3130
3131 if (first == -1) {
3132 // There are only space characters.
3133 out[0] = '\0';
3134 return;
3135 }
3136
3137 // Find the last non-space character.
3138 for (i = strlen(tmp)-1; i >= first && isspace((int)tmp[i]); i--);
3139 int last = i;
3140
3141 strncpy(out, tmp+first, last-first+1);
3142 out[last-first+1] = '\0';
3143}
3144
3145static const char * wn = "Warning";
3146
3147static const char * wn1_9[] = {
3148 "specified temperature exceeded",
3149 "enclosure degraded",
3150 "background self-test failed",
3151 "background pre-scan detected medium error",
3152 "background medium scan detected medium error",
3153 "non-volatile cache now volatile",
3154 "degraded power to non-volatile cache",
3155 "power loss expected",
3156 "device statistics notification active",
3157};
3158
3159static const char * five_d_t[] = {
3160 "Hardware",
3161 "Controller",
3162 "Data channel",
3163 "Servo",
3164 "Spindle",
3165 "Firmware",
3166};
3167
3168static const char * impfail = "impending failure";
3169
3170static const char * impending0_c[] = {
3171 "general hard drive failure",
3172 "drive error rate too high",
3173 "data error rate too high",
3174 "seek error rate too high",
3175 "too many block reassigns",
3176 "access times too high",
3177 "start unit times too high",
3178 "channel parametrics",
3179 "controller detected",
3180 "throughput performance",
3181 "seek time performance",
3182 "spin-up retry count",
3183 "drive calibration retry count",
3184};
3185
3186static const char * pred = "prediction threshold exceeded";
3187
3188/* The SCSI Informational Exceptions log page and various other mechanisms
3189 * yield an additional sense code (and its qualifier) [asc and ascq] when
3190 * triggered. It seems only two asc values are involved: 0xb and 0xd.
3191 * If asc,ascq strings are known (in spc6r06.pdf) for asc 0xb and 0x5d
3192 * then a pointer to that string is returned, else nullptr is returned. The
3193 * caller provides a buffer (b) and its length (blen) that a string (if
3194 * found) is placed in. So if a match is found b is returned. */
3195char *
3196scsiGetIEString(uint8_t asc, uint8_t ascq, char * b, int blen)
3197{
3198 if (asc == 0xb) {
3199 switch (ascq) {
3200 case 0:
3201 snprintf(b, blen, "%s", wn);
3202 return b;
3203 case 0x1:
3204 case 0x2:
3205 case 0x3:
3206 case 0x4:
3207 case 0x5:
3208 case 0x6:
3209 case 0x7:
3210 case 0x8:
3211 case 0x9:
3212 snprintf(b, blen, "%s - %s", wn, wn1_9[ascq - 1]);
3213 return b;
3214 case 0x12:
3215 snprintf(b, blen, "%s - microcode security at risk", wn);
3216 return b;
3217 case 0x13:
3218 snprintf(b, blen, "%s - microcode digital signature validation "
3219 "failure", wn);
3220 return b;
3221 case 0x14:
3222 snprintf(b, blen, "%s - physical element status change", wn);
3223 return b;
3224 default:
3225 if ((ascq >= 0xa) && (ascq <= 0x11)) {
3226 uint8_t q = ascq - 0xa;
3227
3228 snprintf(b, blen, "%s - %s %s %s limit exceeded", wn,
3229 (((q % 2) == 0) ? "high" : "low"),
3230 ((((q / 2) % 2) == 0) ? "critical" : "operating"),
3231 ((((q / 4) % 2) == 0) ? "temperature" : "humidity"));
3232 return b;
3233 } else
3234 return nullptr;
3235 }
3236 } else if (asc == 0x5d) {
3237 switch (ascq) {
3238 case 0:
3239 snprintf(b, blen, "Failure %s", pred);
3240 return b;
3241 case 1:
3242 snprintf(b, blen, "Media failure %s", pred);
3243 return b;
3244 case 2:
3245 snprintf(b, blen, "Logical unit failure %s", pred);
3246 return b;
3247 case 3:
3248 snprintf(b, blen, "spare area exhaustion failure %s", pred);
3249 return b;
3250 case 0x1d:
3251 snprintf(b, blen, "%s %s power loss protection circuit area "
3252 "exhaustion failure", five_d_t[0], impfail);
3253 return b;
3254 case 0x73:
3255 snprintf(b, blen, "Media %s endurance limit met", impfail);
3256 return b;
3257 case 0xff:
3258 snprintf(b, blen, "Failure %s (false)", pred);
3259 return b;
3260 default:
3261 if ((ascq >= 0x10) && (ascq <= 0x6c)) {
3262 uint8_t q = ascq - 0x10;
3263 uint8_t rem = q % 0x10;
3264
3265 if (rem <= 0xc) {
3266 snprintf(b, blen, "%s %s %s", five_d_t[q / 0x10], impfail,
3267 impending0_c[rem]);
3268 return b;
3269 } else
3270 return nullptr;
3271 } else
3272 return nullptr;
3273 }
3274 } else
3275 return nullptr;
3276}
SCSI device access.
scsi_cmd_support logsense_spc_sup
bool is_spc4_or_higher() const
scsi_cmd_support rdefect12_sup
void set_rcap16_first()
Always try READ CAPACITY(10) (rcap10) first but once we know rcap16 is needed, use it instead.
bool query_cmd_support()
Definition: scsicmds.cpp:80
scsi_cmd_support logsense_sup
scsi_cmd_support rsoc_sup
virtual bool scsi_pass_through(scsi_cmnd_io *iop)=0
SCSI pass through.
scsi_cmd_support rdefect10_sup
scsi_cmd_support rcap16_sup
enum scsi_cmd_support cmd_support_level(uint8_t opcode, bool sa_valid, uint16_t sa, bool for_lsense_spc=false) const
Definition: scsicmds.cpp:172
void set_spc4_or_higher()
int get_errno() const
Get last error number.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
bool is_supported(int vpd_page_num) const
Definition: scsicmds.cpp:216
unsigned char pages[256]
Definition: scsicmds.h:400
supported_vpd_pages(scsi_device *device)
Definition: scsicmds.cpp:201
scsi_cmd_support
@ SC_SUPPORT
@ SC_SUPPORT_UNKNOWN
@ SC_NO_SUPPORT
u8 sense_len
Definition: megaraid.h:2
uint8_t opcode
Definition: megaraid.h:0
u8 cdb[16]
Definition: megaraid.h:21
u8 b[12]
Definition: megaraid.h:17
u16 s[6]
Definition: megaraid.h:18
int scsiSetPowerCondition(scsi_device *device, int power_cond, int pcond_modifier)
Definition: scsicmds.cpp:1361
int scsiReadDefect12(scsi_device *device, int req_plist, int req_glist, int dl_format, int addrDescIndex, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1506
int scsiFetchExtendedSelfTestTime(scsi_device *device, int *durationSec, int modese_len)
Definition: scsicmds.cpp:2555
void scsiDecodeErrCounterPage(unsigned char *resp, struct scsiErrorCounter *ecp, int allocLen)
Definition: scsicmds.cpp:2607
int scsiModeSelect(scsi_device *device, int sp, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1040
int scsiSimpleSenseFilter(const struct scsi_sense_disect *sinfo)
Definition: scsicmds.cpp:587
#define SCSI_IEC_MP_BYTE2_ENABLED
Definition: scsicmds.cpp:1913
int scsiSetExceptionControlAndWarning(scsi_device *device, int enabled, const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1928
#define RSOC_ALL_CMDS_CTDP_0
Definition: scsicmds.cpp:50
static struct scsi_sa_var_map sa_var_a[]
Definition: scsicmds.cpp:451
int scsiSmartExtendCapSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2530
static const char * TapeAlertsMessageTable[]
Definition: scsicmds.cpp:2083
int scsiFetchIECmpage(scsi_device *device, struct scsi_iec_mode_page *iecp, int modese_len)
Definition: scsicmds.cpp:1838
int scsiGetTemp(scsi_device *device, uint8_t *currenttemp, uint8_t *triptemp)
Definition: scsicmds.cpp:1998
static const char * pred
Definition: scsicmds.cpp:3186
int scsiSmartShortCapSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2519
int scsiSmartSelfTestAbort(scsi_device *device)
Definition: scsicmds.cpp:2542
char * scsi_get_sense_key_str(int sense_key, int buff_len, char *buff)
Definition: scsicmds.cpp:695
static const char * ChangerTapeAlertsMessageTable[]
Definition: scsicmds.cpp:2336
static const char * wn
Definition: scsicmds.cpp:3145
static const char * impfail
Definition: scsicmds.cpp:3168
const char * scsiTapeAlertsTapeDevice(unsigned short code)
Definition: scsicmds.cpp:2327
int scsiFetchTransportProtocol(scsi_device *device, int modese_len)
Definition: scsicmds.cpp:3055
int scsi_decode_lu_dev_id(const unsigned char *b, int blen, char *s, int slen, int *transport)
Definition: scsicmds.cpp:747
bool is_scsi_cdb(const uint8_t *cdbp, int clen)
Definition: scsicmds.cpp:391
static const char * wn1_9[]
Definition: scsicmds.cpp:3147
void dStrHexFp(const uint8_t *up, int len, int no_ascii, FILE *fp)
Definition: scsicmds.cpp:344
int scsiTestUnitReady(scsi_device *device)
Definition: scsicmds.cpp:1456
int scsiModeSense10(scsi_device *device, int pagenum, int subpagenum, int pc, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1079
int scsiModePageOffset(const uint8_t *resp, int len, int modese_len)
Definition: scsicmds.cpp:1795
void scsi_do_sense_disect(const struct scsi_cmnd_io *io_buf, struct scsi_sense_disect *out)
Definition: scsicmds.cpp:565
#define RSOC_1_CMD_CTDP_0
Definition: scsicmds.cpp:52
#define RSOC_ALL_CMDS_CTDP_1
Definition: scsicmds.cpp:51
int scsiInquiryVpd(scsi_device *device, int vpd_page, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1210
static void dStrHexHelper(const uint8_t *up, int len, int no_ascii, void(*out)(const char *s, void *ctx), void *ctx=nullptr)
Definition: scsicmds.cpp:248
#define SCSI_IEC_MP_REPORT_COUNT
Definition: scsicmds.cpp:1918
static scsi_cmd_support chk_lsense_spc(scsi_device *device)
Definition: scsicmds.cpp:56
static int trimTrailingSpaces(char *b)
Definition: scsicmds.cpp:236
int scsiSmartExtendSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2507
void scsiDecodeNonMediumErrPage(unsigned char *resp, struct scsiNonMediumError *nmep, int allocLen)
Definition: scsicmds.cpp:2652
int scsiRequestSense(scsi_device *device, struct scsi_sense_disect *sense_info)
Definition: scsicmds.cpp:1268
int scsiCheckIE(scsi_device *device, int hasIELogPage, int hasTempLogPage, uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp, uint8_t *triptemp)
Definition: scsicmds.cpp:2026
const char * scsicmds_c_cvsid
Definition: scsicmds.cpp:39
uint64_t scsiGetSize(scsi_device *device, bool avoid_rcap16, struct scsi_readcap_resp *srrp)
Definition: scsicmds.cpp:1713
int scsiSelfTestInProgress(scsi_device *fd, int *inProgress)
Definition: scsicmds.cpp:2771
static const char * sense_key_desc[]
Definition: scsicmds.cpp:668
#define DEXCPT_ENABLE
Definition: scsicmds.cpp:1826
char * scsiGetIEString(uint8_t asc, uint8_t ascq, char *b, int blen)
Definition: scsicmds.cpp:3196
static const char * vendor_specific
Definition: scsicmds.cpp:506
int scsiGetSetCache(scsi_device *device, int modese_len, short int *wcep, short int *rcdp)
Definition: scsicmds.cpp:2881
int scsiRSOCcmd(scsi_device *device, bool rctd, uint8_t rep_opt, uint8_t opcode, uint16_t serv_act, uint8_t *pBuf, int bufLen, int &rspLen)
Definition: scsicmds.cpp:1672
#define SCSI_IEC_MP_INTERVAL_T
Definition: scsicmds.cpp:1917
supported_vpd_pages * supported_vpd_pages_p
Definition: scsicmds.cpp:47
bool scsi_pass_through_yield_sense(scsi_device *device, scsi_cmnd_io *iop, scsi_sense_disect &sinfo)
Definition: scsicmds.cpp:1543
int scsiGetRPM(scsi_device *device, int modese_len, int *form_factorp, int *haw_zbcp)
Definition: scsicmds.cpp:2836
void scsi_format_id_string(char *out, const uint8_t *in, int n)
Definition: scsicmds.cpp:3115
#define EWASC_ENABLE
Definition: scsicmds.cpp:1827
int scsiReadCapacity16(scsi_device *device, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1645
int scsiStdInquiry(scsi_device *device, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1163
#define SCSI_IEC_MP_MRIE
Definition: scsicmds.cpp:1916
scsi_sa_t
Definition: scsicmds.cpp:440
@ scsi_sa_b8b7n16
Definition: scsicmds.cpp:443
@ scsi_sa_b1b4n5
Definition: scsicmds.cpp:442
@ scsi_sa_none
Definition: scsicmds.cpp:441
int scsiModeSelect10(scsi_device *device, int sp, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1123
const unsigned char * sg_scsi_sense_desc_find(const unsigned char *sensep, int sense_len, int desc_type)
Definition: scsicmds.cpp:3088
static const char * logSenStr
Definition: scsicmds.cpp:42
#define SCSI_IEC_MP_BYTE2_TEST_MASK
Definition: scsicmds.cpp:1914
int scsiSmartDefaultSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2485
static int _testunitready(scsi_device *device, struct scsi_sense_disect *sinfop)
Definition: scsicmds.cpp:1425
void dStrHex(const uint8_t *up, int len, int no_ascii)
Definition: scsicmds.cpp:368
int scsiSendDiagnostic(scsi_device *device, int functioncode, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1392
const char * scsiErrString(int scsiErr)
Definition: scsicmds.cpp:630
const char * scsiTapeAlertsChangerDevice(unsigned short code)
Definition: scsicmds.cpp:2475
int scsiReadCapacity10(scsi_device *device, unsigned int *last_lbap, unsigned int *lb_sizep)
Definition: scsicmds.cpp:1609
int scsiFetchControlGLTSD(scsi_device *device, int modese_len, int current)
Definition: scsicmds.cpp:2799
static int my_isprint(uint8_t ch)
Definition: scsicmds.cpp:230
static struct scsi_opcode_name opcode_name_arr[]
Definition: scsicmds.cpp:478
int scsiModeSense(scsi_device *device, int pagenum, int subpagenum, int pc, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:994
int scsiCountFailedSelfTests(scsi_device *fd, int noisy)
Definition: scsicmds.cpp:2720
int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1899
int scsiSetControlGLTSD(scsi_device *device, int enabled, int modese_len)
Definition: scsicmds.cpp:2985
int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1885
#define TEST_DISABLE
Definition: scsicmds.cpp:1830
int scsiSmartShortSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2496
int scsiLogSense(scsi_device *device, int pagenum, int subpagenum, uint8_t *pBuf, int bufLen, int known_resp_len)
Definition: scsicmds.cpp:873
unsigned char scsi_debugmode
Definition: scsicmds.cpp:45
#define EWASC_DISABLE
Definition: scsicmds.cpp:1829
const char * scsi_get_opcode_name(const uint8_t *cdbp)
Definition: scsicmds.cpp:511
#define RSOC_RESP_SZ
Definition: scsicmds.cpp:49
int scsiLogSelect(scsi_device *device, int pcr, int sp, int pc, int pagenum, int subpagenum, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:962
static const char * five_d_t[]
Definition: scsicmds.cpp:3159
int scsiReadDefect10(scsi_device *device, int req_plist, int req_glist, int dl_format, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1472
static const char * impending0_c[]
Definition: scsicmds.cpp:3170
int scsi_vpd_dev_id_iter(const unsigned char *initial_desig_desc, int page_len, int *off, int m_assoc, int m_desig_type, int m_code_set)
Definition: scsicmds.cpp:718
#define REPORT_LUNS
Definition: scsicmds.h:76
#define SIMPLE_ERR_BECOMING_READY
Definition: scsicmds.h:354
#define SCSI_SK_MEDIUM_ERROR
Definition: scsicmds.h:326
#define SIMPLE_ERR_MEDIUM_HARDWARE
Definition: scsicmds.h:356
#define START_STOP_UNIT
Definition: scsicmds.h:73
#define MPAGE_CONTROL_CURRENT
Definition: scsicmds.h:301
#define SAI_READ_CAPACITY_16
Definition: scsicmds.h:85
#define SCSI_ASC_UNKNOWN_OPCODE
Definition: scsicmds.h:338
#define MODE_SENSE_6
Definition: scsicmds.h:43
#define SIMPLE_ERR_BAD_FIELD
Definition: scsicmds.h:350
#define SAI_GET_PHY_ELEM_STATUS
Definition: scsicmds.h:88
#define INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE
Definition: scsicmds.h:292
#define READ_CAPACITY_10
Definition: scsicmds.h:79
#define MAINTENANCE_IN_12
Definition: scsicmds.h:94
#define SCSI_DIAG_DEF_SELF_TEST
Definition: scsicmds.h:365
#define SCSI_SK_UNIT_ATTENTION
Definition: scsicmds.h:329
#define MI_REP_SUP_OPCODES
Definition: scsicmds.h:97
#define SAT_ATA_PASSTHROUGH_12
Definition: scsicmds.h:101
#define DXFER_NONE
Definition: scsicmds.h:108
#define SCSICMDS_H_CVSID
Definition: scsicmds.h:22
#define SIMPLE_NO_ERROR
Definition: scsicmds.h:347
#define SEND_DIAGNOSTIC
Definition: scsicmds.h:64
#define SIMPLE_ERR_NOT_READY
Definition: scsicmds.h:348
#define RIGID_DISK_DRIVE_GEOMETRY_PAGE
Definition: scsicmds.h:276
#define SCSI_DIAG_BG_SHORT_SELF_TEST
Definition: scsicmds.h:366
#define SIMPLE_ERR_ABORTED_COMMAND
Definition: scsicmds.h:358
#define READ_DEFECT_12
Definition: scsicmds.h:70
#define SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS
Definition: scsicmds.h:315
#define READ_DEFECT_10
Definition: scsicmds.h:67
#define SCSI_DIAG_BG_EXTENDED_SELF_TEST
Definition: scsicmds.h:367
#define SIMPLE_ERR_TRY_AGAIN
Definition: scsicmds.h:355
#define SIMPLE_ERR_NO_MEDIUM
Definition: scsicmds.h:353
#define RECEIVE_DIAGNOSTIC
Definition: scsicmds.h:61
#define SCSI_ASC_INVALID_FIELD
Definition: scsicmds.h:339
int scsiInquiryVpd(scsi_device *device, int vpd_page, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1210
#define CACHING_PAGE
Definition: scsicmds.h:279
#define SELFTEST_RESULTS_LPAGE
Definition: scsicmds.h:232
#define MODE_SELECT_10
Definition: scsicmds.h:52
#define LOG_SENSE
Definition: scsicmds.h:40
#define SIMPLE_ERR_PROTECTION
Definition: scsicmds.h:359
#define DXFER_FROM_DEVICE
Definition: scsicmds.h:109
#define SCSI_SK_ILLEGAL_REQUEST
Definition: scsicmds.h:328
#define SCSI_TIMEOUT_DEFAULT
Definition: scsicmds.h:379
#define SCSI_SK_ABORTED_COMMAND
Definition: scsicmds.h:331
#define SCSI_IECMP_RAW_LEN
Definition: scsicmds.h:143
#define SCSI_DIAG_ABORT_SELF_TEST
Definition: scsicmds.h:370
#define MODE_SELECT_6
Definition: scsicmds.h:49
#define SUPPORTED_LPAGES
Definition: scsicmds.h:218
#define SCSI_SK_COMPLETED
Definition: scsicmds.h:333
#define SAT_ATA_PASSTHROUGH_16
Definition: scsicmds.h:104
#define SCSI_DIAG_FG_SHORT_SELF_TEST
Definition: scsicmds.h:368
#define SIMPLE_ERR_BAD_OPCODE
Definition: scsicmds.h:349
#define SCSI_PT_MEDIUM_CHANGER
Definition: scsicmds.h:196
#define SCSI_ASC_UNKNOWN_PARAM
Definition: scsicmds.h:340
#define DXFER_TO_DEVICE
Definition: scsicmds.h:110
#define SCSI_PT_SEQUENTIAL_ACCESS
Definition: scsicmds.h:192
#define SCSI_SK_HARDWARE_ERROR
Definition: scsicmds.h:327
#define SCSI_STATUS_CHECK_CONDITION
Definition: scsicmds.h:320
#define MODE_SENSE_10
Definition: scsicmds.h:46
#define LOG_SELECT
Definition: scsicmds.h:37
#define SIMPLE_ERR_BAD_PARAM
Definition: scsicmds.h:351
#define SCSI_PT_HOST_MANAGED
Definition: scsicmds.h:199
#define MPAGE_CONTROL_DEFAULT
Definition: scsicmds.h:303
#define SCSI_VPD_EXTENDED_INQUIRY_DATA
Definition: scsicmds.h:310
#define SCSI_DIAG_NO_SELF_TEST
Definition: scsicmds.h:364
#define LOG_RESP_SELF_TEST_LEN
Definition: scsicmds.h:265
#define SCSI_VPD_SUPPORTED_VPD_PAGES
Definition: scsicmds.h:307
#define TEST_UNIT_READY
Definition: scsicmds.h:34
#define SIMPLE_ERR_MISCOMPARE
Definition: scsicmds.h:360
#define TEMPERATURE_LPAGE
Definition: scsicmds.h:229
#define MPAGE_CONTROL_CHANGEABLE
Definition: scsicmds.h:302
#define SIMPLE_ERR_BAD_RESP
Definition: scsicmds.h:352
#define SCSI_PT_DIRECT_ACCESS
Definition: scsicmds.h:191
#define SERVICE_ACTION_IN_16
Definition: scsicmds.h:82
#define SCSI_ASC_NOT_READY
Definition: scsicmds.h:336
#define SIMPLE_ERR_UNKNOWN
Definition: scsicmds.h:357
#define SCSI_SK_NO_SENSE
Definition: scsicmds.h:323
#define IE_LPAGE
Definition: scsicmds.h:241
#define ALL_MODE_PAGES
Definition: scsicmds.h:298
#define INQUIRY
Definition: scsicmds.h:55
#define SCSI_SK_RECOVERED_ERR
Definition: scsicmds.h:324
#define SCSI_SK_NOT_READY
Definition: scsicmds.h:325
#define REQUEST_SENSE
Definition: scsicmds.h:58
#define CONTROL_MODE_PAGE
Definition: scsicmds.h:282
#define SCSI_SK_DATA_PROTECT
Definition: scsicmds.h:330
#define SCSI_SK_MISCOMPARE
Definition: scsicmds.h:332
#define SCSI_DIAG_FG_EXTENDED_SELF_TEST
Definition: scsicmds.h:369
#define SCSI_TIMEOUT_SELF_TEST
Definition: scsicmds.h:382
#define SCSI_ASC_NO_MEDIUM
Definition: scsicmds.h:337
#define PROTOCOL_SPECIFIC_PORT_PAGE
Definition: scsicmds.h:290
static int modese_len
Definition: scsiprint.cpp:83
static void sg_put_unaligned_be32(uint32_t val, void *p)
Definition: sg_unaligned.h:279
static void sg_put_unaligned_be16(uint16_t val, void *p)
Definition: sg_unaligned.h:273
static uint64_t sg_get_unaligned_be64(const void *p)
Definition: sg_unaligned.h:267
static uint64_t sg_get_unaligned_be(int num_bytes, const void *p)
Definition: sg_unaligned.h:350
static uint16_t sg_get_unaligned_be16(const void *p)
Definition: sg_unaligned.h:256
static uint32_t sg_get_unaligned_be32(const void *p)
Definition: sg_unaligned.h:261
for(char *p=buf, *q;p &&*p;p=q)
Definition: smartd.cpp:1318
void pout(const char *fmt,...)
Definition: smartd.cpp:1338
uint8_t gotPC[7]
Definition: scsicmds.h:156
uint64_t counter[8]
Definition: scsicmds.h:158
uint8_t gotExtraPC
Definition: scsicmds.h:157
uint64_t counterTFE_H
Definition: scsicmds.h:167
uint64_t counterPE_H
Definition: scsicmds.h:169
uint8_t gotTFE_H
Definition: scsicmds.h:166
uint8_t gotExtraPC
Definition: scsicmds.h:164
uint64_t counterPC0
Definition: scsicmds.h:165
uint8_t * sensep
Definition: scsicmds.h:123
uint8_t * dxferp
Definition: scsicmds.h:121
int dxfer_dir
Definition: scsicmds.h:119
size_t cmnd_len
Definition: scsicmds.h:118
size_t resp_sense_len
Definition: scsicmds.h:127
size_t dxfer_len
Definition: scsicmds.h:122
size_t max_sense_len
Definition: scsicmds.h:125
uint8_t scsi_status
Definition: scsicmds.h:128
uint8_t * cmnd
Definition: scsicmds.h:117
unsigned timeout
Definition: scsicmds.h:126
uint8_t gotChangeable
Definition: scsicmds.h:148
uint8_t gotCurrent
Definition: scsicmds.h:146
uint8_t modese_len
Definition: scsicmds.h:149
uint8_t raw_curr[SCSI_IECMP_RAW_LEN]
Definition: scsicmds.h:150
uint8_t raw_chg[SCSI_IECMP_RAW_LEN]
Definition: scsicmds.h:151
uint8_t requestedChangeable
Definition: scsicmds.h:147
uint8_t requestedCurrent
Definition: scsicmds.h:145
const char * name
Definition: scsicmds.cpp:474
uint16_t l_a_lba
Definition: scsicmds.h:182
uint8_t lb_p_pb_exp
Definition: scsicmds.h:179
uint8_t prot_type
Definition: scsicmds.h:176
uint8_t p_i_exp
Definition: scsicmds.h:178
uint32_t lb_size
Definition: scsicmds.h:174
uint64_t num_lblocks
Definition: scsicmds.h:173
enum scsi_sa_t sa_var
Definition: scsicmds.cpp:448
uint8_t resp_code
Definition: scsicmds.h:135
uint8_t sense_key
Definition: scsicmds.h:136