smartmontools SVN Rev 5645
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 5618 2024-10-05 10:58:14Z chrfranke $"
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(b) - 4;
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 if ((offset + 12) > SCSI_IECMP_RAW_LEN)
1953 return -EINVAL;
1954 rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
1955 if (scsi_debugmode > 2)
1956 rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK;
1957 rout[offset + 3] = SCSI_IEC_MP_MRIE;
1960 if (iecp->gotChangeable) {
1961 uint8_t chg2 = iecp->raw_chg[offset + 2];
1962
1963 rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) :
1964 iecp->raw_curr[offset + 2];
1965 for (int k = 3; k < 12; ++k) {
1966 if (0 == iecp->raw_chg[offset + k])
1967 rout[offset + k] = iecp->raw_curr[offset + k];
1968 }
1969 }
1970 if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) {
1971 if (scsi_debugmode > 0)
1972 pout("scsiSetExceptionControlAndWarning: already enabled\n");
1973 return 0;
1974 }
1975 } else { /* disabling Exception Control and (temperature) Warnings */
1976 int eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1977 int wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0;
1978 if ((! eCEnabled) && (! wEnabled)) {
1979 if (scsi_debugmode > 0)
1980 pout("scsiSetExceptionControlAndWarning: already disabled\n");
1981 return 0; /* nothing to do, leave other setting alone */
1982 }
1983 if (wEnabled)
1984 rout[offset + 2] &= EWASC_DISABLE;
1985 if (eCEnabled) {
1986 if (iecp->gotChangeable &&
1987 (iecp->raw_chg[offset + 2] & DEXCPT_ENABLE))
1988 rout[offset + 2] |= DEXCPT_ENABLE;
1989 rout[offset + 2] &= TEST_DISABLE; /* clear TEST bit for spec */
1990 }
1991 }
1992 if (10 == iecp->modese_len)
1993 err = scsiModeSelect10(device, sp, rout, resp_len);
1994 else if (6 == iecp->modese_len)
1995 err = scsiModeSelect(device, sp, rout, resp_len);
1996 return err;
1997}
1998
1999int
2000scsiGetTemp(scsi_device * device, uint8_t *currenttemp, uint8_t *triptemp)
2001{
2002 uint8_t tBuf[252] = {};
2003 int err;
2004
2005 if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 0, tBuf,
2006 sizeof(tBuf), 0))) {
2007 *currenttemp = 0;
2008 *triptemp = 0;
2009 pout("%s for temperature failed [%s]\n", logSenStr,
2010 scsiErrString(err));
2011 return err;
2012 }
2013 *currenttemp = tBuf[9];
2014 *triptemp = tBuf[15];
2015 return 0;
2016}
2017
2018/* Informational Exception conditions specified by spc6r06.pdf seem to be
2019 * associated with ASC values 0xb (warnings) and 0x5d (impending failures).
2020 * The asc/accq value 0x5d,0xff is reported in response to setting the TEST
2021 * bit in the Informationl Exception Control mode page. */
2022
2023/* Read informational exception log page or Request Sense response.
2024 * Fetching asc/ascq code potentially flagging an exception or warning.
2025 * Returns 0 if ok, else error number. A current temperature of 255
2026 * (Celsius) implies that the temperature not available. */
2027int
2028scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
2029 uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp,
2030 uint8_t *triptemp)
2031{
2032 uint8_t tBuf[252] = {};
2033 struct scsi_sense_disect sense_info;
2034 int err;
2035 uint8_t currTemp, trTemp;
2036
2037 memset(&sense_info, 0, sizeof(sense_info));
2038 *asc = 0;
2039 *ascq = 0;
2040 *currenttemp = 0;
2041 *triptemp = 0;
2042 if (hasIELogPage) {
2043 if ((err = scsiLogSense(device, IE_LPAGE, 0, tBuf,
2044 sizeof(tBuf), 0))) {
2045 pout("%s failed, IE page [%s]\n", logSenStr, scsiErrString(err));
2046 return err;
2047 }
2048 // pull out page size from response, don't forget to add 4
2049 unsigned short pagesize = sg_get_unaligned_be16(tBuf + 2) + 4;
2050 if ((pagesize < 4) || tBuf[4] || tBuf[5]) {
2051 pout("%s failed, IE page, bad parameter code or length\n",
2052 logSenStr);
2053 return SIMPLE_ERR_BAD_PARAM;
2054 }
2055 if (tBuf[7] > 1) {
2056 sense_info.asc = tBuf[8];
2057 sense_info.ascq = tBuf[9];
2058 if (! hasTempLogPage) {
2059 if (tBuf[7] > 2)
2060 *currenttemp = tBuf[10];
2061 if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */
2062 *triptemp = tBuf[11];
2063 }
2064 }
2065 }
2066 if (0 == sense_info.asc) {
2067 /* ties in with MRIE field of 6 in IEC mode page (0x1c) */
2068 if ((err = scsiRequestSense(device, &sense_info))) {
2069 pout("Request Sense failed, [%s]\n", scsiErrString(err));
2070 return err;
2071 }
2072 }
2073 *asc = sense_info.asc;
2074 *ascq = sense_info.ascq;
2075 if (hasTempLogPage) {
2076 if (0 == scsiGetTemp(device, &currTemp, &trTemp)) {
2077 *currenttemp = currTemp;
2078 *triptemp = trTemp;
2079 }
2080 }
2081 return 0;
2082}
2083
2084// The first character (W, C, I) tells the severity
2085static const char * TapeAlertsMessageTable[]= {
2086 " ",
2087 /* 0x01 */
2088 "W: The tape drive is having problems reading data. No data has been "
2089 "lost,\n"
2090 " but there has been a reduction in the performance of the tape.",
2091 /* 0x02 */
2092 "W: The tape drive is having problems writing data. No data has been "
2093 "lost,\n"
2094 " but there has been a reduction in the capacity of the tape.",
2095 /* 0x03 */
2096 "W: The operation has stopped because an error has occurred while "
2097 "reading\n"
2098 " or writing data that the drive cannot correct.",
2099 /* 0x04 */
2100 "C: Your data is at risk:\n"
2101 " 1. Copy any data you require from this tape. \n"
2102 " 2. Do not use this tape again.\n"
2103 " 3. Restart the operation with a different tape.",
2104 /* 0x05 */
2105 "C: The tape is damaged or the drive is faulty. Call the tape drive\n"
2106 " supplier helpline.",
2107 /* 0x06 */
2108 "C: The tape is from a faulty batch or the tape drive is faulty:\n"
2109 " 1. Use a good tape to test the drive.\n"
2110 " 2. If problem persists, call the tape drive supplier helpline.",
2111 /* 0x07 */
2112 "W: The tape cartridge has reached the end of its calculated useful "
2113 "life:\n"
2114 " 1. Copy data you need to another tape.\n"
2115 " 2. Discard the old tape.",
2116 /* 0x08 */
2117 "W: The tape cartridge is not data-grade. Any data you back up to the "
2118 "tape\n"
2119 " is at risk. Replace the cartridge with a data-grade tape.",
2120 /* 0x09 */
2121 "C: You are trying to write to a write-protected cartridge. Remove the\n"
2122 " write-protection or use another tape.",
2123 /* 0x0a */
2124 "I: You cannot eject the cartridge because the tape drive is in use. "
2125 "Wait\n"
2126 " until the operation is complete before ejecting the cartridge.",
2127 /* 0x0b */
2128 "I: The tape in the drive is a cleaning cartridge.",
2129 /* 0x0c */
2130 "I: You have tried to load a cartridge of a type which is not supported\n"
2131 " by this drive.",
2132 /* 0x0d */
2133 "C: The operation has failed because the tape in the drive has "
2134 "experienced\n"
2135 " a mechanical failure:\n"
2136 " 1. Discard the old tape.\n"
2137 " 2. Restart the operation with a different tape.",
2138 /* 0x0e */
2139 "C: The operation has failed because the tape in the drive has "
2140 "experienced\n"
2141 " a mechanical failure:\n"
2142 " 1. Do not attempt to extract the tape cartridge\n"
2143 " 2. Call the tape drive supplier helpline.",
2144 /* 0x0f */
2145 "W: The memory in the tape cartridge has failed, which reduces\n"
2146 " performance. Do not use the cartridge for further write "
2147 "operations.",
2148 /* 0x10 */
2149 "C: The operation has failed because the tape cartridge was manually\n"
2150 " de-mounted while the tape drive was actively writing or reading.",
2151 /* 0x11 */
2152 "W: You have loaded a cartridge of a type that is read-only in this "
2153 "drive.\n"
2154 " The cartridge will appear as write-protected.",
2155 /* 0x12 */
2156 "W: The tape directory on the tape cartridge has been corrupted. File\n"
2157 " search performance will be degraded. The tape directory can be "
2158 "rebuilt\n"
2159 " by reading all the data on the cartridge.",
2160 /* 0x13 */
2161 "I: The tape cartridge is nearing the end of its calculated life. It is\n"
2162 " recommended that you:\n"
2163 " 1. Use another tape cartridge for your next backup.\n"
2164 " 2. Store this tape in a safe place in case you need to restore "
2165 " data from it.",
2166 /* 0x14 */
2167 "C: The tape drive needs cleaning:\n"
2168 " 1. If the operation has stopped, eject the tape and clean the "
2169 "drive.\n"
2170 " 2. If the operation has not stopped, wait for it to finish and "
2171 "then\n"
2172 " clean the drive.\n"
2173 " Check the tape drive users manual for device specific cleaning "
2174 "instructions.",
2175 /* 0x15 */
2176 "W: The tape drive is due for routine cleaning:\n"
2177 " 1. Wait for the current operation to finish.\n"
2178 " 2. The use a cleaning cartridge.\n"
2179 " Check the tape drive users manual for device specific cleaning "
2180 "instructions.",
2181 /* 0x16 */
2182 "C: The last cleaning cartridge used in the tape drive has worn out:\n"
2183 " 1. Discard the worn out cleaning cartridge.\n"
2184 " 2. Wait for the current operation to finish.\n"
2185 " 3. Then use a new cleaning cartridge.",
2186 /* 0x17 */
2187 "C: The last cleaning cartridge used in the tape drive was an invalid\n"
2188 " type:\n"
2189 " 1. Do not use this cleaning cartridge in this drive.\n"
2190 " 2. Wait for the current operation to finish.\n"
2191 " 3. Then use a new cleaning cartridge.",
2192 /* 0x18 */
2193 "W: The tape drive has requested a retention operation",
2194 /* 0x19 */
2195 "W: A redundant interface port on the tape drive has failed",
2196 /* 0x1a */
2197 "W: A tape drive cooling fan has failed",
2198 /* 0x1b */
2199 "W: A redundant power supply has failed inside the tape drive enclosure.\n"
2200 " Check the enclosure users manual for instructions on replacing "
2201 "the\n"
2202 " failed power supply.",
2203 /* 0x1c */
2204 "W: The tape drive power consumption is outside the specified range.",
2205 /* 0x1d */
2206 "W: Preventive maintenance of the tape drive is required. Check the tape\n"
2207 " drive users manual for device specific preventive maintenance\n"
2208 " tasks or call the tape drive supplier helpline.",
2209 /* 0x1e */
2210 "C: The tape drive has a hardware fault:\n"
2211 " 1. Eject the tape or magazine.\n"
2212 " 2. Reset the drive.\n"
2213 " 3. Restart the operation.",
2214 /* 0x1f */
2215 "C: The tape drive has a hardware fault:\n"
2216 " 1. Turn the tape drive off and then on again.\n"
2217 " 2. Restart the operation.\n"
2218 " 3. If the problem persists, call the tape drive supplier helpline.",
2219 /* 0x20 */
2220 "W: The tape drive has a problem with the application client interface:\n"
2221 " 1. Check the cables and cable connections.\n"
2222 " 2. Restart the operation.",
2223 /* 0x21 */
2224 "C: The operation has failed:\n"
2225 " 1. Eject the tape or magazine.\n"
2226 " 2. Insert the tape or magazine again.\n"
2227 " 3. Restart the operation.",
2228 /* 0x22 */
2229 "W: The firmware download has failed because you have tried to use the\n"
2230 " incorrect firmware for this tape drive. Obtain the correct\n"
2231 " firmware and try again.",
2232 /* 0x23 */
2233 "W: Environmental conditions inside the tape drive are outside the\n"
2234 " specified humidity range.",
2235 /* 0x24 */
2236 "W: Environmental conditions inside the tape drive are outside the\n"
2237 " specified temperature range.",
2238 /* 0x25 */
2239 "W: The voltage supply to the tape drive is outside the specified range.",
2240 /* 0x26 */
2241 "C: A hardware failure of the tape drive is predicted. Call the tape\n"
2242 " drive supplier helpline.",
2243 /* 0x27 */
2244 "W: The tape drive may have a hardware fault. Run extended diagnostics to\n"
2245 " verify and diagnose the problem. Check the tape drive users manual "
2246 "for\n"
2247 " device specific instructions on running extended diagnostic tests.",
2248 /* 0x28 */
2249 "C: The changer mechanism is having difficulty communicating with the "
2250 "tape\n"
2251 " drive:\n"
2252 " 1. Turn the autoloader off then on.\n"
2253 " 2. Restart the operation.\n"
2254 " 3. If problem persists, call the tape drive supplier helpline.",
2255 /* 0x29 */
2256 "C: A tape has been left in the autoloader by a previous hardware fault:\n"
2257 " 1. Insert an empty magazine to clear the fault.\n"
2258 " 2. If the fault does not clear, turn the autoloader off and then\n"
2259 " on again.\n"
2260 " 3. If the problem persists, call the tape drive supplier helpline.",
2261 /* 0x2a */
2262 "W: There is a problem with the autoloader mechanism.",
2263 /* 0x2b */
2264 "C: The operation has failed because the autoloader door is open:\n"
2265 " 1. Clear any obstructions from the autoloader door.\n"
2266 " 2. Eject the magazine and then insert it again.\n"
2267 " 3. If the fault does not clear, turn the autoloader off and then\n"
2268 " on again.\n"
2269 " 4. If the problem persists, call the tape drive supplier helpline.",
2270 /* 0x2c */
2271 "C: The autoloader has a hardware fault:\n"
2272 " 1. Turn the autoloader off and then on again.\n"
2273 " 2. Restart the operation.\n"
2274 " 3. If the problem persists, call the tape drive supplier helpline.\n"
2275 " Check the autoloader users manual for device specific instructions\n"
2276 " on turning the device power on and off.",
2277 /* 0x2d */
2278 "C: The autoloader cannot operate without the magazine,\n"
2279 " 1. Insert the magazine into the autoloader.\n"
2280 " 2. Restart the operation.",
2281 /* 0x2e */
2282 "W: A hardware failure of the changer mechanism is predicted. Call the\n"
2283 " tape drive supplier helpline.",
2284 /* 0x2f */
2285 "I: Reserved.",
2286 /* 0x30 */
2287 "I: Reserved.",
2288 /* 0x31 */
2289 "I: Reserved.",
2290 /* 0x32 */
2291 "W: Media statistics have been lost at some time in the past",
2292 /* 0x33 */
2293 "W: The tape directory on the tape cartridge just unloaded has been\n"
2294 " corrupted. File search performance will be degraded. The tape\n"
2295 " directory can be rebuilt by reading all the data.",
2296 /* 0x34 */
2297 "C: The tape just unloaded could not write its system area successfully:\n"
2298 " 1. Copy data to another tape cartridge.\n"
2299 " 2. Discard the old cartridge.",
2300 /* 0x35 */
2301 "C: The tape system are could not be read successfully at load time:\n"
2302 " 1. Copy data to another tape cartridge.\n",
2303 /* 0x36 */
2304 "C: The start or data could not be found on the tape:\n"
2305 " 1. Check you are using the correct format tape.\n"
2306 " 2. Discard the tape or return the tape to your supplier",
2307 /* 0x37 */
2308 "C: The operation has failed because the media cannot be loaded\n"
2309 " and threaded.\n"
2310 " 1. Remove the cartridge, inspect it as specified in the product\n"
2311 " manual, and retry the operation.\n"
2312 " 2. If the problem persists, call the tape drive supplier help "
2313 "line.",
2314 /* 0x38 */
2315 "C: The operation has failed because the medium cannot be unloaded:\n"
2316 " 1. Do not attempt to extract the tape cartridge.\n"
2317 " 2. Call the tape driver supplier help line.",
2318 /* 0x39 */
2319 "C: The tape drive has a problem with the automation interface:\n"
2320 " 1. Check the power to the automation system.\n"
2321 " 2. Check the cables and cable connections.\n"
2322 " 3. Call the supplier help line if problem persists.",
2323 /* 0x3a */
2324 "W: The tape drive has reset itself due to a detected firmware\n"
2325 " fault. If problem persists, call the supplier help line.",
2326 };
2327
2328const char *
2329scsiTapeAlertsTapeDevice(unsigned short code)
2330{
2331 static const int num = sizeof(TapeAlertsMessageTable) /
2332 sizeof(TapeAlertsMessageTable[0]);
2333
2334 return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert";
2335}
2336
2337// The first character (W, C, I) tells the severity
2338static const char * ChangerTapeAlertsMessageTable[]= {
2339 " ",
2340 /* 0x01 */
2341 "C: The library mechanism is having difficulty communicating with the\n"
2342 " drive:\n"
2343 " 1. Turn the library off then on.\n"
2344 " 2. Restart the operation.\n"
2345 " 3. If the problem persists, call the library supplier help line.",
2346 /* 0x02 */
2347 "W: There is a problem with the library mechanism. If problem persists,\n"
2348 " call the library supplier help line.",
2349 /* 0x03 */
2350 "C: The library has a hardware fault:\n"
2351 " 1. Reset the library.\n"
2352 " 2. Restart the operation.\n"
2353 " Check the library users manual for device specific instructions on "
2354 "resetting\n"
2355 " the device.",
2356 /* 0x04 */
2357 "C: The library has a hardware fault:\n"
2358 " 1. Turn the library off then on again.\n"
2359 " 2. Restart the operation.\n"
2360 " 3. If the problem persists, call the library supplier help line.\n"
2361 " Check the library users manual for device specific instructions on "
2362 "turning the\n"
2363 " device power on and off.",
2364 /* 0x05 */
2365 "W: The library mechanism may have a hardware fault.\n"
2366 " Run extended diagnostics to verify and diagnose the problem. "
2367 "Check the library\n"
2368 " users manual for device specific instructions on running extended "
2369 "diagnostic\n"
2370 " tests.",
2371 /* 0x06 */
2372 "C: The library has a problem with the host interface:\n"
2373 " 1. Check the cables and connections.\n"
2374 " 2. Restart the operation.",
2375 /* 0x07 */
2376 "W: A hardware failure of the library is predicted. Call the library\n"
2377 " supplier help line.",
2378 /* 0x08 */
2379 "W: Preventive maintenance of the library is required.\n"
2380 " Check the library users manual for device specific preventative "
2381 "maintenance\n"
2382 " tasks, or call your library supplier help line.",
2383 /* 0x09 */
2384 "C: General environmental conditions inside the library are outside the\n"
2385 " specified humidity range.",
2386 /* 0x0a */
2387 "C: General environmental conditions inside the library are outside the\n"
2388 " specified temperature range.",
2389 /* 0x0b */
2390 "C: The voltage supply to the library is outside the specified range.\n"
2391 " There is a potential problem with the power supply or failure of\n"
2392 " a redundant power supply.",
2393 /* 0x0c */
2394 "C: A cartridge has been left inside the library by a previous hardware\n"
2395 " fault:\n"
2396 " 1. Insert an empty magazine to clear the fault.\n"
2397 " 2. If the fault does not clear, turn the library off and then on "
2398 "again.\n"
2399 " 3. If the problem persists, call the library supplier help line.",
2400 /* 0x0d */
2401 "W: There is a potential problem with the drive ejecting cartridges or\n"
2402 " with the library mechanism picking a cartridge from a slot.\n"
2403 " 1. No action needs to be taken at this time.\n"
2404 " 2. If the problem persists, call the library supplier help line.",
2405 /* 0x0e */
2406 "W: There is a potential problem with the library mechanism placing a\n"
2407 " cartridge into a slot.\n"
2408 " 1. No action needs to be taken at this time.\n"
2409 " 2. If the problem persists, call the library supplier help line.",
2410 /* 0x0f */
2411 "W: There is a potential problem with the drive or the library mechanism\n"
2412 " loading cartridges, or an incompatible cartridge.",
2413 /* 0x10 */
2414 "C: The library has failed because the door is open:\n"
2415 " 1. Clear any obstructions from the library door.\n"
2416 " 2. Close the library door.\n"
2417 " 3. If the problem persists, call the library supplier help line.",
2418 /* 0x11 */
2419 "C: There is a mechanical problem with the library media import/export\n"
2420 " mailslot.",
2421 /* 0x12 */
2422 "C: The library cannot operate without the magazine.\n"
2423 " 1. Insert the magazine into the library.\n"
2424 " 2. Restart the operation.",
2425 /* 0x13 */
2426 "W: Library security has been compromised.",
2427 /* 0x14 */
2428 "I: The library security mode has been changed.\n"
2429 " The library has either been put into secure mode, or the library "
2430 "has exited\n"
2431 " the secure mode.\n"
2432 " This is for information purposes only. No action is required.",
2433 /* 0x15 */
2434 "I: The library has been manually turned offline and is unavailable for "
2435 "use.",
2436 /* 0x16 */
2437 "I: A drive inside the library has been taken offline.\n"
2438 " This is for information purposes only. No action is required.",
2439 /* 0x17 */
2440 "W: There is a potential problem with the bar code label or the scanner\n"
2441 " hardware in the library mechanism.\n"
2442 " 1. No action needs to be taken at this time.\n"
2443 " 2. If the problem persists, call the library supplier help line.",
2444 /* 0x18 */
2445 "C: The library has detected an inconsistency in its inventory.\n"
2446 " 1. Redo the library inventory to correct inconsistency.\n"
2447 " 2. Restart the operation.\n"
2448 " Check the applications users manual or the hardware users manual "
2449 "for\n"
2450 " specific instructions on redoing the library inventory.",
2451 /* 0x19 */
2452 "W: A library operation has been attempted that is invalid at this time.",
2453 /* 0x1a */
2454 "W: A redundant interface port on the library has failed.",
2455 /* 0x1b */
2456 "W: A library cooling fan has failed.",
2457 /* 0x1c */
2458 "W: A redundant power supply has failed inside the library. Check the\n"
2459 " library users manual for instructions on replacing the failed "
2460 "power supply.",
2461 /* 0x1d */
2462 "W: The library power consumption is outside the specified range.",
2463 /* 0x1e */
2464 "C: A failure has occurred in the cartridge pass-through mechanism "
2465 "between\n"
2466 " two library modules.",
2467 /* 0x1f */
2468 "C: A cartridge has been left in the pass-through mechanism from a\n"
2469 " previous hardware fault. Check the library users guide for "
2470 "instructions on\n"
2471 " clearing this fault.",
2472 /* 0x20 */
2473 "I: The library was unable to read the bar code on a cartridge.",
2474};
2475
2476const char *
2478{
2479 static const int num = sizeof(ChangerTapeAlertsMessageTable) /
2481
2482 return (code < num) ? ChangerTapeAlertsMessageTable[code] :
2483 "Unknown Alert";
2484}
2485
2486int
2488{
2489 int res;
2490
2491 res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, nullptr, 0);
2492 if (res)
2493 pout("Default self test failed [%s]\n", scsiErrString(res));
2494 return res;
2495}
2496
2497int
2499{
2500 int res;
2501
2502 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, nullptr, 0);
2503 if (res)
2504 pout("Short offline self test failed [%s]\n", scsiErrString(res));
2505 return res;
2506}
2507
2508int
2510{
2511 int res;
2512
2513 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, nullptr, 0);
2514 if (res)
2515 pout("Long (extended) offline self test failed [%s]\n",
2516 scsiErrString(res));
2517 return res;
2518}
2519
2520int
2522{
2523 int res;
2524
2525 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, nullptr, 0);
2526 if (res)
2527 pout("Short foreground self test failed [%s]\n", scsiErrString(res));
2528 return res;
2529}
2530
2531int
2533{
2534 int res;
2535
2536 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, nullptr, 0);
2537 if (res)
2538 pout("Long (extended) foreground self test failed [%s]\n",
2539 scsiErrString(res));
2540 return res;
2541}
2542
2543int
2545{
2546 int res;
2547
2548 res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, nullptr, 0);
2549 if (res)
2550 pout("Abort self test failed [%s]\n", scsiErrString(res));
2551 return res;
2552}
2553
2554/* Returns 0 and the expected duration of an extended self test (in seconds)
2555 if successful; any other return value indicates a failure. */
2556int
2557scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
2558 int modese_len)
2559{
2560 int err, offset;
2561 uint8_t buff[64] = {};
2562
2563 if (modese_len <= 6) {
2564 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2566 buff, sizeof(buff)))) {
2567 if (SIMPLE_ERR_BAD_OPCODE == err)
2568 modese_len = 10;
2569 else
2570 return err;
2571 } else if (0 == modese_len)
2572 modese_len = 6;
2573 }
2574 if (10 == modese_len) {
2575 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2577 buff, sizeof(buff));
2578 if (err)
2579 return err;
2580 }
2581 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2582 if (offset < 0)
2583 return -EINVAL;
2584 if (buff[offset + 1] >= 0xa) {
2585 int res = sg_get_unaligned_be16(buff + offset + 10);
2586
2587 if (res < 0xffff) {
2588 *durationSec = res;
2589 return 0;
2590 }
2591 /* The value 0xffff (all bits set in 16 bit field) indicates that
2592 * the Extended Inquiry VPD page should be consulted, it has a
2593 * similarly named 16 bit field, but the unit is minutes. */
2594 uint8_t b[64];
2595
2597 b, sizeof(b))) &&
2598 ((sg_get_unaligned_be16(b + 2)) > 11)) {
2599 res = sg_get_unaligned_be16(b + 10);
2600 *durationSec = res * 60; /* VPD field is in minutes */
2601 return 0;
2602 } else
2603 return -EINVAL;
2604 } else
2605 return -EINVAL;
2606}
2607
2608void
2609scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp,
2610 int allocLen)
2611{
2612 memset(ecp, 0, sizeof(*ecp));
2613 int num = sg_get_unaligned_be16(resp + 2);
2614 unsigned char * ucp = &resp[0] + 4;
2615
2616 /* allocLen is length of whole log page including 4 byte log page header */
2617 num = num < allocLen - 4 ? num : allocLen - 4;
2618 while (num >= 4) { /* header of each parameter takes 4 bytes */
2619 int pc = sg_get_unaligned_be16(ucp + 0);
2620 int pl = ucp[3] + 4;
2621 uint64_t * ullp;
2622
2623 if (num < pl) /* remaining length less than a complete parameter */
2624 break;
2625 switch (pc) {
2626 case 0:
2627 case 1:
2628 case 2:
2629 case 3:
2630 case 4:
2631 case 5:
2632 case 6:
2633 ecp->gotPC[pc] = 1;
2634 ullp = &ecp->counter[pc];
2635 break;
2636 default:
2637 ecp->gotExtraPC = 1;
2638 ullp = &ecp->counter[7];
2639 break;
2640 }
2641 int k = pl - 4;
2642 unsigned char * xp = ucp + 4;
2643 if (k > (int)sizeof(*ullp)) {
2644 xp += (k - sizeof(*ullp));
2645 k = sizeof(*ullp);
2646 }
2647 *ullp = sg_get_unaligned_be(k, xp);
2648 num -= pl;
2649 ucp += pl;
2650 }
2651}
2652
2653void
2654scsiDecodeNonMediumErrPage(unsigned char *resp,
2655 struct scsiNonMediumError *nmep,
2656 int allocLen)
2657{
2658 memset(nmep, 0, sizeof(*nmep));
2659 int num = sg_get_unaligned_be16(resp + 2);
2660 unsigned char * ucp = &resp[0] + 4;
2661 static int szof = sizeof(nmep->counterPC0);
2662
2663 /* allocLen is length of whole log page including 4 byte log page header */
2664 num = num < allocLen - 4 ? num : allocLen - 4;
2665 while (num >= 4) { /* header of each parameter takes 4 bytes */
2666 int pc = sg_get_unaligned_be16(ucp + 0);
2667 int pl = ucp[3] + 4;
2668 int k;
2669 unsigned char * xp;
2670
2671 if (num < pl) /* remaining length less than a complete parameter */
2672 break;
2673 switch (pc) {
2674 case 0:
2675 nmep->gotPC0 = 1;
2676 k = pl - 4;
2677 xp = ucp + 4;
2678 if (k > szof) {
2679 xp += (k - szof);
2680 k = szof;
2681 }
2682 nmep->counterPC0 = sg_get_unaligned_be(k, xp + 0);
2683 break;
2684 case 0x8009:
2685 nmep->gotTFE_H = 1;
2686 k = pl - 4;
2687 xp = ucp + 4;
2688 if (k > szof) {
2689 xp += (k - szof);
2690 k = szof;
2691 }
2692 nmep->counterTFE_H = sg_get_unaligned_be(k, xp + 0);
2693 break;
2694 case 0x8015:
2695 nmep->gotPE_H = 1;
2696 k = pl - 4;
2697 xp = ucp + 4;
2698 if (k > szof) {
2699 xp += (k - szof);
2700 k = szof;
2701 }
2702 nmep->counterPE_H = sg_get_unaligned_be(k, xp + 0);
2703 break;
2704 default:
2705 nmep->gotExtraPC = 1;
2706 break;
2707 }
2708 num -= pl;
2709 ucp += pl;
2710 }
2711}
2712
2713/* Counts number of failed self-tests. Also encodes the poweron_hour
2714 of the most recent failed self-test. Return value is negative if
2715 this function has a problem (typically -1), otherwise the bottom 8
2716 bits are the number of failed self tests and the 16 bits above that
2717 are the poweron hour of the most recent failure. Note: aborted self
2718 tests (typically by the user) and self tests in progress are not
2719 considered failures. See Working Draft SCSI Primary Commands - 3
2720 (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
2721int
2723{
2724 int num, k, err, fails, fail_hour;
2725 uint8_t * ucp;
2726 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2727
2728 if ((err = scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2730 if (noisy)
2731 pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err));
2732 return -1;
2733 }
2734 if ((resp[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
2735 if (noisy)
2736 pout("Self-test %s Failed, page mismatch\n", logSenStr);
2737 return -1;
2738 }
2739 // compute page length
2740 num = sg_get_unaligned_be16(resp + 2);
2741 // Log sense page length 0x190 bytes
2742 if (num != 0x190) {
2743 if (noisy)
2744 pout("Self-test %s length is 0x%x not 0x190 bytes\n", logSenStr,
2745 num);
2746 return -1;
2747 }
2748 fails = 0;
2749 fail_hour = 0;
2750 // loop through the twenty possible entries
2751 for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) {
2752
2753 // timestamp in power-on hours (or zero if test in progress)
2754 int n = sg_get_unaligned_be16(ucp + 6);
2755
2756 // The spec says "all 20 bytes will be zero if no test" but
2757 // DG has found otherwise. So this is a heuristic.
2758 if ((0 == n) && (0 == ucp[4]))
2759 break;
2760 int res = ucp[4] & 0xf;
2761 if ((res > 2) && (res < 8)) {
2762 fails++;
2763 if (1 == fails)
2764 fail_hour = sg_get_unaligned_be16(ucp + 6);
2765 }
2766 }
2767 return (fail_hour << 8) + fails;
2768}
2769
2770/* Returns 0 if able to read self test log page; then outputs 1 into
2771 *inProgress if self test still in progress, else outputs 0. */
2772int
2774{
2775 int num;
2776 uint8_t * ucp;
2777 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2778
2779 if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2781 return -1;
2782 if (resp[0] != SELFTEST_RESULTS_LPAGE)
2783 return -1;
2784 // compute page length
2785 num = sg_get_unaligned_be16(resp + 2);
2786 // Log sense page length 0x190 bytes
2787 if (num != 0x190) {
2788 return -1;
2789 }
2790 ucp = resp + 4;
2791 if (inProgress)
2792 *inProgress = (0xf == (ucp[4] & 0xf)) ? 1 : 0;
2793 return 0;
2794}
2795
2796/* Returns a negative value if failed to fetch Control mode page or it was
2797 malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD
2798 bit is set. Examines default mode page when current==0 else examines
2799 current mode page. */
2800int
2802{
2803 int err, offset;
2804 uint8_t buff[64] = {};
2805 int pc = current ? MPAGE_CONTROL_CURRENT : MPAGE_CONTROL_DEFAULT;
2806
2807 if (modese_len <= 6) {
2808 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, pc,
2809 buff, sizeof(buff)))) {
2810 if (SIMPLE_ERR_BAD_OPCODE == err)
2811 modese_len = 10;
2812 else
2813 return -EINVAL;
2814 } else if (0 == modese_len)
2815 modese_len = 6;
2816 }
2817 if (10 == modese_len) {
2818 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, pc,
2819 buff, sizeof(buff));
2820 if (err)
2821 return -EINVAL;
2822 }
2823 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2824 if ((offset >= 0) && (buff[offset + 1] >= 0xa))
2825 return (buff[offset + 2] & 2) ? 1 : 0;
2826 return -EINVAL;
2827}
2828
2829/* Returns a negative value on error, 0 if unknown and 1 if SSD,
2830 * otherwise the positive returned value is the speed in rpm. First checks
2831 * the Block Device Characteristics VPD page and if that fails it tries the
2832 * RIGID_DISK_DRIVE_GEOMETRY_PAGE mode page.
2833 * In SBC-4 the 2 bit ZONED field in this VPD page is written to *haw_zbcp
2834 * if haw_zbcp is non-nullptr. In SBC-5 the ZONED field is now obsolete,
2835 * the Zoned block device characteristics VPD page should be used instead. */
2836
2837int
2838scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp,
2839 int * haw_zbcp)
2840{
2841 int err, offset;
2842 uint8_t buff[64] = {};
2843 int pc = MPAGE_CONTROL_DEFAULT;
2844
2846 buff, sizeof(buff))) &&
2847 ((sg_get_unaligned_be16(buff + 2)) > 2)) {
2848 int speed = sg_get_unaligned_be16(buff + 4);
2849 if (form_factorp)
2850 *form_factorp = buff[7] & 0xf;
2851 if (haw_zbcp)
2852 *haw_zbcp = (buff[8] >> 4) & 0x3;
2853 return speed;
2854 }
2855 if (form_factorp)
2856 *form_factorp = 0;
2857 if (haw_zbcp)
2858 *haw_zbcp = 0;
2859 if (modese_len <= 6) {
2860 if ((err = scsiModeSense(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc,
2861 buff, sizeof(buff)))) {
2862 if (SIMPLE_ERR_BAD_OPCODE == err)
2863 modese_len = 10;
2864 else
2865 return -EINVAL;
2866 } else if (0 == modese_len)
2867 modese_len = 6;
2868 }
2869 if (10 == modese_len) {
2871 buff, sizeof(buff));
2872 if (err)
2873 return -EINVAL;
2874 }
2875 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2876 return sg_get_unaligned_be16(buff + offset + 20);
2877}
2878
2879/* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value,
2880 0 - clear bit, 1 - set bit */
2881
2882int
2883scsiGetSetCache(scsi_device * device, int modese_len, short int * wcep,
2884 short int * rcdp)
2885{
2886 int err, offset, resp_len, sp;
2887 uint8_t buff[64] = {};
2888 uint8_t ch_buff[64];
2889 short set_wce = *wcep;
2890 short set_rcd = *rcdp;
2891
2892 if (modese_len <= 6) {
2894 buff, sizeof(buff));
2895 if (err) {
2896 if (SIMPLE_ERR_BAD_OPCODE == err)
2897 modese_len = 10;
2898 else {
2899 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2900 return -EINVAL;
2901 }
2902 } else if (0 == modese_len)
2903 modese_len = 6;
2904 }
2905
2906 if (10 == modese_len) {
2908 buff, sizeof(buff));
2909 if (err) {
2910 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2911 return -EINVAL;
2912 }
2913 }
2914 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2915 if ((offset < 0) || (buff[offset + 1] < 0xa)) {
2916 device->set_err(EINVAL, "Bad response");
2917 return SIMPLE_ERR_BAD_RESP;
2918 }
2919
2920 *wcep = ((buff[offset + 2] & 0x04) != 0);
2921 *rcdp = ((buff[offset + 2] & 0x01) != 0);
2922
2923 if((*wcep == set_wce || set_wce == -1)
2924 && ((*rcdp == set_rcd) || set_rcd == -1))
2925 return 0; // no changes needed or nothing to set
2926
2927 if (modese_len == 6)
2928 err = scsiModeSense(device, CACHING_PAGE, 0,
2930 ch_buff, sizeof(ch_buff));
2931 else
2932 err = scsiModeSense10(device, CACHING_PAGE, 0,
2934 ch_buff, sizeof(ch_buff));
2935 if (err) {
2936 device->set_err(EINVAL, "WCE/RCD bits not changeable");
2937 return err;
2938 }
2939
2940 // set WCE bit
2941 if(set_wce >= 0 && *wcep != set_wce) {
2942 if (0 == (ch_buff[offset + 2] & 0x04)) {
2943 device->set_err(EINVAL, "WCE bit not changeable");
2944 return 1;
2945 }
2946 if(set_wce)
2947 buff[offset + 2] |= 0x04; // set bit
2948 else
2949 buff[offset + 2] &= 0xfb; // clear bit
2950 }
2951 // set RCD bit
2952 if(set_rcd >= 0 && *rcdp != set_rcd) {
2953 if (0 == (ch_buff[offset + 2] & 0x01)) {
2954 device->set_err(EINVAL, "RCD bit not changeable");
2955 return 1;
2956 }
2957 if(set_rcd)
2958 buff[offset + 2] |= 0x01; // set bit
2959 else
2960 buff[offset + 2] &= 0xfe; // clear bit
2961 }
2962
2963 /* mask out DPOFUA device specific (disk) parameter bit */
2964 if (10 == modese_len) {
2965 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
2966 buff[3] &= 0xef;
2967 } else {
2968 resp_len = buff[0] + 1;
2969 buff[2] &= 0xef;
2970 }
2971 sp = 0; /* Do not change saved values */
2972 if (10 == modese_len)
2973 err = scsiModeSelect10(device, sp, buff, resp_len);
2974 else if (6 == modese_len)
2975 err = scsiModeSelect(device, sp, buff, resp_len);
2976 if(err)
2977 device->set_err(EINVAL, "MODE SELECT command failed");
2978 return err;
2979}
2980
2981
2982/* Attempts to set or clear GLTSD bit in Control mode page. If enabled is
2983 0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if
2984 successful, negative if low level error, > 0 if higher level error (e.g.
2985 SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */
2986int
2987scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len)
2988{
2989 int err, offset, resp_len, sp;
2990 uint8_t buff[64] = {};
2991 uint8_t ch_buff[64];
2992
2993 if (modese_len <= 6) {
2994 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2996 buff, sizeof(buff)))) {
2997 if (SIMPLE_ERR_BAD_OPCODE == err)
2998 modese_len = 10;
2999 else
3000 return err;
3001 } else if (0 == modese_len)
3002 modese_len = 6;
3003 }
3004 if (10 == modese_len) {
3005 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
3007 buff, sizeof(buff));
3008 if (err)
3009 return err;
3010 }
3011 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
3012 if ((offset < 0) || (buff[offset + 1] < 0xa))
3013 return SIMPLE_ERR_BAD_RESP;
3014
3015 if (enabled)
3016 enabled = 2;
3017 if (enabled == (buff[offset + 2] & 2))
3018 return 0; /* GLTSD already in wanted state so nothing to do */
3019
3020 if (modese_len == 6)
3021 err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
3023 ch_buff, sizeof(ch_buff));
3024 else
3025 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
3027 ch_buff, sizeof(ch_buff));
3028 if (err)
3029 return err;
3030 if (0 == (ch_buff[offset + 2] & 2))
3031 return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not changeable */
3032
3033 /* mask out DPOFUA device specific (disk) parameter bit */
3034 if (10 == modese_len) {
3035 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
3036 buff[3] &= 0xef;
3037 } else {
3038 resp_len = buff[0] + 1;
3039 buff[2] &= 0xef;
3040 }
3041 sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
3042 if (enabled)
3043 buff[offset + 2] |= 0x2; /* set GLTSD bit */
3044 else
3045 buff[offset + 2] &= 0xfd; /* clear GLTSD bit */
3046 if (10 == modese_len)
3047 err = scsiModeSelect10(device, sp, buff, resp_len);
3048 else if (6 == modese_len)
3049 err = scsiModeSelect(device, sp, buff, resp_len);
3050 return err;
3051}
3052
3053/* Returns a negative value if failed to fetch Protocol specific port mode
3054 page or it was malformed. Returns transport protocol identifier when
3055 value >= 0 . */
3056int
3058{
3059 int err, offset;
3060 uint8_t buff[64] {};
3061
3062 if (modese_len <= 6) {
3063 if ((err = scsiModeSense(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0,
3065 buff, sizeof(buff)))) {
3066 if (SIMPLE_ERR_BAD_OPCODE == err)
3067 modese_len = 10;
3068 else
3069 return -EINVAL;
3070 } else if (0 == modese_len)
3071 modese_len = 6;
3072 }
3073 if (10 == modese_len) {
3076 buff, sizeof(buff));
3077 if (err)
3078 return -EINVAL;
3079 }
3080 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
3081 if ((offset >= 0) && (buff[offset + 1] > 1)) {
3082 if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */
3083 (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f)))
3084 return (buff[offset + 2] & 0xf);
3085 }
3086 return -EINVAL;
3087}
3088
3089const unsigned char *
3090sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len,
3091 int desc_type)
3092{
3093 int add_sen_len;
3094 const unsigned char * descp;
3095
3096 if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
3097 return nullptr;
3098 if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
3099 return nullptr;
3100 add_sen_len = (add_sen_len < (sense_len - 8)) ?
3101 add_sen_len : (sense_len - 8);
3102 descp = &sensep[8];
3103 for (int desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
3104 descp += desc_len;
3105 int add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
3106 desc_len = add_len + 2;
3107 if (descp[0] == desc_type)
3108 return descp;
3109 if (add_len < 0) /* short descriptor ?? */
3110 break;
3111 }
3112 return nullptr;
3113}
3114
3115// Convenience function for formatting strings from SCSI identify
3116void
3117scsi_format_id_string(char * out, const uint8_t * in, int n)
3118{
3119 char tmp[65];
3120 n = n > 64 ? 64 : n;
3121 strncpy(tmp, (const char *)in, n);
3122 tmp[n] = '\0';
3123
3124 // Find the first non-space character (maybe none).
3125 int first = -1;
3126 int i;
3127 for (i = 0; tmp[i]; i++)
3128 if (!isspace((int)tmp[i])) {
3129 first = i;
3130 break;
3131 }
3132
3133 if (first == -1) {
3134 // There are only space characters.
3135 out[0] = '\0';
3136 return;
3137 }
3138
3139 // Find the last non-space character.
3140 for (i = strlen(tmp)-1; i >= first && isspace((int)tmp[i]); i--);
3141 int last = i;
3142
3143 strncpy(out, tmp+first, last-first+1);
3144 out[last-first+1] = '\0';
3145}
3146
3147static const char * wn = "Warning";
3148
3149static const char * wn1_9[] = {
3150 "specified temperature exceeded",
3151 "enclosure degraded",
3152 "background self-test failed",
3153 "background pre-scan detected medium error",
3154 "background medium scan detected medium error",
3155 "non-volatile cache now volatile",
3156 "degraded power to non-volatile cache",
3157 "power loss expected",
3158 "device statistics notification active",
3159};
3160
3161static const char * five_d_t[] = {
3162 "Hardware",
3163 "Controller",
3164 "Data channel",
3165 "Servo",
3166 "Spindle",
3167 "Firmware",
3168};
3169
3170static const char * impfail = "impending failure";
3171
3172static const char * impending0_c[] = {
3173 "general hard drive failure",
3174 "drive error rate too high",
3175 "data error rate too high",
3176 "seek error rate too high",
3177 "too many block reassigns",
3178 "access times too high",
3179 "start unit times too high",
3180 "channel parametrics",
3181 "controller detected",
3182 "throughput performance",
3183 "seek time performance",
3184 "spin-up retry count",
3185 "drive calibration retry count",
3186};
3187
3188static const char * pred = "prediction threshold exceeded";
3189
3190/* The SCSI Informational Exceptions log page and various other mechanisms
3191 * yield an additional sense code (and its qualifier) [asc and ascq] when
3192 * triggered. It seems only two asc values are involved: 0xb and 0xd.
3193 * If asc,ascq strings are known (in spc6r06.pdf) for asc 0xb and 0x5d
3194 * then a pointer to that string is returned, else nullptr is returned. The
3195 * caller provides a buffer (b) and its length (blen) that a string (if
3196 * found) is placed in. So if a match is found b is returned. */
3197char *
3198scsiGetIEString(uint8_t asc, uint8_t ascq, char * b, int blen)
3199{
3200 if (asc == 0xb) {
3201 switch (ascq) {
3202 case 0:
3203 snprintf(b, blen, "%s", wn);
3204 return b;
3205 case 0x1:
3206 case 0x2:
3207 case 0x3:
3208 case 0x4:
3209 case 0x5:
3210 case 0x6:
3211 case 0x7:
3212 case 0x8:
3213 case 0x9:
3214 snprintf(b, blen, "%s - %s", wn, wn1_9[ascq - 1]);
3215 return b;
3216 case 0x12:
3217 snprintf(b, blen, "%s - microcode security at risk", wn);
3218 return b;
3219 case 0x13:
3220 snprintf(b, blen, "%s - microcode digital signature validation "
3221 "failure", wn);
3222 return b;
3223 case 0x14:
3224 snprintf(b, blen, "%s - physical element status change", wn);
3225 return b;
3226 default:
3227 if ((ascq >= 0xa) && (ascq <= 0x11)) {
3228 uint8_t q = ascq - 0xa;
3229
3230 snprintf(b, blen, "%s - %s %s %s limit exceeded", wn,
3231 (((q % 2) == 0) ? "high" : "low"),
3232 ((((q / 2) % 2) == 0) ? "critical" : "operating"),
3233 ((((q / 4) % 2) == 0) ? "temperature" : "humidity"));
3234 return b;
3235 } else
3236 return nullptr;
3237 }
3238 } else if (asc == 0x5d) {
3239 switch (ascq) {
3240 case 0:
3241 snprintf(b, blen, "Failure %s", pred);
3242 return b;
3243 case 1:
3244 snprintf(b, blen, "Media failure %s", pred);
3245 return b;
3246 case 2:
3247 snprintf(b, blen, "Logical unit failure %s", pred);
3248 return b;
3249 case 3:
3250 snprintf(b, blen, "spare area exhaustion failure %s", pred);
3251 return b;
3252 case 0x1d:
3253 snprintf(b, blen, "%s %s power loss protection circuit area "
3254 "exhaustion failure", five_d_t[0], impfail);
3255 return b;
3256 case 0x73:
3257 snprintf(b, blen, "Media %s endurance limit met", impfail);
3258 return b;
3259 case 0xff:
3260 snprintf(b, blen, "Failure %s (false)", pred);
3261 return b;
3262 default:
3263 if ((ascq >= 0x10) && (ascq <= 0x6c)) {
3264 uint8_t q = ascq - 0x10;
3265 uint8_t rem = q % 0x10;
3266
3267 if (rem <= 0xc) {
3268 snprintf(b, blen, "%s %s %s", five_d_t[q / 0x10], impfail,
3269 impending0_c[rem]);
3270 return b;
3271 } else
3272 return nullptr;
3273 } else
3274 return nullptr;
3275 }
3276 } else
3277 return nullptr;
3278}
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:2557
void scsiDecodeErrCounterPage(unsigned char *resp, struct scsiErrorCounter *ecp, int allocLen)
Definition: scsicmds.cpp:2609
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:2532
static const char * TapeAlertsMessageTable[]
Definition: scsicmds.cpp:2085
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:2000
static const char * pred
Definition: scsicmds.cpp:3188
int scsiSmartShortCapSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2521
int scsiSmartSelfTestAbort(scsi_device *device)
Definition: scsicmds.cpp:2544
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:2338
static const char * wn
Definition: scsicmds.cpp:3147
static const char * impfail
Definition: scsicmds.cpp:3170
const char * scsiTapeAlertsTapeDevice(unsigned short code)
Definition: scsicmds.cpp:2329
int scsiFetchTransportProtocol(scsi_device *device, int modese_len)
Definition: scsicmds.cpp:3057
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:3149
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:2509
void scsiDecodeNonMediumErrPage(unsigned char *resp, struct scsiNonMediumError *nmep, int allocLen)
Definition: scsicmds.cpp:2654
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:2028
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:2773
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:3198
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:2883
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:2838
void scsi_format_id_string(char *out, const uint8_t *in, int n)
Definition: scsicmds.cpp:3117
#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:3090
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:2487
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:2477
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:2801
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:2722
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:2987
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:2498
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:3161
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:3172
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:1327
void pout(const char *fmt,...)
Definition: smartd.cpp:1347
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