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