Home | History | Annotate | Download | only in sg_write_buffer
      1 /*
      2  * Copyright (c) 2005-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 /* sg_pt_linux version 1.37 20180126 */
      9 
     10 
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <stdarg.h>
     14 #include <stdbool.h>
     15 #include <string.h>
     16 #include <ctype.h>
     17 #include <unistd.h>
     18 #include <errno.h>
     19 #include <fcntl.h>
     20 #include <sys/ioctl.h>
     21 #include <sys/stat.h>
     22 #include <sys/sysmacros.h>      /* to define 'major' */
     23 #ifndef major
     24 #include <sys/types.h>
     25 #endif
     26 
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #include "config.h"
     30 #endif
     31 
     32 #include <linux/major.h>
     33 
     34 #include "sg_pt.h"
     35 #include "sg_lib.h"
     36 #include "sg_linux_inc.h"
     37 #include "sg_pt_linux.h"
     38 
     39 
     40 #ifdef major
     41 #define SG_DEV_MAJOR major
     42 #else
     43 #ifdef HAVE_LINUX_KDEV_T_H
     44 #include <linux/kdev_t.h>
     45 #endif
     46 #define SG_DEV_MAJOR MAJOR  /* MAJOR() macro faulty if > 255 minors */
     47 #endif
     48 
     49 #ifndef BLOCK_EXT_MAJOR
     50 #define BLOCK_EXT_MAJOR 259
     51 #endif
     52 
     53 #define DEF_TIMEOUT 60000       /* 60,000 millisecs (60 seconds) */
     54 
     55 static const char * linux_host_bytes[] = {
     56     "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
     57     "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR",
     58     "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR",
     59     "DID_IMM_RETRY", "DID_REQUEUE" /* 0xd */,
     60     "DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST",
     61     "DID_TARGET_FAILURE" /* 0x10 */,
     62     "DID_NEXUS_FAILURE (reservation conflict)",
     63     "DID_ALLOC_FAILURE",
     64     "DID_MEDIUM_ERROR",
     65 };
     66 
     67 #define LINUX_HOST_BYTES_SZ \
     68         (int)(sizeof(linux_host_bytes) / sizeof(linux_host_bytes[0]))
     69 
     70 static const char * linux_driver_bytes[] = {
     71     "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA",
     72     "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",
     73     "DRIVER_SENSE"
     74 };
     75 
     76 #define LINUX_DRIVER_BYTES_SZ \
     77     (int)(sizeof(linux_driver_bytes) / sizeof(linux_driver_bytes[0]))
     78 
     79 #if 0
     80 static const char * linux_driver_suggests[] = {
     81     "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP",
     82     "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN",
     83     "SUGGEST_SENSE"
     84 };
     85 
     86 #define LINUX_DRIVER_SUGGESTS_SZ \
     87     (int)(sizeof(linux_driver_suggests) / sizeof(linux_driver_suggests[0]))
     88 #endif
     89 
     90 /*
     91  * These defines are for constants that should be visible in the
     92  * /usr/include/scsi directory (brought in by sg_linux_inc.h).
     93  * Redefined and aliased here to decouple this code from
     94  * sg_io_linux.h  N.B. the SUGGEST_* constants are no longer used.
     95  */
     96 #ifndef DRIVER_MASK
     97 #define DRIVER_MASK 0x0f
     98 #endif
     99 #ifndef SUGGEST_MASK
    100 #define SUGGEST_MASK 0xf0
    101 #endif
    102 #ifndef DRIVER_SENSE
    103 #define DRIVER_SENSE 0x08
    104 #endif
    105 #define SG_LIB_DRIVER_MASK      DRIVER_MASK
    106 #define SG_LIB_SUGGEST_MASK     SUGGEST_MASK
    107 #define SG_LIB_DRIVER_SENSE    DRIVER_SENSE
    108 
    109 bool sg_bsg_nvme_char_major_checked = false;
    110 int sg_bsg_major = 0;
    111 volatile int sg_nvme_char_major = 0;
    112 
    113 long sg_lin_page_size = 4096;   /* default, overridden with correct value */
    114 
    115 
    116 #if defined(__GNUC__) || defined(__clang__)
    117 static int pr2ws(const char * fmt, ...)
    118         __attribute__ ((format (printf, 1, 2)));
    119 #else
    120 static int pr2ws(const char * fmt, ...);
    121 #endif
    122 
    123 
    124 static int
    125 pr2ws(const char * fmt, ...)
    126 {
    127     va_list args;
    128     int n;
    129 
    130     va_start(args, fmt);
    131     n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
    132     va_end(args);
    133     return n;
    134 }
    135 
    136 /* This function only needs to be called once (unless a NVMe controller
    137  * can be hot-plugged into system in which case it should be called
    138  * (again) after that event). */
    139 void
    140 sg_find_bsg_nvme_char_major(int verbose)
    141 {
    142     bool got_one = false;
    143     int n;
    144     const char * proc_devices = "/proc/devices";
    145     char * cp;
    146     FILE *fp;
    147     char a[128];
    148     char b[128];
    149 
    150     sg_lin_page_size = sysconf(_SC_PAGESIZE);
    151     if (NULL == (fp = fopen(proc_devices, "r"))) {
    152         if (verbose)
    153             pr2ws("fopen %s failed: %s\n", proc_devices, strerror(errno));
    154         return;
    155     }
    156     while ((cp = fgets(b, sizeof(b), fp))) {
    157         if ((1 == sscanf(b, "%126s", a)) &&
    158             (0 == memcmp(a, "Character", 9)))
    159             break;
    160     }
    161     while (cp && (cp = fgets(b, sizeof(b), fp))) {
    162         if (2 == sscanf(b, "%d %126s", &n, a)) {
    163             if (0 == strcmp("bsg", a)) {
    164                 sg_bsg_major = n;
    165                 if (got_one)
    166                     break;
    167                 got_one = true;
    168             } else if (0 == strcmp("nvme", a)) {
    169                 sg_nvme_char_major = n;
    170                 if (got_one)
    171                     break;
    172                 got_one = true;
    173             }
    174         } else
    175             break;
    176     }
    177     if (verbose > 3) {
    178         if (cp) {
    179             if (sg_bsg_major > 0)
    180                 pr2ws("found sg_bsg_major=%d\n", sg_bsg_major);
    181             if (sg_nvme_char_major > 0)
    182                 pr2ws("found sg_nvme_char_major=%d\n", sg_nvme_char_major);
    183         } else
    184             pr2ws("found no bsg not nvme char device in %s\n", proc_devices);
    185     }
    186     fclose(fp);
    187 }
    188 
    189 /* Assumes that sg_find_bsg_nvme_char_major() has already been called. Returns
    190  * true if dev_fd is a scsi generic pass-through device. If yields
    191  * *is_nvme_p = true with *nsid_p = 0 then dev_fd is a NVMe char device.
    192  * If yields *nsid_p > 0 then dev_fd is a NVMe block device. */
    193 static bool
    194 check_file_type(int dev_fd, struct stat * dev_statp, bool * is_bsg_p,
    195                 bool * is_nvme_p, uint32_t * nsid_p, int * os_err_p,
    196                 int verbose)
    197 {
    198     bool is_nvme = false;
    199     bool is_sg = false;
    200     bool is_bsg = false;
    201     bool is_block = false;
    202     int os_err = 0;
    203     int major_num;
    204     uint32_t nsid = 0;          /* invalid NSID */
    205 
    206     if (dev_fd >= 0) {
    207         if (fstat(dev_fd, dev_statp) < 0) {
    208             os_err = errno;
    209             if (verbose)
    210                 pr2ws("%s: fstat() failed: %s (errno=%d)\n", __func__,
    211                       safe_strerror(os_err), os_err);
    212             goto skip_out;
    213         }
    214         major_num = (int)SG_DEV_MAJOR(dev_statp->st_rdev);
    215         if (S_ISCHR(dev_statp->st_mode)) {
    216             if (SCSI_GENERIC_MAJOR == major_num)
    217                 is_sg = true;
    218             else if (sg_bsg_major == major_num)
    219                 is_bsg = true;
    220             else if (sg_nvme_char_major == major_num)
    221                 is_nvme = true;
    222         } else if (S_ISBLK(dev_statp->st_mode)) {
    223             is_block = true;
    224             if (BLOCK_EXT_MAJOR == major_num) {
    225                 is_nvme = true;
    226                 nsid = ioctl(dev_fd, NVME_IOCTL_ID, NULL);
    227                 if (SG_NVME_BROADCAST_NSID == nsid) {  /* means ioctl error */
    228                     os_err = errno;
    229                     if (verbose)
    230                         pr2ws("%s: ioctl(NVME_IOCTL_ID) failed: %s "
    231                               "(errno=%d)\n", __func__, safe_strerror(os_err),
    232                               os_err);
    233                 } else
    234                     os_err = 0;
    235             }
    236         }
    237     } else {
    238         os_err = EBADF;
    239         if (verbose)
    240             pr2ws("%s: invalid file descriptor (%d)\n", __func__, dev_fd);
    241     }
    242 skip_out:
    243     if (verbose > 3) {
    244         pr2ws("%s: file descriptor is ", __func__);
    245         if (is_sg)
    246             pr2ws("sg device\n");
    247         else if (is_bsg)
    248             pr2ws("bsg device\n");
    249         else if (is_nvme && (0 == nsid))
    250             pr2ws("NVMe char device\n");
    251         else if (is_nvme)
    252             pr2ws("NVMe block device, nsid=%lld\n",
    253                   ((uint32_t)-1 == nsid) ? -1LL : (long long)nsid);
    254         else if (is_block)
    255             pr2ws("block device\n");
    256         else
    257             pr2ws("undetermined device, could be regular file\n");
    258     }
    259     if (is_bsg_p)
    260         *is_bsg_p = is_bsg;
    261     if (is_nvme_p)
    262         *is_nvme_p = is_nvme;
    263     if (nsid_p)
    264         *nsid_p = nsid;
    265     if (os_err_p)
    266         *os_err_p = os_err;
    267     return is_sg;
    268 }
    269 
    270 /* Assumes dev_fd is an "open" file handle associated with device_name. If
    271  * the implementation (possibly for one OS) cannot determine from dev_fd if
    272  * a SCSI or NVMe pass-through is referenced, then it might guess based on
    273  * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if
    274  * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is
    275  * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes
    276  * NSID), or 0 if something else (e.g. ATA block device) or dev_fd < 0.
    277  * If error, returns negated errno (operating system) value. */
    278 int
    279 check_pt_file_handle(int dev_fd, const char * device_name, int verbose)
    280 {
    281     if (verbose > 4)
    282         pr2ws("%s: dev_fd=%d, device_name: %s\n", __func__, dev_fd,
    283               device_name);
    284     /* Linux doesn't need device_name to determine which pass-through */
    285     if (! sg_bsg_nvme_char_major_checked) {
    286         sg_bsg_nvme_char_major_checked = true;
    287         sg_find_bsg_nvme_char_major(verbose);
    288     }
    289     if (dev_fd >= 0) {
    290         bool is_sg, is_bsg, is_nvme;
    291         int err;
    292         uint32_t nsid;
    293         struct stat a_stat;
    294 
    295         is_sg = check_file_type(dev_fd, &a_stat, &is_bsg, &is_nvme, &nsid,
    296                                 &err, verbose);
    297         if (err)
    298             return -err;
    299         else if (is_sg)
    300             return 1;
    301         else if (is_bsg)
    302             return 2;
    303         else if (is_nvme && (0 == nsid))
    304             return 3;
    305         else if (is_nvme)
    306             return 4;
    307         else
    308             return 0;
    309     } else
    310         return 0;
    311 }
    312 
    313 /*
    314  * We make a runtime decision whether to use the sg v3 interface or the sg
    315  * v4 interface (currently exclusively used by the bsg driver). If all the
    316  * following are true we use sg v4 which is only currently supported on bsg
    317  * device nodes:
    318  *   a) there is a bsg entry in the /proc/devices file
    319  *   b) the device node given to scsi_pt_open() is a char device
    320  *   c) the char major number of the device node given to scsi_pt_open()
    321  *      matches the char major number of the bsg entry in /proc/devices
    322  * Otherwise the sg v3 interface is used.
    323  *
    324  * Note that in either case we prepare the data in a sg v4 structure. If
    325  * the runtime tests indicate that the v3 interface is needed then
    326  * do_scsi_pt_v3() transfers the input data into a v3 structure and
    327  * then the output data is transferred back into a sg v4 structure.
    328  * That implementation detail could change in the future.
    329  *
    330  * [20120806] Only use MAJOR() macro in kdev_t.h if that header file is
    331  * available and major() macro [N.B. lower case] is not available.
    332  */
    333 
    334 
    335 #ifdef major
    336 #define SG_DEV_MAJOR major
    337 #else
    338 #ifdef HAVE_LINUX_KDEV_T_H
    339 #include <linux/kdev_t.h>
    340 #endif
    341 #define SG_DEV_MAJOR MAJOR  /* MAJOR() macro faulty if > 255 minors */
    342 #endif
    343 
    344 
    345 /* Returns >= 0 if successful. If error in Unix returns negated errno. */
    346 int
    347 scsi_pt_open_device(const char * device_name, bool read_only, int verbose)
    348 {
    349     int oflags = O_NONBLOCK;
    350 
    351     oflags |= (read_only ? O_RDONLY : O_RDWR);
    352     return scsi_pt_open_flags(device_name, oflags, verbose);
    353 }
    354 
    355 /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed */
    356 /* together. The 'flags' argument is advisory and may be ignored. */
    357 /* Returns >= 0 if successful, otherwise returns negated errno. */
    358 int
    359 scsi_pt_open_flags(const char * device_name, int flags, int verbose)
    360 {
    361     int fd;
    362 
    363     if (! sg_bsg_nvme_char_major_checked) {
    364         sg_bsg_nvme_char_major_checked = true;
    365         sg_find_bsg_nvme_char_major(verbose);
    366     }
    367     if (verbose > 1) {
    368         pr2ws("open %s with flags=0x%x\n", device_name, flags);
    369     }
    370     fd = open(device_name, flags);
    371     if (fd < 0) {
    372         fd = -errno;
    373         if (verbose > 1)
    374             pr2ws("%s: open(%s, 0x%x) failed: %s\n", __func__, device_name,
    375                   flags, safe_strerror(-fd));
    376     }
    377     return fd;
    378 }
    379 
    380 /* Returns 0 if successful. If error in Unix returns negated errno. */
    381 int
    382 scsi_pt_close_device(int device_fd)
    383 {
    384     int res;
    385 
    386     res = close(device_fd);
    387     if (res < 0)
    388         res = -errno;
    389     return res;
    390 }
    391 
    392 
    393 /* Caller should additionally call get_scsi_pt_os_err() after this call */
    394 struct sg_pt_base *
    395 construct_scsi_pt_obj_with_fd(int dev_fd, int verbose)
    396 {
    397     int err;
    398     struct sg_pt_linux_scsi * ptp;
    399 
    400     /* The following 2 lines are temporary. It is to avoid a NULL pointer
    401      * crash when an old utility is used with a newer library built after
    402      * the sg_warnings_strm cleanup */
    403     if (NULL == sg_warnings_strm)
    404         sg_warnings_strm = stderr;
    405 
    406     ptp = (struct sg_pt_linux_scsi *)
    407           calloc(1, sizeof(struct sg_pt_linux_scsi));
    408     if (ptp) {
    409         err = set_pt_file_handle((struct sg_pt_base *)ptp, dev_fd, verbose);
    410         if ((0 == err) && (! ptp->is_nvme)) {
    411             ptp->io_hdr.guard = 'Q';
    412 #ifdef BSG_PROTOCOL_SCSI
    413             ptp->io_hdr.protocol = BSG_PROTOCOL_SCSI;
    414 #endif
    415 #ifdef BSG_SUB_PROTOCOL_SCSI_CMD
    416             ptp->io_hdr.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
    417 #endif
    418         }
    419     } else if (verbose)
    420         pr2ws("%s: calloc() failed, out of memory?\n", __func__);
    421 
    422     return (struct sg_pt_base *)ptp;
    423 }
    424 
    425 struct sg_pt_base *
    426 construct_scsi_pt_obj()
    427 {
    428     return construct_scsi_pt_obj_with_fd(-1 /* dev_fd */, 0 /* verbose */);
    429 }
    430 
    431 void
    432 destruct_scsi_pt_obj(struct sg_pt_base * vp)
    433 {
    434     struct sg_pt_linux_scsi * ptp = &vp->impl;
    435 
    436     if (ptp->free_nvme_id_ctlp) {
    437         free(ptp->free_nvme_id_ctlp);
    438         ptp->free_nvme_id_ctlp = NULL;
    439         ptp->nvme_id_ctlp = NULL;
    440     }
    441     if (ptp)
    442         free(ptp);
    443 }
    444 
    445 /* Remembers previous device file descriptor */
    446 void
    447 clear_scsi_pt_obj(struct sg_pt_base * vp)
    448 {
    449     bool is_sg, is_bsg, is_nvme;
    450     int fd;
    451     uint32_t nvme_nsid;
    452     struct sg_pt_linux_scsi * ptp = &vp->impl;
    453 
    454     if (ptp) {
    455         fd = ptp->dev_fd;
    456         is_sg = ptp->is_sg;
    457         is_bsg = ptp->is_bsg;
    458         is_nvme = ptp->is_nvme;
    459         nvme_nsid = ptp->nvme_nsid;
    460         memset(ptp, 0, sizeof(struct sg_pt_linux_scsi));
    461         ptp->io_hdr.guard = 'Q';
    462 #ifdef BSG_PROTOCOL_SCSI
    463         ptp->io_hdr.protocol = BSG_PROTOCOL_SCSI;
    464 #endif
    465 #ifdef BSG_SUB_PROTOCOL_SCSI_CMD
    466         ptp->io_hdr.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
    467 #endif
    468         ptp->dev_fd = fd;
    469         ptp->is_sg = is_sg;
    470         ptp->is_bsg = is_bsg;
    471         ptp->is_nvme = is_nvme;
    472         ptp->nvme_direct = false;
    473         ptp->nvme_nsid = nvme_nsid;
    474     }
    475 }
    476 
    477 /* Forget any previous dev_fd and install the one given. May attempt to
    478  * find file type (e.g. if pass-though) from OS so there could be an error.
    479  * Returns 0 for success or the same value as get_scsi_pt_os_err()
    480  * will return. dev_fd should be >= 0 for a valid file handle or -1 . */
    481 int
    482 set_pt_file_handle(struct sg_pt_base * vp, int dev_fd, int verbose)
    483 {
    484     struct sg_pt_linux_scsi * ptp = &vp->impl;
    485     struct stat a_stat;
    486 
    487     if (! sg_bsg_nvme_char_major_checked) {
    488         sg_bsg_nvme_char_major_checked = true;
    489         sg_find_bsg_nvme_char_major(verbose);
    490     }
    491     ptp->dev_fd = dev_fd;
    492     if (dev_fd >= 0)
    493         ptp->is_sg = check_file_type(dev_fd, &a_stat, &ptp->is_bsg,
    494                                      &ptp->is_nvme, &ptp->nvme_nsid,
    495                                      &ptp->os_err, verbose);
    496     else {
    497         ptp->is_sg = false;
    498         ptp->is_bsg = false;
    499         ptp->is_nvme = false;
    500         ptp->nvme_direct = false;
    501         ptp->nvme_nsid = 0;
    502         ptp->os_err = 0;
    503     }
    504     return ptp->os_err;
    505 }
    506 
    507 /* Valid file handles (which is the return value) are >= 0 . Returns -1
    508  * if there is no valid file handle. */
    509 int
    510 get_pt_file_handle(const struct sg_pt_base * vp)
    511 {
    512     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    513 
    514     return ptp->dev_fd;
    515 }
    516 
    517 void
    518 set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb,
    519                 int cdb_len)
    520 {
    521     struct sg_pt_linux_scsi * ptp = &vp->impl;
    522 
    523     if (ptp->io_hdr.request)
    524         ++ptp->in_err;
    525     ptp->io_hdr.request = (__u64)(sg_uintptr_t)cdb;
    526     ptp->io_hdr.request_len = cdb_len;
    527 }
    528 
    529 void
    530 set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense,
    531                   int max_sense_len)
    532 {
    533     struct sg_pt_linux_scsi * ptp = &vp->impl;
    534 
    535     if (ptp->io_hdr.response)
    536         ++ptp->in_err;
    537     memset(sense, 0, max_sense_len);
    538     ptp->io_hdr.response = (__u64)(sg_uintptr_t)sense;
    539     ptp->io_hdr.max_response_len = max_sense_len;
    540 }
    541 
    542 /* Setup for data transfer from device */
    543 void
    544 set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp,
    545                     int dxfer_ilen)
    546 {
    547     struct sg_pt_linux_scsi * ptp = &vp->impl;
    548 
    549     if (ptp->io_hdr.din_xferp)
    550         ++ptp->in_err;
    551     if (dxfer_ilen > 0) {
    552         ptp->io_hdr.din_xferp = (__u64)(sg_uintptr_t)dxferp;
    553         ptp->io_hdr.din_xfer_len = dxfer_ilen;
    554     }
    555 }
    556 
    557 /* Setup for data transfer toward device */
    558 void
    559 set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp,
    560                      int dxfer_olen)
    561 {
    562     struct sg_pt_linux_scsi * ptp = &vp->impl;
    563 
    564     if (ptp->io_hdr.dout_xferp)
    565         ++ptp->in_err;
    566     if (dxfer_olen > 0) {
    567         ptp->io_hdr.dout_xferp = (__u64)(sg_uintptr_t)dxferp;
    568         ptp->io_hdr.dout_xfer_len = dxfer_olen;
    569     }
    570 }
    571 
    572 void
    573 set_pt_metadata_xfer(struct sg_pt_base * vp, unsigned char * dxferp,
    574                      uint32_t dxfer_len, bool out_true)
    575 {
    576     struct sg_pt_linux_scsi * ptp = &vp->impl;
    577 
    578     if (dxfer_len > 0) {
    579         ptp->mdxferp = dxferp;
    580         ptp->mdxfer_len = dxfer_len;
    581         ptp->mdxfer_out = out_true;
    582     }
    583 }
    584 
    585 void
    586 set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id)
    587 {
    588     struct sg_pt_linux_scsi * ptp = &vp->impl;
    589 
    590     ptp->io_hdr.spare_in = pack_id;
    591 }
    592 
    593 void
    594 set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag)
    595 {
    596     struct sg_pt_linux_scsi * ptp = &vp->impl;
    597 
    598     ptp->io_hdr.request_tag = tag;
    599 }
    600 
    601 /* Note that task management function codes are transport specific */
    602 void
    603 set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code)
    604 {
    605     struct sg_pt_linux_scsi * ptp = &vp->impl;
    606 
    607     ptp->io_hdr.subprotocol = 1;        /* SCSI task management function */
    608     ptp->tmf_request[0] = (unsigned char)tmf_code;      /* assume it fits */
    609     ptp->io_hdr.request = (__u64)(sg_uintptr_t)(&(ptp->tmf_request[0]));
    610     ptp->io_hdr.request_len = 1;
    611 }
    612 
    613 void
    614 set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority)
    615 {
    616     struct sg_pt_linux_scsi * ptp = &vp->impl;
    617 
    618     ptp->io_hdr.request_attr = attribute;
    619     ptp->io_hdr.request_priority = priority;
    620 }
    621 
    622 #ifndef BSG_FLAG_Q_AT_TAIL
    623 #define BSG_FLAG_Q_AT_TAIL 0x10
    624 #endif
    625 #ifndef BSG_FLAG_Q_AT_HEAD
    626 #define BSG_FLAG_Q_AT_HEAD 0x20
    627 #endif
    628 
    629 /* Need this later if translated to v3 interface */
    630 #ifndef SG_FLAG_Q_AT_TAIL
    631 #define SG_FLAG_Q_AT_TAIL 0x10
    632 #endif
    633 #ifndef SG_FLAG_Q_AT_HEAD
    634 #define SG_FLAG_Q_AT_HEAD 0x20
    635 #endif
    636 
    637 void
    638 set_scsi_pt_flags(struct sg_pt_base * vp, int flags)
    639 {
    640     struct sg_pt_linux_scsi * ptp = &vp->impl;
    641 
    642     /* default action of bsg driver (sg v4) is QUEUE_AT_HEAD */
    643     /* default action of block layer SG_IO ioctl is QUEUE_AT_TAIL */
    644     if (SCSI_PT_FLAGS_QUEUE_AT_HEAD & flags) {  /* favour AT_HEAD */
    645         ptp->io_hdr.flags |= BSG_FLAG_Q_AT_HEAD;
    646         ptp->io_hdr.flags &= ~BSG_FLAG_Q_AT_TAIL;
    647     } else if (SCSI_PT_FLAGS_QUEUE_AT_TAIL & flags) {
    648         ptp->io_hdr.flags |= BSG_FLAG_Q_AT_TAIL;
    649         ptp->io_hdr.flags &= ~BSG_FLAG_Q_AT_HEAD;
    650     }
    651 }
    652 
    653 /* N.B. Returns din_resid and ignores dout_resid */
    654 int
    655 get_scsi_pt_resid(const struct sg_pt_base * vp)
    656 {
    657     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    658 
    659     if (NULL == ptp)
    660         return 0;
    661     return ptp->nvme_direct ? 0 : ptp->io_hdr.din_resid;
    662 }
    663 
    664 int
    665 get_scsi_pt_status_response(const struct sg_pt_base * vp)
    666 {
    667     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    668 
    669     if (NULL == ptp)
    670         return 0;
    671     return (int)(ptp->nvme_direct ? ptp->nvme_status :
    672                                     ptp->io_hdr.device_status);
    673 }
    674 
    675 uint32_t
    676 get_pt_result(const struct sg_pt_base * vp)
    677 {
    678     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    679 
    680     if (NULL == ptp)
    681         return 0;
    682     return ptp->nvme_direct ? ptp->nvme_result :
    683                               ptp->io_hdr.device_status;
    684 }
    685 
    686 int
    687 get_scsi_pt_sense_len(const struct sg_pt_base * vp)
    688 {
    689     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    690 
    691     return ptp->io_hdr.response_len;
    692 }
    693 
    694 int
    695 get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
    696 {
    697     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    698 
    699     return ptp->io_hdr.duration;
    700 }
    701 
    702 int
    703 get_scsi_pt_transport_err(const struct sg_pt_base * vp)
    704 {
    705     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    706 
    707     return ptp->io_hdr.transport_status;
    708 }
    709 
    710 void
    711 set_scsi_pt_transport_err(struct sg_pt_base * vp, int err)
    712 {
    713     struct sg_pt_linux_scsi * ptp = &vp->impl;
    714 
    715     ptp->io_hdr.transport_status = err;
    716 }
    717 
    718 /* Returns b which will contain a null char terminated string (if
    719  * max_b_len > 0). Combined driver and transport (called "host" in Linux
    720  * kernel) statuses */
    721 char *
    722 get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len,
    723                               char * b)
    724 {
    725     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    726     int ds = ptp->io_hdr.driver_status;
    727     int hs = ptp->io_hdr.transport_status;
    728     int n, m;
    729     char * cp = b;
    730     int driv;
    731     const char * driv_cp = "invalid";
    732 
    733     if (max_b_len < 1)
    734         return b;
    735     m = max_b_len;
    736     n = 0;
    737     if (hs) {
    738         if ((hs < 0) || (hs >= LINUX_HOST_BYTES_SZ))
    739             n = snprintf(cp, m, "Host_status=0x%02x is invalid\n", hs);
    740         else
    741             n = snprintf(cp, m, "Host_status=0x%02x [%s]\n", hs,
    742                          linux_host_bytes[hs]);
    743     }
    744     m -= n;
    745     if (m < 1) {
    746         b[max_b_len - 1] = '\0';
    747         return b;
    748     }
    749     cp += n;
    750     driv = ds & SG_LIB_DRIVER_MASK;
    751     if (driv < LINUX_DRIVER_BYTES_SZ)
    752         driv_cp = linux_driver_bytes[driv];
    753 #if 0
    754     sugg = (ds & SG_LIB_SUGGEST_MASK) >> 4;
    755     if (sugg < LINUX_DRIVER_SUGGESTS_SZ)
    756         sugg_cp = linux_driver_suggests[sugg];
    757 #endif
    758     n = snprintf(cp, m, "Driver_status=0x%02x [%s]\n", ds, driv_cp);
    759     m -= n;
    760     if (m < 1)
    761         b[max_b_len - 1] = '\0';
    762     return b;
    763 }
    764 
    765 int
    766 get_scsi_pt_result_category(const struct sg_pt_base * vp)
    767 {
    768     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    769     int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK;
    770     int scsi_st = ptp->io_hdr.device_status & 0x7e;
    771 
    772     if (ptp->os_err)
    773         return SCSI_PT_RESULT_OS_ERR;
    774     else if (ptp->io_hdr.transport_status)
    775         return SCSI_PT_RESULT_TRANSPORT_ERR;
    776     else if (dr_st && (SG_LIB_DRIVER_SENSE != dr_st))
    777         return SCSI_PT_RESULT_TRANSPORT_ERR;
    778     else if ((SG_LIB_DRIVER_SENSE == dr_st) ||
    779              (SAM_STAT_CHECK_CONDITION == scsi_st) ||
    780              (SAM_STAT_COMMAND_TERMINATED == scsi_st))
    781         return SCSI_PT_RESULT_SENSE;
    782     else if (scsi_st)
    783         return SCSI_PT_RESULT_STATUS;
    784     else
    785         return SCSI_PT_RESULT_GOOD;
    786 }
    787 
    788 int
    789 get_scsi_pt_os_err(const struct sg_pt_base * vp)
    790 {
    791     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    792 
    793     return ptp->os_err;
    794 }
    795 
    796 char *
    797 get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
    798 {
    799     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    800     const char * cp;
    801 
    802     cp = safe_strerror(ptp->os_err);
    803     strncpy(b, cp, max_b_len);
    804     if ((int)strlen(cp) >= max_b_len)
    805         b[max_b_len - 1] = '\0';
    806     return b;
    807 }
    808 
    809 bool
    810 pt_device_is_nvme(const struct sg_pt_base * vp)
    811 {
    812     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    813 
    814     return ptp->is_nvme;
    815 }
    816 
    817 /* If a NVMe block device (which includes the NSID) handle is associated
    818  * with 'vp', then its NSID is returned (values range from 0x1 to
    819  * 0xffffffe). Otherwise 0 is returned. */
    820 uint32_t
    821 get_pt_nvme_nsid(const struct sg_pt_base * vp)
    822 {
    823     const struct sg_pt_linux_scsi * ptp = &vp->impl;
    824 
    825     return ptp->nvme_nsid;
    826 }
    827 
    828 /* Executes SCSI command using sg v3 interface */
    829 static int
    830 do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
    831               int verbose)
    832 {
    833     struct sg_io_hdr v3_hdr;
    834 
    835     memset(&v3_hdr, 0, sizeof(v3_hdr));
    836     /* convert v4 to v3 header */
    837     v3_hdr.interface_id = 'S';
    838     v3_hdr.dxfer_direction = SG_DXFER_NONE;
    839     v3_hdr.cmdp = (unsigned char *)(long)ptp->io_hdr.request;
    840     v3_hdr.cmd_len = (unsigned char)ptp->io_hdr.request_len;
    841     if (ptp->io_hdr.din_xfer_len > 0) {
    842         if (ptp->io_hdr.dout_xfer_len > 0) {
    843             if (verbose)
    844                 pr2ws("sgv3 doesn't support bidi\n");
    845             return SCSI_PT_DO_BAD_PARAMS;
    846         }
    847         v3_hdr.dxferp = (void *)(long)ptp->io_hdr.din_xferp;
    848         v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.din_xfer_len;
    849         v3_hdr.dxfer_direction =  SG_DXFER_FROM_DEV;
    850     } else if (ptp->io_hdr.dout_xfer_len > 0) {
    851         v3_hdr.dxferp = (void *)(long)ptp->io_hdr.dout_xferp;
    852         v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.dout_xfer_len;
    853         v3_hdr.dxfer_direction =  SG_DXFER_TO_DEV;
    854     }
    855     if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) {
    856         v3_hdr.sbp = (unsigned char *)(long)ptp->io_hdr.response;
    857         v3_hdr.mx_sb_len = (unsigned char)ptp->io_hdr.max_response_len;
    858     }
    859     v3_hdr.pack_id = (int)ptp->io_hdr.spare_in;
    860     if (BSG_FLAG_Q_AT_HEAD & ptp->io_hdr.flags)
    861         v3_hdr.flags |= SG_FLAG_Q_AT_HEAD;      /* favour AT_HEAD */
    862     else if (BSG_FLAG_Q_AT_TAIL & ptp->io_hdr.flags)
    863         v3_hdr.flags |= SG_FLAG_Q_AT_TAIL;
    864 
    865     if (NULL == v3_hdr.cmdp) {
    866         if (verbose)
    867             pr2ws("No SCSI command (cdb) given\n");
    868         return SCSI_PT_DO_BAD_PARAMS;
    869     }
    870     /* io_hdr.timeout is in milliseconds, if greater than zero */
    871     v3_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT);
    872     /* Finally do the v3 SG_IO ioctl */
    873     if (ioctl(fd, SG_IO, &v3_hdr) < 0) {
    874         ptp->os_err = errno;
    875         if (verbose > 1)
    876             pr2ws("ioctl(SG_IO v3) failed: %s (errno=%d)\n",
    877                   safe_strerror(ptp->os_err), ptp->os_err);
    878         return -ptp->os_err;
    879     }
    880     ptp->io_hdr.device_status = (__u32)v3_hdr.status;
    881     ptp->io_hdr.driver_status = (__u32)v3_hdr.driver_status;
    882     ptp->io_hdr.transport_status = (__u32)v3_hdr.host_status;
    883     ptp->io_hdr.response_len = (__u32)v3_hdr.sb_len_wr;
    884     ptp->io_hdr.duration = (__u32)v3_hdr.duration;
    885     ptp->io_hdr.din_resid = (__s32)v3_hdr.resid;
    886     /* v3_hdr.info not passed back since no mapping defined (yet) */
    887     return 0;
    888 }
    889 
    890 /* Executes SCSI command (or at least forwards it to lower layers).
    891  * Returns 0 for success, negative numbers are negated 'errno' values from
    892  * OS system calls. Positive return values are errors from this package. */
    893 int
    894 do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose)
    895 {
    896     int err;
    897     struct sg_pt_linux_scsi * ptp = &vp->impl;
    898     bool have_checked_for_type = (ptp->dev_fd >= 0);
    899 
    900     if (! sg_bsg_nvme_char_major_checked) {
    901         sg_bsg_nvme_char_major_checked = true;
    902         sg_find_bsg_nvme_char_major(verbose);
    903     }
    904     if (ptp->in_err) {
    905         if (verbose)
    906             pr2ws("Replicated or unused set_scsi_pt... functions\n");
    907         return SCSI_PT_DO_BAD_PARAMS;
    908     }
    909     if (fd >= 0) {
    910         if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) {
    911             if (verbose)
    912                 pr2ws("%s: file descriptor given to create() and here "
    913                       "differ\n", __func__);
    914             return SCSI_PT_DO_BAD_PARAMS;
    915         }
    916         ptp->dev_fd = fd;
    917     } else if (ptp->dev_fd < 0) {
    918         if (verbose)
    919             pr2ws("%s: invalid file descriptors\n", __func__);
    920         return SCSI_PT_DO_BAD_PARAMS;
    921     } else
    922         fd = ptp->dev_fd;
    923     if (! have_checked_for_type) {
    924         err = set_pt_file_handle(vp, ptp->dev_fd, verbose);
    925         if (err)
    926             return -ptp->os_err;
    927     }
    928     if (ptp->os_err)
    929         return -ptp->os_err;
    930     if (ptp->is_nvme)
    931         return sg_do_nvme_pt(vp, -1, time_secs, verbose);
    932     else if (sg_bsg_major <= 0)
    933         return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
    934     else if (ptp->is_bsg)
    935         ; /* drop through to sg v4 implementation */
    936     else
    937         return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
    938 
    939     if (! ptp->io_hdr.request) {
    940         if (verbose)
    941             pr2ws("No SCSI command (cdb) given (v4)\n");
    942         return SCSI_PT_DO_BAD_PARAMS;
    943     }
    944     /* io_hdr.timeout is in milliseconds */
    945     ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) :
    946                                              DEF_TIMEOUT);
    947 #if 0
    948     /* sense buffer already zeroed */
    949     if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) {
    950         void * p;
    951 
    952         p = (void *)(long)ptp->io_hdr.response;
    953         memset(p, 0, ptp->io_hdr.max_response_len);
    954     }
    955 #endif
    956     if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) {
    957         ptp->os_err = errno;
    958         if (verbose > 1)
    959             pr2ws("ioctl(SG_IO v4) failed: %s (errno=%d)\n",
    960                   safe_strerror(ptp->os_err), ptp->os_err);
    961         return -ptp->os_err;
    962     }
    963     return 0;
    964 }
    965