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 /*
      9  * CONTENTS
     10  *    Some SCSI commands are executed in many contexts and hence began
     11  *    to appear in several sg3_utils utilities. This files centralizes
     12  *    some of the low level command execution code. In most cases the
     13  *    interpretation of the command response is left to the each
     14  *    utility.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <stdarg.h>
     20 #include <string.h>
     21 #include <unistd.h>
     22 
     23 #ifdef HAVE_CONFIG_H
     24 #include "config.h"
     25 #endif
     26 
     27 #include "sg_lib.h"
     28 #include "sg_cmds_basic.h"
     29 #include "sg_pt.h"
     30 #include "sg_unaligned.h"
     31 
     32 
     33 
     34 #define SENSE_BUFF_LEN 64       /* Arbitrary, could be larger */
     35 #define EBUFF_SZ 256
     36 
     37 #define DEF_PT_TIMEOUT 60       /* 60 seconds */
     38 #define START_PT_TIMEOUT 120    /* 120 seconds == 2 minutes */
     39 #define LONG_PT_TIMEOUT 7200    /* 7,200 seconds == 120 minutes */
     40 
     41 #define SYNCHRONIZE_CACHE_CMD     0x35
     42 #define SYNCHRONIZE_CACHE_CMDLEN  10
     43 #define SERVICE_ACTION_IN_16_CMD 0x9e
     44 #define SERVICE_ACTION_IN_16_CMDLEN 16
     45 #define READ_CAPACITY_16_SA 0x10
     46 #define READ_CAPACITY_10_CMD 0x25
     47 #define READ_CAPACITY_10_CMDLEN 10
     48 #define MODE_SENSE6_CMD      0x1a
     49 #define MODE_SENSE6_CMDLEN   6
     50 #define MODE_SENSE10_CMD     0x5a
     51 #define MODE_SENSE10_CMDLEN  10
     52 #define MODE_SELECT6_CMD   0x15
     53 #define MODE_SELECT6_CMDLEN   6
     54 #define MODE_SELECT10_CMD   0x55
     55 #define MODE_SELECT10_CMDLEN  10
     56 #define LOG_SENSE_CMD     0x4d
     57 #define LOG_SENSE_CMDLEN  10
     58 #define LOG_SELECT_CMD     0x4c
     59 #define LOG_SELECT_CMDLEN  10
     60 #define START_STOP_CMD          0x1b
     61 #define START_STOP_CMDLEN       6
     62 #define PREVENT_ALLOW_CMD    0x1e
     63 #define PREVENT_ALLOW_CMDLEN   6
     64 
     65 #define MODE6_RESP_HDR_LEN 4
     66 #define MODE10_RESP_HDR_LEN 8
     67 #define MODE_RESP_ARB_LEN 1024
     68 
     69 #define INQUIRY_RESP_INITIAL_LEN 36
     70 
     71 
     72 #if defined(__GNUC__) || defined(__clang__)
     73 static int pr2ws(const char * fmt, ...)
     74         __attribute__ ((format (printf, 1, 2)));
     75 #else
     76 static int pr2ws(const char * fmt, ...);
     77 #endif
     78 
     79 
     80 static int
     81 pr2ws(const char * fmt, ...)
     82 {
     83     va_list args;
     84     int n;
     85 
     86     va_start(args, fmt);
     87     n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
     88     va_end(args);
     89     return n;
     90 }
     91 
     92 static struct sg_pt_base *
     93 create_pt_obj(const char * cname)
     94 {
     95     struct sg_pt_base * ptvp = construct_scsi_pt_obj();
     96     if (NULL == ptvp)
     97         pr2ws("%s: out of memory\n", cname);
     98     return ptvp;
     99 }
    100 
    101 /* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success,
    102  * various SG_LIB_CAT_* positive values or -1 -> other errors */
    103 int
    104 sg_ll_sync_cache_10(int sg_fd, bool sync_nv, bool immed, int group,
    105                     unsigned int lba, unsigned int count, bool noisy,
    106                     int verbose)
    107 {
    108     static const char * const cdb_name_s = "synchronize cache(10)";
    109     int res, ret, k, sense_cat;
    110     unsigned char sc_cdb[SYNCHRONIZE_CACHE_CMDLEN] =
    111                 {SYNCHRONIZE_CACHE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    112     unsigned char sense_b[SENSE_BUFF_LEN];
    113     struct sg_pt_base * ptvp;
    114 
    115     if (sync_nv)
    116         sc_cdb[1] |= 4;
    117     if (immed)
    118         sc_cdb[1] |= 2;
    119     sg_put_unaligned_be32((uint32_t)lba, sc_cdb + 2);
    120     sc_cdb[6] = group & 0x1f;
    121     if (count > 0xffff) {
    122         pr2ws("count too big\n");
    123         return -1;
    124     }
    125     sg_put_unaligned_be16((int16_t)count, sc_cdb + 7);
    126 
    127     if (verbose) {
    128         pr2ws("    %s cdb: ", cdb_name_s);
    129         for (k = 0; k < SYNCHRONIZE_CACHE_CMDLEN; ++k)
    130             pr2ws("%02x ", sc_cdb[k]);
    131         pr2ws("\n");
    132     }
    133     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    134         return -1;
    135     set_scsi_pt_cdb(ptvp, sc_cdb, sizeof(sc_cdb));
    136     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    137     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    138     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
    139                                noisy, verbose, &sense_cat);
    140     if (-1 == ret) {
    141         int os_err = get_scsi_pt_os_err(ptvp);
    142 
    143         if ((os_err > 0) && (os_err < 47))
    144             ret = SG_LIB_OS_BASE_ERR + os_err;
    145     } else if (-2 == ret) {
    146         switch (sense_cat) {
    147         case SG_LIB_CAT_RECOVERED:
    148         case SG_LIB_CAT_NO_SENSE:
    149             ret = 0;
    150             break;
    151         default:
    152             ret = sense_cat;
    153             break;
    154         }
    155     } else
    156         ret = 0;
    157 
    158     destruct_scsi_pt_obj(ptvp);
    159     return ret;
    160 }
    161 
    162 /* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success,
    163  * various SG_LIB_CAT_* positive values or -1 -> other errors */
    164 int
    165 sg_ll_readcap_16(int sg_fd, bool pmi, uint64_t llba, void * resp,
    166                  int mx_resp_len, bool noisy, int verbose)
    167 {
    168     static const char * const cdb_name_s = "read capacity(16)";
    169     int k, ret, res, sense_cat;
    170     unsigned char rc_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
    171                         {SERVICE_ACTION_IN_16_CMD, READ_CAPACITY_16_SA,
    172                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    173     unsigned char sense_b[SENSE_BUFF_LEN];
    174     struct sg_pt_base * ptvp;
    175 
    176     if (pmi) { /* lbs only valid when pmi set */
    177         rc_cdb[14] |= 1;
    178         sg_put_unaligned_be64(llba, rc_cdb + 2);
    179     }
    180     /* Allocation length, no guidance in SBC-2 rev 15b */
    181     sg_put_unaligned_be32((uint32_t)mx_resp_len, rc_cdb + 10);
    182     if (verbose) {
    183         pr2ws("    %s cdb: ", cdb_name_s);
    184         for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
    185             pr2ws("%02x ", rc_cdb[k]);
    186         pr2ws("\n");
    187     }
    188     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    189         return -1;
    190     set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
    191     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    192     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
    193     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    194     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
    195                                noisy, verbose, &sense_cat);
    196     if (-1 == ret) {
    197         int os_err = get_scsi_pt_os_err(ptvp);
    198 
    199         if ((os_err > 0) && (os_err < 47))
    200             ret = SG_LIB_OS_BASE_ERR + os_err;
    201     } else if (-2 == ret) {
    202         switch (sense_cat) {
    203         case SG_LIB_CAT_RECOVERED:
    204         case SG_LIB_CAT_NO_SENSE:
    205             ret = 0;
    206             break;
    207         default:
    208             ret = sense_cat;
    209             break;
    210         }
    211     } else
    212         ret = 0;
    213 
    214     destruct_scsi_pt_obj(ptvp);
    215     return ret;
    216 }
    217 
    218 /* Invokes a SCSI READ CAPACITY (10) command. Returns 0 -> success,
    219  * various SG_LIB_CAT_* positive values or -1 -> other errors */
    220 int
    221 sg_ll_readcap_10(int sg_fd, bool pmi, unsigned int lba, void * resp,
    222                  int mx_resp_len, bool noisy, int verbose)
    223 {
    224     static const char * const cdb_name_s = "read capacity(10)";
    225     int k, ret, res, sense_cat;
    226     unsigned char rc_cdb[READ_CAPACITY_10_CMDLEN] =
    227                          {READ_CAPACITY_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    228     unsigned char sense_b[SENSE_BUFF_LEN];
    229     struct sg_pt_base * ptvp;
    230 
    231     if (pmi) { /* lbs only valid when pmi set */
    232         rc_cdb[8] |= 1;
    233         sg_put_unaligned_be32((uint32_t)lba, rc_cdb + 2);
    234     }
    235     if (verbose) {
    236         pr2ws("    %s cdb: ", cdb_name_s);
    237         for (k = 0; k < READ_CAPACITY_10_CMDLEN; ++k)
    238             pr2ws("%02x ", rc_cdb[k]);
    239         pr2ws("\n");
    240     }
    241     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    242         return -1;
    243     set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
    244     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    245     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
    246     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    247     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
    248                                noisy, verbose, &sense_cat);
    249     if (-1 == ret) {
    250         int os_err = get_scsi_pt_os_err(ptvp);
    251 
    252         if ((os_err > 0) && (os_err < 47))
    253             ret = SG_LIB_OS_BASE_ERR + os_err;
    254     } else if (-2 == ret) {
    255         switch (sense_cat) {
    256         case SG_LIB_CAT_RECOVERED:
    257         case SG_LIB_CAT_NO_SENSE:
    258             ret = 0;
    259             break;
    260         default:
    261             ret = sense_cat;
    262             break;
    263         }
    264     } else
    265         ret = 0;
    266 
    267     destruct_scsi_pt_obj(ptvp);
    268     return ret;
    269 }
    270 
    271 /* Invokes a SCSI MODE SENSE (6) command. Return of 0 -> success,
    272  * various SG_LIB_CAT_* positive values or -1 -> other errors */
    273 int
    274 sg_ll_mode_sense6(int sg_fd, bool dbd, int pc, int pg_code, int sub_pg_code,
    275                   void * resp, int mx_resp_len, bool noisy, int verbose)
    276 {
    277     static const char * const cdb_name_s = "mode sense(6)";
    278     int res, ret, k, sense_cat, resid;
    279     unsigned char modes_cdb[MODE_SENSE6_CMDLEN] =
    280         {MODE_SENSE6_CMD, 0, 0, 0, 0, 0};
    281     unsigned char sense_b[SENSE_BUFF_LEN];
    282     struct sg_pt_base * ptvp;
    283 
    284     modes_cdb[1] = (unsigned char)(dbd ? 0x8 : 0);
    285     modes_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
    286     modes_cdb[3] = (unsigned char)(sub_pg_code & 0xff);
    287     modes_cdb[4] = (unsigned char)(mx_resp_len & 0xff);
    288     if (mx_resp_len > 0xff) {
    289         pr2ws("mx_resp_len too big\n");
    290         return -1;
    291     }
    292     if (verbose) {
    293         pr2ws("    %s cdb: ", cdb_name_s);
    294         for (k = 0; k < MODE_SENSE6_CMDLEN; ++k)
    295             pr2ws("%02x ", modes_cdb[k]);
    296         pr2ws("\n");
    297     }
    298     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    299         return -1;
    300     set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
    301     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    302     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
    303     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    304     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
    305                                noisy, verbose, &sense_cat);
    306     resid = get_scsi_pt_resid(ptvp);
    307     if (-1 == ret) {
    308         int os_err = get_scsi_pt_os_err(ptvp);
    309 
    310         if ((os_err > 0) && (os_err < 47))
    311             ret = SG_LIB_OS_BASE_ERR + os_err;
    312     } else if (-2 == ret) {
    313         switch (sense_cat) {
    314         case SG_LIB_CAT_RECOVERED:
    315         case SG_LIB_CAT_NO_SENSE:
    316             ret = 0;
    317             break;
    318         default:
    319             ret = sense_cat;
    320             break;
    321         }
    322     } else {
    323         if ((verbose > 2) && (ret > 0)) {
    324             pr2ws("    %s: response", cdb_name_s);
    325             if (3 == verbose) {
    326                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
    327                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
    328                            -1);
    329             } else {
    330                 pr2ws(":\n");
    331                 hex2stderr((const uint8_t *)resp, ret, 0);
    332             }
    333         }
    334         ret = 0;
    335     }
    336     destruct_scsi_pt_obj(ptvp);
    337 
    338     if (resid > 0) {
    339         if (resid > mx_resp_len) {
    340             pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
    341                   cdb_name_s, resid, mx_resp_len);
    342             return ret ? ret : SG_LIB_CAT_MALFORMED;
    343         }
    344         /* zero unfilled section of response buffer */
    345         memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
    346     }
    347     return ret;
    348 }
    349 
    350 /* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
    351  * various SG_LIB_CAT_* positive values or -1 -> other errors */
    352 int
    353 sg_ll_mode_sense10(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
    354                    int sub_pg_code, void * resp, int mx_resp_len,
    355                    bool noisy, int verbose)
    356 {
    357     return sg_ll_mode_sense10_v2(sg_fd, llbaa, dbd, pc, pg_code, sub_pg_code,
    358                                  resp, mx_resp_len, 0, NULL, noisy, verbose);
    359 }
    360 
    361 /* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
    362  * various SG_LIB_CAT_* positive values or -1 -> other errors.
    363  * Adds the ability to set the command abort timeout
    364  * and the ability to report the residual count. If timeout_secs is zero
    365  * or less the default command abort timeout (60 seconds) is used.
    366  * If residp is non-NULL then the residual value is written where residp
    367  * points. A residual value of 0 implies mx_resp_len bytes have be written
    368  * where resp points. If the residual value equals mx_resp_len then no
    369  * bytes have been written. */
    370 int
    371 sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
    372                       int sub_pg_code, void * resp, int mx_resp_len,
    373                       int timeout_secs, int * residp, bool noisy, int verbose)
    374 {
    375     int res, ret, k, sense_cat, resid;
    376     static const char * const cdb_name_s = "mode sense(10)";
    377     struct sg_pt_base * ptvp;
    378     unsigned char modes_cdb[MODE_SENSE10_CMDLEN] =
    379         {MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    380     unsigned char sense_b[SENSE_BUFF_LEN];
    381 
    382     modes_cdb[1] = (unsigned char)((dbd ? 0x8 : 0) | (llbaa ? 0x10 : 0));
    383     modes_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
    384     modes_cdb[3] = (unsigned char)(sub_pg_code & 0xff);
    385     sg_put_unaligned_be16((int16_t)mx_resp_len, modes_cdb + 7);
    386     if (mx_resp_len > 0xffff) {
    387         pr2ws("mx_resp_len too big\n");
    388         goto gen_err;
    389     }
    390     if (verbose) {
    391         pr2ws("    %s cdb: ", cdb_name_s);
    392         for (k = 0; k < MODE_SENSE10_CMDLEN; ++k)
    393             pr2ws("%02x ", modes_cdb[k]);
    394         pr2ws("\n");
    395     }
    396     if (timeout_secs <= 0)
    397         timeout_secs = DEF_PT_TIMEOUT;
    398 
    399     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    400         goto gen_err;
    401     set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
    402     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    403     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
    404     res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
    405     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
    406                                noisy, verbose, &sense_cat);
    407     resid = get_scsi_pt_resid(ptvp);
    408     if (residp)
    409         *residp = resid;
    410     if (-1 == ret) {
    411         int os_err = get_scsi_pt_os_err(ptvp);
    412 
    413         if ((os_err > 0) && (os_err < 47))
    414             ret = SG_LIB_OS_BASE_ERR + os_err;
    415     } else if (-2 == ret) {
    416         switch (sense_cat) {
    417         case SG_LIB_CAT_RECOVERED:
    418         case SG_LIB_CAT_NO_SENSE:
    419             ret = 0;
    420             break;
    421         default:
    422             ret = sense_cat;
    423             break;
    424         }
    425     } else {
    426         if ((verbose > 2) && (ret > 0)) {
    427             pr2ws("    %s: response", cdb_name_s);
    428             if (3 == verbose) {
    429                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
    430                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
    431                            -1);
    432             } else {
    433                 pr2ws(":\n");
    434                 hex2stderr((const uint8_t *)resp, ret, 0);
    435             }
    436         }
    437         ret = 0;
    438     }
    439     destruct_scsi_pt_obj(ptvp);
    440 
    441     if (resid > 0) {
    442         if (resid > mx_resp_len) {
    443             pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
    444                   cdb_name_s, resid, mx_resp_len);
    445             return ret ? ret : SG_LIB_CAT_MALFORMED;
    446         }
    447         /* zero unfilled section of response buffer */
    448         memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
    449     }
    450     return ret;
    451 gen_err:
    452     if (residp)
    453         *residp = 0;
    454     return -1;
    455 }
    456 
    457 /* Invokes a SCSI MODE SELECT (6) command.  Return of 0 -> success,
    458  * various SG_LIB_CAT_* positive values or -1 -> other errors */
    459 int
    460 sg_ll_mode_select6(int sg_fd, bool pf, bool sp, void * paramp, int param_len,
    461                    bool noisy, int verbose)
    462 {
    463     static const char * const cdb_name_s = "mode select(6)";
    464     int res, ret, k, sense_cat;
    465     unsigned char modes_cdb[MODE_SELECT6_CMDLEN] =
    466         {MODE_SELECT6_CMD, 0, 0, 0, 0, 0};
    467     unsigned char sense_b[SENSE_BUFF_LEN];
    468     struct sg_pt_base * ptvp;
    469 
    470     modes_cdb[1] = (unsigned char)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
    471     modes_cdb[4] = (unsigned char)(param_len & 0xff);
    472     if (param_len > 0xff) {
    473         pr2ws("%s: param_len too big\n", cdb_name_s);
    474         return -1;
    475     }
    476     if (verbose) {
    477         pr2ws("    %s cdb: ", cdb_name_s);
    478         for (k = 0; k < MODE_SELECT6_CMDLEN; ++k)
    479             pr2ws("%02x ", modes_cdb[k]);
    480         pr2ws("\n");
    481     }
    482     if (verbose > 1) {
    483         pr2ws("    %s parameter list\n", cdb_name_s);
    484         hex2stderr((const uint8_t *)paramp, param_len, -1);
    485     }
    486 
    487     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    488         return -1;
    489     set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
    490     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    491     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
    492     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    493     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
    494                                noisy, verbose, &sense_cat);
    495     if (-1 == ret) {
    496         int os_err = get_scsi_pt_os_err(ptvp);
    497 
    498         if ((os_err > 0) && (os_err < 47))
    499             ret = SG_LIB_OS_BASE_ERR + os_err;
    500     } else if (-2 == ret) {
    501         switch (sense_cat) {
    502         case SG_LIB_CAT_RECOVERED:
    503         case SG_LIB_CAT_NO_SENSE:
    504             ret = 0;
    505             break;
    506         default:
    507             ret = sense_cat;
    508             break;
    509         }
    510     } else
    511         ret = 0;
    512 
    513     destruct_scsi_pt_obj(ptvp);
    514     return ret;
    515 }
    516 
    517 /* Invokes a SCSI MODE SELECT (10) command.  Return of 0 -> success,
    518  * various SG_LIB_CAT_* positive values or -1 -> other errors */
    519 int
    520 sg_ll_mode_select10(int sg_fd, bool pf, bool sp, void * paramp, int param_len,
    521                     bool noisy, int verbose)
    522 {
    523     static const char * const cdb_name_s = "mode select(10)";
    524     int res, ret, k, sense_cat;
    525     unsigned char modes_cdb[MODE_SELECT10_CMDLEN] =
    526         {MODE_SELECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    527     unsigned char sense_b[SENSE_BUFF_LEN];
    528     struct sg_pt_base * ptvp;
    529 
    530     modes_cdb[1] = (unsigned char)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
    531     sg_put_unaligned_be16((int16_t)param_len, modes_cdb + 7);
    532     if (param_len > 0xffff) {
    533         pr2ws("%s: param_len too big\n", cdb_name_s);
    534         return -1;
    535     }
    536     if (verbose) {
    537         pr2ws("    %s cdb: ", cdb_name_s);
    538         for (k = 0; k < MODE_SELECT10_CMDLEN; ++k)
    539             pr2ws("%02x ", modes_cdb[k]);
    540         pr2ws("\n");
    541     }
    542     if (verbose > 1) {
    543         pr2ws("    %s parameter list\n", cdb_name_s);
    544         hex2stderr((const uint8_t *)paramp, param_len, -1);
    545     }
    546 
    547     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    548         return -1;
    549     set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
    550     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    551     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
    552     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    553     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
    554                                noisy, verbose, &sense_cat);
    555     if (-1 == ret) {
    556         int os_err = get_scsi_pt_os_err(ptvp);
    557 
    558         if ((os_err > 0) && (os_err < 47))
    559             ret = SG_LIB_OS_BASE_ERR + os_err;
    560     } else if (-2 == ret) {
    561         switch (sense_cat) {
    562         case SG_LIB_CAT_RECOVERED:
    563         case SG_LIB_CAT_NO_SENSE:
    564             ret = 0;
    565             break;
    566         default:
    567             ret = sense_cat;
    568             break;
    569         }
    570     } else
    571         ret = 0;
    572 
    573     destruct_scsi_pt_obj(ptvp);
    574     return ret;
    575 }
    576 
    577 /* MODE SENSE commands yield a response that has header then zero or more
    578  * block descriptors followed by mode pages. In most cases users are
    579  * interested in the first mode page. This function returns the (byte)
    580  * offset of the start of the first mode page. Set mode_sense_6 to true for
    581  * MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful
    582  * or -1 if failure. If there is a failure a message is written to err_buff
    583  * if it is non-NULL and err_buff_len > 0. */
    584 int
    585 sg_mode_page_offset(const unsigned char * resp, int resp_len,
    586                     bool mode_sense_6, char * err_buff, int err_buff_len)
    587 {
    588     int bd_len, calc_len, offset;
    589     bool err_buff_ok = ((err_buff_len > 0) && err_buff);
    590 
    591     if ((NULL == resp) || (resp_len < 4))
    592             goto too_short;
    593     if (mode_sense_6) {
    594         calc_len = resp[0] + 1;
    595         bd_len = resp[3];
    596         offset = bd_len + MODE6_RESP_HDR_LEN;
    597     } else {    /* Mode sense(10) */
    598         if (resp_len < 8)
    599             goto too_short;
    600         calc_len = sg_get_unaligned_be16(resp) + 2;
    601         bd_len = sg_get_unaligned_be16(resp + 6);
    602         /* LongLBA doesn't change this calculation */
    603         offset = bd_len + MODE10_RESP_HDR_LEN;
    604     }
    605     if ((offset + 2) > calc_len) {
    606         if (err_buff_ok)
    607             snprintf(err_buff, err_buff_len, "calculated response "
    608                      "length too small, offset=%d calc_len=%d bd_len=%d\n",
    609                      offset, calc_len, bd_len);
    610         offset = -1;
    611     }
    612     return offset;
    613 too_short:
    614     if (err_buff_ok)
    615         snprintf(err_buff, err_buff_len, "given MS(%d) response length (%d) "
    616                  "too short\n", (mode_sense_6 ? 6 : 10), resp_len);
    617     return -1;
    618 }
    619 
    620 /* MODE SENSE commands yield a response that has header then zero or more
    621  * block descriptors followed by mode pages. This functions returns the
    622  * length (in bytes) of those three components. Note that the return value
    623  * can exceed resp_len in which case the MODE SENSE command should be
    624  * re-issued with a larger response buffer. If bd_lenp is non-NULL and if
    625  * successful the block descriptor length (in bytes) is written to *bd_lenp.
    626  * Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10)
    627  * responses. Returns -1 if there is an error (e.g. response too short). */
    628 int
    629 sg_msense_calc_length(const unsigned char * resp, int resp_len,
    630                       bool mode_sense_6, int * bd_lenp)
    631 {
    632     int calc_len;
    633 
    634     if (NULL == resp)
    635         goto an_err;
    636     if (mode_sense_6) {
    637         if (resp_len < 4)
    638             goto an_err;
    639         calc_len = resp[0] + 1;
    640     } else {
    641         if (resp_len < 8)
    642             goto an_err;
    643         calc_len = sg_get_unaligned_be16(resp + 0) + 2;
    644     }
    645     if (bd_lenp)
    646         *bd_lenp = mode_sense_6 ? resp[3] : sg_get_unaligned_be16(resp + 6);
    647     return calc_len;
    648 an_err:
    649     if (bd_lenp)
    650         *bd_lenp = 0;
    651     return -1;
    652 }
    653 
    654 /* Fetches current, changeable, default and/or saveable modes pages as
    655  * indicated by pcontrol_arr for given pg_code and sub_pg_code. If
    656  * mode6==false then use MODE SENSE (10) else use MODE SENSE (6). If
    657  * flexible set and mode data length seems wrong then try and
    658  * fix (compensating hack for bad device or driver). pcontrol_arr
    659  * should have 4 elements for output of current, changeable, default
    660  * and saved values respectively. Each element should be NULL or
    661  * at least mx_mpage_len bytes long.
    662  * Return of 0 -> overall success, various SG_LIB_CAT_* positive values or
    663  * -1 -> other errors.
    664  * If success_mask pointer is not NULL then first zeros it. Then set bits
    665  * 0, 1, 2 and/or 3 if the current, changeable, default and saved values
    666  * respectively have been fetched. If error on current page
    667  * then stops and returns that error; otherwise continues if an error is
    668  * detected but returns the first error encountered.  */
    669 int
    670 sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code, int sub_pg_code,
    671                           bool dbd, bool flexible, int mx_mpage_len,
    672                           int * success_mask, void * pcontrol_arr[],
    673                           int * reported_lenp, int verbose)
    674 {
    675     bool resp_mode6;
    676     int k, n, res, offset, calc_len, xfer_len;
    677     int resid = 0;
    678     const int msense10_hlen = MODE10_RESP_HDR_LEN;
    679     unsigned char buff[MODE_RESP_ARB_LEN];
    680     char ebuff[EBUFF_SZ];
    681     int first_err = 0;
    682 
    683     if (success_mask)
    684         *success_mask = 0;
    685     if (reported_lenp)
    686         *reported_lenp = 0;
    687     if (mx_mpage_len < 4)
    688         return 0;
    689     memset(ebuff, 0, sizeof(ebuff));
    690     /* first try to find length of current page response */
    691     memset(buff, 0, msense10_hlen);
    692     if (mode6)  /* want first 8 bytes just in case */
    693         res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code,
    694                                 sub_pg_code, buff, msense10_hlen, true,
    695                                 verbose);
    696     else        /* MODE SENSE(10) obviously */
    697         res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
    698                                     0 /* pc */, pg_code, sub_pg_code, buff,
    699                                     msense10_hlen, 0, &resid, true, verbose);
    700     if (0 != res)
    701         return res;
    702     n = buff[0];
    703     if (reported_lenp) {
    704         int m;
    705 
    706         m = sg_msense_calc_length(buff, msense10_hlen, mode6, NULL) - resid;
    707         if (m < 0)      /* Grrr, this should not happen */
    708             m = 0;
    709         *reported_lenp = m;
    710     }
    711     resp_mode6 = mode6;
    712     if (flexible) {
    713         if (mode6 && (n < 3)) {
    714             resp_mode6 = false;
    715             if (verbose)
    716                 pr2ws(">>> msense(6) but resp[0]=%d so try msense(10) "
    717                       "response processing\n", n);
    718         }
    719         if ((! mode6) && (n > 5)) {
    720             if ((n > 11) && (0 == (n % 2)) && (0 == buff[4]) &&
    721                 (0 == buff[5]) && (0 == buff[6])) {
    722                 buff[1] = n;
    723                 buff[0] = 0;
    724                 if (verbose)
    725                     pr2ws(">>> msense(10) but resp[0]=%d and not msense(6) "
    726                           "response so fix length\n", n);
    727             } else
    728                 resp_mode6 = true;
    729         }
    730     }
    731     if (verbose && (resp_mode6 != mode6))
    732         pr2ws(">>> msense(%d) but resp[0]=%d so switch response "
    733               "processing\n", (mode6 ? 6 : 10), buff[0]);
    734     calc_len = sg_msense_calc_length(buff, msense10_hlen, resp_mode6, NULL);
    735     if (calc_len > MODE_RESP_ARB_LEN)
    736         calc_len = MODE_RESP_ARB_LEN;
    737     offset = sg_mode_page_offset(buff, calc_len, resp_mode6, ebuff, EBUFF_SZ);
    738     if (offset < 0) {
    739         if (('\0' != ebuff[0]) && (verbose > 0))
    740             pr2ws("%s: %s\n", __func__, ebuff);
    741         return SG_LIB_CAT_MALFORMED;
    742     }
    743     xfer_len = calc_len - offset;
    744     if (xfer_len > mx_mpage_len)
    745         xfer_len = mx_mpage_len;
    746 
    747     for (k = 0; k < 4; ++k) {
    748         if (NULL == pcontrol_arr[k])
    749             continue;
    750         memset(pcontrol_arr[k], 0, mx_mpage_len);
    751         resid = 0;
    752         if (mode6)
    753             res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */,
    754                                     pg_code, sub_pg_code, buff,
    755                                     calc_len, true, verbose);
    756         else
    757             res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
    758                                         k /* pc */, pg_code, sub_pg_code,
    759                                         buff, calc_len, 0, &resid, true,
    760                                         verbose);
    761         if (res || resid) {
    762             if (0 == first_err) {
    763                 if (res)
    764                     first_err = res;
    765                 else {
    766                     first_err = -49;    /* unexpected resid != 0 */
    767                     if (verbose)
    768                         pr2ws("%s: unexpected resid=%d, page=0x%x, "
    769                               "pcontrol=%d\n", __func__, resid, pg_code, k);
    770                 }
    771             }
    772             if (0 == k)
    773                 break;  /* if problem on current page, it won't improve */
    774             else
    775                 continue;
    776         }
    777         if (xfer_len > 0)
    778             memcpy(pcontrol_arr[k], buff + offset, xfer_len);
    779         if (success_mask)
    780             *success_mask |= (1 << k);
    781     }
    782     return first_err;
    783 }
    784 
    785 /* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
    786  * various SG_LIB_CAT_* positive values or -1 -> other errors. */
    787 int
    788 sg_ll_log_sense(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
    789                 int subpg_code, int paramp, unsigned char * resp,
    790                 int mx_resp_len, bool noisy, int verbose)
    791 {
    792     return sg_ll_log_sense_v2(sg_fd, ppc, sp, pc, pg_code, subpg_code,
    793                               paramp, resp, mx_resp_len, 0, NULL, noisy,
    794                               verbose);
    795 }
    796 
    797 /* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
    798  * various SG_LIB_CAT_* positive values or -1 -> other errors.
    799  * Adds the ability to set the command abort timeout
    800  * and the ability to report the residual count. If timeout_secs is zero
    801  * or less the default command abort timeout (60 seconds) is used.
    802  * If residp is non-NULL then the residual value is written where residp
    803  * points. A residual value of 0 implies mx_resp_len bytes have be written
    804  * where resp points. If the residual value equals mx_resp_len then no
    805  * bytes have been written. */
    806 int
    807 sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
    808                    int subpg_code, int paramp, unsigned char * resp,
    809                    int mx_resp_len, int timeout_secs, int * residp,
    810                    bool noisy, int verbose)
    811 {
    812     static const char * const cdb_name_s = "log sense";
    813     int res, ret, k, sense_cat, resid;
    814     unsigned char logs_cdb[LOG_SENSE_CMDLEN] =
    815         {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    816     unsigned char sense_b[SENSE_BUFF_LEN];
    817     struct sg_pt_base * ptvp;
    818 
    819     if (mx_resp_len > 0xffff) {
    820         pr2ws("mx_resp_len too big\n");
    821         goto gen_err;
    822     }
    823     logs_cdb[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0));
    824     logs_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
    825     logs_cdb[3] = (unsigned char)(subpg_code & 0xff);
    826     sg_put_unaligned_be16((int16_t)paramp, logs_cdb + 5);
    827     sg_put_unaligned_be16((int16_t)mx_resp_len, logs_cdb + 7);
    828     if (verbose) {
    829         pr2ws("    %s cdb: ", cdb_name_s);
    830         for (k = 0; k < LOG_SENSE_CMDLEN; ++k)
    831             pr2ws("%02x ", logs_cdb[k]);
    832         pr2ws("\n");
    833     }
    834     if (timeout_secs <= 0)
    835         timeout_secs = DEF_PT_TIMEOUT;
    836 
    837     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    838         goto gen_err;
    839     set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
    840     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    841     set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
    842     res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
    843     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len,
    844                                sense_b, noisy, verbose, &sense_cat);
    845     resid = get_scsi_pt_resid(ptvp);
    846     if (residp)
    847         *residp = resid;
    848     if (-1 == ret) {
    849         int os_err = get_scsi_pt_os_err(ptvp);
    850 
    851         if ((os_err > 0) && (os_err < 47))
    852             ret = SG_LIB_OS_BASE_ERR + os_err;
    853     } else if (-2 == ret) {
    854         switch (sense_cat) {
    855         case SG_LIB_CAT_RECOVERED:
    856         case SG_LIB_CAT_NO_SENSE:
    857             ret = 0;
    858             break;
    859         default:
    860             ret = sense_cat;
    861             break;
    862         }
    863     } else {
    864         if ((mx_resp_len > 3) && (ret < 4)) {
    865             /* resid indicates LOG SENSE response length bad, so zero it */
    866             resp[2] = 0;
    867             resp[3] = 0;
    868         }
    869         ret = 0;
    870     }
    871     destruct_scsi_pt_obj(ptvp);
    872 
    873     if (resid > 0) {
    874         if (resid > mx_resp_len) {
    875             pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
    876                   cdb_name_s, resid, mx_resp_len);
    877             return ret ? ret : SG_LIB_CAT_MALFORMED;
    878         }
    879         /* zero unfilled section of response buffer */
    880         memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
    881     }
    882     return ret;
    883 gen_err:
    884     if (residp)
    885         *residp = 0;
    886     return -1;
    887 }
    888 
    889 /* Invokes a SCSI LOG SELECT command. Return of 0 -> success,
    890  * various SG_LIB_CAT_* positive values or -1 -> other errors */
    891 int
    892 sg_ll_log_select(int sg_fd, bool pcr, bool sp, int pc, int pg_code,
    893                  int subpg_code, unsigned char * paramp, int param_len,
    894                  bool noisy, int verbose)
    895 {
    896     static const char * const cdb_name_s = "log select";
    897     int res, ret, k, sense_cat;
    898     unsigned char logs_cdb[LOG_SELECT_CMDLEN] =
    899         {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    900     unsigned char sense_b[SENSE_BUFF_LEN];
    901     struct sg_pt_base * ptvp;
    902 
    903     if (param_len > 0xffff) {
    904         pr2ws("%s: param_len too big\n", cdb_name_s);
    905         return -1;
    906     }
    907     logs_cdb[1] = (unsigned char)((pcr ? 2 : 0) | (sp ? 1 : 0));
    908     logs_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
    909     logs_cdb[3] = (unsigned char)(subpg_code & 0xff);
    910     sg_put_unaligned_be16((int16_t)param_len, logs_cdb + 7);
    911     if (verbose) {
    912         pr2ws("    %s cdb: ", cdb_name_s);
    913         for (k = 0; k < LOG_SELECT_CMDLEN; ++k)
    914             pr2ws("%02x ", logs_cdb[k]);
    915         pr2ws("\n");
    916     }
    917     if ((verbose > 1) && (param_len > 0)) {
    918         pr2ws("    %s parameter list\n", cdb_name_s);
    919         hex2stderr(paramp, param_len, -1);
    920     }
    921 
    922     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    923         return -1;
    924     set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
    925     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    926     set_scsi_pt_data_out(ptvp, paramp, param_len);
    927     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
    928     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
    929                                noisy, verbose, &sense_cat);
    930     if (-1 == ret) {
    931         int os_err = get_scsi_pt_os_err(ptvp);
    932 
    933         if ((os_err > 0) && (os_err < 47))
    934             ret = SG_LIB_OS_BASE_ERR + os_err;
    935     } else if (-2 == ret) {
    936         switch (sense_cat) {
    937         case SG_LIB_CAT_RECOVERED:
    938         case SG_LIB_CAT_NO_SENSE:
    939             ret = 0;
    940             break;
    941         default:
    942             ret = sense_cat;
    943             break;
    944         }
    945     } else
    946         ret = 0;
    947 
    948     destruct_scsi_pt_obj(ptvp);
    949     return ret;
    950 }
    951 
    952 /* Invokes a SCSI START STOP UNIT command (SBC + MMC).
    953  * Return of 0 -> success,
    954  * various SG_LIB_CAT_* positive values or -1 -> other errors.
    955  * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and
    956  * format_layer_number(mmc) fields. They also overlap on the noflush(sbc)
    957  * and fl(mmc) one bit field. This is the cause of the awkardly named
    958  * pc_mod__fl_num and noflush__fl arguments to this function.
    959  *  */
    960 int
    961 sg_ll_start_stop_unit(int sg_fd, bool immed, int pc_mod__fl_num,
    962                       int power_cond, bool noflush__fl, bool loej, bool start,
    963                       bool noisy, int verbose)
    964 {
    965     static const char * const cdb_name_s = "start stop unit";
    966     int k, res, ret, sense_cat;
    967     struct sg_pt_base * ptvp;
    968     unsigned char ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0};
    969     unsigned char sense_b[SENSE_BUFF_LEN];
    970 
    971     if (immed)
    972         ssuBlk[1] = 0x1;
    973     ssuBlk[3] = pc_mod__fl_num & 0xf;  /* bits 2 and 3 are reserved in MMC */
    974     ssuBlk[4] = ((power_cond & 0xf) << 4);
    975     if (noflush__fl)
    976         ssuBlk[4] |= 0x4;
    977     if (loej)
    978         ssuBlk[4] |= 0x2;
    979     if (start)
    980         ssuBlk[4] |= 0x1;
    981     if (verbose) {
    982         pr2ws("    %s command:", cdb_name_s);
    983         for (k = 0; k < (int)sizeof(ssuBlk); ++k)
    984                 pr2ws(" %02x", ssuBlk[k]);
    985         pr2ws("\n");
    986     }
    987 
    988     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
    989         return -1;
    990     set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk));
    991     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
    992     res = do_scsi_pt(ptvp, sg_fd, START_PT_TIMEOUT, verbose);
    993     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
    994                                noisy, verbose, &sense_cat);
    995     if (-1 == ret) {
    996         int os_err = get_scsi_pt_os_err(ptvp);
    997 
    998         if ((os_err > 0) && (os_err < 47))
    999             ret = SG_LIB_OS_BASE_ERR + os_err;
   1000     } else if (-2 == ret) {
   1001         switch (sense_cat) {
   1002         case SG_LIB_CAT_RECOVERED:
   1003         case SG_LIB_CAT_NO_SENSE:
   1004             ret = 0;
   1005             break;
   1006         default:
   1007             ret = sense_cat;
   1008             break;
   1009         }
   1010     } else
   1011             ret = 0;
   1012     destruct_scsi_pt_obj(ptvp);
   1013     return ret;
   1014 }
   1015 
   1016 /* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command
   1017  * [was in SPC-3 but displaced from SPC-4 into SBC-3, MMC-5, SSC-3]
   1018  * prevent==0 allows removal, prevent==1 prevents removal ...
   1019  * Return of 0 -> success,
   1020  * various SG_LIB_CAT_* positive values or -1 -> other errors */
   1021 int
   1022 sg_ll_prevent_allow(int sg_fd, int prevent, bool noisy, int verbose)
   1023 {
   1024     static const char * const cdb_name_s = "prevent allow medium removal";
   1025     int k, res, ret, sense_cat;
   1026     unsigned char p_cdb[PREVENT_ALLOW_CMDLEN] =
   1027                 {PREVENT_ALLOW_CMD, 0, 0, 0, 0, 0};
   1028     unsigned char sense_b[SENSE_BUFF_LEN];
   1029     struct sg_pt_base * ptvp;
   1030 
   1031     if ((prevent < 0) || (prevent > 3)) {
   1032         pr2ws("prevent argument should be 0, 1, 2 or 3\n");
   1033         return -1;
   1034     }
   1035     p_cdb[4] |= (prevent & 0x3);
   1036     if (verbose) {
   1037         pr2ws("    %s cdb: ", cdb_name_s);
   1038         for (k = 0; k < PREVENT_ALLOW_CMDLEN; ++k)
   1039             pr2ws("%02x ", p_cdb[k]);
   1040         pr2ws("\n");
   1041     }
   1042 
   1043     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
   1044         return -1;
   1045     set_scsi_pt_cdb(ptvp, p_cdb, sizeof(p_cdb));
   1046     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
   1047     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
   1048     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
   1049                                noisy, verbose, &sense_cat);
   1050     if (-1 == ret) {
   1051         int os_err = get_scsi_pt_os_err(ptvp);
   1052 
   1053         if ((os_err > 0) && (os_err < 47))
   1054             ret = SG_LIB_OS_BASE_ERR + os_err;
   1055     } else if (-2 == ret) {
   1056         switch (sense_cat) {
   1057         case SG_LIB_CAT_RECOVERED:
   1058         case SG_LIB_CAT_NO_SENSE:
   1059             ret = 0;
   1060             break;
   1061         default:
   1062             ret = sense_cat;
   1063             break;
   1064         }
   1065     } else
   1066             ret = 0;
   1067     destruct_scsi_pt_obj(ptvp);
   1068     return ret;
   1069 }
   1070