1 /*
2 * Copyright (c) 1999-2022 Douglas Gilbert.
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the BSD_LICENSE file.
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 */
9
10 /* NOTICE:
11 * On 5th October 2004 (v1.00) this file name was changed from sg_err.c
12 * to sg_lib.c and the previous GPL was changed to a FreeBSD license.
13 * The intention is to maintain this file and the related sg_lib.h file
14 * as open source and encourage their unencumbered use.
15 *
16 * CONTRIBUTIONS:
17 * This file started out as a copy of SCSI opcodes, sense keys and
18 * additional sense codes (ASC/ASCQ) kept in the Linux SCSI subsystem
19 * in the kernel source file: drivers/scsi/constant.c . That file
20 * bore this notice: "Copyright (C) 1993, 1994, 1995 Eric Youngdale"
21 * and a GPL notice.
22 *
23 * Much of the data in this file is derived from SCSI draft standards
24 * found at https://www.t10.org with the "SCSI Primary Commands-4" (SPC-4)
25 * being the central point of reference.
26 *
27 * Contributions:
28 * sense key specific field decoding [Trent Piepho 20031116]
29 *
30 */
31
32 #define _POSIX_C_SOURCE 200809L /* for posix_memalign() */
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <stdbool.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <ctype.h>
40 #define __STDC_FORMAT_MACROS 1
41 #include <inttypes.h>
42 #include <errno.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include "sg_lib.h"
53 #include "sg_lib_data.h"
54 #include "sg_unaligned.h"
55 #include "sg_pr2serr.h"
56
57 /* sg_lib_version_str (and datestamp) defined in sg_lib_data.c file */
58
59 #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d /* corresponding ASC is 0 */
60
61 typedef unsigned int my_uint; /* convenience to save a few line wraps */
62
63 FILE * sg_warnings_strm = NULL; /* would like to default to stderr */
64
65
66 int
pr2ws(const char * fmt,...)67 pr2ws(const char * fmt, ...)
68 {
69 va_list args;
70 int n;
71
72 va_start(args, fmt);
73 n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
74 va_end(args);
75 return n;
76 }
77
78 /* Want safe, 'n += snprintf(b + n, blen - n, ...)' style sequence of
79 * functions. Returns number of chars placed in cp excluding the
80 * trailing null char. So for cp_max_len > 0 the return value is always
81 * < cp_max_len; for cp_max_len <= 1 the return value is 0 and no chars are
82 * written to cp. Note this means that when cp_max_len = 1, this function
83 * assumes that cp[0] is the null character and does nothing (and returns
84 * 0). Linux kernel has a similar function called scnprintf(). Public
85 * declaration in sg_pr2serr.h header */
86 int
sg_scnpr(char * cp,int cp_max_len,const char * fmt,...)87 sg_scnpr(char * cp, int cp_max_len, const char * fmt, ...)
88 {
89 va_list args;
90 int n;
91
92 if (cp_max_len < 2)
93 return 0;
94 va_start(args, fmt);
95 n = vsnprintf(cp, cp_max_len, fmt, args);
96 va_end(args);
97 return (n < cp_max_len) ? n : (cp_max_len - 1);
98 }
99
100 /* Simple ASCII printable (does not use locale), includes space and excludes
101 * DEL (0x7f). */
102 static inline int
my_isprint(int ch)103 my_isprint(int ch)
104 {
105 return ((ch >= ' ') && (ch < 0x7f));
106 }
107
108 /* DSENSE is 'descriptor sense' as opposed to the older 'fixed sense'.
109 * Only (currently) used in SNTL. */
110 bool
sg_get_initial_dsense(void)111 sg_get_initial_dsense(void)
112 {
113 int k;
114 const char * cp;
115
116 cp = getenv("SG3_UTILS_DSENSE");
117 if (cp) {
118 if (1 == sscanf(cp, "%d", &k))
119 return k ? true : false;
120 }
121 return false;
122 }
123
124 /* Searches 'arr' for match on 'value' then 'peri_type'. If matches
125 'value' but not 'peri_type' then yields first 'value' match entry.
126 Last element of 'arr' has NULL 'name'. If no match returns NULL. */
127 static const struct sg_lib_value_name_t *
get_value_name(const struct sg_lib_value_name_t * arr,int value,int peri_type)128 get_value_name(const struct sg_lib_value_name_t * arr, int value,
129 int peri_type)
130 {
131 const struct sg_lib_value_name_t * vp = arr;
132 const struct sg_lib_value_name_t * holdp;
133
134 if (peri_type < 0)
135 peri_type = 0;
136 for (; vp->name; ++vp) {
137 if (value == vp->value) {
138 if (sg_pdt_s_eq(peri_type, vp->peri_dev_type))
139 return vp;
140 holdp = vp;
141 while ((vp + 1)->name && (value == (vp + 1)->value)) {
142 ++vp;
143 if (sg_pdt_s_eq(peri_type, vp->peri_dev_type))
144 return vp;
145 }
146 return holdp;
147 }
148 }
149 return NULL;
150 }
151
152 /* If this function is not called, sg_warnings_strm will be NULL and all users
153 * (mainly fprintf() ) need to check and substitute stderr as required */
154 void
sg_set_warnings_strm(FILE * warnings_strm)155 sg_set_warnings_strm(FILE * warnings_strm)
156 {
157 sg_warnings_strm = warnings_strm;
158 }
159
160 /* Take care to minimize printf() parsing delays when printing commands */
161 static char bin2hexascii[] = {'0', '1', '2', '3', '4', '5', '6', '7',
162 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
163
164
165 /* Given a SCSI command pointed to by cdbp of sz bytes this function forms
166 * a SCSI command in ASCII surrounded by square brackets in 'b'. 'b' is at
167 * least blen bytes long. If cmd_name is true then the command is prefixed
168 * by its SCSI command name (e.g. "VERIFY(10) [2f ...]". The command is
169 * shown as spaced separated pairs of hexadecimal digits (i.e. 0-9, a-f).
170 * Each pair represents byte. The leftmost pair of digits is cdbp[0] . If
171 * sz <= 0 then this function tries to guess the length of the command. */
172 char *
sg_get_command_str(const uint8_t * cdbp,int sz,bool cmd_name,int blen,char * b)173 sg_get_command_str(const uint8_t * cdbp, int sz, bool cmd_name, int blen,
174 char * b)
175 {
176 int k, j, jj;
177
178 if ((cdbp == NULL) || (b == NULL) || (blen < 1))
179 return b;
180 if (cmd_name && (blen > 16)) {
181 sg_get_command_name(cdbp, 0, blen, b);
182 j = (int)strlen(b);
183 if (j < (blen - 1))
184 b[j++] = ' ';
185 } else
186 j = 0;
187 if (j >= blen)
188 goto fini;
189 b[j++] = '[';
190 if (j >= blen)
191 goto fini;
192 if (sz <= 0) {
193 if (SG_VARIABLE_LENGTH_CMD == cdbp[0])
194 sz = cdbp[7] + 8;
195 else
196 sz = sg_get_command_size(cdbp[0]);
197 }
198 jj = j;
199 for (k = 0; (k < sz) && (j < (blen - 3)); ++k, j += 3, ++cdbp) {
200 b[j] = bin2hexascii[(*cdbp >> 4) & 0xf];
201 b[j + 1] = bin2hexascii[*cdbp & 0xf];
202 b[j + 2] = ' ';
203 }
204 if (j > jj)
205 --j; /* don't want trailing space before ']' */
206 if (j >= blen)
207 goto fini;
208 b[j++] = ']';
209 fini:
210 if (j >= blen)
211 b[blen - 1] = '\0'; /* truncated string */
212 else
213 b[j] = '\0';
214 return b;
215 }
216
217 #define CMD_NAME_LEN 128
218
219 void
sg_print_command_len(const uint8_t * cdbp,int sz)220 sg_print_command_len(const uint8_t * cdbp, int sz)
221 {
222 char buff[CMD_NAME_LEN];
223
224 sg_get_command_str(cdbp, sz, true, sizeof(buff), buff);
225 pr2ws("%s\n", buff);
226 }
227
228 void
sg_print_command(const uint8_t * cdbp)229 sg_print_command(const uint8_t * cdbp)
230 {
231 sg_print_command_len(cdbp, 0);
232 }
233
234 bool
sg_scsi_status_is_good(int sstatus)235 sg_scsi_status_is_good(int sstatus)
236 {
237 sstatus &= 0xfe;
238 switch (sstatus) {
239 case SAM_STAT_GOOD:
240 case SAM_STAT_CONDITION_MET:
241 return true;
242 default:
243 return false;
244 }
245 }
246
247 bool
sg_scsi_status_is_bad(int sstatus)248 sg_scsi_status_is_bad(int sstatus)
249 {
250 sstatus &= 0xfe;
251 switch (sstatus) {
252 case SAM_STAT_GOOD:
253 case SAM_STAT_CONDITION_MET:
254 return false;
255 default:
256 return true;
257 }
258 }
259
260 void
sg_get_scsi_status_str(int scsi_status,int buff_len,char * buff)261 sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff)
262 {
263 const struct sg_lib_simple_value_name_t * sstatus_p;
264
265 if ((NULL == buff) || (buff_len < 1))
266 return;
267 else if (1 == buff_len) {
268 buff[0] = '\0';
269 return;
270 }
271 scsi_status &= 0x7e; /* sanitize as much as possible */
272 for (sstatus_p = sg_lib_sstatus_str_arr; sstatus_p->name; ++sstatus_p) {
273 if (scsi_status == sstatus_p->value)
274 break;
275 }
276 if (sstatus_p->name)
277 sg_scnpr(buff, buff_len, "%s", sstatus_p->name);
278 else
279 sg_scnpr(buff, buff_len, "Unknown status [0x%x]", scsi_status);
280 }
281
282 void
sg_print_scsi_status(int scsi_status)283 sg_print_scsi_status(int scsi_status)
284 {
285 char buff[128];
286
287 sg_get_scsi_status_str(scsi_status, sizeof(buff) - 1, buff);
288 buff[sizeof(buff) - 1] = '\0';
289 pr2ws("%s ", buff);
290 }
291
292 /* Get sense key from sense buffer. If successful returns a sense key value
293 * between 0 and 15. If sense buffer cannot be decode, returns -1 . */
294 int
sg_get_sense_key(const uint8_t * sbp,int sb_len)295 sg_get_sense_key(const uint8_t * sbp, int sb_len)
296 {
297 if ((NULL == sbp) || (sb_len < 2))
298 return -1;
299 switch (sbp[0] & 0x7f) {
300 case 0x70:
301 case 0x71:
302 return (sb_len < 3) ? -1 : (sbp[2] & 0xf);
303 case 0x72:
304 case 0x73:
305 return sbp[1] & 0xf;
306 default:
307 return -1;
308 }
309 }
310
311 /* Yield string associated with sense_key value. Returns 'buff'. */
312 char *
sg_get_sense_key_str(int sense_key,int buff_len,char * buff)313 sg_get_sense_key_str(int sense_key, int buff_len, char * buff)
314 {
315 if (1 == buff_len) {
316 buff[0] = '\0';
317 return buff;
318 }
319 if ((sense_key >= 0) && (sense_key < 16))
320 sg_scnpr(buff, buff_len, "%s", sg_lib_sense_key_desc[sense_key]);
321 else
322 sg_scnpr(buff, buff_len, "invalid value: 0x%x", sense_key);
323 return buff;
324 }
325
326 /* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
327 char *
sg_get_additional_sense_str(int asc,int ascq,bool add_sense_leadin,int buff_len,char * buff)328 sg_get_additional_sense_str(int asc, int ascq, bool add_sense_leadin,
329 int buff_len, char * buff)
330 {
331 int k, num, rlen;
332 bool found = false;
333
334 if (1 == buff_len) {
335 buff[0] = '\0';
336 return buff;
337 }
338 for (k = 0; sg_lib_asc_ascq_range[k].text; ++k) {
339 struct sg_lib_asc_ascq_range_t * ei2p = &sg_lib_asc_ascq_range[k];
340
341 if ((ei2p->asc == asc) &&
342 (ascq >= ei2p->ascq_min) &&
343 (ascq <= ei2p->ascq_max)) {
344 found = true;
345 if (add_sense_leadin)
346 num = sg_scnpr(buff, buff_len, "Additional sense: ");
347 else
348 num = 0;
349 rlen = buff_len - num;
350 sg_scnpr(buff + num, ((rlen > 0) ? rlen : 0), ei2p->text, ascq);
351 }
352 }
353 if (found)
354 return buff;
355
356 for (k = 0; sg_lib_asc_ascq[k].text; ++k) {
357 struct sg_lib_asc_ascq_t * eip = &sg_lib_asc_ascq[k];
358
359 if (eip->asc == asc &&
360 eip->ascq == ascq) {
361 found = true;
362 if (add_sense_leadin)
363 sg_scnpr(buff, buff_len, "Additional sense: %s", eip->text);
364 else
365 sg_scnpr(buff, buff_len, "%s", eip->text);
366 }
367 }
368 if (! found) {
369 if (asc >= 0x80)
370 sg_scnpr(buff, buff_len, "vendor specific ASC=%02x, ASCQ=%02x "
371 "(hex)", asc, ascq);
372 else if (ascq >= 0x80)
373 sg_scnpr(buff, buff_len, "ASC=%02x, vendor specific qualification "
374 "ASCQ=%02x (hex)", asc, ascq);
375 else
376 sg_scnpr(buff, buff_len, "ASC=%02x, ASCQ=%02x (hex)", asc, ascq);
377 }
378 return buff;
379 }
380
381 /* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
382 char *
sg_get_asc_ascq_str(int asc,int ascq,int buff_len,char * buff)383 sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
384 {
385 return sg_get_additional_sense_str(asc, ascq, true, buff_len, buff);
386 }
387
388 /* Attempt to find the first SCSI sense data descriptor that matches the
389 * given 'desc_type'. If found return pointer to start of sense data
390 * descriptor; otherwise (including fixed format sense data) returns NULL. */
391 const uint8_t *
sg_scsi_sense_desc_find(const uint8_t * sbp,int sb_len,int desc_type)392 sg_scsi_sense_desc_find(const uint8_t * sbp, int sb_len,
393 int desc_type)
394 {
395 int add_sb_len, desc_len, k;
396 const uint8_t * descp;
397
398 if ((sb_len < 8) || (0 == (add_sb_len = sbp[7])))
399 return NULL;
400 if ((sbp[0] < 0x72) || (sbp[0] > 0x73))
401 return NULL;
402 add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8);
403 descp = &sbp[8];
404 for (desc_len = 0, k = 0; k < add_sb_len; k += desc_len) {
405 int add_d_len;
406
407 descp += desc_len;
408 add_d_len = (k < (add_sb_len - 1)) ? descp[1]: -1;
409 desc_len = add_d_len + 2;
410 if (descp[0] == desc_type)
411 return descp;
412 if (add_d_len < 0) /* short descriptor ?? */
413 break;
414 }
415 return NULL;
416 }
417
418 /* Returns true if valid bit set, false if valid bit clear. Irrespective the
419 * information field is written out via 'info_outp' (except when it is
420 * NULL). Handles both fixed and descriptor sense formats. */
421 bool
sg_get_sense_info_fld(const uint8_t * sbp,int sb_len,uint64_t * info_outp)422 sg_get_sense_info_fld(const uint8_t * sbp, int sb_len,
423 uint64_t * info_outp)
424 {
425 const uint8_t * bp;
426
427 if (info_outp)
428 *info_outp = 0;
429 if (sb_len < 7)
430 return false;
431 switch (sbp[0] & 0x7f) {
432 case 0x70:
433 case 0x71:
434 if (info_outp)
435 *info_outp = sg_get_unaligned_be32(sbp + 3);
436 return !!(sbp[0] & 0x80);
437 case 0x72:
438 case 0x73:
439 bp = sg_scsi_sense_desc_find(sbp, sb_len, 0 /* info desc */);
440 if (bp && (0xa == bp[1])) {
441 uint64_t ull = sg_get_unaligned_be64(bp + 4);
442
443 if (info_outp)
444 *info_outp = ull;
445 return !!(bp[2] & 0x80); /* since spc3r23 should be set */
446 } else
447 return false;
448 default:
449 return false;
450 }
451 }
452
453 /* Returns true if fixed format or command specific information descriptor
454 * is found in the descriptor sense; else false. If available the command
455 * specific information field (4 byte integer in fixed format, 8 byte
456 * integer in descriptor format) is written out via 'cmd_spec_outp'.
457 * Handles both fixed and descriptor sense formats. */
458 bool
sg_get_sense_cmd_spec_fld(const uint8_t * sbp,int sb_len,uint64_t * cmd_spec_outp)459 sg_get_sense_cmd_spec_fld(const uint8_t * sbp, int sb_len,
460 uint64_t * cmd_spec_outp)
461 {
462 const uint8_t * bp;
463
464 if (cmd_spec_outp)
465 *cmd_spec_outp = 0;
466 if (sb_len < 7)
467 return false;
468 switch (sbp[0] & 0x7f) {
469 case 0x70:
470 case 0x71:
471 if (cmd_spec_outp)
472 *cmd_spec_outp = sg_get_unaligned_be32(sbp + 8);
473 return true;
474 case 0x72:
475 case 0x73:
476 bp = sg_scsi_sense_desc_find(sbp, sb_len,
477 1 /* command specific info desc */);
478 if (bp && (0xa == bp[1])) {
479 if (cmd_spec_outp)
480 *cmd_spec_outp = sg_get_unaligned_be64(bp + 4);
481 return true;
482 } else
483 return false;
484 default:
485 return false;
486 }
487 }
488
489 /* Returns true if any of the 3 bits (i.e. FILEMARK, EOM or ILI) are set.
490 * In descriptor format if the stream commands descriptor not found
491 * then returns false. Writes true or false corresponding to these bits to
492 * the last three arguments if they are non-NULL. */
493 bool
sg_get_sense_filemark_eom_ili(const uint8_t * sbp,int sb_len,bool * filemark_p,bool * eom_p,bool * ili_p)494 sg_get_sense_filemark_eom_ili(const uint8_t * sbp, int sb_len,
495 bool * filemark_p, bool * eom_p, bool * ili_p)
496 {
497 const uint8_t * bp;
498
499 if (sb_len < 7)
500 return false;
501 switch (sbp[0] & 0x7f) {
502 case 0x70:
503 case 0x71:
504 if (sbp[2] & 0xe0) {
505 if (filemark_p)
506 *filemark_p = !!(sbp[2] & 0x80);
507 if (eom_p)
508 *eom_p = !!(sbp[2] & 0x40);
509 if (ili_p)
510 *ili_p = !!(sbp[2] & 0x20);
511 return true;
512 } else
513 return false;
514 case 0x72:
515 case 0x73:
516 /* Look for stream commands sense data descriptor */
517 bp = sg_scsi_sense_desc_find(sbp, sb_len, 4);
518 if (bp && (bp[1] >= 2)) {
519 if (bp[3] & 0xe0) {
520 if (filemark_p)
521 *filemark_p = !!(bp[3] & 0x80);
522 if (eom_p)
523 *eom_p = !!(bp[3] & 0x40);
524 if (ili_p)
525 *ili_p = !!(bp[3] & 0x20);
526 return true;
527 }
528 }
529 return false;
530 default:
531 return false;
532 }
533 }
534
535 /* Returns true if SKSV is set and sense key is NO_SENSE or NOT_READY. Also
536 * returns true if progress indication sense data descriptor found. Places
537 * progress field from sense data where progress_outp points. If progress
538 * field is not available returns false and *progress_outp is unaltered.
539 * Handles both fixed and descriptor sense formats.
540 * Hint: if true is returned *progress_outp may be multiplied by 100 then
541 * divided by 65536 to get the percentage completion. */
542 bool
sg_get_sense_progress_fld(const uint8_t * sbp,int sb_len,int * progress_outp)543 sg_get_sense_progress_fld(const uint8_t * sbp, int sb_len,
544 int * progress_outp)
545 {
546 const uint8_t * bp;
547 int sk, sk_pr;
548
549 if (sb_len < 7)
550 return false;
551 switch (sbp[0] & 0x7f) {
552 case 0x70:
553 case 0x71:
554 sk = (sbp[2] & 0xf);
555 if ((sb_len < 18) ||
556 ((SPC_SK_NO_SENSE != sk) && (SPC_SK_NOT_READY != sk)))
557 return false;
558 if (sbp[15] & 0x80) { /* SKSV bit set */
559 if (progress_outp)
560 *progress_outp = sg_get_unaligned_be16(sbp + 16);
561 return true;
562 } else
563 return false;
564 case 0x72:
565 case 0x73:
566 /* sense key specific progress (0x2) or progress descriptor (0xa) */
567 sk = (sbp[1] & 0xf);
568 sk_pr = (SPC_SK_NO_SENSE == sk) || (SPC_SK_NOT_READY == sk);
569 if (sk_pr && ((bp = sg_scsi_sense_desc_find(sbp, sb_len, 2))) &&
570 (0x6 == bp[1]) && (0x80 & bp[4])) {
571 if (progress_outp)
572 *progress_outp = sg_get_unaligned_be16(bp + 5);
573 return true;
574 } else if (((bp = sg_scsi_sense_desc_find(sbp, sb_len, 0xa))) &&
575 ((0x6 == bp[1]))) {
576 if (progress_outp)
577 *progress_outp = sg_get_unaligned_be16(bp + 6);
578 return true;
579 } else
580 return false;
581 default:
582 return false;
583 }
584 }
585
586 char *
sg_get_pdt_str(int pdt,int buff_len,char * buff)587 sg_get_pdt_str(int pdt, int buff_len, char * buff)
588 {
589 if ((pdt < 0) || (pdt > PDT_MAX))
590 sg_scnpr(buff, buff_len, "bad pdt");
591 else
592 sg_scnpr(buff, buff_len, "%s", sg_lib_pdt_strs[pdt]);
593 return buff;
594 }
595
596 /* Returns true if left argument is "equal" to the right argument. l_pdt_s
597 * is a compound PDT (SCSI Peripheral Device Type) or a negative number
598 * which represents a wildcard (i.e. match anything). r_pdt_s has a similar
599 * form. PDT values are 5 bits long (0 to 31) and a compound pdt_s is
600 * formed by shifting the second (upper) PDT by eight bits to the left and
601 * OR-ing it with the first PDT. The pdt_s values must be defined so
602 * PDT_DISK (0) is _not_ the upper value in a compound pdt_s. */
603 bool
sg_pdt_s_eq(int l_pdt_s,int r_pdt_s)604 sg_pdt_s_eq(int l_pdt_s, int r_pdt_s)
605 {
606 bool upper_l = !!(l_pdt_s & PDT_UPPER_MASK);
607 bool upper_r = !!(r_pdt_s & PDT_UPPER_MASK);
608
609 if ((l_pdt_s < 0) || (r_pdt_s < 0))
610 return true;
611 if (!upper_l && !upper_r)
612 return l_pdt_s == r_pdt_s;
613 else if (upper_l && upper_r)
614 return (((PDT_UPPER_MASK & l_pdt_s) == (PDT_UPPER_MASK & r_pdt_s)) ||
615 ((PDT_LOWER_MASK & l_pdt_s) == (PDT_LOWER_MASK & r_pdt_s)));
616 else if (upper_l)
617 return (((PDT_LOWER_MASK & l_pdt_s) == r_pdt_s) ||
618 ((PDT_UPPER_MASK & l_pdt_s) >> 8) == r_pdt_s);
619 return (((PDT_LOWER_MASK & r_pdt_s) == l_pdt_s) ||
620 ((PDT_UPPER_MASK & r_pdt_s) >> 8) == l_pdt_s);
621 }
622
623 int
sg_lib_pdt_decay(int pdt)624 sg_lib_pdt_decay(int pdt)
625 {
626 if ((pdt < 0) || (pdt > PDT_MAX))
627 return 0;
628 return sg_lib_pdt_decay_arr[pdt];
629 }
630
631 char *
sg_get_trans_proto_str(int tpi,int buff_len,char * buff)632 sg_get_trans_proto_str(int tpi, int buff_len, char * buff)
633 {
634 if ((tpi < 0) || (tpi > 15))
635 sg_scnpr(buff, buff_len, "bad tpi");
636 else
637 sg_scnpr(buff, buff_len, "%s", sg_lib_transport_proto_strs[tpi]);
638 return buff;
639 }
640
641 #define TRANSPORT_ID_MIN_LEN 24
642
643 char *
sg_decode_transportid_str(const char * lip,uint8_t * bp,int bplen,bool only_one,int blen,char * b)644 sg_decode_transportid_str(const char * lip, uint8_t * bp, int bplen,
645 bool only_one, int blen, char * b)
646 {
647 int num, k, n;
648 uint64_t ull;
649 int bump;
650
651 if ((NULL == b) || (blen < 1))
652 return b;
653 else if (1 == blen) {
654 b[0] = '\0';
655 return b;
656 }
657 if (NULL == lip)
658 lip = "";
659 /* bump = TRANSPORT_ID_MIN_LEN; // some old compilers insisted on this */
660 for (k = 0, n = 0; bplen > 0; ++k, bp += bump, bplen -= bump) {
661 int proto_id, normal_len, tpid_format;
662
663 if ((k > 0) && only_one)
664 break;
665 if ((bplen < 24) || (0 != (bplen % 4)))
666 n += sg_scnpr(b + n, blen - n, "%sTransport Id short or not "
667 "multiple of 4 [length=%d]:\n", lip, blen);
668 else
669 n += sg_scnpr(b + n, blen - n, "%sTransport Id of initiator:\n",
670 lip);
671 tpid_format = ((bp[0] >> 6) & 0x3);
672 proto_id = (bp[0] & 0xf);
673 normal_len = (bplen > TRANSPORT_ID_MIN_LEN) ?
674 TRANSPORT_ID_MIN_LEN : bplen;
675 switch (proto_id) {
676 case TPROTO_FCP: /* Fibre channel */
677 n += sg_scnpr(b + n, blen - n, "%s FCP-2 World Wide Name:\n",
678 lip);
679 if (0 != tpid_format)
680 n += sg_scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
681 "%d]\n", lip, tpid_format);
682 n += hex2str(bp + 8, 8, lip, 1, blen - n, b + n);
683 bump = TRANSPORT_ID_MIN_LEN;
684 break;
685 case TPROTO_SPI: /* Scsi Parallel Interface, obsolete */
686 n += sg_scnpr(b + n, blen - n, "%s Parallel SCSI initiator SCSI "
687 "address: 0x%x\n", lip,
688 sg_get_unaligned_be16(bp + 2));
689 if (0 != tpid_format)
690 n += sg_scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
691 "%d]\n", lip, tpid_format);
692 n += sg_scnpr(b + n, blen - n, "%s relative port number (of "
693 "corresponding target): 0x%x\n", lip,
694 sg_get_unaligned_be16(bp + 6));
695 bump = TRANSPORT_ID_MIN_LEN;
696 break;
697 case TPROTO_SSA:
698 n += sg_scnpr(b + n, blen - n, "%s SSA (transport id not "
699 "defined):\n", lip);
700 n += sg_scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
701 tpid_format);
702 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
703 bump = TRANSPORT_ID_MIN_LEN;
704 break;
705 case TPROTO_1394: /* IEEE 1394 */
706 n += sg_scnpr(b + n, blen - n, "%s IEEE 1394 EUI-64 name:\n",
707 lip);
708 if (0 != tpid_format)
709 n += sg_scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
710 "%d]\n", lip, tpid_format);
711 n += hex2str(&bp[8], 8, lip, 1, blen - n, b + n);
712 bump = TRANSPORT_ID_MIN_LEN;
713 break;
714 case TPROTO_SRP: /* SCSI over RDMA */
715 n += sg_scnpr(b + n, blen - n, "%s RDMA initiator port "
716 "identifier:\n", lip);
717 if (0 != tpid_format)
718 n += sg_scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
719 "%d]\n", lip, tpid_format);
720 n += hex2str(bp + 8, 16, lip, 1, blen - n, b + n);
721 bump = TRANSPORT_ID_MIN_LEN;
722 break;
723 case TPROTO_ISCSI:
724 n += sg_scnpr(b + n, blen - n, "%s iSCSI ", lip);
725 num = sg_get_unaligned_be16(bp + 2);
726 if (0 == tpid_format)
727 n += sg_scnpr(b + n, blen - n, "name: %.*s\n", num, &bp[4]);
728 else if (1 == tpid_format)
729 n += sg_scnpr(b + n, blen - n, "world wide unique port id: "
730 "%.*s\n", num, &bp[4]);
731 else {
732 n += sg_scnpr(b + n, blen - n, " [Unexpected TPID format: "
733 "%d]\n", tpid_format);
734 n += hex2str(bp, num + 4, lip, 0, blen - n, b + n);
735 }
736 bump = (((num + 4) < TRANSPORT_ID_MIN_LEN) ?
737 TRANSPORT_ID_MIN_LEN : num + 4);
738 break;
739 case TPROTO_SAS:
740 ull = sg_get_unaligned_be64(bp + 4);
741 n += sg_scnpr(b + n, blen - n, "%s SAS address: 0x%" PRIx64 "\n",
742 lip, ull);
743 if (0 != tpid_format)
744 n += sg_scnpr(b + n, blen - n, "%s [Unexpected TPID format: "
745 "%d]\n", lip, tpid_format);
746 bump = TRANSPORT_ID_MIN_LEN;
747 break;
748 case TPROTO_ADT: /* no TransportID defined by T10 yet */
749 n += sg_scnpr(b + n, blen - n, "%s ADT:\n", lip);
750 n += sg_scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
751 tpid_format);
752 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
753 bump = TRANSPORT_ID_MIN_LEN;
754 break;
755 case TPROTO_ATA: /* no TransportID defined by T10 yet */
756 n += sg_scnpr(b + n, blen - n, "%s ATAPI:\n", lip);
757 n += sg_scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
758 tpid_format);
759 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
760 bump = TRANSPORT_ID_MIN_LEN;
761 break;
762 case TPROTO_UAS: /* no TransportID defined by T10 yet */
763 n += sg_scnpr(b + n, blen - n, "%s UAS:\n", lip);
764 n += sg_scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
765 tpid_format);
766 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
767 bump = TRANSPORT_ID_MIN_LEN;
768 break;
769 case TPROTO_SOP:
770 n += sg_scnpr(b + n, blen - n, "%s SOP ", lip);
771 num = sg_get_unaligned_be16(bp + 2);
772 if (0 == tpid_format)
773 n += sg_scnpr(b + n, blen - n, "Routing ID: 0x%x\n", num);
774 else {
775 n += sg_scnpr(b + n, blen - n, " [Unexpected TPID format: "
776 "%d]\n", tpid_format);
777 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
778 }
779 bump = TRANSPORT_ID_MIN_LEN;
780 break;
781 case TPROTO_PCIE: /* no TransportID defined by T10 yet */
782 n += sg_scnpr(b + n, blen - n, "%s PCIE:\n", lip);
783 n += sg_scnpr(b + n, blen - n, "%s TPID format: %d\n", lip,
784 tpid_format);
785 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
786 bump = TRANSPORT_ID_MIN_LEN;
787 break;
788 case TPROTO_NONE: /* no TransportID defined by T10 */
789 n += sg_scnpr(b + n, blen - n, "%s No specified protocol\n",
790 lip);
791 /* n += hex2str(bp, ((bplen > 24) ? 24 : bplen),
792 * lip, 0, blen - n, b + n); */
793 bump = TRANSPORT_ID_MIN_LEN;
794 break;
795 default:
796 n += sg_scnpr(b + n, blen - n, "%s unknown protocol id=0x%x "
797 "TPID format=%d\n", lip, proto_id, tpid_format);
798 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n);
799 bump = TRANSPORT_ID_MIN_LEN;
800 break;
801 }
802 }
803 return b;
804 }
805
806
807 static const char * desig_code_set_str_arr[] =
808 {
809 "Reserved [0x0]",
810 "Binary",
811 "ASCII",
812 "UTF-8",
813 "Reserved [0x4]", "Reserved [0x5]", "Reserved [0x6]", "Reserved [0x7]",
814 "Reserved [0x8]", "Reserved [0x9]", "Reserved [0xa]", "Reserved [0xb]",
815 "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
816 };
817
818 const char *
sg_get_desig_code_set_str(int val)819 sg_get_desig_code_set_str(int val)
820 {
821 if ((val >= 0) && (val < (int)SG_ARRAY_SIZE(desig_code_set_str_arr)))
822 return desig_code_set_str_arr[val];
823 else
824 return NULL;
825 }
826
827 static const char * desig_assoc_str_arr[] =
828 {
829 "Addressed logical unit",
830 "Target port", /* that received request; unless SCSI ports VPD */
831 "Target device that contains addressed lu",
832 "Reserved [0x3]",
833 };
834
835 const char *
sg_get_desig_assoc_str(int val)836 sg_get_desig_assoc_str(int val)
837 {
838 if ((val >= 0) && (val < (int)SG_ARRAY_SIZE(desig_assoc_str_arr)))
839 return desig_assoc_str_arr[val];
840 else
841 return NULL;
842 }
843
844 static const char * desig_type_str_arr[] =
845 {
846 "Vendor specific [0x0]",
847 "T10 vendor identification",
848 "EUI-64 based",
849 "NAA",
850 "Relative target port",
851 "Target port group", /* spc4r09: _primary_ target port group */
852 "Logical unit group",
853 "MD5 logical unit identifier",
854 "SCSI name string",
855 "Protocol specific port identifier", /* spc4r36 */
856 "UUID identifier", /* spc5r08 */
857 "Reserved [0xb]",
858 "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
859 };
860
861 const char *
sg_get_desig_type_str(int val)862 sg_get_desig_type_str(int val)
863 {
864 if ((val >= 0) && (val < (int)SG_ARRAY_SIZE(desig_type_str_arr)))
865 return desig_type_str_arr[val];
866 else
867 return NULL;
868 }
869
870 char *
sg_get_zone_type_str(uint8_t zt,int buff_len,char * buff)871 sg_get_zone_type_str(uint8_t zt, int buff_len, char * buff)
872 {
873 if ((NULL == buff) || (buff_len < 1))
874 return NULL;
875 switch (zt) {
876 case 1:
877 sg_scnpr(buff, buff_len, "conventional");
878 break;
879 case 2:
880 sg_scnpr(buff, buff_len, "sequential write required");
881 break;
882 case 3:
883 sg_scnpr(buff, buff_len, "sequential write preferred");
884 break;
885 case 4:
886 sg_scnpr(buff, buff_len, "sequential or before required");
887 break;
888 case 5:
889 sg_scnpr(buff, buff_len, "gap");
890 break;
891 default:
892 sg_scnpr(buff, buff_len, "unknown [0x%x]", zt);
893 break;
894 }
895 return buff;
896 }
897
898
899 /* Expects a T10 UUID designator (as found in the Device Identification VPD
900 * page) pointed to by 'dp'. To not produce an error string in 'b', c_set
901 * should be 1 (binary) and dlen should be 18. Currently T10 only supports
902 * locally assigned UUIDs. Writes output to string 'b' of no more than blen
903 * bytes and returns the number of bytes actually written to 'b' but doesn't
904 * count the trailing null character it always appends (if blen > 0). 'lip'
905 * is lead-in string (on each line) than may be NULL. skip_prefix avoids
906 * outputting: ' Locally assigned UUID: ' before the UUID. */
907 int
sg_t10_uuid_desig2str(const uint8_t * dp,int dlen,int c_set,bool do_long,bool skip_prefix,const char * lip,int blen,char * b)908 sg_t10_uuid_desig2str(const uint8_t *dp, int dlen, int c_set, bool do_long,
909 bool skip_prefix, const char * lip /* lead-in */,
910 int blen, char * b)
911 {
912 int m;
913 int n = 0;
914
915 if (NULL == lip)
916 lip = "";
917 if (1 != c_set) {
918 n += sg_scnpr(b + n, blen - n, "%s << expected binary "
919 "code_set >>\n", lip);
920 n += hex2str(dp, dlen, lip, 0, blen - n, b + n);
921 return n;
922 }
923 if ((1 != ((dp[0] >> 4) & 0xf)) || (18 != dlen)) {
924 n += sg_scnpr(b + n, blen - n, "%s << expected locally "
925 "assigned UUID, 16 bytes long >>\n", lip);
926 n += hex2str(dp, dlen, lip, 0, blen - n, b + n);
927 return n;
928 }
929 if (skip_prefix) {
930 if (strlen(lip) > 0)
931 n += sg_scnpr(b + n, blen - n, "%s", lip);
932 } else
933 n += sg_scnpr(b + n, blen - n, "%s Locally assigned UUID: ",
934 lip);
935 for (m = 0; m < 16; ++m) {
936 if ((4 == m) || (6 == m) || (8 == m) || (10 == m))
937 n += sg_scnpr(b + n, blen - n, "-");
938 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)dp[2 + m]);
939 }
940 n += sg_scnpr(b + n, blen - n, "\n");
941 if (do_long) {
942 n += sg_scnpr(b + n, blen - n, "%s [0x", lip);
943 for (m = 0; m < 16; ++m)
944 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)dp[2 + m]);
945 n += sg_scnpr(b + n, blen - n, "]\n");
946 }
947 return n;
948 }
949
950 int
sg_get_designation_descriptor_str(const char * lip,const uint8_t * ddp,int dd_len,bool print_assoc,bool do_long,int blen,char * b)951 sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
952 int dd_len, bool print_assoc, bool do_long,
953 int blen, char * b)
954 {
955 int m, p_id, piv, c_set, assoc, desig_type, ci_off, c_id, d_id, naa;
956 int vsi, k, n, dlen;
957 uint64_t ccc_id, vsei;
958 const uint8_t * ip;
959 char e[64];
960 const char * cp;
961
962 n = 0;
963 if (NULL == lip)
964 lip = "";
965 if (dd_len < 4) {
966 n += sg_scnpr(b + n, blen - n, "%sdesignator desc too short: got "
967 "length of %d want 4 or more\n", lip, dd_len);
968 return n;
969 }
970 dlen = ddp[3];
971 if (dlen > (dd_len - 4)) {
972 n += sg_scnpr(b + n, blen - n, "%sdesignator too long: says it is %d "
973 "bytes, but given %d bytes\n", lip, dlen, dd_len - 4);
974 return n;
975 }
976 ip = ddp + 4;
977 p_id = ((ddp[0] >> 4) & 0xf);
978 c_set = (ddp[0] & 0xf);
979 piv = ((ddp[1] & 0x80) ? 1 : 0);
980 assoc = ((ddp[1] >> 4) & 0x3);
981 desig_type = (ddp[1] & 0xf);
982 if (print_assoc && ((cp = sg_get_desig_assoc_str(assoc))))
983 n += sg_scnpr(b + n, blen - n, "%s %s:\n", lip, cp);
984 n += sg_scnpr(b + n, blen - n, "%s designator type: ", lip);
985 cp = sg_get_desig_type_str(desig_type);
986 if (cp)
987 n += sg_scnpr(b + n, blen - n, "%s", cp);
988 n += sg_scnpr(b + n, blen - n, ", code set: ");
989 cp = sg_get_desig_code_set_str(c_set);
990 if (cp)
991 n += sg_scnpr(b + n, blen - n, "%s", cp);
992 n += sg_scnpr(b + n, blen - n, "\n");
993 if (piv && ((1 == assoc) || (2 == assoc)))
994 n += sg_scnpr(b + n, blen - n, "%s transport: %s\n", lip,
995 sg_get_trans_proto_str(p_id, sizeof(e), e));
996 switch (desig_type) {
997 case 0: /* vendor specific */
998 k = 0;
999 if ((1 == c_set) || (2 == c_set)) { /* ASCII or UTF-8 */
1000 for (k = 0; (k < dlen) && my_isprint(ip[k]); ++k)
1001 ;
1002 if (k >= dlen)
1003 k = 1;
1004 }
1005 if (k)
1006 n += sg_scnpr(b + n, blen - n, "%s vendor specific: %.*s\n",
1007 lip, dlen, ip);
1008 else {
1009 n += sg_scnpr(b + n, blen - n, "%s vendor specific:\n", lip);
1010 n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
1011 }
1012 break;
1013 case 1: /* T10 vendor identification */
1014 n += sg_scnpr(b + n, blen - n, "%s vendor id: %.8s\n", lip, ip);
1015 if (dlen > 8) {
1016 if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */
1017 n += sg_scnpr(b + n, blen - n, "%s vendor specific: "
1018 "%.*s\n", lip, dlen - 8, ip + 8);
1019 } else {
1020 n += sg_scnpr(b + n, blen - n, "%s vendor specific: 0x",
1021 lip);
1022 for (m = 8; m < dlen; ++m)
1023 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1024 n += sg_scnpr(b + n, blen - n, "\n");
1025 }
1026 }
1027 break;
1028 case 2: /* EUI-64 based */
1029 if (! do_long) {
1030 if ((8 != dlen) && (12 != dlen) && (16 != dlen)) {
1031 n += sg_scnpr(b + n, blen - n, "%s << expect 8, 12 and "
1032 "16 byte EUI, got %d >>\n", lip, dlen);
1033 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1034 break;
1035 }
1036 n += sg_scnpr(b + n, blen - n, "%s 0x", lip);
1037 for (m = 0; m < dlen; ++m)
1038 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1039 n += sg_scnpr(b + n, blen - n, "\n");
1040 break;
1041 }
1042 n += sg_scnpr(b + n, blen - n, "%s EUI-64 based %d byte "
1043 "identifier\n", lip, dlen);
1044 if (1 != c_set) {
1045 n += sg_scnpr(b + n, blen - n, "%s << expected binary "
1046 "code_set (1) >>\n", lip);
1047 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1048 break;
1049 }
1050 ci_off = 0;
1051 if (16 == dlen) { /* first 8 bytes are 'Identifier Extension' */
1052 uint64_t id_ext = sg_get_unaligned_be64(ip);
1053
1054 ci_off = 8;
1055 n += sg_scnpr(b + n, blen - n, "%s Identifier extension: 0x%"
1056 PRIx64 "\n", lip, id_ext);
1057 } else if ((8 != dlen) && (12 != dlen)) {
1058 n += sg_scnpr(b + n, blen - n, "%s << can only decode 8, 12 "
1059 "and 16 byte ids >>\n", lip);
1060 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1061 break;
1062 }
1063 ccc_id = sg_get_unaligned_be64(ip + ci_off);
1064 n += sg_scnpr(b + n, blen - n, "%s IEEE identifier: 0x%"
1065 PRIx64 "\n", lip, ccc_id);
1066 if (12 == dlen) {
1067 d_id = sg_get_unaligned_be32(ip + 8);
1068 n += sg_scnpr(b + n, blen - n, "%s Directory ID: 0x%x\n",
1069 lip, d_id);
1070 }
1071 break;
1072 case 3: /* NAA <n> */
1073 if (1 != c_set) {
1074 n += sg_scnpr(b + n, blen - n, "%s << unexpected code set "
1075 "%d for NAA >>\n", lip, c_set);
1076 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1077 break;
1078 }
1079 naa = (ip[0] >> 4) & 0xff;
1080 switch (naa) {
1081 case 2: /* NAA 2: IEEE Extended */
1082 if (8 != dlen) {
1083 n += sg_scnpr(b + n, blen - n, "%s << unexpected NAA 2 "
1084 "identifier length: 0x%x >>\n", lip, dlen);
1085 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1086 break;
1087 }
1088 d_id = (((ip[0] & 0xf) << 8) | ip[1]);
1089 c_id = sg_get_unaligned_be24(ip + 2);
1090 vsi = sg_get_unaligned_be24(ip + 5);
1091 if (do_long) {
1092 n += sg_scnpr(b + n, blen - n, "%s NAA 2, vendor "
1093 "specific identifier A: 0x%x\n", lip, d_id);
1094 n += sg_scnpr(b + n, blen - n, "%s AOI: 0x%x\n", lip,
1095 c_id);
1096 n += sg_scnpr(b + n, blen - n, "%s vendor specific "
1097 "identifier B: 0x%x\n", lip, vsi);
1098 n += sg_scnpr(b + n, blen - n, "%s [0x", lip);
1099 for (m = 0; m < 8; ++m)
1100 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1101 n += sg_scnpr(b + n, blen - n, "]\n");
1102 }
1103 n += sg_scnpr(b + n, blen - n, "%s 0x", lip);
1104 for (m = 0; m < 8; ++m)
1105 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1106 n += sg_scnpr(b + n, blen - n, "\n");
1107 break;
1108 case 3: /* NAA 3: Locally assigned */
1109 if (8 != dlen) {
1110 n += sg_scnpr(b + n, blen - n, "%s << unexpected NAA 3 "
1111 "identifier length: 0x%x >>\n", lip, dlen);
1112 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1113 break;
1114 }
1115 if (do_long)
1116 n += sg_scnpr(b + n, blen - n, "%s NAA 3, Locally "
1117 "assigned:\n", lip);
1118 n += sg_scnpr(b + n, blen - n, "%s 0x", lip);
1119 for (m = 0; m < 8; ++m)
1120 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1121 n += sg_scnpr(b + n, blen - n, "\n");
1122 break;
1123 case 5: /* NAA 5: IEEE Registered */
1124 if (8 != dlen) {
1125 n += sg_scnpr(b + n, blen - n, "%s << unexpected NAA 5 "
1126 "identifier length: 0x%x >>\n", lip, dlen);
1127 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1128 break;
1129 }
1130 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1131 (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
1132 vsei = ip[3] & 0xf;
1133 for (m = 1; m < 5; ++m) {
1134 vsei <<= 8;
1135 vsei |= ip[3 + m];
1136 }
1137 if (do_long) {
1138 n += sg_scnpr(b + n, blen - n, "%s NAA 5, AOI: 0x%x\n",
1139 lip, c_id);
1140 n += sg_scnpr(b + n, blen - n, "%s Vendor Specific "
1141 "Identifier: 0x%" PRIx64 "\n", lip, vsei);
1142 n += sg_scnpr(b + n, blen - n, "%s [0x", lip);
1143 for (m = 0; m < 8; ++m)
1144 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1145 n += sg_scnpr(b + n, blen - n, "]\n");
1146 } else {
1147 n += sg_scnpr(b + n, blen - n, "%s 0x", lip);
1148 for (m = 0; m < 8; ++m)
1149 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1150 n += sg_scnpr(b + n, blen - n, "\n");
1151 }
1152 break;
1153 case 6: /* NAA 6: IEEE Registered extended */
1154 if (16 != dlen) {
1155 n += sg_scnpr(b + n, blen - n, "%s << unexpected NAA 6 "
1156 "identifier length: 0x%x >>\n", lip, dlen);
1157 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1158 break;
1159 }
1160 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1161 (ip[2] << 4) | ((ip[3] & 0xf0) >> 4));
1162 vsei = ip[3] & 0xf;
1163 for (m = 1; m < 5; ++m) {
1164 vsei <<= 8;
1165 vsei |= ip[3 + m];
1166 }
1167 if (do_long) {
1168 n += sg_scnpr(b + n, blen - n, "%s NAA 6, AOI: 0x%x\n",
1169 lip, c_id);
1170 n += sg_scnpr(b + n, blen - n, "%s Vendor Specific "
1171 "Identifier: 0x%" PRIx64 "\n", lip, vsei);
1172 vsei = sg_get_unaligned_be64(ip + 8);
1173 n += sg_scnpr(b + n, blen - n, "%s Vendor Specific "
1174 "Identifier Extension: 0x%" PRIx64 "\n", lip,
1175 vsei);
1176 n += sg_scnpr(b + n, blen - n, "%s [0x", lip);
1177 for (m = 0; m < 16; ++m)
1178 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1179 n += sg_scnpr(b + n, blen - n, "]\n");
1180 } else {
1181 n += sg_scnpr(b + n, blen - n, "%s 0x", lip);
1182 for (m = 0; m < 16; ++m)
1183 n += sg_scnpr(b + n, blen - n, "%02x", (my_uint)ip[m]);
1184 n += sg_scnpr(b + n, blen - n, "\n");
1185 }
1186 break;
1187 default:
1188 n += sg_scnpr(b + n, blen - n, "%s << unexpected NAA [0x%x] "
1189 ">>\n", lip, naa);
1190 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1191 break;
1192 }
1193 break;
1194 case 4: /* Relative target port */
1195 if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
1196 n += sg_scnpr(b + n, blen - n, "%s << expected binary "
1197 "code_set, target port association, length 4 >>\n",
1198 lip);
1199 n += hex2str(ip, dlen, "", 1, blen - n, b + n);
1200 break;
1201 }
1202 d_id = sg_get_unaligned_be16(ip + 2);
1203 n += sg_scnpr(b + n, blen - n, "%s Relative target port: 0x%x\n",
1204 lip, d_id);
1205 break;
1206 case 5: /* (primary) Target port group */
1207 if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
1208 n += sg_scnpr(b + n, blen - n, "%s << expected binary "
1209 "code_set, target port association, length 4 >>\n",
1210 lip);
1211 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1212 break;
1213 }
1214 d_id = sg_get_unaligned_be16(ip + 2);
1215 n += sg_scnpr(b + n, blen - n, "%s Target port group: 0x%x\n",
1216 lip, d_id);
1217 break;
1218 case 6: /* Logical unit group */
1219 if ((1 != c_set) || (0 != assoc) || (4 != dlen)) {
1220 n += sg_scnpr(b + n, blen - n, "%s << expected binary "
1221 "code_set, logical unit association, length 4 >>\n",
1222 lip);
1223 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1224 break;
1225 }
1226 d_id = sg_get_unaligned_be16(ip + 2);
1227 n += sg_scnpr(b + n, blen - n, "%s Logical unit group: 0x%x\n",
1228 lip, d_id);
1229 break;
1230 case 7: /* MD5 logical unit identifier */
1231 if ((1 != c_set) || (0 != assoc)) {
1232 n += sg_scnpr(b + n, blen - n, "%s << expected binary "
1233 "code_set, logical unit association >>\n", lip);
1234 n += hex2str(ip, dlen, "", 1, blen - n, b + n);
1235 break;
1236 }
1237 n += sg_scnpr(b + n, blen - n, "%s MD5 logical unit "
1238 "identifier:\n", lip);
1239 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1240 break;
1241 case 8: /* SCSI name string */
1242 if (3 != c_set) { /* accept ASCII as subset of UTF-8 */
1243 if (2 == c_set) {
1244 if (do_long)
1245 n += sg_scnpr(b + n, blen - n, "%s << expected "
1246 "UTF-8, use ASCII >>\n", lip);
1247 } else {
1248 n += sg_scnpr(b + n, blen - n, "%s << expected UTF-8 "
1249 "code_set >>\n", lip);
1250 n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
1251 break;
1252 }
1253 }
1254 n += sg_scnpr(b + n, blen - n, "%s SCSI name string:\n", lip);
1255 /* does %s print out UTF-8 ok??
1256 * Seems to depend on the locale. Looks ok here with my
1257 * locale setting: en_AU.UTF-8
1258 */
1259 n += sg_scnpr(b + n, blen - n, "%s %.*s\n", lip, dlen,
1260 (const char *)ip);
1261 break;
1262 case 9: /* Protocol specific port identifier */
1263 /* added in spc4r36, PIV must be set, proto_id indicates */
1264 /* whether UAS (USB) or SOP (PCIe) or ... */
1265 if (! piv)
1266 n += sg_scnpr(b + n, blen - n, " %s >>>> Protocol specific "
1267 "port identifier expects protocol\n%s "
1268 "identifier to be valid and it is not\n", lip, lip);
1269 if (TPROTO_UAS == p_id) {
1270 n += sg_scnpr(b + n, blen - n, "%s USB device address: "
1271 "0x%x\n", lip, 0x7f & ip[0]);
1272 n += sg_scnpr(b + n, blen - n, "%s USB interface number: "
1273 "0x%x\n", lip, ip[2]);
1274 } else if (TPROTO_SOP == p_id) {
1275 n += sg_scnpr(b + n, blen - n, "%s PCIe routing ID, bus "
1276 "number: 0x%x\n", lip, ip[0]);
1277 n += sg_scnpr(b + n, blen - n, "%s function number: "
1278 "0x%x\n", lip, ip[1]);
1279 n += sg_scnpr(b + n, blen - n, "%s [or device number: "
1280 "0x%x, function number: 0x%x]\n", lip,
1281 (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
1282 } else
1283 n += sg_scnpr(b + n, blen - n, "%s >>>> unexpected protocol "
1284 "identifier: %s\n%s with Protocol "
1285 "specific port identifier\n", lip,
1286 sg_get_trans_proto_str(p_id, sizeof(e), e), lip);
1287 break;
1288 case 0xa: /* UUID identifier */
1289 n += sg_t10_uuid_desig2str(ip, dlen, c_set, do_long, false, lip,
1290 blen - n, b + n);
1291 break;
1292 default: /* reserved */
1293 n += sg_scnpr(b + n, blen - n, "%s reserved designator=0x%x\n",
1294 lip, desig_type);
1295 n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
1296 break;
1297 }
1298 return n;
1299 }
1300
1301 static int
decode_sks(const char * lip,const uint8_t * descp,int add_d_len,int sense_key,bool * processedp,int blen,char * b)1302 decode_sks(const char * lip, const uint8_t * descp, int add_d_len,
1303 int sense_key, bool * processedp, int blen, char * b)
1304 {
1305 int progress, pr, rem, n;
1306
1307 n = 0;
1308 if (NULL == lip)
1309 lip = "";
1310 switch (sense_key) {
1311 case SPC_SK_ILLEGAL_REQUEST:
1312 if (add_d_len < 6) {
1313 n += sg_scnpr(b + n, blen - n, "Field pointer: ");
1314 goto too_short;
1315 }
1316 /* abbreviate to fit on one line */
1317 n += sg_scnpr(b + n, blen - n, "Field pointer:\n");
1318 n += sg_scnpr(b + n, blen - n, "%s Error in %s: byte %d", lip,
1319 (descp[4] & 0x40) ? "Command" : "Data parameters",
1320 sg_get_unaligned_be16(descp + 5));
1321 if (descp[4] & 0x08) {
1322 n += sg_scnpr(b + n, blen - n, " bit %d\n", descp[4] & 0x07);
1323 } else
1324 n += sg_scnpr(b + n, blen - n, "\n");
1325 break;
1326 case SPC_SK_HARDWARE_ERROR:
1327 case SPC_SK_MEDIUM_ERROR:
1328 case SPC_SK_RECOVERED_ERROR:
1329 n += sg_scnpr(b + n, blen - n, "Actual retry count: ");
1330 if (add_d_len < 6)
1331 goto too_short;
1332 n += sg_scnpr(b + n, blen - n,"%u\n",
1333 sg_get_unaligned_be16(descp + 5));
1334 break;
1335 case SPC_SK_NO_SENSE:
1336 case SPC_SK_NOT_READY:
1337 n += sg_scnpr(b + n, blen - n, "Progress indication: ");
1338 if (add_d_len < 6)
1339 goto too_short;
1340 progress = sg_get_unaligned_be16(descp + 5);
1341 pr = (progress * 100) / 65536;
1342 rem = ((progress * 100) % 65536) / 656;
1343 n += sg_scnpr(b + n, blen - n, "%d.%02d%%\n", pr, rem);
1344 break;
1345 case SPC_SK_COPY_ABORTED:
1346 n += sg_scnpr(b + n, blen - n, "Segment pointer:\n");
1347 if (add_d_len < 6)
1348 goto too_short;
1349 n += sg_scnpr(b + n, blen - n, "%s Relative to start of %s, "
1350 "byte %d", lip, (descp[4] & 0x20) ?
1351 "segment descriptor" : "parameter list",
1352 sg_get_unaligned_be16(descp + 5));
1353 if (descp[4] & 0x08)
1354 n += sg_scnpr(b + n, blen - n, " bit %d\n", descp[4] & 0x07);
1355 else
1356 n += sg_scnpr(b + n, blen - n, "\n");
1357 break;
1358 case SPC_SK_UNIT_ATTENTION:
1359 n += sg_scnpr(b + n, blen - n, "Unit attention condition queue:\n");
1360 n += sg_scnpr(b + n, blen - n, "%s overflow flag is %d\n", lip,
1361 !!(descp[4] & 0x1));
1362 break;
1363 default:
1364 n += sg_scnpr(b + n, blen - n, "Sense_key: 0x%x unexpected\n",
1365 sense_key);
1366 *processedp = false;
1367 break;
1368 }
1369 return n;
1370
1371 too_short:
1372 n += sg_scnpr(b + n, blen - n, "%s\n", " >> descriptor too short");
1373 *processedp = false;
1374 return n;
1375 }
1376
1377 #define TPGS_STATE_OPTIMIZED 0x0
1378 #define TPGS_STATE_NONOPTIMIZED 0x1
1379 #define TPGS_STATE_STANDBY 0x2
1380 #define TPGS_STATE_UNAVAILABLE 0x3
1381 #define TPGS_STATE_OFFLINE 0xe
1382 #define TPGS_STATE_TRANSITIONING 0xf
1383
1384 static int
decode_tpgs_state(int st,char * b,int blen)1385 decode_tpgs_state(int st, char * b, int blen)
1386 {
1387 switch (st) {
1388 case TPGS_STATE_OPTIMIZED:
1389 return sg_scnpr(b, blen, "active/optimized");
1390 case TPGS_STATE_NONOPTIMIZED:
1391 return sg_scnpr(b, blen, "active/non optimized");
1392 case TPGS_STATE_STANDBY:
1393 return sg_scnpr(b, blen, "standby");
1394 case TPGS_STATE_UNAVAILABLE:
1395 return sg_scnpr(b, blen, "unavailable");
1396 case TPGS_STATE_OFFLINE:
1397 return sg_scnpr(b, blen, "offline");
1398 case TPGS_STATE_TRANSITIONING:
1399 return sg_scnpr(b, blen, "transitioning between states");
1400 default:
1401 return sg_scnpr(b, blen, "unknown: 0x%x", st);
1402 }
1403 }
1404
1405 static int
uds_referral_descriptor_str(char * b,int blen,const uint8_t * dp,int alen,const char * lip)1406 uds_referral_descriptor_str(char * b, int blen, const uint8_t * dp,
1407 int alen, const char * lip)
1408 {
1409 int n = 0;
1410 int dlen = alen - 2;
1411 int k, j, g, f;
1412 const uint8_t * tp;
1413 char c[40];
1414
1415 if (NULL == lip)
1416 lip = "";
1417 n += sg_scnpr(b + n, blen - n, "%s Not all referrals: %d\n", lip,
1418 !!(dp[2] & 0x1));
1419 dp += 4;
1420 for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) {
1421 int ntpgd = dp[3];
1422 uint64_t ull;
1423
1424 g = (ntpgd * 4) + 20;
1425 n += sg_scnpr(b + n, blen - n, "%s Descriptor %d\n", lip, f);
1426 if ((k + g) > dlen) {
1427 n += sg_scnpr(b + n, blen - n, "%s truncated descriptor, "
1428 "stop\n", lip);
1429 return n;
1430 }
1431 ull = sg_get_unaligned_be64(dp + 4);
1432 n += sg_scnpr(b + n, blen - n, "%s first uds LBA: 0x%" PRIx64
1433 "\n", lip, ull);
1434 ull = sg_get_unaligned_be64(dp + 12);
1435 n += sg_scnpr(b + n, blen - n, "%s last uds LBA: 0x%" PRIx64
1436 "\n", lip, ull);
1437 for (j = 0; j < ntpgd; ++j) {
1438 tp = dp + 20 + (j * 4);
1439 decode_tpgs_state(tp[0] & 0xf, c, sizeof(c));
1440 n += sg_scnpr(b + n, blen - n, "%s tpg: %d state: %s\n",
1441 lip, sg_get_unaligned_be16(tp + 2), c);
1442 }
1443 }
1444 return n;
1445 }
1446
1447 static const char * dd_usage_reason_str_arr[] = {
1448 "Unknown",
1449 "resend this and further commands to:",
1450 "resend this command to:",
1451 "new subsidiary lu added to this administrative lu:",
1452 "administrative lu associated with a preferred binding:",
1453 };
1454
1455
1456 /* Decode descriptor format sense descriptors (assumes sense buffer is
1457 * in descriptor format). 'leadin' is string prepended to each line written
1458 * to 'b', NULL treated as "". Returns the number of bytes written to 'b'
1459 * excluding the trailing '\0'. If problem, returns 0. */
1460 int
sg_get_sense_descriptors_str(const char * lip,const uint8_t * sbp,int sb_len,int blen,char * b)1461 sg_get_sense_descriptors_str(const char * lip, const uint8_t * sbp,
1462 int sb_len, int blen, char * b)
1463 {
1464 int add_sb_len, desc_len, k, j, sense_key;
1465 int n, progress, pr, rem;
1466 uint16_t sct_sc;
1467 bool processed;
1468 const uint8_t * descp;
1469 char z[64];
1470 static const char * dtsp = " >> descriptor too short";
1471 static const char * eccp = "Extended copy command";
1472 static const char * ddp = "destination device";
1473
1474 if ((NULL == b) || (blen <= 0))
1475 return 0;
1476 b[0] = '\0';
1477 if (lip)
1478 sg_scnpr(z, sizeof(z), "%.60s ", lip);
1479 else
1480 sg_scnpr(z, sizeof(z), " ");
1481 if ((sb_len < 8) || (0 == (add_sb_len = sbp[7])))
1482 return 0;
1483 add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8);
1484 sense_key = (sbp[1] & 0xf);
1485
1486 for (descp = (sbp + 8), k = 0, n = 0;
1487 (k < add_sb_len) && (n < blen);
1488 k += desc_len, descp += desc_len) {
1489 int add_d_len = (k < (add_sb_len - 1)) ? descp[1] : -1;
1490
1491 if ((k + add_d_len + 2) > add_sb_len)
1492 add_d_len = add_sb_len - k - 2;
1493 desc_len = add_d_len + 2;
1494 n += sg_scnpr(b + n, blen - n, "%s Descriptor type: ", lip);
1495 processed = true;
1496 switch (descp[0]) {
1497 case 0:
1498 n += sg_scnpr(b + n, blen - n, "Information: ");
1499 if (add_d_len >= 10) {
1500 if (! (0x80 & descp[2]))
1501 n += sg_scnpr(b + n, blen - n, "Valid=0 (-> vendor "
1502 "specific) ");
1503 n += sg_scnpr(b + n, blen - n, "0x");
1504 for (j = 0; j < 8; ++j)
1505 n += sg_scnpr(b + n, blen - n, "%02x", descp[4 + j]);
1506 n += sg_scnpr(b + n, blen - n, "\n");
1507 } else {
1508 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1509 processed = false;
1510 }
1511 break;
1512 case 1:
1513 n += sg_scnpr(b + n, blen - n, "Command specific: ");
1514 if (add_d_len >= 10) {
1515 n += sg_scnpr(b + n, blen - n, "0x");
1516 for (j = 0; j < 8; ++j)
1517 n += sg_scnpr(b + n, blen - n, "%02x", descp[4 + j]);
1518 n += sg_scnpr(b + n, blen - n, "\n");
1519 } else {
1520 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1521 processed = false;
1522 }
1523 break;
1524 case 2: /* Sense Key Specific */
1525 n += sg_scnpr(b + n, blen - n, "Sense key specific: ");
1526 n += decode_sks(lip, descp, add_d_len, sense_key, &processed,
1527 blen - n, b + n);
1528 break;
1529 case 3:
1530 n += sg_scnpr(b + n, blen - n, "Field replaceable unit code: ");
1531 if (add_d_len >= 2)
1532 n += sg_scnpr(b + n, blen - n, "0x%x\n", descp[3]);
1533 else {
1534 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1535 processed = false;
1536 }
1537 break;
1538 case 4:
1539 n += sg_scnpr(b + n, blen - n, "Stream commands: ");
1540 if (add_d_len >= 2) {
1541 if (descp[3] & 0x80)
1542 n += sg_scnpr(b + n, blen - n, "FILEMARK");
1543 if (descp[3] & 0x40)
1544 n += sg_scnpr(b + n, blen - n, "End Of Medium (EOM)");
1545 if (descp[3] & 0x20)
1546 n += sg_scnpr(b + n, blen - n, "Incorrect Length "
1547 "Indicator (ILI)");
1548 n += sg_scnpr(b + n, blen - n, "\n");
1549 } else {
1550 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1551 processed = false;
1552 }
1553 break;
1554 case 5:
1555 n += sg_scnpr(b + n, blen - n, "Block commands: ");
1556 if (add_d_len >= 2)
1557 n += sg_scnpr(b + n, blen - n, "Incorrect Length Indicator "
1558 "(ILI) %s\n",
1559 (descp[3] & 0x20) ? "set" : "clear");
1560 else {
1561 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1562 processed = false;
1563 }
1564 break;
1565 case 6:
1566 n += sg_scnpr(b + n, blen - n, "OSD object identification\n");
1567 processed = false;
1568 break;
1569 case 7:
1570 n += sg_scnpr(b + n, blen - n, "OSD response integrity check "
1571 "value\n");
1572 processed = false;
1573 break;
1574 case 8:
1575 n += sg_scnpr(b + n, blen - n, "OSD attribute identification\n");
1576 processed = false;
1577 break;
1578 case 9: /* this is defined in SAT (SAT-2) */
1579 n += sg_scnpr(b + n, blen - n, "ATA Status Return: ");
1580 if (add_d_len >= 12) {
1581 int extend, count;
1582
1583 extend = descp[2] & 1;
1584 count = descp[5] + (extend ? (descp[4] << 8) : 0);
1585 n += sg_scnpr(b + n, blen - n, "extend=%d error=0x%x \n%s"
1586 " count=0x%x ", extend, descp[3], lip,
1587 count);
1588 if (extend)
1589 n += sg_scnpr(b + n, blen - n,
1590 "lba=0x%02x%02x%02x%02x%02x%02x ",
1591 descp[10], descp[8], descp[6], descp[11],
1592 descp[9], descp[7]);
1593 else
1594 n += sg_scnpr(b + n, blen - n, "lba=0x%02x%02x%02x ",
1595 descp[11], descp[9], descp[7]);
1596 n += sg_scnpr(b + n, blen - n, "device=0x%x status=0x%x\n",
1597 descp[12], descp[13]);
1598 } else {
1599 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1600 processed = false;
1601 }
1602 break;
1603 case 0xa:
1604 /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */
1605 n += sg_scnpr(b + n, blen - n, "Another progress indication: ");
1606 if (add_d_len < 6) {
1607 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1608 processed = false;
1609 break;
1610 }
1611 progress = sg_get_unaligned_be16(descp + 6);
1612 pr = (progress * 100) / 65536;
1613 rem = ((progress * 100) % 65536) / 656;
1614 n += sg_scnpr(b + n, blen - n, "%d.02%d%%\n", pr, rem);
1615 n += sg_scnpr(b + n, blen - n, "%s [sense_key=0x%x "
1616 "asc,ascq=0x%x,0x%x]\n", lip, descp[2], descp[3],
1617 descp[4]);
1618 break;
1619 case 0xb: /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */
1620 n += sg_scnpr(b + n, blen - n, "User data segment referral: ");
1621 if (add_d_len < 2) {
1622 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1623 processed = false;
1624 break;
1625 }
1626 n += sg_scnpr(b + n, blen - n, "\n");
1627 n += uds_referral_descriptor_str(b + n, blen - n, descp,
1628 add_d_len, lip);
1629 break;
1630 case 0xc: /* Added in SPC-4 rev 28 */
1631 n += sg_scnpr(b + n, blen - n, "Forwarded sense data\n");
1632 if (add_d_len < 2) {
1633 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1634 processed = false;
1635 break;
1636 }
1637 n += sg_scnpr(b + n, blen - n, "%s FSDT: %s\n", lip,
1638 (descp[2] & 0x80) ? "set" : "clear");
1639 j = descp[2] & 0xf;
1640 n += sg_scnpr(b + n, blen - n, "%s Sense data source: ", lip);
1641 switch (j) {
1642 case 0:
1643 n += sg_scnpr(b + n, blen - n, "%s source device\n", eccp);
1644 break;
1645 case 1:
1646 case 2:
1647 case 3:
1648 case 4:
1649 case 5:
1650 case 6:
1651 case 7:
1652 n += sg_scnpr(b + n, blen - n, "%s %s %d\n", eccp, ddp, j - 1);
1653 break;
1654 default:
1655 n += sg_scnpr(b + n, blen - n, "unknown [%d]\n", j);
1656 }
1657 {
1658 char c[480];
1659
1660 sg_get_scsi_status_str(descp[3], sizeof(c) - 1, c);
1661 c[sizeof(c) - 1] = '\0';
1662 n += sg_scnpr(b + n, blen - n, "%s Forwarded status: %s\n",
1663 lip, c);
1664 if (add_d_len > 2) {
1665 /* recursing; hope not to get carried away */
1666 n += sg_scnpr(b + n, blen - n, "%s vvvvvvvvvvvvvvvv\n",
1667 lip);
1668 sg_get_sense_str(lip, descp + 4, add_d_len - 2, false,
1669 sizeof(c), c);
1670 n += sg_scnpr(b + n, blen - n, "%s", c);
1671 n += sg_scnpr(b + n, blen - n, "%s ^^^^^^^^^^^^^^^^\n",
1672 lip);
1673 }
1674 }
1675 break;
1676 case 0xd: /* Added in SBC-3 rev 36d */
1677 /* this descriptor combines descriptors 0, 1, 2 and 3 */
1678 n += sg_scnpr(b + n, blen - n, "Direct-access block device\n");
1679 if (add_d_len < 28) {
1680 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1681 processed = false;
1682 break;
1683 }
1684 if (0x20 & descp[2])
1685 n += sg_scnpr(b + n, blen - n, "%s ILI (incorrect length "
1686 "indication) set\n", lip);
1687 if (0x80 & descp[4]) {
1688 n += sg_scnpr(b + n, blen - n, "%s Sense key specific: ",
1689 lip);
1690 n += decode_sks(lip, descp, add_d_len, sense_key, &processed,
1691 blen - n, b + n);
1692 }
1693 n += sg_scnpr(b + n, blen - n, "%s Field replaceable unit "
1694 "code: 0x%x\n", lip, descp[7]);
1695 if (0x80 & descp[2]) {
1696 n += sg_scnpr(b + n, blen - n, "%s Information: 0x", lip);
1697 for (j = 0; j < 8; ++j)
1698 n += sg_scnpr(b + n, blen - n, "%02x", descp[8 + j]);
1699 n += sg_scnpr(b + n, blen - n, "\n");
1700 }
1701 n += sg_scnpr(b + n, blen - n, "%s Command specific: 0x", lip);
1702 for (j = 0; j < 8; ++j)
1703 n += sg_scnpr(b + n, blen - n, "%02x", descp[16 + j]);
1704 n += sg_scnpr(b + n, blen - n, "\n");
1705 break;
1706 case 0xe: /* Added in SPC-5 rev 6 (for Bind/Unbind) */
1707 n += sg_scnpr(b + n, blen - n, "Device designation\n");
1708 j = (int)SG_ARRAY_SIZE(dd_usage_reason_str_arr);
1709 if (descp[3] < j)
1710 n += sg_scnpr(b + n, blen - n, "%s Usage reason: %s\n",
1711 lip, dd_usage_reason_str_arr[descp[3]]);
1712 else
1713 n += sg_scnpr(b + n, blen - n, "%s Usage reason: "
1714 "reserved[%d]\n", lip, descp[3]);
1715 n += sg_get_designation_descriptor_str(z, descp + 4, descp[1] - 2,
1716 true, false, blen - n,
1717 b + n);
1718 break;
1719 case 0xf: /* Added in SPC-5 rev 10 (for Write buffer) */
1720 n += sg_scnpr(b + n, blen - n, "Microcode activation ");
1721 if (add_d_len < 6) {
1722 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1723 processed = false;
1724 break;
1725 }
1726 progress = sg_get_unaligned_be16(descp + 6);
1727 n += sg_scnpr(b + n, blen - n, "time: ");
1728 if (0 == progress)
1729 n += sg_scnpr(b + n, blen - n, "unknown\n");
1730 else
1731 n += sg_scnpr(b + n, blen - n, "%d seconds\n", progress);
1732 break;
1733 case 0xde: /* NVME Status Field; vendor (sg3_utils) specific */
1734 n += sg_scnpr(b + n, blen - n, "NVMe Status: ");
1735 if (add_d_len < 6) {
1736 n += sg_scnpr(b + n, blen - n, "%s\n", dtsp);
1737 processed = false;
1738 break;
1739 }
1740 n += sg_scnpr(b + n, blen - n, "DNR=%d, M=%d, ",
1741 (int)!!(0x80 & descp[5]), (int)!!(0x40 & descp[5]));
1742 sct_sc = sg_get_unaligned_be16(descp + 6);
1743 n += sg_scnpr(b + n, blen - n, "SCT_SC=0x%x\n", sct_sc);
1744 if (sct_sc > 0) {
1745 char d[80];
1746
1747 n += sg_scnpr(b + n, blen - n, " %s\n",
1748 sg_get_nvme_cmd_status_str(sct_sc, sizeof(d), d));
1749 }
1750 break;
1751 default:
1752 if (descp[0] >= 0x80)
1753 n += sg_scnpr(b + n, blen - n, "Vendor specific [0x%x]\n",
1754 descp[0]);
1755 else
1756 n += sg_scnpr(b + n, blen - n, "Unknown [0x%x]\n", descp[0]);
1757 processed = false;
1758 break;
1759 }
1760 if (! processed) {
1761 if (add_d_len > 0) {
1762 n += sg_scnpr(b + n, blen - n, "%s ", lip);
1763 for (j = 0; j < add_d_len; ++j) {
1764 if ((j > 0) && (0 == (j % 24)))
1765 n += sg_scnpr(b + n, blen - n, "\n%s ", lip);
1766 n += sg_scnpr(b + n, blen - n, "%02x ", descp[j + 2]);
1767 }
1768 n += sg_scnpr(b + n, blen - n, "\n");
1769 }
1770 }
1771 if (add_d_len < 0)
1772 n += sg_scnpr(b + n, blen - n, "%s short descriptor\n", lip);
1773 }
1774 return n;
1775 }
1776
1777 /* Decode SAT ATA PASS-THROUGH fixed format sense. Shows "+" after 'count'
1778 * and/or 'lba' values to indicate that not all data in those fields is shown.
1779 * That extra field information may be available in the ATA pass-through
1780 * results log page parameter with the corresponding 'log_index'. */
1781 static int
sg_get_sense_sat_pt_fixed_str(const char * lip,const uint8_t * sp,int slen,int blen,char * b)1782 sg_get_sense_sat_pt_fixed_str(const char * lip, const uint8_t * sp,
1783 int slen, int blen, char * b)
1784 {
1785 int n = 0;
1786 bool extend, count_upper_nz, lba_upper_nz;
1787
1788 if ((blen < 1) || (slen < 12))
1789 return n;
1790 if (NULL == lip)
1791 lip = "";
1792 if (SPC_SK_RECOVERED_ERROR != (0xf & sp[2]))
1793 n += sg_scnpr(b + n, blen - n, "%s >> expected Sense key: Recovered "
1794 "Error ??\n", lip);
1795 /* Fixed sense command-specific information field starts at sp + 8 */
1796 extend = !!(0x80 & sp[8]);
1797 count_upper_nz = !!(0x40 & sp[8]);
1798 lba_upper_nz = !!(0x20 & sp[8]);
1799 /* Fixed sense information field starts at sp + 3 */
1800 n += sg_scnpr(b + n, blen - n, "%s error=0x%x, status=0x%x, "
1801 "device=0x%x, count(7:0)=0x%x%c\n", lip, sp[3], sp[4],
1802 sp[5], sp[6], (count_upper_nz ? '+' : ' '));
1803 n += sg_scnpr(b + n, blen - n, "%s extend=%d, log_index=0x%x, "
1804 "lba_high,mid,low(7:0)=0x%x,0x%x,0x%x%c\n", lip,
1805 (int)extend, (0xf & sp[8]), sp[11], sp[10], sp[9],
1806 (lba_upper_nz ? '+' : ' '));
1807 return n;
1808 }
1809
1810 /* Fetch sense information */
1811 int
sg_get_sense_str(const char * lip,const uint8_t * sbp,int sb_len,bool raw_sinfo,int cblen,char * cbp)1812 sg_get_sense_str(const char * lip, const uint8_t * sbp, int sb_len,
1813 bool raw_sinfo, int cblen, char * cbp)
1814 {
1815 bool descriptor_format = false;
1816 bool sdat_ovfl = false;
1817 bool valid_info_fld;
1818 int len, progress, n, r, pr, rem, blen;
1819 unsigned int info;
1820 uint8_t resp_code;
1821 const char * ebp = NULL;
1822 char ebuff[64];
1823 char b[256];
1824 struct sg_scsi_sense_hdr ssh;
1825
1826 if ((NULL == cbp) || (cblen <= 0))
1827 return 0;
1828 else if (1 == cblen) {
1829 cbp[0] = '\0';
1830 return 0;
1831 }
1832 blen = sizeof(b);
1833 n = 0;
1834 if (NULL == lip)
1835 lip = "";
1836 if ((NULL == sbp) || (sb_len < 1)) {
1837 n += sg_scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip);
1838 return n;
1839 }
1840 resp_code = 0x7f & sbp[0];
1841 valid_info_fld = !!(sbp[0] & 0x80);
1842 len = sb_len;
1843 if (sg_scsi_normalize_sense(sbp, sb_len, &ssh)) {
1844 switch (ssh.response_code) {
1845 case 0x70: /* fixed, current */
1846 ebp = "Fixed format, current";
1847 len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
1848 len = (len > sb_len) ? sb_len : len;
1849 sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
1850 break;
1851 case 0x71: /* fixed, deferred */
1852 /* error related to a previous command */
1853 ebp = "Fixed format, <<<deferred>>>";
1854 len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
1855 len = (len > sb_len) ? sb_len : len;
1856 sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
1857 break;
1858 case 0x72: /* descriptor, current */
1859 descriptor_format = true;
1860 ebp = "Descriptor format, current";
1861 sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
1862 break;
1863 case 0x73: /* descriptor, deferred */
1864 descriptor_format = true;
1865 ebp = "Descriptor format, <<<deferred>>>";
1866 sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
1867 break;
1868 case 0x0:
1869 ebp = "Response code: 0x0 (?)";
1870 break;
1871 default:
1872 sg_scnpr(ebuff, sizeof(ebuff), "Unknown response code: 0x%x",
1873 ssh.response_code);
1874 ebp = ebuff;
1875 break;
1876 }
1877 n += sg_scnpr(cbp + n, cblen - n, "%s%s; Sense key: %s\n", lip, ebp,
1878 sg_lib_sense_key_desc[ssh.sense_key]);
1879 if (sdat_ovfl)
1880 n += sg_scnpr(cbp + n, cblen - n, "%s<<<Sense data overflow "
1881 "(SDAT_OVFL)>>>\n", lip);
1882 if (descriptor_format) {
1883 n += sg_scnpr(cbp + n, cblen - n, "%s%s\n", lip,
1884 sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
1885 n += sg_get_sense_descriptors_str(lip, sbp, len,
1886 cblen - n, cbp + n);
1887 } else if ((len > 12) && (0 == ssh.asc) &&
1888 (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) {
1889 /* SAT ATA PASS-THROUGH fixed format */
1890 n += sg_scnpr(cbp + n, cblen - n, "%s%s\n", lip,
1891 sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
1892 n += sg_get_sense_sat_pt_fixed_str(lip, sbp, len,
1893 cblen - n, cbp + n);
1894 } else if (len > 2) { /* fixed format */
1895 if (len > 12)
1896 n += sg_scnpr(cbp + n, cblen - n, "%s%s\n", lip,
1897 sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b));
1898 r = 0;
1899 if (strlen(lip) > 0)
1900 r += sg_scnpr(b + r, blen - r, "%s", lip);
1901 if (len > 6) {
1902 info = sg_get_unaligned_be32(sbp + 3);
1903 if (valid_info_fld)
1904 r += sg_scnpr(b + r, blen - r, " Info fld=0x%x [%u] ",
1905 info, info);
1906 else if (info > 0)
1907 r += sg_scnpr(b + r, blen - r, " Valid=0, Info fld=0x%x "
1908 "[%u] ", info, info);
1909 } else
1910 info = 0;
1911 if (sbp[2] & 0xe0) {
1912 if (sbp[2] & 0x80)
1913 r += sg_scnpr(b + r, blen - r, " FMK");
1914 /* current command has read a filemark */
1915 if (sbp[2] & 0x40)
1916 r += sg_scnpr(b + r, blen - r, " EOM");
1917 /* end-of-medium condition exists */
1918 if (sbp[2] & 0x20)
1919 r += sg_scnpr(b + r, blen - r, " ILI");
1920 /* incorrect block length requested */
1921 r += sg_scnpr(b + r, blen - r, "\n");
1922 } else if (valid_info_fld || (info > 0))
1923 r += sg_scnpr(b + r, blen - r, "\n");
1924 if ((len >= 14) && sbp[14])
1925 r += sg_scnpr(b + r, blen - r, "%s Field replaceable unit "
1926 "code: %d\n", lip, sbp[14]);
1927 if ((len >= 18) && (sbp[15] & 0x80)) {
1928 /* sense key specific decoding */
1929 switch (ssh.sense_key) {
1930 case SPC_SK_ILLEGAL_REQUEST:
1931 r += sg_scnpr(b + r, blen - r, "%s Sense Key Specific: "
1932 "Error in %s: byte %d", lip,
1933 ((sbp[15] & 0x40) ?
1934 "Command" : "Data parameters"),
1935 sg_get_unaligned_be16(sbp + 16));
1936 if (sbp[15] & 0x08)
1937 r += sg_scnpr(b + r, blen - r, " bit %d\n",
1938 sbp[15] & 0x07);
1939 else
1940 r += sg_scnpr(b + r, blen - r, "\n");
1941 break;
1942 case SPC_SK_NO_SENSE:
1943 case SPC_SK_NOT_READY:
1944 progress = sg_get_unaligned_be16(sbp + 16);
1945 pr = (progress * 100) / 65536;
1946 rem = ((progress * 100) % 65536) / 656;
1947 r += sg_scnpr(b + r, blen - r, "%s Progress indication: "
1948 "%d.%02d%%\n", lip, pr, rem);
1949 break;
1950 case SPC_SK_HARDWARE_ERROR:
1951 case SPC_SK_MEDIUM_ERROR:
1952 case SPC_SK_RECOVERED_ERROR:
1953 r += sg_scnpr(b + r, blen - r, "%s Actual retry count: "
1954 "0x%02x%02x\n", lip, sbp[16], sbp[17]);
1955 break;
1956 case SPC_SK_COPY_ABORTED:
1957 r += sg_scnpr(b + r, blen - r, "%s Segment pointer: ",
1958 lip);
1959 r += sg_scnpr(b + r, blen - r, "Relative to start of %s, "
1960 "byte %d", ((sbp[15] & 0x20) ?
1961 "segment descriptor" : "parameter list"),
1962 sg_get_unaligned_be16(sbp + 16));
1963 if (sbp[15] & 0x08)
1964 r += sg_scnpr(b + r, blen - r, " bit %d\n",
1965 sbp[15] & 0x07);
1966 else
1967 r += sg_scnpr(b + r, blen - r, "\n");
1968 break;
1969 case SPC_SK_UNIT_ATTENTION:
1970 r += sg_scnpr(b + r, blen - r, "%s Unit attention "
1971 "condition queue: ", lip);
1972 r += sg_scnpr(b + r, blen - r, "overflow flag is %d\n",
1973 !!(sbp[15] & 0x1));
1974 break;
1975 default:
1976 r += sg_scnpr(b + r, blen - r, "%s Sense_key: 0x%x "
1977 "unexpected\n", lip, ssh.sense_key);
1978 break;
1979 }
1980 }
1981 if (r > 0)
1982 n += sg_scnpr(cbp + n, cblen - n, "%s", b);
1983 } else
1984 n += sg_scnpr(cbp + n, cblen - n, "%s fixed descriptor length "
1985 "too short, len=%d\n", lip, len);
1986 } else { /* unable to normalise sense buffer, something irregular */
1987 if (sb_len < 4) { /* Too short */
1988 n += sg_scnpr(cbp + n, cblen - n, "%ssense buffer too short (4 "
1989 "byte minimum)\n", lip);
1990 goto check_raw;
1991 }
1992 if (0x7f == resp_code) { /* Vendor specific */
1993 n += sg_scnpr(cbp + n, cblen - n, "%sVendor specific sense "
1994 "buffer, in hex:\n", lip);
1995 n += hex2str(sbp, sb_len, lip, -1, cblen - n, cbp + n);
1996 return n; /* no need to check raw, just output in hex */
1997 }
1998 /* non-extended SCSI-1 sense data ?? */
1999 r = 0;
2000 if (strlen(lip) > 0)
2001 r += sg_scnpr(b + r, blen - r, "%s", lip);
2002 r += sg_scnpr(b + r, blen - r, "Probably uninitialized data.\n%s "
2003 "Try to view as SCSI-1 non-extended sense:\n", lip);
2004 r += sg_scnpr(b + r, blen - r, " AdValid=%d Error class=%d Error "
2005 "code=%d\n", valid_info_fld, ((sbp[0] >> 4) & 0x7),
2006 (sbp[0] & 0xf));
2007 if (valid_info_fld)
2008 sg_scnpr(b + r, blen - r, "%s lba=0x%x\n", lip,
2009 sg_get_unaligned_be24(sbp + 1) & 0x1fffff);
2010 n += sg_scnpr(cbp + n, cblen - n, "%s\n", b);
2011 }
2012 check_raw:
2013 if (raw_sinfo) {
2014 int calculated_len;
2015 char z[64];
2016
2017 n += sg_scnpr(cbp + n, cblen - n, "%s Raw sense data (in hex), "
2018 "sb_len=%d", lip, sb_len);
2019 if (n >= (cblen - 1))
2020 return n;
2021 if ((sb_len > 7) && (sbp[0] >= 0x70) && (sbp[0] < 0x74)) {
2022 calculated_len = sbp[7] + 8;
2023 n += sg_scnpr(cbp + n, cblen - n, ", calculated_len=%d\n",
2024 calculated_len);
2025 } else {
2026 calculated_len = sb_len;
2027 n += sg_scnpr(cbp + n, cblen - n, "\n");
2028 }
2029 if (n >= (cblen - 1))
2030 return n;
2031
2032 sg_scnpr(z, sizeof(z), "%.50s ", lip);
2033 n += hex2str(sbp, calculated_len, z, -1, cblen - n, cbp + n);
2034 }
2035 return n;
2036 }
2037
2038 /* Print sense information */
2039 void
sg_print_sense(const char * leadin,const uint8_t * sbp,int sb_len,bool raw_sinfo)2040 sg_print_sense(const char * leadin, const uint8_t * sbp, int sb_len,
2041 bool raw_sinfo)
2042 {
2043 uint32_t pg_sz = sg_get_page_size();
2044 char *cp;
2045 uint8_t *free_cp;
2046
2047 cp = (char *)sg_memalign(pg_sz, pg_sz, &free_cp, false);
2048 if (NULL == cp)
2049 return;
2050 sg_get_sense_str(leadin, sbp, sb_len, raw_sinfo, pg_sz, cp);
2051 pr2ws("%s", cp);
2052 free(free_cp);
2053 }
2054
2055 /* This examines exit_status and if an error message is known it is output
2056 * as a string to 'b' and true is returned. If 'longer' is true and extra
2057 * information is available then it is added to the output. If no error
2058 * message is available a null character is output and false is returned.
2059 * If exit_status is zero (no error) and 'longer' is true then the string
2060 * 'No errors' is output; if 'longer' is false then a null character is
2061 * output; in both cases true is returned. If exit_status is negative then
2062 * a null character is output and false is returned. All messages are a
2063 * single line (less than 80 characters) with no trailing LF. The output
2064 * string including the trailing null character is no longer than b_len.
2065 * exit_status represents the Unix exit status available after a utility
2066 * finishes executing (for whatever reason). */
sg_exit2str(int exit_status,bool longer,int b_len,char * b)2067 bool sg_exit2str(int exit_status, bool longer, int b_len, char *b)
2068 {
2069 const struct sg_value_2names_t * ess = sg_exit_str_arr;
2070
2071 if ((b_len < 1) || (NULL == b))
2072 return false;
2073 /* if there is a valid buffer, initialize it to a valid empty string */
2074 b[0] = '\0';
2075 if (exit_status < 0)
2076 return false;
2077 else if ((0 == exit_status) || (SG_LIB_OK_FALSE == exit_status)) {
2078 if (longer)
2079 goto fini;
2080 return true;
2081 }
2082
2083 if ((exit_status > SG_LIB_OS_BASE_ERR) && /* 51 to 96 inclusive */
2084 (exit_status < SG_LIB_CAT_MALFORMED)) {
2085 snprintf(b, b_len, "%s%s", (longer ? "OS error: " : ""),
2086 safe_strerror(exit_status - SG_LIB_OS_BASE_ERR));
2087 return true;
2088 } else if ((exit_status > 128) && (exit_status < 255)) {
2089 snprintf(b, b_len, "Utility stopped/aborted by signal number: %d",
2090 exit_status - 128);
2091 return true;
2092 }
2093 fini:
2094 for ( ; ess->name; ++ess) {
2095 if (exit_status == ess->value)
2096 break;
2097 }
2098 if (ess->name) {
2099 if (longer && ess->name2)
2100 snprintf(b, b_len, "%s, %s", ess->name, ess->name2);
2101 else
2102 snprintf(b, b_len, "%s", ess->name);
2103 return true;
2104 }
2105 return false;
2106 }
2107
2108 static bool
sg_if_can2fp(const char * leadin,int exit_status,FILE * fp)2109 sg_if_can2fp(const char * leadin, int exit_status, FILE * fp)
2110 {
2111 char b[256];
2112 const char * s = leadin ? leadin : "";
2113
2114 if ((0 == exit_status) || (SG_LIB_OK_FALSE == exit_status))
2115 return true; /* don't print anything */
2116 else if (sg_exit2str(exit_status, false, sizeof(b), b)) {
2117 fprintf(fp, "%s%s\n", s, b);
2118 return true;
2119 } else
2120 return false;
2121 }
2122
2123 /* This examines exit_status and if an error message is known it is output
2124 * to stdout/stderr and true is returned. If no error message is
2125 * available nothing is output and false is returned. If exit_status is
2126 * zero (no error) nothing is output and true is returned. If exit_status
2127 * is negative then nothing is output and false is returned. If leadin is
2128 * non-NULL then it is printed before the error message. All messages are
2129 * a single line with a trailing LF. */
2130 bool
sg_if_can2stdout(const char * leadin,int exit_status)2131 sg_if_can2stdout(const char * leadin, int exit_status)
2132 {
2133 return sg_if_can2fp(leadin, exit_status, stdout);
2134 }
2135
2136 /* See sg_if_can2stdout() comments */
2137 bool
sg_if_can2stderr(const char * leadin,int exit_status)2138 sg_if_can2stderr(const char * leadin, int exit_status)
2139 {
2140 return sg_if_can2fp(leadin, exit_status,
2141 sg_warnings_strm ? sg_warnings_strm : stderr);
2142 }
2143
2144 /* If os_err_num is within bounds then the returned value is 'os_err_num +
2145 * SG_LIB_OS_BASE_ERR' otherwise SG_LIB_OS_BASE_ERR is returned. If
2146 * os_err_num is 0 then 0 is returned. */
2147 int
sg_convert_errno(int os_err_num)2148 sg_convert_errno(int os_err_num)
2149 {
2150 if (os_err_num <= 0) {
2151 if (os_err_num < 0)
2152 return SG_LIB_OS_BASE_ERR;
2153 return os_err_num; /* os_err_num of 0 maps to 0 */
2154 }
2155 if (os_err_num < (SG_LIB_CAT_MALFORMED - SG_LIB_OS_BASE_ERR))
2156 return SG_LIB_OS_BASE_ERR + os_err_num;
2157 return SG_LIB_OS_BASE_ERR;
2158 }
2159
2160 static const char * const bad_sense_cat = "Bad sense category";
2161
2162 /* Yield string associated with sense category. Returns 'b' (or pointer
2163 * to "Bad sense category" if 'b' is NULL). If sense_cat unknown then
2164 * yield "Sense category: <sense_cat_val>" string. The original 'sense
2165 * category' concept has been expanded to most detected errors and is
2166 * returned by these utilities as their exit status value (an (unsigned)
2167 * 8 bit value where 0 means good (i.e. no errors)). Uses sg_exit2str()
2168 * function. */
2169 const char *
sg_get_category_sense_str(int sense_cat,int b_len,char * b,int verbose)2170 sg_get_category_sense_str(int sense_cat, int b_len, char * b, int verbose)
2171 {
2172 if (NULL == b)
2173 return bad_sense_cat;
2174 if (b_len <= 0)
2175 return b;
2176 if (! sg_exit2str(sense_cat, (verbose > 0), b_len, b)) {
2177 int n = sg_scnpr(b, b_len, "Sense category: %d", sense_cat);
2178
2179 if ((0 == verbose) && (n < (b_len - 1)))
2180 sg_scnpr(b + n, b_len - n, ", try '-v' option for more "
2181 "information");
2182 }
2183 return b; /* Note that a valid C string is returned in all cases */
2184 }
2185
2186 /* See description in sg_lib.h header file */
2187 bool
sg_scsi_normalize_sense(const uint8_t * sbp,int sb_len,struct sg_scsi_sense_hdr * sshp)2188 sg_scsi_normalize_sense(const uint8_t * sbp, int sb_len,
2189 struct sg_scsi_sense_hdr * sshp)
2190 {
2191 uint8_t resp_code;
2192 if (sshp)
2193 memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
2194 if ((NULL == sbp) || (sb_len < 1))
2195 return false;
2196 resp_code = 0x7f & sbp[0];
2197 if ((resp_code < 0x70) || (resp_code > 0x73))
2198 return false;
2199 if (sshp) {
2200 sshp->response_code = resp_code;
2201 if (sshp->response_code >= 0x72) { /* descriptor format */
2202 if (sb_len > 1)
2203 sshp->sense_key = (0xf & sbp[1]);
2204 if (sb_len > 2)
2205 sshp->asc = sbp[2];
2206 if (sb_len > 3)
2207 sshp->ascq = sbp[3];
2208 if (sb_len > 7)
2209 sshp->additional_length = sbp[7];
2210 sshp->byte4 = sbp[4]; /* bit 7: SDAT_OVFL bit */
2211 /* sbp[5] and sbp[6] reserved for descriptor format */
2212 } else { /* fixed format */
2213 if (sb_len > 2)
2214 sshp->sense_key = (0xf & sbp[2]);
2215 if (sb_len > 7) {
2216 sb_len = (sb_len < (sbp[7] + 8)) ? sb_len : (sbp[7] + 8);
2217 if (sb_len > 12)
2218 sshp->asc = sbp[12];
2219 if (sb_len > 13)
2220 sshp->ascq = sbp[13];
2221 }
2222 if (sb_len > 6) { /* lower 3 bytes of INFO field */
2223 sshp->byte4 = sbp[4];
2224 sshp->byte5 = sbp[5];
2225 sshp->byte6 = sbp[6];
2226 }
2227 }
2228 }
2229 return true;
2230 }
2231
2232 /* Returns a SG_LIB_CAT_* value. If cannot decode sense buffer (sbp) or a
2233 * less common sense key then return SG_LIB_CAT_SENSE .*/
2234 int
sg_err_category_sense(const uint8_t * sbp,int sb_len)2235 sg_err_category_sense(const uint8_t * sbp, int sb_len)
2236 {
2237 struct sg_scsi_sense_hdr ssh;
2238
2239 if ((sbp && (sb_len > 2)) &&
2240 (sg_scsi_normalize_sense(sbp, sb_len, &ssh))) {
2241 switch (ssh.sense_key) { /* 0 to 0x1f */
2242 case SPC_SK_NO_SENSE:
2243 return SG_LIB_CAT_NO_SENSE;
2244 case SPC_SK_RECOVERED_ERROR:
2245 return SG_LIB_CAT_RECOVERED;
2246 case SPC_SK_NOT_READY:
2247 if ((0x04 == ssh.asc) && (0x0b == ssh.ascq))
2248 return SG_LIB_CAT_STANDBY;
2249 if ((0x04 == ssh.asc) && (0x0c == ssh.ascq))
2250 return SG_LIB_CAT_UNAVAILABLE;
2251 return SG_LIB_CAT_NOT_READY;
2252 case SPC_SK_MEDIUM_ERROR:
2253 case SPC_SK_HARDWARE_ERROR:
2254 case SPC_SK_BLANK_CHECK:
2255 return SG_LIB_CAT_MEDIUM_HARD;
2256 case SPC_SK_UNIT_ATTENTION:
2257 return SG_LIB_CAT_UNIT_ATTENTION;
2258 /* used to return SG_LIB_CAT_MEDIA_CHANGED when ssh.asc==0x28 */
2259 case SPC_SK_ILLEGAL_REQUEST:
2260 if ((0x20 == ssh.asc) && (0x0 == ssh.ascq))
2261 return SG_LIB_CAT_INVALID_OP;
2262 else if ((0x21 == ssh.asc) && (0x0 == ssh.ascq))
2263 return SG_LIB_LBA_OUT_OF_RANGE;
2264 else
2265 return SG_LIB_CAT_ILLEGAL_REQ;
2266 break;
2267 case SPC_SK_ABORTED_COMMAND:
2268 if (0x10 == ssh.asc)
2269 return SG_LIB_CAT_PROTECTION;
2270 else
2271 return SG_LIB_CAT_ABORTED_COMMAND;
2272 case SPC_SK_MISCOMPARE:
2273 return SG_LIB_CAT_MISCOMPARE;
2274 case SPC_SK_DATA_PROTECT:
2275 return SG_LIB_CAT_DATA_PROTECT;
2276 case SPC_SK_COPY_ABORTED:
2277 return SG_LIB_CAT_COPY_ABORTED;
2278 case SPC_SK_COMPLETED:
2279 case SPC_SK_VOLUME_OVERFLOW:
2280 return SG_LIB_CAT_SENSE;
2281 default:
2282 ; /* reserved and vendor specific sense keys fall through */
2283 }
2284 }
2285 return SG_LIB_CAT_SENSE;
2286 }
2287
2288 /* Beware: gives wrong answer for variable length command (opcode=0x7f) */
2289 int
sg_get_command_size(uint8_t opcode)2290 sg_get_command_size(uint8_t opcode)
2291 {
2292 switch ((opcode >> 5) & 0x7) {
2293 case 0:
2294 return 6;
2295 case 3: case 5:
2296 return 12;
2297 case 4:
2298 return 16;
2299 default: /* 1, 2, 6, 7 */
2300 return 10;
2301 }
2302 }
2303
2304 void
sg_get_command_name(const uint8_t * cdbp,int peri_type,int buff_len,char * buff)2305 sg_get_command_name(const uint8_t * cdbp, int peri_type, int buff_len,
2306 char * buff)
2307 {
2308 int service_action;
2309
2310 if ((NULL == buff) || (buff_len < 1))
2311 return;
2312 else if (1 == buff_len) {
2313 buff[0] = '\0';
2314 return;
2315 }
2316 if (NULL == cdbp) {
2317 sg_scnpr(buff, buff_len, "%s", "<null> command pointer");
2318 return;
2319 }
2320 service_action = (SG_VARIABLE_LENGTH_CMD == cdbp[0]) ?
2321 sg_get_unaligned_be16(cdbp + 8) : (cdbp[1] & 0x1f);
2322 sg_get_opcode_sa_name(cdbp[0], service_action, peri_type, buff_len, buff);
2323 }
2324
2325 struct op_code2sa_t {
2326 int op_code;
2327 int pdt_s;
2328 struct sg_lib_value_name_t * arr;
2329 const char * prefix;
2330 };
2331
2332 static struct op_code2sa_t op_code2sa_arr[] = {
2333 {SG_VARIABLE_LENGTH_CMD, PDT_ALL, sg_lib_variable_length_arr, NULL},
2334 {SG_MAINTENANCE_IN, PDT_ALL, sg_lib_maint_in_arr, NULL},
2335 {SG_MAINTENANCE_OUT, PDT_ALL, sg_lib_maint_out_arr, NULL},
2336 {SG_SERVICE_ACTION_IN_12, PDT_ALL, sg_lib_serv_in12_arr, NULL},
2337 {SG_SERVICE_ACTION_OUT_12, PDT_ALL, sg_lib_serv_out12_arr, NULL},
2338 {SG_SERVICE_ACTION_IN_16, PDT_ALL, sg_lib_serv_in16_arr, NULL},
2339 {SG_SERVICE_ACTION_OUT_16, PDT_ALL, sg_lib_serv_out16_arr, NULL},
2340 {SG_SERVICE_ACTION_BIDI, PDT_ALL, sg_lib_serv_bidi_arr, NULL},
2341 {SG_PERSISTENT_RESERVE_IN, PDT_ALL, sg_lib_pr_in_arr,
2342 "Persistent reserve in"},
2343 {SG_PERSISTENT_RESERVE_OUT, PDT_ALL, sg_lib_pr_out_arr,
2344 "Persistent reserve out"},
2345 {SG_3PARTY_COPY_OUT, PDT_ALL, sg_lib_xcopy_sa_arr, NULL},
2346 {SG_3PARTY_COPY_IN, PDT_ALL, sg_lib_rec_copy_sa_arr, NULL},
2347 {SG_READ_BUFFER, PDT_ALL, sg_lib_read_buff_arr, "Read buffer(10)"},
2348 {SG_READ_BUFFER_16, PDT_ALL, sg_lib_read_buff_arr, "Read buffer(16)"},
2349 {SG_READ_ATTRIBUTE, PDT_ALL, sg_lib_read_attr_arr, "Read attribute"},
2350 {SG_READ_POSITION, PDT_TAPE, sg_lib_read_pos_arr, "Read position"},
2351 {SG_SANITIZE, PDT_DISK_ZBC, sg_lib_sanitize_sa_arr, "Sanitize"},
2352 {SG_WRITE_BUFFER, PDT_ALL, sg_lib_write_buff_arr, "Write buffer"},
2353 {SG_ZONING_IN, PDT_DISK_ZBC, sg_lib_zoning_in_arr, NULL},
2354 {SG_ZONING_OUT, PDT_DISK_ZBC, sg_lib_zoning_out_arr, NULL},
2355 {0xffff, -1, NULL, NULL},
2356 };
2357
2358 void
sg_get_opcode_sa_name(uint8_t cmd_byte0,int service_action,int peri_type,int buff_len,char * buff)2359 sg_get_opcode_sa_name(uint8_t cmd_byte0, int service_action,
2360 int peri_type, int buff_len, char * buff)
2361 {
2362 int d_pdt;
2363 const struct sg_lib_value_name_t * vnp;
2364 const struct op_code2sa_t * osp;
2365 char b[80];
2366
2367 if ((NULL == buff) || (buff_len < 1))
2368 return;
2369 else if (1 == buff_len) {
2370 buff[0] = '\0';
2371 return;
2372 }
2373
2374 if (peri_type < 0)
2375 peri_type = 0;
2376 d_pdt = sg_lib_pdt_decay(peri_type);
2377 for (osp = op_code2sa_arr; osp->arr; ++osp) {
2378 if ((int)cmd_byte0 == osp->op_code) {
2379 if (sg_pdt_s_eq(osp->pdt_s, d_pdt)) {
2380 vnp = get_value_name(osp->arr, service_action, peri_type);
2381 if (vnp) {
2382 if (osp->prefix)
2383 sg_scnpr(buff, buff_len, "%s, %s", osp->prefix,
2384 vnp->name);
2385 else
2386 sg_scnpr(buff, buff_len, "%s", vnp->name);
2387 } else {
2388 sg_get_opcode_name(cmd_byte0, peri_type, sizeof(b), b);
2389 sg_scnpr(buff, buff_len, "%s service action=0x%x", b,
2390 service_action);
2391 }
2392 } else
2393 sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff);
2394 return;
2395 }
2396 }
2397 sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff);
2398 }
2399
2400 void
sg_get_opcode_name(uint8_t cmd_byte0,int peri_type,int buff_len,char * buff)2401 sg_get_opcode_name(uint8_t cmd_byte0, int peri_type, int buff_len,
2402 char * buff)
2403 {
2404 const struct sg_lib_value_name_t * vnp;
2405 int grp;
2406
2407 if ((NULL == buff) || (buff_len < 1))
2408 return;
2409 else if (1 == buff_len) {
2410 buff[0] = '\0';
2411 return;
2412 }
2413 if (SG_VARIABLE_LENGTH_CMD == cmd_byte0) {
2414 sg_scnpr(buff, buff_len, "%s", "Variable length");
2415 return;
2416 }
2417 grp = (cmd_byte0 >> 5) & 0x7;
2418 switch (grp) {
2419 case 0:
2420 case 1:
2421 case 2:
2422 case 4:
2423 case 5:
2424 vnp = get_value_name(sg_lib_normal_opcodes, cmd_byte0, peri_type);
2425 if (vnp)
2426 sg_scnpr(buff, buff_len, "%s", vnp->name);
2427 else
2428 sg_scnpr(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0);
2429 break;
2430 case 3:
2431 sg_scnpr(buff, buff_len, "Reserved [0x%x]", (int)cmd_byte0);
2432 break;
2433 case 6:
2434 case 7:
2435 sg_scnpr(buff, buff_len, "Vendor specific [0x%x]", (int)cmd_byte0);
2436 break;
2437 }
2438 }
2439
2440 /* Fetch NVMe command name given first byte (byte offset 0 in 64 byte
2441 * command) of command. Gets Admin NVMe command name if 'admin' is true
2442 * (e.g. opcode=0x6 -> Identify), otherwise gets NVM command set name
2443 * (e.g. opcode=0 -> Flush). Returns 'buff'. */
2444 char *
sg_get_nvme_opcode_name(uint8_t cmd_byte0,bool admin,int buff_len,char * buff)2445 sg_get_nvme_opcode_name(uint8_t cmd_byte0, bool admin, int buff_len,
2446 char * buff)
2447 {
2448 const struct sg_lib_simple_value_name_t * vnp = admin ?
2449 sg_lib_nvme_admin_cmd_arr : sg_lib_nvme_nvm_cmd_arr;
2450
2451 if ((NULL == buff) || (buff_len < 1))
2452 return buff;
2453 else if (1 == buff_len) {
2454 buff[0] = '\0';
2455 return buff;
2456 }
2457 for ( ; vnp->name; ++vnp) {
2458 if (cmd_byte0 == (uint8_t)vnp->value) {
2459 snprintf(buff, buff_len, "%s", vnp->name);
2460 return buff;
2461 }
2462 }
2463 if (admin) {
2464 if (cmd_byte0 >= 0xc0)
2465 snprintf(buff, buff_len, "Vendor specific opcode: 0x%x",
2466 cmd_byte0);
2467 else if (cmd_byte0 >= 0x80)
2468 snprintf(buff, buff_len, "Command set specific opcode: 0x%x",
2469 cmd_byte0);
2470 else
2471 snprintf(buff, buff_len, "Unknown opcode: 0x%x", cmd_byte0);
2472 } else { /* NVM (non-Admin) command set */
2473 if (cmd_byte0 >= 0x80)
2474 snprintf(buff, buff_len, "Vendor specific opcode: 0x%x",
2475 cmd_byte0);
2476 else
2477 snprintf(buff, buff_len, "Unknown opcode: 0x%x", cmd_byte0);
2478 }
2479 return buff;
2480 }
2481
2482 /* Iterates to next designation descriptor in the device identification
2483 * VPD page. The 'initial_desig_desc' should point to start of first
2484 * descriptor with 'page_len' being the number of valid bytes in that
2485 * and following descriptors. To start, 'off' should point to a negative
2486 * value, thereafter it should point to the value yielded by the previous
2487 * call. If 0 returned then 'initial_desig_desc + *off' should be a valid
2488 * descriptor; returns -1 if normal end condition and -2 for an abnormal
2489 * termination. Matches association, designator_type and/or code_set when
2490 * any of those values are greater than or equal to zero. */
2491 int
sg_vpd_dev_id_iter(const uint8_t * initial_desig_desc,int page_len,int * off,int m_assoc,int m_desig_type,int m_code_set)2492 sg_vpd_dev_id_iter(const uint8_t * initial_desig_desc, int page_len,
2493 int * off, int m_assoc, int m_desig_type, int m_code_set)
2494 {
2495 bool fltr = ((m_assoc >= 0) || (m_desig_type >= 0) || (m_code_set >= 0));
2496 int k = *off;
2497 const uint8_t * bp = initial_desig_desc;
2498
2499 while ((k + 3) < page_len) {
2500 k = (k < 0) ? 0 : (k + bp[k + 3] + 4);
2501 if ((k + 4) > page_len)
2502 break;
2503 if (fltr) {
2504 if (m_code_set >= 0) {
2505 if ((bp[k] & 0xf) != m_code_set)
2506 continue;
2507 }
2508 if (m_assoc >= 0) {
2509 if (((bp[k + 1] >> 4) & 0x3) != m_assoc)
2510 continue;
2511 }
2512 if (m_desig_type >= 0) {
2513 if ((bp[k + 1] & 0xf) != m_desig_type)
2514 continue;
2515 }
2516 }
2517 *off = k;
2518 return 0;
2519 }
2520 return (k == page_len) ? -1 : -2;
2521 }
2522
2523 static const char * sg_sfs_spc_reserved = "SPC Reserved";
2524 static const char * sg_sfs_sbc_reserved = "SBC Reserved";
2525 static const char * sg_sfs_ssc_reserved = "SSC Reserved";
2526 static const char * sg_sfs_zbc_reserved = "ZBC Reserved";
2527 static const char * sg_sfs_reserved = "Reserved";
2528
2529 /* Yield SCSI Feature Set (sfs) string. When 'peri_type' is < -1 (or > 31)
2530 * returns pointer to string (same as 'buff') associated with 'sfs_code'.
2531 * When 'peri_type' is between -1 (for SPC) and 31 (inclusive) then a match
2532 * on both 'sfs_code' and 'peri_type' is required. If 'foundp' is not NULL
2533 * then where it points is set to true if a match is found else it is set to
2534 * false. If 'buff' is not NULL then in the case of a match a descriptive
2535 * string is written to 'buff' while if there is not a not then a string
2536 * ending in "Reserved" is written (and may be prefixed with SPC, SBC, SSC
2537 * or ZBC). Returns 'buff' (i.e. a pointer value) even if it is NULL.
2538 * Example:
2539 * char b[64];
2540 * ...
2541 * printf("%s\n", sg_get_sfs_str(sfs_code, -2, sizeof(b), b, NULL, 0));
2542 */
2543 const char *
sg_get_sfs_str(uint16_t sfs_code,int peri_type,int buff_len,char * buff,bool * foundp,int verbose)2544 sg_get_sfs_str(uint16_t sfs_code, int peri_type, int buff_len, char * buff,
2545 bool * foundp, int verbose)
2546 {
2547 const struct sg_lib_value_name_t * vnp = NULL;
2548 int n = 0;
2549 int my_pdt;
2550
2551 if ((NULL == buff) || (buff_len < 1)) {
2552 if (foundp)
2553 *foundp = false;
2554 return NULL;
2555 } else if (1 == buff_len) {
2556 buff[0] = '\0';
2557 if (foundp)
2558 *foundp = false;
2559 return NULL;
2560 }
2561 my_pdt = ((peri_type < -1) || (peri_type > PDT_MAX)) ? -2 : peri_type;
2562 vnp = get_value_name(sg_lib_scsi_feature_sets, sfs_code, my_pdt);
2563 if (vnp && (-2 != my_pdt)) {
2564 if (! sg_pdt_s_eq(my_pdt, vnp->peri_dev_type))
2565 vnp = NULL; /* shouldn't really happen */
2566 }
2567 if (foundp)
2568 *foundp = vnp ? true : false;
2569 if (sfs_code < 0x100) { /* SPC Feature Sets */
2570 if (vnp) {
2571 if (verbose)
2572 n += sg_scnpr(buff, buff_len, "SPC %s", vnp->name);
2573 else
2574 n += sg_scnpr(buff, buff_len, "%s", vnp->name);
2575 } else
2576 n += sg_scnpr(buff, buff_len, "%s", sg_sfs_spc_reserved);
2577 } else if (sfs_code < 0x200) { /* SBC Feature Sets */
2578 if (vnp) {
2579 if (verbose)
2580 n += sg_scnpr(buff, buff_len, "SBC %s", vnp->name);
2581 else
2582 n += sg_scnpr(buff, buff_len, "%s", vnp->name);
2583 } else
2584 n += sg_scnpr(buff, buff_len, "%s", sg_sfs_sbc_reserved);
2585 } else if (sfs_code < 0x300) { /* SSC Feature Sets */
2586 if (vnp) {
2587 if (verbose)
2588 n += sg_scnpr(buff, buff_len, "SSC %s", vnp->name);
2589 else
2590 n += sg_scnpr(buff, buff_len, "%s", vnp->name);
2591 } else
2592 n += sg_scnpr(buff, buff_len, "%s", sg_sfs_ssc_reserved);
2593 } else if (sfs_code < 0x400) { /* ZBC Feature Sets */
2594 if (vnp) {
2595 if (verbose)
2596 n += sg_scnpr(buff, buff_len, "ZBC %s", vnp->name);
2597 else
2598 n += sg_scnpr(buff, buff_len, "%s", vnp->name);
2599 } else
2600 n += sg_scnpr(buff, buff_len, "%s", sg_sfs_zbc_reserved);
2601 } else { /* Other SCSI Feature Sets */
2602 if (vnp) {
2603 if (verbose)
2604 n += sg_scnpr(buff, buff_len, "[unrecognized PDT] %s",
2605 vnp->name);
2606 else
2607 n += sg_scnpr(buff, buff_len, "%s", vnp->name);
2608 } else
2609 n += sg_scnpr(buff, buff_len, "%s", sg_sfs_reserved);
2610
2611 }
2612 if (verbose > 4)
2613 pr2ws("%s: length of returned string (n) %d\n", __func__, n);
2614 return buff;
2615 }
2616
2617 /* This is a heuristic that takes into account the command bytes and length
2618 * to decide whether the presented unstructured sequence of bytes could be
2619 * a SCSI command. If so it returns true otherwise false. Vendor specific
2620 * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
2621 * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
2622 * only SCSI commands considered above 16 bytes of length are the Variable
2623 * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
2624 * Both have an inbuilt length field which can be cross checked with clen.
2625 * No NVMe commands (64 bytes long plus some extra added by some OSes) have
2626 * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
2627 * structures that are sent across the wire. The FIS register structure is
2628 * used to move a command from a SATA host to device, but the ATA 'command'
2629 * is not the first byte. So it is harder to say what will happen if a
2630 * FIS structure is presented as a SCSI command, hopefully there is a low
2631 * probability this function will yield true in that case. */
2632 bool
sg_is_scsi_cdb(const uint8_t * cdbp,int clen)2633 sg_is_scsi_cdb(const uint8_t * cdbp, int clen)
2634 {
2635 uint8_t opcode;
2636 uint8_t top3bits;
2637
2638 if (clen < 6)
2639 return false;
2640 opcode = cdbp[0];
2641 top3bits = opcode >> 5;
2642 if (0x3 == top3bits) {
2643 int ilen, sa;
2644
2645 if ((clen < 12) || (clen % 4))
2646 return false; /* must be modulo 4 and 12 or more bytes */
2647 switch (opcode) {
2648 case 0x7e: /* Extended cdb (XCDB) */
2649 ilen = 4 + sg_get_unaligned_be16(cdbp + 2);
2650 return (ilen == clen);
2651 case 0x7f: /* Variable Length cdb */
2652 ilen = 8 + cdbp[7];
2653 sa = sg_get_unaligned_be16(cdbp + 8);
2654 /* service action (sa) 0x0 is reserved */
2655 return ((ilen == clen) && sa);
2656 default:
2657 return false;
2658 }
2659 } else if (clen <= 16) {
2660 switch (clen) {
2661 case 6:
2662 if (top3bits > 0x5) /* vendor */
2663 return true;
2664 return (0x0 == top3bits); /* 6 byte cdb */
2665 case 10:
2666 if (top3bits > 0x5) /* vendor */
2667 return true;
2668 return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */
2669 case 16:
2670 if (top3bits > 0x5) /* vendor */
2671 return true;
2672 return (0x4 == top3bits); /* 16 byte cdb */
2673 case 12:
2674 if (top3bits > 0x5) /* vendor */
2675 return true;
2676 return (0x5 == top3bits); /* 12 byte cdb */
2677 default:
2678 return false;
2679 }
2680 }
2681 /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or
2682 * opcode > 0x7f). */
2683 return false;
2684 }
2685
2686 /* Yield string associated with NVMe command status value in sct_sc. It
2687 * expects to decode DW3 bits 27:17 from the completion queue. Bits 27:25
2688 * are the Status Code Type (SCT) and bits 24:17 are the Status Code (SC).
2689 * Bit 17 in DW3 should be bit 0 in sct_sc. If no status string is found
2690 * a string of the form "Reserved [0x<sct_sc_in_hex>]" is generated.
2691 * Returns 'buff'. Does nothing if buff_len<=0 or if buff is NULL.*/
2692 char *
sg_get_nvme_cmd_status_str(uint16_t sct_sc,int b_len,char * b)2693 sg_get_nvme_cmd_status_str(uint16_t sct_sc, int b_len, char * b)
2694 {
2695 int k;
2696 uint16_t s = 0x3ff & sct_sc;
2697 const struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr;
2698
2699 if ((b_len <= 0) || (NULL == b))
2700 return b;
2701 else if (1 == b_len) {
2702 b[0] = '\0';
2703 return b;
2704 }
2705 for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) {
2706 if (s == (uint16_t)vp->value) {
2707 strncpy(b, vp->name, b_len);
2708 b[b_len - 1] = '\0';
2709 return b;
2710 }
2711 }
2712 if (k >= 1000)
2713 pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n",
2714 __func__);
2715 snprintf(b, b_len, "Reserved [0x%x]", sct_sc);
2716 return b;
2717 }
2718
2719 /* Attempts to map NVMe status value ((SCT << 8) | SC) to SCSI status,
2720 * sense_key, asc and ascq tuple. If successful returns true and writes to
2721 * non-NULL pointer arguments; otherwise returns false. */
2722 bool
sg_nvme_status2scsi(uint16_t sct_sc,uint8_t * status_p,uint8_t * sk_p,uint8_t * asc_p,uint8_t * ascq_p)2723 sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p,
2724 uint8_t * asc_p, uint8_t * ascq_p)
2725 {
2726 int k, ind;
2727 uint16_t s = 0x3ff & sct_sc;
2728 struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr;
2729 struct sg_lib_4tuple_u8 * mp = sg_lib_scsi_status_sense_arr;
2730
2731 for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) {
2732 if (s == (uint16_t)vp->value)
2733 break;
2734 }
2735 if (k >= 1000) {
2736 pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n",
2737 __func__);
2738 return false;
2739 }
2740 if (NULL == vp->name)
2741 return false;
2742 ind = vp->peri_dev_type;
2743
2744
2745 for (k = 0; (0xff != mp->t2) && k < 1000; ++k, ++mp)
2746 ; /* count entries for valid index range */
2747 if (k >= 1000) {
2748 pr2ws("%s: where is sentinel for sg_lib_scsi_status_sense_arr ??\n",
2749 __func__);
2750 return false;
2751 } else if (ind >= k)
2752 return false;
2753
2754 mp = sg_lib_scsi_status_sense_arr + ind;
2755 if (status_p)
2756 *status_p = mp->t1;
2757 if (sk_p)
2758 *sk_p = mp->t2;
2759 if (asc_p)
2760 *asc_p = mp->t3;
2761 if (ascq_p)
2762 *ascq_p = mp->t4;
2763 return true;
2764 }
2765
2766 /* Add vendor (sg3_utils) specific sense descriptor for the NVMe Status
2767 * field. Assumes descriptor (i.e. not fixed) sense. Assumes sbp has room. */
2768 void
sg_nvme_desc2sense(uint8_t * sbp,bool dnr,bool more,uint16_t sct_sc)2769 sg_nvme_desc2sense(uint8_t * sbp, bool dnr, bool more, uint16_t sct_sc)
2770 {
2771 int len = sbp[7] + 8;
2772
2773 sbp[len] = 0xde; /* vendor specific descriptor type */
2774 sbp[len + 1] = 6; /* descriptor is 8 bytes long */
2775 memset(sbp + len + 2, 0, 6);
2776 if (dnr)
2777 sbp[len + 5] = 0x80;
2778 if (more)
2779 sbp[len + 5] |= 0x40;
2780 sg_put_unaligned_be16(sct_sc, sbp + len + 6);
2781 sbp[7] += 8;
2782 }
2783
2784 /* Build minimum sense buffer, either descriptor type (desc=true) or fixed
2785 * type (desc=false). Assume sbp has enough room (8 or 14 bytes
2786 * respectively). sbp should have room for 32 or 18 bytes respectively */
2787 void
sg_build_sense_buffer(bool desc,uint8_t * sbp,uint8_t skey,uint8_t asc,uint8_t ascq)2788 sg_build_sense_buffer(bool desc, uint8_t *sbp, uint8_t skey, uint8_t asc,
2789 uint8_t ascq)
2790 {
2791 if (desc) {
2792 sbp[0] = 0x72; /* descriptor, current */
2793 sbp[1] = skey;
2794 sbp[2] = asc;
2795 sbp[3] = ascq;
2796 sbp[7] = 0;
2797 } else {
2798 sbp[0] = 0x70; /* fixed, current */
2799 sbp[2] = skey;
2800 sbp[7] = 0xa; /* Assumes length is 18 bytes */
2801 sbp[12] = asc;
2802 sbp[13] = ascq;
2803 }
2804 }
2805
2806 /* safe_strerror() contributed by Clayton Weaver <cgweav at email dot com>
2807 * Allows for situation in which strerror() is given a wild value (or the
2808 * C library is incomplete) and returns NULL. Still not thread safe.
2809 */
2810
2811 static char safe_errbuf[64] = {'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ',
2812 'e', 'r', 'r', 'n', 'o', ':', ' ', 0};
2813
2814 char *
safe_strerror(int errnum)2815 safe_strerror(int errnum)
2816 {
2817 char * errstr;
2818
2819 if (errnum < 0)
2820 errnum = -errnum;
2821 errstr = strerror(errnum);
2822 if (NULL == errstr) {
2823 size_t len = strlen(safe_errbuf);
2824
2825 sg_scnpr(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i", errnum);
2826 return safe_errbuf;
2827 }
2828 return errstr;
2829 }
2830
2831 static int
trimTrailingSpaces(char * b)2832 trimTrailingSpaces(char * b)
2833 {
2834 int n = strlen(b);
2835
2836 while ((n > 0) && (' ' == b[n - 1]))
2837 b[--n] = '\0';
2838 return n;
2839 }
2840
2841 /* Read binary starting at 'str' for 'len' bytes and output as ASCII
2842 * hexadecinal into file pointer (fp). 16 bytes per line are output with an
2843 * additional space between 8th and 9th byte on each line (for readability).
2844 * 'no_ascii' selects one of 3 output format types:
2845 * > 0 each line has address then up to 16 ASCII-hex bytes
2846 * = 0 in addition, the bytes are listed in ASCII to the right
2847 * < 0 only the ASCII-hex bytes are listed (i.e. without address) */
2848 void
dStrHexFp(const char * str,int len,int no_ascii,FILE * fp)2849 dStrHexFp(const char* str, int len, int no_ascii, FILE * fp)
2850 {
2851 const char * p = str;
2852 const char * formatstr;
2853 uint8_t c;
2854 char buff[82];
2855 int a = 0;
2856 int bpstart = 5;
2857 const int cpstart = 60;
2858 int cpos = cpstart;
2859 int bpos = bpstart;
2860 int i, k, blen;
2861
2862 if (len <= 0)
2863 return;
2864 blen = (int)sizeof(buff);
2865 if (0 == no_ascii) /* address at left and ASCII at right */
2866 formatstr = "%.76s\n";
2867 else /* previously when > 0 str was "%.58s\n" */
2868 formatstr = "%s\n"; /* when < 0 str was: "%.48s\n" */
2869 memset(buff, ' ', 80);
2870 buff[80] = '\0';
2871 if (no_ascii < 0) {
2872 bpstart = 0;
2873 bpos = bpstart;
2874 for (k = 0; k < len; k++) {
2875 c = *p++;
2876 if (bpos == (bpstart + (8 * 3)))
2877 bpos++;
2878 sg_scnpr(&buff[bpos], blen - bpos, "%.2x", (int)(uint8_t)c);
2879 buff[bpos + 2] = ' ';
2880 if ((k > 0) && (0 == ((k + 1) % 16))) {
2881 trimTrailingSpaces(buff);
2882 fprintf(fp, formatstr, buff);
2883 bpos = bpstart;
2884 memset(buff, ' ', 80);
2885 } else
2886 bpos += 3;
2887 }
2888 if (bpos > bpstart) {
2889 buff[bpos + 2] = '\0';
2890 trimTrailingSpaces(buff);
2891 fprintf(fp, "%s\n", buff);
2892 }
2893 return;
2894 }
2895 /* no_ascii>=0, start each line with address (offset) */
2896 k = sg_scnpr(buff + 1, blen - 1, "%.2x", a);
2897 buff[k + 1] = ' ';
2898
2899 for (i = 0; i < len; i++) {
2900 c = *p++;
2901 bpos += 3;
2902 if (bpos == (bpstart + (9 * 3)))
2903 bpos++;
2904 sg_scnpr(&buff[bpos], blen - bpos, "%.2x", (int)(uint8_t)c);
2905 buff[bpos + 2] = ' ';
2906 if (no_ascii)
2907 buff[cpos++] = ' ';
2908 else {
2909 if (! my_isprint(c))
2910 c = '.';
2911 buff[cpos++] = c;
2912 }
2913 if (cpos > (cpstart + 15)) {
2914 if (no_ascii)
2915 trimTrailingSpaces(buff);
2916 fprintf(fp, formatstr, buff);
2917 bpos = bpstart;
2918 cpos = cpstart;
2919 a += 16;
2920 memset(buff, ' ', 80);
2921 k = sg_scnpr(buff + 1, blen - 1, "%.2x", a);
2922 buff[k + 1] = ' ';
2923 }
2924 }
2925 if (cpos > cpstart) {
2926 buff[cpos] = '\0';
2927 if (no_ascii)
2928 trimTrailingSpaces(buff);
2929 fprintf(fp, "%s\n", buff);
2930 }
2931 }
2932
2933 void
dStrHex(const char * str,int len,int no_ascii)2934 dStrHex(const char* str, int len, int no_ascii)
2935 {
2936 dStrHexFp(str, len, no_ascii, stdout);
2937 }
2938
2939 void
dStrHexErr(const char * str,int len,int no_ascii)2940 dStrHexErr(const char* str, int len, int no_ascii)
2941 {
2942 dStrHexFp(str, len, no_ascii,
2943 (sg_warnings_strm ? sg_warnings_strm : stderr));
2944 }
2945
2946 #define DSHS_LINE_BLEN 160 /* maximum characters per line */
2947 #define DSHS_BPL 16 /* bytes per line */
2948
2949 /* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space separated)
2950 * to 'b' not to exceed 'b_len' characters. Each line starts with 'leadin'
2951 * (NULL for no leadin) and there are 16 bytes per line with an extra space
2952 * between the 8th and 9th bytes. 'oformat' is 0 for repeat in printable ASCII
2953 * ('.' for non printable chars) to right of each line; 1 don't (so just
2954 * output ASCII hex). If 'oformat' is 2 output same as 1 but any LFs are
2955 * replaced by space (and trailing spaces are trimmed). Note that an address
2956 * is not printed on each line preceding the hex data. Returns number of bytes
2957 * written to 'b' excluding the trailing '\0'. The only difference between
2958 * dStrHexStr() and hex2str() is the type of the first argument. */
2959 int
dStrHexStr(const char * str,int len,const char * leadin,int oformat,int b_len,char * b)2960 dStrHexStr(const char * str, int len, const char * leadin, int oformat,
2961 int b_len, char * b)
2962 {
2963 bool want_ascii = (0 == oformat);
2964 int bpstart, bpos, k, n, prior_ascii_len;
2965 char buff[DSHS_LINE_BLEN + 2]; /* allow for trailing null */
2966 char a[DSHS_BPL + 1]; /* printable ASCII bytes or '.' */
2967 const char * p = str;
2968 const char * lf_or = (oformat > 1) ? " " : "\n";
2969
2970 if (len <= 0) {
2971 if (b_len > 0)
2972 b[0] = '\0';
2973 return 0;
2974 }
2975 if (b_len <= 0)
2976 return 0;
2977 if (want_ascii) {
2978 memset(a, ' ', DSHS_BPL);
2979 a[DSHS_BPL] = '\0';
2980 }
2981 n = 0;
2982 bpstart = 0;
2983 if (leadin) {
2984 if (oformat > 1)
2985 n += sg_scnpr(b + n, b_len - n, "%s", leadin);
2986 else {
2987 bpstart = strlen(leadin);
2988 /* Cap leadin at (DSHS_LINE_BLEN - 70) characters */
2989 if (bpstart > (DSHS_LINE_BLEN - 70))
2990 bpstart = DSHS_LINE_BLEN - 70;
2991 }
2992 }
2993 bpos = bpstart;
2994 prior_ascii_len = bpstart + (DSHS_BPL * 3) + 1;
2995 memset(buff, ' ', DSHS_LINE_BLEN);
2996 buff[DSHS_LINE_BLEN] = '\0';
2997 if (bpstart > 0)
2998 memcpy(buff, leadin, bpstart);
2999 for (k = 0; k < len; k++) {
3000 uint8_t c = *p++;
3001
3002 if (bpos == (bpstart + ((DSHS_BPL / 2) * 3)))
3003 bpos++; /* for extra space in middle of each line's hex */
3004 sg_scnpr(buff + bpos, (int)sizeof(buff) - bpos, "%.2x",
3005 (int)(uint8_t)c);
3006 buff[bpos + 2] = ' ';
3007 if (want_ascii)
3008 a[k % DSHS_BPL] = my_isprint(c) ? c : '.';
3009 if ((k > 0) && (0 == ((k + 1) % DSHS_BPL))) {
3010 trimTrailingSpaces(buff);
3011 if (want_ascii) {
3012 n += sg_scnpr(b + n, b_len - n, "%-*s %s\n",
3013 prior_ascii_len, buff, a);
3014 memset(a, ' ', DSHS_BPL);
3015 } else
3016 n += sg_scnpr(b + n, b_len - n, "%s%s", buff, lf_or);
3017 if (n >= (b_len - 1))
3018 goto fini;
3019 memset(buff, ' ', DSHS_LINE_BLEN);
3020 bpos = bpstart;
3021 if (bpstart > 0)
3022 memcpy(buff, leadin, bpstart);
3023 } else
3024 bpos += 3;
3025 }
3026 if (bpos > bpstart) {
3027 trimTrailingSpaces(buff);
3028 if (want_ascii)
3029 n += sg_scnpr(b + n, b_len - n, "%-*s %s\n", prior_ascii_len,
3030 buff, a);
3031 else
3032 n += sg_scnpr(b + n, b_len - n, "%s%s", buff, lf_or);
3033 }
3034 fini:
3035 if (oformat > 1)
3036 n = trimTrailingSpaces(b);
3037 return n;
3038 }
3039
3040 void
hex2stdout(const uint8_t * b_str,int len,int no_ascii)3041 hex2stdout(const uint8_t * b_str, int len, int no_ascii)
3042 {
3043 dStrHex((const char *)b_str, len, no_ascii);
3044 }
3045
3046 void
hex2stderr(const uint8_t * b_str,int len,int no_ascii)3047 hex2stderr(const uint8_t * b_str, int len, int no_ascii)
3048 {
3049 dStrHexErr((const char *)b_str, len, no_ascii);
3050 }
3051
3052 int
hex2str(const uint8_t * b_str,int len,const char * leadin,int oformat,int b_len,char * b)3053 hex2str(const uint8_t * b_str, int len, const char * leadin, int oformat,
3054 int b_len, char * b)
3055 {
3056 return dStrHexStr((const char *)b_str, len, leadin, oformat, b_len, b);
3057 }
3058
3059 void
hex2fp(const uint8_t * b_str,int len,const char * leadin,int oformat,FILE * fp)3060 hex2fp(const uint8_t * b_str, int len, const char * leadin, int oformat,
3061 FILE * fp)
3062 {
3063 int k, num;
3064 char b[800]; /* allow for 4 lines of 16 bytes (in hex) each */
3065
3066 if (leadin && (strlen(leadin) > 118)) {
3067 fprintf(fp, ">>> leadin parameter is too large\n");
3068 return;
3069 }
3070 for (k = 0; k < len; k += num) {
3071 num = ((k + 64) < len) ? 64 : (len - k);
3072 hex2str(b_str + k, num, leadin, oformat, sizeof(b), b);
3073 fprintf(fp, "%s", b);
3074 }
3075 }
3076
3077 /* Returns true when executed on big endian machine; else returns false.
3078 * Useful for displaying ATA identify words (which need swapping on a
3079 * big endian machine). */
3080 bool
sg_is_big_endian()3081 sg_is_big_endian()
3082 {
3083 union u_t {
3084 uint16_t s;
3085 uint8_t c[sizeof(uint16_t)];
3086 } u;
3087
3088 u.s = 0x0102;
3089 return (u.c[0] == 0x01); /* The lowest address contains
3090 the most significant byte */
3091 }
3092
3093 bool
sg_all_zeros(const uint8_t * bp,int b_len)3094 sg_all_zeros(const uint8_t * bp, int b_len)
3095 {
3096 if ((NULL == bp) || (b_len <= 0))
3097 return false;
3098 for (--b_len; b_len >= 0; --b_len) {
3099 if (0x0 != bp[b_len])
3100 return false;
3101 }
3102 return true;
3103 }
3104
3105 bool
sg_all_ffs(const uint8_t * bp,int b_len)3106 sg_all_ffs(const uint8_t * bp, int b_len)
3107 {
3108 if ((NULL == bp) || (b_len <= 0))
3109 return false;
3110 for (--b_len; b_len >= 0; --b_len) {
3111 if (0xff != bp[b_len])
3112 return false;
3113 }
3114 return true;
3115 }
3116
3117 static uint16_t
swapb_uint16(uint16_t u)3118 swapb_uint16(uint16_t u)
3119 {
3120 uint16_t r;
3121
3122 r = (u >> 8) & 0xff;
3123 r |= ((u & 0xff) << 8);
3124 return r;
3125 }
3126
3127 /* Note the ASCII-hex output goes to stdout. [Most other output from functions
3128 * in this file go to sg_warnings_strm (default stderr).]
3129 * 'no_ascii' allows for 3 output types:
3130 * > 0 each line has address then up to 8 ASCII-hex 16 bit words
3131 * = 0 in addition, the ASCI bytes pairs are listed to the right
3132 * = -1 only the ASCII-hex words are listed (i.e. without address)
3133 * = -2 only the ASCII-hex words, formatted for "hdparm --Istdin"
3134 * < -2 same as -1
3135 * If 'swapb' is true then bytes in each word swapped. Needs to be set
3136 * for ATA IDENTIFY DEVICE response on big-endian machines. */
3137 void
dWordHex(const uint16_t * words,int num,int no_ascii,bool swapb)3138 dWordHex(const uint16_t* words, int num, int no_ascii, bool swapb)
3139 {
3140 const uint16_t * p = words;
3141 uint16_t c;
3142 char buff[82];
3143 uint8_t upp, low;
3144 int a = 0;
3145 const int bpstart = 3;
3146 const int cpstart = 52;
3147 int cpos = cpstart;
3148 int bpos = bpstart;
3149 int i, k, blen;
3150
3151 if (num <= 0)
3152 return;
3153 blen = (int)sizeof(buff);
3154 memset(buff, ' ', 80);
3155 buff[80] = '\0';
3156 if (no_ascii < 0) {
3157 for (k = 0; k < num; k++) {
3158 c = *p++;
3159 if (swapb)
3160 c = swapb_uint16(c);
3161 bpos += 5;
3162 sg_scnpr(buff + bpos, blen - bpos, "%.4x", (my_uint)c);
3163 buff[bpos + 4] = ' ';
3164 if ((k > 0) && (0 == ((k + 1) % 8))) {
3165 if (-2 == no_ascii)
3166 printf("%.39s\n", buff +8);
3167 else
3168 printf("%.47s\n", buff);
3169 bpos = bpstart;
3170 memset(buff, ' ', 80);
3171 }
3172 }
3173 if (bpos > bpstart) {
3174 if (-2 == no_ascii)
3175 printf("%.39s\n", buff +8);
3176 else
3177 printf("%.47s\n", buff);
3178 }
3179 return;
3180 }
3181 /* no_ascii>=0, start each line with address (offset) */
3182 k = sg_scnpr(buff + 1, blen - 1, "%.2x", a);
3183 buff[k + 1] = ' ';
3184
3185 for (i = 0; i < num; i++) {
3186 c = *p++;
3187 if (swapb)
3188 c = swapb_uint16(c);
3189 bpos += 5;
3190 sg_scnpr(buff + bpos, blen - bpos, "%.4x", (my_uint)c);
3191 buff[bpos + 4] = ' ';
3192 if (no_ascii) {
3193 buff[cpos++] = ' ';
3194 buff[cpos++] = ' ';
3195 buff[cpos++] = ' ';
3196 } else {
3197 upp = (c >> 8) & 0xff;
3198 low = c & 0xff;
3199 if (! my_isprint(upp))
3200 upp = '.';
3201 buff[cpos++] = upp;
3202 if (! my_isprint(low))
3203 low = '.';
3204 buff[cpos++] = low;
3205 buff[cpos++] = ' ';
3206 }
3207 if (cpos > (cpstart + 23)) {
3208 printf("%.76s\n", buff);
3209 bpos = bpstart;
3210 cpos = cpstart;
3211 a += 8;
3212 memset(buff, ' ', 80);
3213 k = sg_scnpr(buff + 1, blen - 1, "%.2x", a);
3214 buff[k + 1] = ' ';
3215 }
3216 }
3217 if (cpos > cpstart)
3218 printf("%.76s\n", buff);
3219 }
3220
3221 /* If the number in 'buf' can not be decoded or the multiplier is unknown
3222 * then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
3223 * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
3224 * Main (SI) multipliers supported: K, M, G. Ignore leading spaces and
3225 * tabs; accept comma, hyphen, space, tab and hash as terminator.
3226 * Handles zero and positive values up to 2**31-1 .
3227 * Experimental: left argument (must in with hexadecimal digit) added
3228 * to, or multiplied, by right argument. No embedded spaces.
3229 * Examples: '3+1k' (evaluates to 1027) and '0x34+1m'. */
3230 int
sg_get_num(const char * buf)3231 sg_get_num(const char * buf)
3232 {
3233 bool is_hex = false;
3234 int res, num, n, len;
3235 unsigned int unum;
3236 char * cp;
3237 const char * b;
3238 const char * b2p;
3239 char c = 'c';
3240 char c2 = '\0'; /* keep static checker happy */
3241 char c3 = '\0'; /* keep static checker happy */
3242 char lb[16];
3243
3244 if ((NULL == buf) || ('\0' == buf[0]))
3245 return -1;
3246 len = strlen(buf);
3247 n = strspn(buf, " \t");
3248 if (n > 0) {
3249 if (n == len)
3250 return -1;
3251 buf += n;
3252 len -= n;
3253 }
3254 /* following hack to keep C++ happy */
3255 cp = strpbrk((char *)buf, " \t,#-");
3256 if (cp) {
3257 len = cp - buf;
3258 n = (int)sizeof(lb) - 1;
3259 len = (len < n) ? len : n;
3260 memcpy(lb, buf, len);
3261 lb[len] = '\0';
3262 b = lb;
3263 } else
3264 b = buf;
3265
3266 b2p = b;
3267 if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
3268 res = sscanf(b + 2, "%x%c", &unum, &c);
3269 num = unum;
3270 is_hex = true;
3271 b2p = b + 2;
3272 } else if ('H' == toupper((int)b[len - 1])) {
3273 res = sscanf(b, "%x", &unum);
3274 num = unum;
3275 } else
3276 res = sscanf(b, "%d%c%c%c", &num, &c, &c2, &c3);
3277
3278 if (res < 1)
3279 return -1;
3280 else if (1 == res)
3281 return num;
3282 else {
3283 c = toupper((int)c);
3284 if (is_hex) {
3285 if (! ((c == '+') || (c == 'X')))
3286 return -1;
3287 }
3288 if (res > 2)
3289 c2 = toupper((int)c2);
3290 if (res > 3)
3291 c3 = toupper((int)c3);
3292
3293 switch (c) {
3294 case 'C':
3295 return num;
3296 case 'W':
3297 return num * 2;
3298 case 'B':
3299 return num * 512;
3300 case 'K':
3301 if (2 == res)
3302 return num * 1024;
3303 if (('B' == c2) || ('D' == c2))
3304 return num * 1000;
3305 if (('I' == c2) && (4 == res) && ('B' == c3))
3306 return num * 1024;
3307 return -1;
3308 case 'M':
3309 if (2 == res)
3310 return num * 1048576;
3311 if (('B' == c2) || ('D' == c2))
3312 return num * 1000000;
3313 if (('I' == c2) && (4 == res) && ('B' == c3))
3314 return num * 1048576;
3315 return -1;
3316 case 'G':
3317 if (2 == res)
3318 return num * 1073741824;
3319 if (('B' == c2) || ('D' == c2))
3320 return num * 1000000000;
3321 if (('I' == c2) && (4 == res) && ('B' == c3))
3322 return num * 1073741824;
3323 return -1;
3324 case 'X': /* experimental: multiplication */
3325 /* left argument must end with hexadecimal digit */
3326 cp = (char *)strchr(b2p, 'x');
3327 if (NULL == cp)
3328 cp = (char *)strchr(b2p, 'X');
3329 if (cp) {
3330 n = sg_get_num(cp + 1);
3331 if (-1 != n)
3332 return num * n;
3333 }
3334 return -1;
3335 case '+': /* experimental: addition */
3336 /* left argument must end with hexadecimal digit */
3337 cp = (char *)strchr(b2p, '+');
3338 if (cp) {
3339 n = sg_get_num(cp + 1);
3340 if (-1 != n)
3341 return num + n;
3342 }
3343 return -1;
3344 default:
3345 pr2ws("unrecognized multiplier\n");
3346 return -1;
3347 }
3348 }
3349 }
3350
3351 /* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
3352 * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is
3353 * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"),
3354 * a whitespace or newline as terminator. */
3355 int
sg_get_num_nomult(const char * buf)3356 sg_get_num_nomult(const char * buf)
3357 {
3358 int res, len, num;
3359 unsigned int unum;
3360 char * commap;
3361
3362 if ((NULL == buf) || ('\0' == buf[0]))
3363 return -1;
3364 len = strlen(buf);
3365 commap = (char *)strchr(buf + 1, ',');
3366 if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
3367 res = sscanf(buf + 2, "%x", &unum);
3368 num = unum;
3369 } else if (commap && ('H' == toupper((int)*(commap - 1)))) {
3370 res = sscanf(buf, "%x", &unum);
3371 num = unum;
3372 } else if ((NULL == commap) && ('H' == toupper((int)buf[len - 1]))) {
3373 res = sscanf(buf, "%x", &unum);
3374 num = unum;
3375 } else
3376 res = sscanf(buf, "%d", &num);
3377 if (1 == res)
3378 return num;
3379 else
3380 return -1;
3381 }
3382
3383 /* If the number in 'buf' can not be decoded or the multiplier is unknown
3384 * then -1LL is returned. Accepts a hex prefix (0x or 0X), hex suffix
3385 * (h or H), or a decimal multiplier suffix (as per GNU's dd (since 2002:
3386 * SI and IEC 60027-2)). Main (SI) multipliers supported: K, M, G, T, P
3387 * and E. Ignore leading spaces and tabs; accept comma, hyphen, space, tab
3388 * and hash as terminator. Handles zero and positive values up to 2**63-1 .
3389 * Experimental: left argument (must in with hexadecimal digit) added
3390 * to, or multiplied by right argument. No embedded spaces.
3391 * Examples: '3+1k' (evaluates to 1027) and '0x34+1m'. */
3392 int64_t
sg_get_llnum(const char * buf)3393 sg_get_llnum(const char * buf)
3394 {
3395 bool is_hex = false;
3396 int res, len, n;
3397 int64_t num, ll;
3398 uint64_t unum;
3399 char * cp;
3400 const char * b;
3401 const char * b2p;
3402 char c = 'c';
3403 char c2 = '\0'; /* keep static checker happy */
3404 char c3 = '\0'; /* keep static checker happy */
3405 char lb[32];
3406
3407 if ((NULL == buf) || ('\0' == buf[0]))
3408 return -1LL;
3409 len = strlen(buf);
3410 n = strspn(buf, " \t");
3411 if (n > 0) {
3412 if (n == len)
3413 return -1LL;
3414 buf += n;
3415 len -= n;
3416 }
3417 /* following cast hack to keep C++ happy */
3418 cp = strpbrk((char *)buf, " \t,#-");
3419 if (cp) {
3420 len = cp - buf;
3421 n = (int)sizeof(lb) - 1;
3422 len = (len < n) ? len : n;
3423 memcpy(lb, buf, len);
3424 lb[len] = '\0';
3425 b = lb;
3426 } else
3427 b = buf;
3428
3429 b2p = b;
3430 if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) {
3431 res = sscanf(b + 2, "%" SCNx64 "%c", &unum, &c);
3432 num = unum;
3433 is_hex = true;
3434 b2p = b + 2;
3435 } else if ('H' == toupper((int)b[len - 1])) {
3436 res = sscanf(b, "%" SCNx64 , &unum);
3437 num = unum;
3438 } else
3439 res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3);
3440
3441 if (res < 1)
3442 return -1LL;
3443 else if (1 == res)
3444 return num;
3445 else {
3446 c = toupper((int)c);
3447 if (is_hex) {
3448 if (! ((c == '+') || (c == 'X')))
3449 return -1;
3450 }
3451 if (res > 2)
3452 c2 = toupper((int)c2);
3453 if (res > 3)
3454 c3 = toupper((int)c3);
3455
3456 switch (c) {
3457 case 'C':
3458 return num;
3459 case 'W':
3460 return num * 2;
3461 case 'B':
3462 return num * 512;
3463 case 'K': /* kilo or kibi */
3464 if (2 == res)
3465 return num * 1024;
3466 if (('B' == c2) || ('D' == c2))
3467 return num * 1000;
3468 if (('I' == c2) && (4 == res) && ('B' == c3))
3469 return num * 1024; /* KiB */
3470 return -1LL;
3471 case 'M': /* mega or mebi */
3472 if (2 == res)
3473 return num * 1048576; /* M */
3474 if (('B' == c2) || ('D' == c2))
3475 return num * 1000000; /* MB */
3476 if (('I' == c2) && (4 == res) && ('B' == c3))
3477 return num * 1048576; /* MiB */
3478 return -1LL;
3479 case 'G': /* giga or gibi */
3480 if (2 == res)
3481 return num * 1073741824; /* G */
3482 if (('B' == c2) || ('D' == c2))
3483 return num * 1000000000; /* GB */
3484 if (('I' == c2) && (4 == res) && ('B' == c3))
3485 return num * 1073741824; /* GiB */
3486 return -1LL;
3487 case 'T': /* tera or tebi */
3488 if (2 == res)
3489 return num * 1099511627776LL; /* T */
3490 if (('B' == c2) || ('D' == c2))
3491 return num * 1000000000000LL; /* TB */
3492 if (('I' == c2) && (4 == res) && ('B' == c3))
3493 return num * 1099511627776LL; /* TiB */
3494 return -1LL;
3495 case 'P': /* peta or pebi */
3496 if (2 == res)
3497 return num * 1099511627776LL * 1024;
3498 if (('B' == c2) || ('D' == c2))
3499 return num * 1000000000000LL * 1000;
3500 if (('I' == c2) && (4 == res) && ('B' == c3))
3501 return num * 1099511627776LL * 1024;
3502 return -1LL;
3503 case 'E': /* exa or exbi */
3504 if (2 == res)
3505 return num * 1099511627776LL * 1024 * 1024;
3506 if (('B' == c2) || ('D' == c2))
3507 return num * 1000000000000LL * 1000 * 1000;
3508 if (('I' == c2) && (4 == res) && ('B' == c3))
3509 return num * 1099511627776LL * 1024 * 1024;
3510 return -1LL;
3511 case 'X': /* experimental: decimal (left arg) multiplication */
3512 cp = (char *)strchr(b2p, 'x');
3513 if (NULL == cp)
3514 cp = (char *)strchr(b2p, 'X');
3515 if (cp) {
3516 ll = sg_get_llnum(cp + 1);
3517 if (-1LL != ll)
3518 return num * ll;
3519 }
3520 return -1LL;
3521 case '+': /* experimental: decimal (left arg) addition */
3522 cp = (char *)strchr(b2p, '+');
3523 if (cp) {
3524 ll = sg_get_llnum(cp + 1);
3525 if (-1LL != ll)
3526 return num + ll;
3527 }
3528 return -1LL;
3529 default:
3530 pr2ws("unrecognized multiplier\n");
3531 return -1LL;
3532 }
3533 }
3534 }
3535
3536 /* If the number in 'buf' can not be decoded then -1 is returned. Accepts a
3537 * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is
3538 * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"),
3539 * a whitespace or newline as terminator. Only decimal numbers can represent
3540 * negative numbers and '-1' must be treated separately. */
3541 int64_t
sg_get_llnum_nomult(const char * buf)3542 sg_get_llnum_nomult(const char * buf)
3543 {
3544 int res, len;
3545 int64_t num;
3546 uint64_t unum;
3547
3548 if ((NULL == buf) || ('\0' == buf[0]))
3549 return -1;
3550 len = strlen(buf);
3551 if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
3552 res = sscanf(buf + 2, "%" SCNx64 "", &unum);
3553 num = unum;
3554 } else if ('H' == toupper(buf[len - 1])) {
3555 res = sscanf(buf, "%" SCNx64 "", &unum);
3556 num = unum;
3557 } else
3558 res = sscanf(buf, "%" SCNd64 "", &num);
3559 return (1 == res) ? num : -1;
3560 }
3561
3562 #define MAX_NUM_ASCII_LINES 1048576
3563
3564 /* Read ASCII hex bytes or binary from fname (a file named '-' taken as
3565 * stdin). If reading ASCII hex then there should be either one entry per
3566 * line or a comma, space, hyphen or tab separated list of bytes. If no_space
3567 * is set then a string of ACSII hex digits is expected, 2 perbyte.
3568 * Everything from and including a '#' on a line is ignored. Returns 0 if ok,
3569 * or an error code. If the error code is SG_LIB_LBA_OUT_OF_RANGE then mp_arr
3570 * would be exceeded and both mp_arr and mp_arr_len are written to.
3571 * The max_arr_len_and argument may carry extra information: when it
3572 * is negative its absolute value is used for the maximum number of bytes to
3573 * write to mp_arr _and_ the first hexadecimal value on each line is skipped.
3574 * Many hexadecimal output programs place a running address (index) as the
3575 * first field on each line. When as_binary and/or no_space are true, the
3576 * absolute value of max_arr_len_and is used. */
3577 int
sg_f2hex_arr(const char * fname,bool as_binary,bool no_space,uint8_t * mp_arr,int * mp_arr_len,int max_arr_len_and)3578 sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
3579 uint8_t * mp_arr, int * mp_arr_len, int max_arr_len_and)
3580 {
3581 bool has_stdin, split_line, skip_first, redo_first;
3582 int fn_len, in_len, k, j, m, fd, err, max_arr_len;
3583 int off = 0;
3584 int ret = 0;
3585 unsigned int h;
3586 const char * lcp;
3587 FILE * fp = NULL;
3588 struct stat a_stat;
3589 char line[512];
3590 char carry_over[4];
3591
3592 if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len)) {
3593 pr2ws("%s: bad arguments\n", __func__);
3594 return SG_LIB_LOGIC_ERROR;
3595 }
3596 if (max_arr_len_and < 0) {
3597 skip_first = true;
3598 max_arr_len = -max_arr_len_and;
3599 } else {
3600 skip_first = false;
3601 max_arr_len = max_arr_len_and;
3602 }
3603 fn_len = strlen(fname);
3604 if (0 == fn_len)
3605 return SG_LIB_SYNTAX_ERROR;
3606 has_stdin = ((1 == fn_len) && ('-' == fname[0])); /* read from stdin */
3607 if (as_binary) {
3608 if (has_stdin)
3609 fd = STDIN_FILENO;
3610 else {
3611 fd = open(fname, O_RDONLY);
3612 if (fd < 0) {
3613 err = errno;
3614 pr2ws("unable to open binary file %s: %s\n", fname,
3615 safe_strerror(err));
3616 return sg_convert_errno(err);
3617 }
3618 }
3619 k = read(fd, mp_arr, max_arr_len);
3620 if (k <= 0) {
3621 if (0 == k) {
3622 ret = SG_LIB_FILE_ERROR;
3623 pr2ws("read 0 bytes from binary file %s\n", fname);
3624 } else {
3625 ret = sg_convert_errno(errno);
3626 pr2ws("read from binary file %s: %s\n", fname,
3627 safe_strerror(errno));
3628 }
3629 } else if ((k < max_arr_len) && (0 == fstat(fd, &a_stat)) &&
3630 S_ISFIFO(a_stat.st_mode)) {
3631 /* pipe; keep reading till error or 0 read */
3632 while (k < max_arr_len) {
3633 m = read(fd, mp_arr + k, max_arr_len - k);
3634 if (0 == m)
3635 break;
3636 if (m < 0) {
3637 err = errno;
3638 pr2ws("read from binary pipe %s: %s\n", fname,
3639 safe_strerror(err));
3640 ret = sg_convert_errno(err);
3641 break;
3642 }
3643 k += m;
3644 }
3645 }
3646 if (k >= 0)
3647 *mp_arr_len = k;
3648 if ((fd >= 0) && (! has_stdin))
3649 close(fd);
3650 return ret;
3651 }
3652
3653 /* So read the file as ASCII hex */
3654 if (has_stdin)
3655 fp = stdin;
3656 else {
3657 fp = fopen(fname, "r");
3658 if (NULL == fp) {
3659 err = errno;
3660 pr2ws("Unable to open %s for reading: %s\n", fname,
3661 safe_strerror(err));
3662 ret = sg_convert_errno(err);
3663 goto fini;
3664 }
3665 }
3666
3667 carry_over[0] = 0;
3668 for (j = 0; j < MAX_NUM_ASCII_LINES; ++j) {
3669 if (NULL == fgets(line, sizeof(line), fp))
3670 break;
3671 in_len = strlen(line);
3672 if (in_len > 0) {
3673 if ('\n' == line[in_len - 1]) {
3674 --in_len;
3675 line[in_len] = '\0';
3676 split_line = false;
3677 } else
3678 split_line = true;
3679 }
3680 if (in_len < 1) {
3681 carry_over[0] = 0;
3682 continue;
3683 }
3684 if (carry_over[0]) {
3685 if (isxdigit(line[0])) {
3686 carry_over[1] = line[0];
3687 carry_over[2] = '\0';
3688 if (1 == sscanf(carry_over, "%4x", &h)) {
3689 if (off > 0) {
3690 if (off > max_arr_len) {
3691 pr2ws("%s: array length exceeded\n", __func__);
3692 ret = SG_LIB_LBA_OUT_OF_RANGE;
3693 *mp_arr_len = max_arr_len;
3694 goto fini;
3695 } else
3696 mp_arr[off - 1] = h; /* back up and overwrite */
3697 }
3698 } else {
3699 pr2ws("%s: carry_over error ['%s'] around line %d\n",
3700 __func__, carry_over, j + 1);
3701 ret = SG_LIB_SYNTAX_ERROR;
3702 goto fini;
3703 }
3704 lcp = line + 1;
3705 --in_len;
3706 } else
3707 lcp = line;
3708 carry_over[0] = 0;
3709 } else
3710 lcp = line;
3711
3712 m = strspn(lcp, " \t");
3713 if (m == in_len)
3714 continue;
3715 lcp += m;
3716 in_len -= m;
3717 if ('#' == *lcp)
3718 continue;
3719 k = strspn(lcp, "0123456789aAbBcCdDeEfF ,-\t");
3720 if ((k < in_len) && ('#' != lcp[k]) && ('\r' != lcp[k])) {
3721 pr2ws("%s: syntax error at line %d, pos %d\n", __func__,
3722 j + 1, m + k + 1);
3723 ret = SG_LIB_SYNTAX_ERROR;
3724 goto fini;
3725 }
3726 if (no_space) {
3727 for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1));
3728 ++k, lcp += 2) {
3729 if (1 != sscanf(lcp, "%2x", &h)) {
3730 pr2ws("%s: bad hex number in line %d, pos %d\n",
3731 __func__, j + 1, (int)(lcp - line + 1));
3732 ret = SG_LIB_SYNTAX_ERROR;
3733 goto fini;
3734 }
3735 if ((off + k) >= max_arr_len) {
3736 pr2ws("%s: array length exceeded\n", __func__);
3737 *mp_arr_len = max_arr_len;
3738 ret = SG_LIB_LBA_OUT_OF_RANGE;
3739 goto fini;
3740 } else
3741 mp_arr[off + k] = h;
3742 }
3743 if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1))))
3744 carry_over[0] = *lcp;
3745 off += k;
3746 } else { /* (white)space separated ASCII hexadecimal bytes */
3747 for (redo_first = false, k = 0; k < 1024;
3748 k = (redo_first ? k : k + 1)) {
3749 if (1 == sscanf(lcp, "%10x", &h)) {
3750 if (h > 0xff) {
3751 pr2ws("%s: hex number larger than 0xff in line "
3752 "%d, pos %d\n", __func__, j + 1,
3753 (int)(lcp - line + 1));
3754 ret = SG_LIB_SYNTAX_ERROR;
3755 goto fini;
3756 }
3757 if (split_line && (1 == strlen(lcp))) {
3758 /* single trailing hex digit might be a split pair */
3759 carry_over[0] = *lcp;
3760 }
3761 if ((off + k) >= max_arr_len) {
3762 pr2ws("%s: array length exceeded\n", __func__);
3763 ret = SG_LIB_LBA_OUT_OF_RANGE;
3764 *mp_arr_len = max_arr_len;
3765 goto fini;
3766 } else if ((0 == k) && skip_first && (! redo_first))
3767 redo_first = true;
3768 else {
3769 redo_first = false;
3770 mp_arr[off + k] = h;
3771 }
3772 lcp = strpbrk(lcp, " ,-\t");
3773 if (NULL == lcp)
3774 break;
3775 lcp += strspn(lcp, " ,-\t");
3776 if ('\0' == *lcp)
3777 break;
3778 } else {
3779 if (('#' == *lcp) || ('\r' == *lcp)) {
3780 --k;
3781 break;
3782 }
3783 pr2ws("%s: error in line %d, at pos %d\n", __func__,
3784 j + 1, (int)(lcp - line + 1));
3785 ret = SG_LIB_SYNTAX_ERROR;
3786 goto fini;
3787 }
3788 }
3789 off += (k + 1);
3790 }
3791 } /* end of per line loop */
3792 if (j >= MAX_NUM_ASCII_LINES) {
3793 pr2ws("%s: wow, more than %d lines of ASCII, give up\n", __func__,
3794 SG_LIB_LBA_OUT_OF_RANGE);
3795 return SG_LIB_LBA_OUT_OF_RANGE;
3796 }
3797 *mp_arr_len = off;
3798 if (fp && (! has_stdin))
3799 fclose(fp);
3800 return 0;
3801 fini:
3802 if (fp && (! has_stdin))
3803 fclose(fp);
3804 return ret;
3805 }
3806
3807 /* Extract character sequence from ATA words as in the model string
3808 * in a IDENTIFY DEVICE response. Returns number of characters
3809 * written to 'ochars' before 0 character is found or 'num' words
3810 * are processed. */
3811 int
sg_ata_get_chars(const uint16_t * word_arr,int start_word,int num_words,bool is_big_endian,char * ochars)3812 sg_ata_get_chars(const uint16_t * word_arr, int start_word,
3813 int num_words, bool is_big_endian, char * ochars)
3814 {
3815 int k;
3816 char * op = ochars;
3817
3818 for (k = start_word; k < (start_word + num_words); ++k) {
3819 char a, b;
3820 uint16_t s = word_arr[k];
3821
3822 if (is_big_endian) {
3823 a = s & 0xff;
3824 b = (s >> 8) & 0xff;
3825 } else {
3826 a = (s >> 8) & 0xff;
3827 b = s & 0xff;
3828 }
3829 if (a == 0)
3830 break;
3831 *op++ = a;
3832 if (b == 0)
3833 break;
3834 *op++ = b;
3835 }
3836 return op - ochars;
3837 }
3838
3839 #ifdef SG_LIB_FREEBSD
3840 #include <sys/param.h>
3841 #elif defined(SG_LIB_WIN32)
3842 #include <windows.h>
3843 #endif
3844
3845 uint32_t
sg_get_page_size(void)3846 sg_get_page_size(void)
3847 {
3848 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
3849 {
3850 long res = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */
3851
3852 return (res <= 0) ? 4096 : res;
3853 }
3854 #elif defined(SG_LIB_WIN32)
3855 static bool got_page_size = false;
3856 static uint32_t win_page_size;
3857
3858 if (! got_page_size) {
3859 SYSTEM_INFO si;
3860
3861 GetSystemInfo(&si);
3862 win_page_size = si.dwPageSize;
3863 got_page_size = true;
3864 }
3865 return win_page_size;
3866 #elif defined(SG_LIB_FREEBSD)
3867 return PAGE_SIZE;
3868 #else
3869 return 4096; /* give up, pick likely figure */
3870 #endif
3871 }
3872
3873 #if defined(SG_LIB_WIN32)
3874 #if defined(MSC_VER) || defined(__MINGW32__)
3875 /* windows.h already included above */
3876 #define sg_sleep_for(seconds) Sleep( (seconds) * 1000)
3877 #else
3878 #define sg_sleep_for(seconds) sleep(seconds)
3879 #endif
3880 #else
3881 #define sg_sleep_for(seconds) sleep(seconds)
3882 #endif
3883
3884 void
sg_sleep_secs(int num_secs)3885 sg_sleep_secs(int num_secs)
3886 {
3887 sg_sleep_for(num_secs);
3888 }
3889
3890 void
sg_warn_and_wait(const char * cmd_name,const char * dev_name,bool stress_all)3891 sg_warn_and_wait(const char * cmd_name, const char * dev_name,
3892 bool stress_all)
3893 {
3894 int k, j;
3895 const char * stressp = stress_all ? "ALL d" : "D";
3896 const char * will_mayp = stress_all ? "will" : "may";
3897
3898 for (k = 0, j = 15; k < 3; ++k, j -= 5) {
3899 printf("\nA %s command will commence in %d seconds\n", cmd_name, j);
3900 printf(" %sata on %s %s be DESTROYED%s\n", stressp, dev_name,
3901 will_mayp, (stress_all ? "" : " or modified"));
3902 printf(" Press control-C to abort\n");
3903 sg_sleep_secs(5);
3904 }
3905 sg_sleep_secs(1);
3906 }
3907
3908 /* Returns pointer to heap (or NULL) that is aligned to a align_to byte
3909 * boundary. Sends back *buff_to_free pointer in third argument that may be
3910 * different from the return value. If it is different then the *buff_to_free
3911 * pointer should be freed (rather than the returned value) when the heap is
3912 * no longer needed. If align_to is 0 then aligns to OS's page size. Sets all
3913 * returned heap to zeros. If num_bytes is 0 then set to page size. */
3914 uint8_t *
sg_memalign(uint32_t num_bytes,uint32_t align_to,uint8_t ** buff_to_free,bool vb)3915 sg_memalign(uint32_t num_bytes, uint32_t align_to, uint8_t ** buff_to_free,
3916 bool vb)
3917 {
3918 size_t psz;
3919
3920 if (buff_to_free) /* make sure buff_to_free is NULL if alloc fails */
3921 *buff_to_free = NULL;
3922 psz = (align_to > 0) ? align_to : sg_get_page_size();
3923 if (0 == num_bytes)
3924 num_bytes = psz; /* ugly to handle otherwise */
3925
3926 #ifdef HAVE_POSIX_MEMALIGN
3927 {
3928 int err;
3929 uint8_t * res;
3930 void * wp = NULL;
3931
3932 err = posix_memalign(&wp, psz, num_bytes);
3933 if (err || (NULL == wp)) {
3934 pr2ws("%s: posix_memalign: error [%d], out of memory?\n",
3935 __func__, err);
3936 return NULL;
3937 }
3938 memset(wp, 0, num_bytes);
3939 if (buff_to_free)
3940 *buff_to_free = (uint8_t *)wp;
3941 res = (uint8_t *)wp;
3942 if (vb) {
3943 pr2ws("%s: posix_ma, len=%d, ", __func__, num_bytes);
3944 if (buff_to_free)
3945 pr2ws("wrkBuffp=%p, ", (void *)res);
3946 pr2ws("psz=%u, rp=%p\n", (unsigned int)psz, (void *)res);
3947 }
3948 return res;
3949 }
3950 #else
3951 {
3952 void * wrkBuff;
3953 uint8_t * res;
3954 sg_uintptr_t align_1 = psz - 1;
3955
3956 wrkBuff = (uint8_t *)calloc(num_bytes + psz, 1);
3957 if (NULL == wrkBuff) {
3958 if (buff_to_free)
3959 *buff_to_free = NULL;
3960 return NULL;
3961 } else if (buff_to_free)
3962 *buff_to_free = (uint8_t *)wrkBuff;
3963 res = (uint8_t *)(void *)
3964 (((sg_uintptr_t)wrkBuff + align_1) & (~align_1));
3965 if (vb) {
3966 pr2ws("%s: hack, len=%d, ", __func__, num_bytes);
3967 if (buff_to_free)
3968 pr2ws("buff_to_free=%p, ", wrkBuff);
3969 pr2ws("align_1=%" PRIuPTR "u, rp=%p\n", align_1, (void *)res);
3970 }
3971 return res;
3972 }
3973 #endif
3974 }
3975
3976 /* If byte_count is 0 or less then the OS page size is used as denominator.
3977 * Returns true if the remainder of ((unsigned)pointer % byte_count) is 0,
3978 * else returns false. */
3979 bool
sg_is_aligned(const void * pointer,int byte_count)3980 sg_is_aligned(const void * pointer, int byte_count)
3981 {
3982 return 0 == ((sg_uintptr_t)pointer %
3983 ((byte_count > 0) ? (uint32_t)byte_count :
3984 sg_get_page_size()));
3985 }
3986
3987 /* Does similar job to sg_get_unaligned_be*() but this function starts at
3988 * a given start_bit (i.e. within byte, so 7 is MSbit of byte and 0 is LSbit)
3989 * offset. Maximum number of num_bits is 64. For example, these two
3990 * invocations are equivalent (and should yield the same result);
3991 * sg_get_big_endian(from_bp, 7, 16)
3992 * sg_get_unaligned_be16(from_bp) */
3993 uint64_t
sg_get_big_endian(const uint8_t * from_bp,int start_bit,int num_bits)3994 sg_get_big_endian(const uint8_t * from_bp, int start_bit /* 0 to 7 */,
3995 int num_bits /* 1 to 64 */)
3996 {
3997 uint64_t res;
3998 int sbit_o1 = start_bit + 1;
3999
4000 res = (*from_bp++ & ((1 << sbit_o1) - 1));
4001 num_bits -= sbit_o1;
4002 while (num_bits > 0) {
4003 res <<= 8;
4004 res |= *from_bp++;
4005 num_bits -= 8;
4006 }
4007 if (num_bits < 0)
4008 res >>= (-num_bits);
4009 return res;
4010 }
4011
4012 /* Does similar job to sg_put_unaligned_be*() but this function starts at
4013 * a given start_bit offset. Maximum number of num_bits is 64. Preserves
4014 * residual bits in partially written bytes. start_bit 7 is MSb. */
4015 void
sg_set_big_endian(uint64_t val,uint8_t * to,int start_bit,int num_bits)4016 sg_set_big_endian(uint64_t val, uint8_t * to,
4017 int start_bit /* 0 to 7 */, int num_bits /* 1 to 64 */)
4018 {
4019 int sbit_o1 = start_bit + 1;
4020 int mask, num, k, x;
4021
4022 if ((NULL == to) || (start_bit > 7) || (num_bits > 64)) {
4023 pr2ws("%s: bad args: start_bit=%d, num_bits=%d\n", __func__,
4024 start_bit, num_bits);
4025 return;
4026 }
4027 mask = (8 != sbit_o1) ? ((1 << sbit_o1) - 1) : 0xff;
4028 k = start_bit - ((num_bits - 1) % 8);
4029 if (0 != k)
4030 val <<= ((k > 0) ? k : (8 + k));
4031 num = (num_bits + 15 - sbit_o1) / 8;
4032 for (k = 0; k < num; ++k) {
4033 if ((sbit_o1 - num_bits) > 0)
4034 mask &= ~((1 << (sbit_o1 - num_bits)) - 1);
4035 if (k < (num - 1))
4036 x = (val >> ((num - k - 1) * 8)) & 0xff;
4037 else
4038 x = val & 0xff;
4039 to[k] = (to[k] & ~mask) | (x & mask);
4040 mask = 0xff;
4041 num_bits -= sbit_o1;
4042 sbit_o1 = 8;
4043 }
4044 }
4045
4046 const char *
sg_lib_version()4047 sg_lib_version()
4048 {
4049 return sg_lib_version_str;
4050 }
4051
4052
4053 #ifdef SG_LIB_MINGW
4054 /* Non Unix OSes distinguish between text and binary files.
4055 Set text mode on fd. Does nothing in Unix. Returns negative number on
4056 failure. */
4057
4058 #include <fcntl.h>
4059
4060 int
sg_set_text_mode(int fd)4061 sg_set_text_mode(int fd)
4062 {
4063 return setmode(fd, O_TEXT);
4064 }
4065
4066 /* Set binary mode on fd. Does nothing in Unix. Returns negative number on
4067 failure. */
4068 int
sg_set_binary_mode(int fd)4069 sg_set_binary_mode(int fd)
4070 {
4071 return setmode(fd, O_BINARY);
4072 }
4073
4074 #else
4075 /* For Unix the following functions are dummies. */
4076 int
sg_set_text_mode(int fd)4077 sg_set_text_mode(int fd)
4078 {
4079 return fd; /* fd should be >= 0 */
4080 }
4081
4082 int
sg_set_binary_mode(int fd)4083 sg_set_binary_mode(int fd)
4084 {
4085 return fd;
4086 }
4087
4088 #endif
4089