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