Home | History | Annotate | Download | only in sg_write_buffer
      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
     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
     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). */
    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 *
    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
    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
    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
    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
    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
    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 *
    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 *
    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 *
    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
    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
    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
    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
    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 *
    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
    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 *
    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 *
    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 *
    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 *
    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 *
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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 *
   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 *
   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
   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 *
   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
   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 *
   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
   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
   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
   2770 dStrHex(const char* str, int len, int no_ascii)
   2771 {
   2772     dStrHexFp(str, len, no_ascii, stdout);
   2773 }
   2774 
   2775 void
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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 *
   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 *
   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
   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
   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
   3483 sg_set_text_mode(int fd)
   3484 {
   3485     return fd;  /* fd should be >= 0 */
   3486 }
   3487 
   3488 int
   3489 sg_set_binary_mode(int fd)
   3490 {
   3491     return fd;
   3492 }
   3493 
   3494 #endif
   3495