• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2005-2021 Douglas Gilbert.
3  * All rights reserved.
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the BSD_LICENSE file.
6  *
7  * SPDX-License-Identifier: BSD-2-Clause
8  */
9 
10 /* sg_pt_linux version 1.54 20210923 */
11 
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdarg.h>
16 #include <stdbool.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <sys/stat.h>
24 #include <sys/sysmacros.h>      /* to define 'major' */
25 #ifndef major
26 #include <sys/types.h>
27 #endif
28 
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include <linux/major.h>
35 
36 #include "sg_pt.h"
37 #include "sg_lib.h"
38 #include "sg_linux_inc.h"
39 #include "sg_pt_linux.h"
40 #include "sg_pr2serr.h"
41 
42 
43 #ifdef major
44 #define SG_DEV_MAJOR major
45 #else
46 #ifdef HAVE_LINUX_KDEV_T_H
47 #include <linux/kdev_t.h>
48 #endif
49 #define SG_DEV_MAJOR MAJOR  /* MAJOR() macro faulty if > 255 minors */
50 #endif
51 
52 #ifndef BLOCK_EXT_MAJOR
53 #define BLOCK_EXT_MAJOR 259
54 #endif
55 
56 #define DEF_TIMEOUT 60000       /* 60,000 millisecs (60 seconds) */
57 
58 /* sg driver displayed format: [x]xyyzz --> [x]x.[y]y.zz */
59 #define SG_LINUX_SG_VER_V4_BASE 40000   /* lowest sg driver version with
60                                          * v4 interface */
61 #define SG_LINUX_SG_VER_V4_FULL 40030   /* lowest version with full v4
62                                          * interface */
63 
64 static const char * linux_host_bytes[] = {
65     "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
66     "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR",
67     "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR",
68     "DID_IMM_RETRY", "DID_REQUEUE" /* 0xd */,
69     "DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST",
70     "DID_TARGET_FAILURE" /* 0x10 */,
71     "DID_NEXUS_FAILURE (reservation conflict)",
72     "DID_ALLOC_FAILURE",
73     "DID_MEDIUM_ERROR",
74     "DID_TRANSPORT_MARGINAL",   /*0x14 */
75 };
76 
77 /* These where made obsolete around lk 5.12.0 . Only DRIVER_SENSE [0x8] is
78  * defined in scsi/sg.h for backward comaptibility */
79 static const char * linux_driver_bytes[] = {
80     "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA",
81     "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",
82     "DRIVER_SENSE"
83 };
84 
85 #if 0
86 
87 static const char * linux_driver_suggests[] = {
88     "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP",
89     "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN",
90     "SUGGEST_SENSE"
91 };
92 
93 #endif
94 
95 /*
96  * These defines are for constants that should be visible in the
97  * /usr/include/scsi directory (brought in by sg_linux_inc.h).
98  * Redefined and aliased here to decouple this code from
99  * sg_io_linux.h  N.B. the SUGGEST_* constants are no longer used.
100  */
101 #ifndef DRIVER_MASK
102 #define DRIVER_MASK 0x0f
103 #endif
104 #ifndef SUGGEST_MASK
105 #define SUGGEST_MASK 0xf0       /* Suggest mask is obsolete */
106 #endif
107 #ifndef DRIVER_SENSE
108 #define DRIVER_SENSE 0x08
109 #endif
110 #define SG_LIB_DRIVER_MASK      DRIVER_MASK
111 #define SG_LIB_SUGGEST_MASK     SUGGEST_MASK
112 #define SG_LIB_DRIVER_SENSE    DRIVER_SENSE
113 
114 bool sg_bsg_nvme_char_major_checked = false;
115 int sg_bsg_major = 0;
116 volatile int sg_nvme_char_major = 0;
117 
118 bool sg_checked_version_num = false;
119 int sg_driver_version_num = 0;
120 bool sg_duration_set_nano = false;
121 
122 long sg_lin_page_size = 4096;   /* default, overridden with correct value */
123 
124 
125 /* This function only needs to be called once (unless a NVMe controller
126  * can be hot-plugged into system in which case it should be called
127  * (again) after that event). */
128 void
sg_find_bsg_nvme_char_major(int verbose)129 sg_find_bsg_nvme_char_major(int verbose)
130 {
131     bool got_one = false;
132     int n;
133     const char * proc_devices = "/proc/devices";
134     char * cp;
135     FILE *fp;
136     char a[128];
137     char b[128];
138 
139     sg_lin_page_size = sysconf(_SC_PAGESIZE);
140     if (NULL == (fp = fopen(proc_devices, "r"))) {
141         if (verbose)
142             pr2ws("fopen %s failed: %s\n", proc_devices, strerror(errno));
143         return;
144     }
145     while ((cp = fgets(b, sizeof(b), fp))) {
146         if ((1 == sscanf(b, "%126s", a)) &&
147             (0 == memcmp(a, "Character", 9)))
148             break;
149     }
150     while (cp && (cp = fgets(b, sizeof(b), fp))) {
151         if (2 == sscanf(b, "%d %126s", &n, a)) {
152             if (0 == strcmp("bsg", a)) {
153                 sg_bsg_major = n;
154                 if (got_one)
155                     break;
156                 got_one = true;
157             } else if (0 == strcmp("nvme", a)) {
158                 sg_nvme_char_major = n;
159                 if (got_one)
160                     break;
161                 got_one = true;
162             }
163         } else
164             break;
165     }
166     if (verbose > 3) {
167         if (cp) {
168             if (sg_bsg_major > 0)
169                 pr2ws("found sg_bsg_major=%d\n", sg_bsg_major);
170             if (sg_nvme_char_major > 0)
171                 pr2ws("found sg_nvme_char_major=%d\n", sg_nvme_char_major);
172         } else
173             pr2ws("found no bsg not nvme char device in %s\n", proc_devices);
174     }
175     fclose(fp);
176 }
177 
178 /* Assumes that sg_find_bsg_nvme_char_major() has already been called. Returns
179  * true if dev_fd is a scsi generic pass-through device. If yields
180  * *is_nvme_p = true with *nsid_p = 0 then dev_fd is a NVMe char device.
181  * If yields *nsid_p > 0 then dev_fd is a NVMe block device. */
182 static bool
check_file_type(int dev_fd,struct stat * dev_statp,bool * is_bsg_p,bool * is_nvme_p,uint32_t * nsid_p,int * os_err_p,int verbose)183 check_file_type(int dev_fd, struct stat * dev_statp, bool * is_bsg_p,
184                 bool * is_nvme_p, uint32_t * nsid_p, int * os_err_p,
185                 int verbose)
186 {
187     bool is_nvme = false;
188     bool is_sg = false;
189     bool is_bsg = false;
190     bool is_block = false;
191     int os_err = 0;
192     int major_num;
193     uint32_t nsid = 0;          /* invalid NSID */
194 
195     if (dev_fd >= 0) {
196         if (fstat(dev_fd, dev_statp) < 0) {
197             os_err = errno;
198             if (verbose)
199                 pr2ws("%s: fstat() failed: %s (errno=%d)\n", __func__,
200                       safe_strerror(os_err), os_err);
201             goto skip_out;
202         }
203         major_num = (int)SG_DEV_MAJOR(dev_statp->st_rdev);
204         if (S_ISCHR(dev_statp->st_mode)) {
205             if (SCSI_GENERIC_MAJOR == major_num)
206                 is_sg = true;
207             else if (sg_bsg_major == major_num)
208                 is_bsg = true;
209             else if (sg_nvme_char_major == major_num)
210                 is_nvme = true;
211         } else if (S_ISBLK(dev_statp->st_mode)) {
212             is_block = true;
213             if (BLOCK_EXT_MAJOR == major_num) {
214                 is_nvme = true;
215                 nsid = ioctl(dev_fd, NVME_IOCTL_ID, NULL);
216                 if (SG_NVME_BROADCAST_NSID == nsid) {  /* means ioctl error */
217                     os_err = errno;
218                     if (verbose)
219                         pr2ws("%s: ioctl(NVME_IOCTL_ID) failed: %s "
220                               "(errno=%d)\n", __func__, safe_strerror(os_err),
221                               os_err);
222                 } else
223                     os_err = 0;
224             }
225         }
226     } else {
227         os_err = EBADF;
228         if (verbose)
229             pr2ws("%s: invalid file descriptor (%d)\n", __func__, dev_fd);
230     }
231 skip_out:
232     if (verbose > 3) {
233         pr2ws("%s: file descriptor is ", __func__);
234         if (is_sg)
235             pr2ws("sg device\n");
236         else if (is_bsg)
237             pr2ws("bsg device\n");
238         else if (is_nvme && (0 == nsid))
239             pr2ws("NVMe char device\n");
240         else if (is_nvme)
241             pr2ws("NVMe block device, nsid=%lld\n",
242                   ((uint32_t)-1 == nsid) ? -1LL : (long long)nsid);
243         else if (is_block)
244             pr2ws("block device\n");
245         else
246             pr2ws("undetermined device, could be regular file\n");
247     }
248     if (is_bsg_p)
249         *is_bsg_p = is_bsg;
250     if (is_nvme_p)
251         *is_nvme_p = is_nvme;
252     if (nsid_p)
253         *nsid_p = nsid;
254     if (os_err_p)
255         *os_err_p = os_err;
256     return is_sg;
257 }
258 
259 /* Assumes dev_fd is an "open" file handle associated with device_name. If
260  * the implementation (possibly for one OS) cannot determine from dev_fd if
261  * a SCSI or NVMe pass-through is referenced, then it might guess based on
262  * device_name. Returns 1 if SCSI generic pass-though device, returns 2 if
263  * secondary SCSI pass-through device (in Linux a bsg device); returns 3 is
264  * char NVMe device (i.e. no NSID); returns 4 if block NVMe device (includes
265  * NSID), or 0 if something else (e.g. ATA block device) or dev_fd < 0.
266  * If error, returns negated errno (operating system) value. */
267 int
check_pt_file_handle(int dev_fd,const char * device_name,int verbose)268 check_pt_file_handle(int dev_fd, const char * device_name, int verbose)
269 {
270     if (verbose > 4)
271         pr2ws("%s: dev_fd=%d, device_name: %s\n", __func__, dev_fd,
272               device_name);
273     /* Linux doesn't need device_name to determine which pass-through */
274     if (! sg_bsg_nvme_char_major_checked) {
275         sg_bsg_nvme_char_major_checked = true;
276         sg_find_bsg_nvme_char_major(verbose);
277     }
278     if (dev_fd >= 0) {
279         bool is_sg, is_bsg, is_nvme;
280         int err;
281         uint32_t nsid;
282         struct stat a_stat;
283 
284         is_sg = check_file_type(dev_fd, &a_stat, &is_bsg, &is_nvme, &nsid,
285                                 &err, verbose);
286         if (err)
287             return -err;
288         else if (is_sg)
289             return 1;
290         else if (is_bsg)
291             return 2;
292         else if (is_nvme && (0 == nsid))
293             return 3;
294         else if (is_nvme)
295             return 4;
296         else
297             return 0;
298     } else
299         return 0;
300 }
301 
302 /*
303  * We make a runtime decision whether to use the sg v3 interface or the sg
304  * v4 interface (currently exclusively used by the bsg driver). If all the
305  * following are true we use sg v4 which is only currently supported on bsg
306  * device nodes:
307  *   a) there is a bsg entry in the /proc/devices file
308  *   b) the device node given to scsi_pt_open() is a char device
309  *   c) the char major number of the device node given to scsi_pt_open()
310  *      matches the char major number of the bsg entry in /proc/devices
311  * Otherwise the sg v3 interface is used.
312  *
313  * Note that in either case we prepare the data in a sg v4 structure. If
314  * the runtime tests indicate that the v3 interface is needed then
315  * do_scsi_pt_v3() transfers the input data into a v3 structure and
316  * then the output data is transferred back into a sg v4 structure.
317  * That implementation detail could change in the future.
318  *
319  * [20120806] Only use MAJOR() macro in kdev_t.h if that header file is
320  * available and major() macro [N.B. lower case] is not available.
321  */
322 
323 
324 #ifdef major
325 #define SG_DEV_MAJOR major
326 #else
327 #ifdef HAVE_LINUX_KDEV_T_H
328 #include <linux/kdev_t.h>
329 #endif
330 #define SG_DEV_MAJOR MAJOR  /* MAJOR() macro faulty if > 255 minors */
331 #endif
332 
333 
334 /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed */
335 /* together. The 'flags' argument is advisory and may be ignored. */
336 /* Returns >= 0 if successful, otherwise returns negated errno. */
337 int
scsi_pt_open_flags(const char * device_name,int flags,int verbose)338 scsi_pt_open_flags(const char * device_name, int flags, int verbose)
339 {
340     int fd;
341 
342     if (! sg_bsg_nvme_char_major_checked) {
343         sg_bsg_nvme_char_major_checked = true;
344         sg_find_bsg_nvme_char_major(verbose);
345     }
346     if (verbose > 1) {
347         pr2ws("open %s with flags=0x%x\n", device_name, flags);
348     }
349     fd = open(device_name, flags);
350     if (fd < 0) {
351         fd = -errno;
352         if (verbose > 1)
353             pr2ws("%s: open(%s, 0x%x) failed: %s\n", __func__, device_name,
354                   flags, safe_strerror(-fd));
355     }
356     return fd;
357 }
358 
359 /* Returns >= 0 if successful. If error in Unix returns negated errno. */
360 int
scsi_pt_open_device(const char * device_name,bool read_only,int verbose)361 scsi_pt_open_device(const char * device_name, bool read_only, int verbose)
362 {
363     int oflags = O_NONBLOCK;
364 
365     oflags |= (read_only ? O_RDONLY : O_RDWR);
366     return scsi_pt_open_flags(device_name, oflags, verbose);
367 }
368 
369 /* Returns 0 if successful. If error in Unix returns negated errno. */
370 int
scsi_pt_close_device(int device_fd)371 scsi_pt_close_device(int device_fd)
372 {
373     int res;
374 
375     res = close(device_fd);
376     if (res < 0)
377         res = -errno;
378     return res;
379 }
380 
381 #if (HAVE_NVME && (! IGNORE_NVME))
382 static bool checked_ev_dsense = false;
383 static bool ev_dsense = false;
384 #endif
385 
386 
387 /* Caller should additionally call get_scsi_pt_os_err() after this call */
388 struct sg_pt_base *
construct_scsi_pt_obj_with_fd(int dev_fd,int verbose)389 construct_scsi_pt_obj_with_fd(int dev_fd, int verbose)
390 {
391     struct sg_pt_linux_scsi * ptp;
392 
393     ptp = (struct sg_pt_linux_scsi *)
394           calloc(1, sizeof(struct sg_pt_linux_scsi));
395     if (ptp) {
396         int err;
397 
398 #if (HAVE_NVME && (! IGNORE_NVME))
399         sntl_init_dev_stat(&ptp->dev_stat);
400         if (! checked_ev_dsense) {
401             ev_dsense = sg_get_initial_dsense();
402             checked_ev_dsense = true;
403         }
404         ptp->dev_stat.scsi_dsense = ev_dsense;
405 #endif
406         err = set_pt_file_handle((struct sg_pt_base *)ptp, dev_fd, verbose);
407         if ((0 == err) && (! ptp->is_nvme)) {
408             ptp->io_hdr.guard = 'Q';
409 #ifdef BSG_PROTOCOL_SCSI
410             ptp->io_hdr.protocol = BSG_PROTOCOL_SCSI;
411 #endif
412 #ifdef BSG_SUB_PROTOCOL_SCSI_CMD
413             ptp->io_hdr.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
414 #endif
415         }
416     } else if (verbose)
417         pr2ws("%s: calloc() failed, out of memory?\n", __func__);
418 
419     return (struct sg_pt_base *)ptp;
420 }
421 
422 struct sg_pt_base *
construct_scsi_pt_obj()423 construct_scsi_pt_obj()
424 {
425     return construct_scsi_pt_obj_with_fd(-1 /* dev_fd */, 0 /* verbose */);
426 }
427 
428 void
destruct_scsi_pt_obj(struct sg_pt_base * vp)429 destruct_scsi_pt_obj(struct sg_pt_base * vp)
430 {
431 
432     if (NULL == vp)
433         pr2ws(">>>>>>> Warning: %s called with NULL pointer\n", __func__);
434     else {
435         struct sg_pt_linux_scsi * ptp = &vp->impl;
436 
437         if (ptp->free_nvme_id_ctlp) {
438             free(ptp->free_nvme_id_ctlp);
439             ptp->free_nvme_id_ctlp = NULL;
440             ptp->nvme_id_ctlp = NULL;
441         }
442         if (vp)
443             free(vp);
444     }
445 }
446 
447 /* Remembers previous device file descriptor */
448 void
clear_scsi_pt_obj(struct sg_pt_base * vp)449 clear_scsi_pt_obj(struct sg_pt_base * vp)
450 {
451     struct sg_pt_linux_scsi * ptp = &vp->impl;
452 
453     if (ptp) {
454         bool is_sg, is_bsg, is_nvme;
455         int fd;
456         uint32_t nvme_nsid;
457         struct sg_sntl_dev_state_t dev_stat;
458 
459         fd = ptp->dev_fd;
460         is_sg = ptp->is_sg;
461         is_bsg = ptp->is_bsg;
462         is_nvme = ptp->is_nvme;
463         nvme_nsid = ptp->nvme_nsid;
464         dev_stat = ptp->dev_stat;
465         if (ptp->free_nvme_id_ctlp)
466             free(ptp->free_nvme_id_ctlp);
467         memset(ptp, 0, sizeof(struct sg_pt_linux_scsi));
468         ptp->io_hdr.guard = 'Q';
469 #ifdef BSG_PROTOCOL_SCSI
470         ptp->io_hdr.protocol = BSG_PROTOCOL_SCSI;
471 #endif
472 #ifdef BSG_SUB_PROTOCOL_SCSI_CMD
473         ptp->io_hdr.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
474 #endif
475         ptp->dev_fd = fd;
476         ptp->is_sg = is_sg;
477         ptp->is_bsg = is_bsg;
478         ptp->is_nvme = is_nvme;
479         ptp->nvme_our_sntl = false;
480         ptp->nvme_nsid = nvme_nsid;
481         ptp->dev_stat = dev_stat;
482     }
483 }
484 
485 void
partial_clear_scsi_pt_obj(struct sg_pt_base * vp)486 partial_clear_scsi_pt_obj(struct sg_pt_base * vp)
487 {
488     struct sg_pt_linux_scsi * ptp = &vp->impl;
489 
490     if (NULL == ptp)
491         return;
492     ptp->in_err = 0;
493     ptp->os_err = 0;
494     ptp->io_hdr.device_status = 0;
495     ptp->io_hdr.transport_status = 0;
496     ptp->io_hdr.driver_status = 0;
497     ptp->io_hdr.din_xferp = 0;
498     ptp->io_hdr.din_xfer_len = 0;
499     ptp->io_hdr.dout_xferp = 0;
500     ptp->io_hdr.dout_xfer_len = 0;
501     ptp->nvme_result = 0;
502 }
503 
504 #ifndef SG_SET_GET_EXTENDED
505 
506 /* If both sei_wr_mask and sei_rd_mask are 0, this ioctl does nothing */
507 struct sg_extended_info {
508     uint32_t   sei_wr_mask;    /* OR-ed SG_SEIM_* user->driver values */
509     uint32_t   sei_rd_mask;    /* OR-ed SG_SEIM_* driver->user values */
510     uint32_t   ctl_flags_wr_mask;      /* OR-ed SG_CTL_FLAGM_* values */
511     uint32_t   ctl_flags_rd_mask;      /* OR-ed SG_CTL_FLAGM_* values */
512     uint32_t   ctl_flags;      /* bit values OR-ed, see SG_CTL_FLAGM_* */
513     uint32_t   read_value;     /* write SG_SEIRV_*, read back related */
514 
515     uint32_t   reserved_sz;    /* data/sgl size of pre-allocated request */
516     uint32_t   tot_fd_thresh;  /* total data/sgat for this fd, 0: no limit */
517     uint32_t   minor_index;    /* rd: kernel's sg device minor number */
518     uint32_t   share_fd;       /* SHARE_FD and CHG_SHARE_FD use this */
519     uint32_t   sgat_elem_sz;   /* sgat element size (must be power of 2) */
520     uint8_t    pad_to_96[52];  /* pad so struct is 96 bytes long */
521 };
522 
523 #define SG_IOCTL_MAGIC_NUM 0x22
524 
525 #define SG_SET_GET_EXTENDED _IOWR(SG_IOCTL_MAGIC_NUM, 0x51,     \
526                                   struct sg_extended_info)
527 
528 #define SG_SEIM_CTL_FLAGS       0x1
529 
530 #define SG_CTL_FLAGM_TIME_IN_NS 0x1
531 
532 #endif
533 
534 /* Forget any previous dev_fd and install the one given. May attempt to
535  * find file type (e.g. if pass-though) from OS so there could be an error.
536  * Returns 0 for success or the same value as get_scsi_pt_os_err()
537  * will return. dev_fd should be >= 0 for a valid file handle or -1 . */
538 int
set_pt_file_handle(struct sg_pt_base * vp,int dev_fd,int verbose)539 set_pt_file_handle(struct sg_pt_base * vp, int dev_fd, int verbose)
540 {
541     struct sg_pt_linux_scsi * ptp = &vp->impl;
542     struct stat a_stat;
543 
544     if (! sg_bsg_nvme_char_major_checked) {
545         sg_bsg_nvme_char_major_checked = true;
546         sg_find_bsg_nvme_char_major(verbose);
547     }
548     ptp->dev_fd = dev_fd;
549     if (dev_fd >= 0) {
550         ptp->is_sg = check_file_type(dev_fd, &a_stat, &ptp->is_bsg,
551                                      &ptp->is_nvme, &ptp->nvme_nsid,
552                                      &ptp->os_err, verbose);
553         if (ptp->is_sg && (! sg_checked_version_num)) {
554             if (ioctl(dev_fd, SG_GET_VERSION_NUM, &ptp->sg_version) < 0) {
555                 ptp->sg_version = 0;
556                 if (verbose > 3)
557                     pr2ws("%s: ioctl(SG_GET_VERSION_NUM) failed: errno: %d "
558                           "[%s]\n", __func__, errno, safe_strerror(errno));
559             } else {    /* got version number */
560                 sg_driver_version_num = ptp->sg_version;
561                 sg_checked_version_num = true;
562             }
563             if (verbose > 4) {
564                 int ver = ptp->sg_version;
565 
566                 if (ptp->sg_version >= SG_LINUX_SG_VER_V4_BASE) {
567 #ifdef IGNORE_LINUX_SGV4
568                     pr2ws("%s: sg driver version %d.%02d.%02d but config "
569                           "override back to v3\n", __func__, ver / 10000,
570                           (ver / 100) % 100, ver % 100);
571 #else
572                     pr2ws("%s: sg driver version %d.%02d.%02d so choose v4\n",
573                           __func__, ver / 10000, (ver / 100) % 100,
574                           ver % 100);
575 #endif
576                 } else if (verbose > 5)
577                     pr2ws("%s: sg driver version %d.%02d.%02d so choose v3\n",
578                           __func__, ver / 10000, (ver / 100) % 100,
579                           ver % 100);
580             }
581         } else if (ptp->is_sg)
582             ptp->sg_version = sg_driver_version_num;
583 
584         if (ptp->is_sg && (ptp->sg_version >= SG_LINUX_SG_VER_V4_FULL) &&
585             getenv("SG3_UTILS_LINUX_NANO")) {
586             struct sg_extended_info sei;
587             struct sg_extended_info * seip = &sei;
588 
589             memset(seip, 0, sizeof(*seip));
590             /* try to override default of milliseconds */
591             seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
592             seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
593             seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
594             if (ioctl(dev_fd, SG_SET_GET_EXTENDED, seip) < 0) {
595                 if (verbose > 2)
596                     pr2ws("%s: unable to override milli --> nanoseconds: "
597                           "%s\n", __func__, safe_strerror(errno));
598             } else {
599                 if (! sg_duration_set_nano)
600                     sg_duration_set_nano = true;
601                 if (verbose > 5)
602                     pr2ws("%s: dev_fd=%d, succeeding in setting durations "
603                           "to nanoseconds\n", __func__, dev_fd);
604             }
605         } else if (ptp->is_sg && (ptp->sg_version >= SG_LINUX_SG_VER_V4_BASE)
606                    && getenv("SG3_UTILS_LINUX_NANO")) {
607             if (verbose > 2)
608                 pr2ws("%s: dev_fd=%d, ignored SG3_UTILS_LINUX_NANO\nbecause "
609                       "base version sg version 4 driver\n", __func__, dev_fd);
610         }
611     } else {
612         ptp->is_sg = false;
613         ptp->is_bsg = false;
614         ptp->is_nvme = false;
615         ptp->nvme_our_sntl = false;
616         ptp->nvme_nsid = 0;
617         ptp->os_err = 0;
618     }
619     return ptp->os_err;
620 }
621 
622 int
sg_linux_get_sg_version(const struct sg_pt_base * vp)623 sg_linux_get_sg_version(const struct sg_pt_base * vp)
624 {
625     const struct sg_pt_linux_scsi * ptp = &vp->impl;
626 
627     return ptp->sg_version;
628 }
629 
630 /* Valid file handles (which is the return value) are >= 0 . Returns -1
631  * if there is no valid file handle. */
632 int
get_pt_file_handle(const struct sg_pt_base * vp)633 get_pt_file_handle(const struct sg_pt_base * vp)
634 {
635     const struct sg_pt_linux_scsi * ptp = &vp->impl;
636 
637     return ptp->dev_fd;
638 }
639 
640 void
set_scsi_pt_cdb(struct sg_pt_base * vp,const uint8_t * cdb,int cdb_len)641 set_scsi_pt_cdb(struct sg_pt_base * vp, const uint8_t * cdb,
642                 int cdb_len)
643 {
644     struct sg_pt_linux_scsi * ptp = &vp->impl;
645 
646     ptp->io_hdr.request = (__u64)(sg_uintptr_t)cdb;
647     ptp->io_hdr.request_len = cdb_len;
648 }
649 
650 int
get_scsi_pt_cdb_len(const struct sg_pt_base * vp)651 get_scsi_pt_cdb_len(const struct sg_pt_base * vp)
652 {
653     const struct sg_pt_linux_scsi * ptp = &vp->impl;
654 
655     return ptp->io_hdr.request_len;
656 }
657 
658 uint8_t *
get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)659 get_scsi_pt_cdb_buf(const struct sg_pt_base * vp)
660 {
661     const struct sg_pt_linux_scsi * ptp = &vp->impl;
662 
663     return (uint8_t *)(sg_uintptr_t)ptp->io_hdr.request;
664 }
665 
666 void
set_scsi_pt_sense(struct sg_pt_base * vp,uint8_t * sense,int max_sense_len)667 set_scsi_pt_sense(struct sg_pt_base * vp, uint8_t * sense,
668                   int max_sense_len)
669 {
670     struct sg_pt_linux_scsi * ptp = &vp->impl;
671 
672     if (sense) {
673         if (max_sense_len > 0)
674             memset(sense, 0, max_sense_len);
675     }
676     ptp->io_hdr.response = (__u64)(sg_uintptr_t)sense;
677     ptp->io_hdr.max_response_len = max_sense_len;
678 }
679 
680 /* Setup for data transfer from device */
681 void
set_scsi_pt_data_in(struct sg_pt_base * vp,uint8_t * dxferp,int dxfer_ilen)682 set_scsi_pt_data_in(struct sg_pt_base * vp, uint8_t * dxferp,
683                     int dxfer_ilen)
684 {
685     struct sg_pt_linux_scsi * ptp = &vp->impl;
686 
687     if (ptp->io_hdr.din_xferp)
688         ++ptp->in_err;
689     if (dxfer_ilen > 0) {
690         ptp->io_hdr.din_xferp = (__u64)(sg_uintptr_t)dxferp;
691         ptp->io_hdr.din_xfer_len = dxfer_ilen;
692     }
693 }
694 
695 /* Setup for data transfer toward device */
696 void
set_scsi_pt_data_out(struct sg_pt_base * vp,const uint8_t * dxferp,int dxfer_olen)697 set_scsi_pt_data_out(struct sg_pt_base * vp, const uint8_t * dxferp,
698                      int dxfer_olen)
699 {
700     struct sg_pt_linux_scsi * ptp = &vp->impl;
701 
702     if (ptp->io_hdr.dout_xferp)
703         ++ptp->in_err;
704     if (dxfer_olen > 0) {
705         ptp->io_hdr.dout_xferp = (__u64)(sg_uintptr_t)dxferp;
706         ptp->io_hdr.dout_xfer_len = dxfer_olen;
707     }
708 }
709 
710 void
set_pt_metadata_xfer(struct sg_pt_base * vp,uint8_t * dxferp,uint32_t dxfer_len,bool out_true)711 set_pt_metadata_xfer(struct sg_pt_base * vp, uint8_t * dxferp,
712                      uint32_t dxfer_len, bool out_true)
713 {
714     struct sg_pt_linux_scsi * ptp = &vp->impl;
715 
716     if (dxfer_len > 0) {
717         ptp->mdxferp = dxferp;
718         ptp->mdxfer_len = dxfer_len;
719         ptp->mdxfer_out = out_true;
720     }
721 }
722 
723 void
set_scsi_pt_packet_id(struct sg_pt_base * vp,int pack_id)724 set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id)
725 {
726     struct sg_pt_linux_scsi * ptp = &vp->impl;
727 
728     ptp->io_hdr.request_extra = pack_id;        /* was placed in spare_in */
729 }
730 
731 void
set_scsi_pt_tag(struct sg_pt_base * vp,uint64_t tag)732 set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag)
733 {
734     struct sg_pt_linux_scsi * ptp = &vp->impl;
735 
736     ptp->io_hdr.request_tag = tag;
737 }
738 
739 /* Note that task management function codes are transport specific */
740 void
set_scsi_pt_task_management(struct sg_pt_base * vp,int tmf_code)741 set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code)
742 {
743     struct sg_pt_linux_scsi * ptp = &vp->impl;
744 
745     ptp->io_hdr.subprotocol = 1;        /* SCSI task management function */
746     ptp->tmf_request[0] = (uint8_t)tmf_code;      /* assume it fits */
747     ptp->io_hdr.request = (__u64)(sg_uintptr_t)(&(ptp->tmf_request[0]));
748     ptp->io_hdr.request_len = 1;
749 }
750 
751 void
set_scsi_pt_task_attr(struct sg_pt_base * vp,int attribute,int priority)752 set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority)
753 {
754     struct sg_pt_linux_scsi * ptp = &vp->impl;
755 
756     ptp->io_hdr.request_attr = attribute;
757     ptp->io_hdr.request_priority = priority;
758 }
759 
760 #ifndef BSG_FLAG_Q_AT_TAIL
761 #define BSG_FLAG_Q_AT_TAIL 0x10
762 #endif
763 #ifndef BSG_FLAG_Q_AT_HEAD
764 #define BSG_FLAG_Q_AT_HEAD 0x20
765 #endif
766 
767 /* Need this later if translated to v3 interface */
768 #ifndef SG_FLAG_Q_AT_TAIL
769 #define SG_FLAG_Q_AT_TAIL 0x10
770 #endif
771 #ifndef SG_FLAG_Q_AT_HEAD
772 #define SG_FLAG_Q_AT_HEAD 0x20
773 #endif
774 
775 void
set_scsi_pt_flags(struct sg_pt_base * vp,int flags)776 set_scsi_pt_flags(struct sg_pt_base * vp, int flags)
777 {
778     struct sg_pt_linux_scsi * ptp = &vp->impl;
779 
780     /* default action of bsg driver (sg v4) is QUEUE_AT_HEAD */
781     /* default action of block layer SG_IO ioctl is QUEUE_AT_TAIL */
782     if (SCSI_PT_FLAGS_QUEUE_AT_HEAD & flags) {  /* favour AT_HEAD */
783         ptp->io_hdr.flags |= BSG_FLAG_Q_AT_HEAD;
784         ptp->io_hdr.flags &= ~BSG_FLAG_Q_AT_TAIL;
785     } else if (SCSI_PT_FLAGS_QUEUE_AT_TAIL & flags) {
786         ptp->io_hdr.flags |= BSG_FLAG_Q_AT_TAIL;
787         ptp->io_hdr.flags &= ~BSG_FLAG_Q_AT_HEAD;
788     }
789 }
790 
791 /* If supported it is the number of bytes requested to transfer less the
792  * number actually transferred. This it typically important for data-in
793  * transfers. For data-out (only) transfers, the 'dout_req_len -
794  * dout_act_len' is returned. For bidi transfer the "din" residual is
795  * returned. */
796 /* N.B. Returns din_resid and ignores dout_resid */
797 int
get_scsi_pt_resid(const struct sg_pt_base * vp)798 get_scsi_pt_resid(const struct sg_pt_base * vp)
799 {
800     const struct sg_pt_linux_scsi * ptp = &vp->impl;
801 
802     if ((NULL == ptp) || (ptp->is_nvme && ! ptp->nvme_our_sntl))
803         return 0;
804     else if ((ptp->io_hdr.din_xfer_len > 0) &&
805              (ptp->io_hdr.dout_xfer_len > 0))
806         return ptp->io_hdr.din_resid;
807     else if (ptp->io_hdr.dout_xfer_len > 0)
808         return ptp->io_hdr.dout_resid;
809     return ptp->io_hdr.din_resid;
810 }
811 
812 void
get_pt_req_lengths(const struct sg_pt_base * vp,int * req_dinp,int * req_doutp)813 get_pt_req_lengths(const struct sg_pt_base * vp, int * req_dinp,
814                    int * req_doutp)
815 {
816     const struct sg_pt_linux_scsi * ptp = &vp->impl;
817 
818     if (req_dinp) {
819         if (ptp->io_hdr.din_xfer_len > 0)
820             *req_dinp = ptp->io_hdr.din_xfer_len;
821         else
822             *req_dinp = 0;
823     }
824     if (req_doutp) {
825         if (ptp->io_hdr.dout_xfer_len > 0)
826             *req_doutp = ptp->io_hdr.dout_xfer_len;
827         else
828             *req_doutp = 0;
829     }
830 }
831 
832 void
get_pt_actual_lengths(const struct sg_pt_base * vp,int * act_dinp,int * act_doutp)833 get_pt_actual_lengths(const struct sg_pt_base * vp, int * act_dinp,
834                       int * act_doutp)
835 {
836     const struct sg_pt_linux_scsi * ptp = &vp->impl;
837 
838     if (act_dinp) {
839         if (ptp->io_hdr.din_xfer_len > 0) {
840             int res = ptp->io_hdr.din_xfer_len - ptp->io_hdr.din_resid;
841 
842             *act_dinp = (res > 0) ? res : 0;
843         } else
844             *act_dinp = 0;
845     }
846     if (act_doutp) {
847         if (ptp->io_hdr.dout_xfer_len > 0)
848             *act_doutp = ptp->io_hdr.dout_xfer_len - ptp->io_hdr.dout_resid;
849         else
850             *act_doutp = 0;
851     }
852 }
853 
854 int
get_scsi_pt_status_response(const struct sg_pt_base * vp)855 get_scsi_pt_status_response(const struct sg_pt_base * vp)
856 {
857     const struct sg_pt_linux_scsi * ptp = &vp->impl;
858 
859     if (NULL == ptp)
860         return 0;
861     return (int)((ptp->is_nvme && ! ptp->nvme_our_sntl) ?
862                          ptp->nvme_status : ptp->io_hdr.device_status);
863 }
864 
865 uint32_t
get_pt_result(const struct sg_pt_base * vp)866 get_pt_result(const struct sg_pt_base * vp)
867 {
868     const struct sg_pt_linux_scsi * ptp = &vp->impl;
869 
870     if (NULL == ptp)
871         return 0;
872     return (ptp->is_nvme && ! ptp->nvme_our_sntl) ?
873                         ptp->nvme_result : ptp->io_hdr.device_status;
874 }
875 
876 int
get_scsi_pt_sense_len(const struct sg_pt_base * vp)877 get_scsi_pt_sense_len(const struct sg_pt_base * vp)
878 {
879     const struct sg_pt_linux_scsi * ptp = &vp->impl;
880 
881     return ptp->io_hdr.response_len;
882 }
883 
884 uint8_t *
get_scsi_pt_sense_buf(const struct sg_pt_base * vp)885 get_scsi_pt_sense_buf(const struct sg_pt_base * vp)
886 {
887     const struct sg_pt_linux_scsi * ptp = &vp->impl;
888 
889     return (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
890 }
891 
892 int
get_scsi_pt_duration_ms(const struct sg_pt_base * vp)893 get_scsi_pt_duration_ms(const struct sg_pt_base * vp)
894 {
895     const struct sg_pt_linux_scsi * ptp = &vp->impl;
896 
897     return sg_duration_set_nano ? (ptp->io_hdr.duration / 1000) :
898                                   ptp->io_hdr.duration;
899 }
900 
901 /* If not available return 0 otherwise return number of nanoseconds that the
902  * lower layers (and hardware) took to execute the command just completed. */
903 uint64_t
get_pt_duration_ns(const struct sg_pt_base * vp)904 get_pt_duration_ns(const struct sg_pt_base * vp)
905 {
906     const struct sg_pt_linux_scsi * ptp = &vp->impl;
907 
908     return sg_duration_set_nano ? (uint32_t)ptp->io_hdr.duration : 0;
909 }
910 
911 int
get_scsi_pt_transport_err(const struct sg_pt_base * vp)912 get_scsi_pt_transport_err(const struct sg_pt_base * vp)
913 {
914     const struct sg_pt_linux_scsi * ptp = &vp->impl;
915 
916     return ptp->io_hdr.transport_status;
917 }
918 
919 void
set_scsi_pt_transport_err(struct sg_pt_base * vp,int err)920 set_scsi_pt_transport_err(struct sg_pt_base * vp, int err)
921 {
922     struct sg_pt_linux_scsi * ptp = &vp->impl;
923 
924     ptp->io_hdr.transport_status = err;
925 }
926 
927 /* Returns b which will contain a null char terminated string (if
928  * max_b_len > 0). Combined driver and transport (called "host" in Linux
929  * kernel) statuses */
930 char *
get_scsi_pt_transport_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)931 get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len,
932                               char * b)
933 {
934     const struct sg_pt_linux_scsi * ptp = &vp->impl;
935     int ds = ptp->io_hdr.driver_status;
936     int hs = ptp->io_hdr.transport_status;
937     int n, m;
938     char * cp = b;
939     int driv;
940     const char * driv_cp = "invalid";
941 
942     if (max_b_len < 1)
943         return b;
944     m = max_b_len;
945     n = 0;
946     if (hs) {
947         if ((hs < 0) || (hs >= (int)SG_ARRAY_SIZE(linux_host_bytes)))
948             n = snprintf(cp, m, "Host_status=0x%02x is invalid\n", hs);
949         else
950             n = snprintf(cp, m, "Host_status=0x%02x [%s]\n", hs,
951                          linux_host_bytes[hs]);
952     }
953     m -= n;
954     if (m < 1) {
955         b[max_b_len - 1] = '\0';
956         return b;
957     }
958     cp += n;
959     if (ds) {
960         driv = ds & SG_LIB_DRIVER_MASK;
961         if (driv < (int)SG_ARRAY_SIZE(linux_driver_bytes))
962             driv_cp = linux_driver_bytes[driv];
963         n = snprintf(cp, m, "Driver_status=0x%02x [%s]\n", ds, driv_cp);
964         m -= n;
965     }
966     if (m < 1)
967         b[max_b_len - 1] = '\0';
968     return b;
969 }
970 
971 int
get_scsi_pt_result_category(const struct sg_pt_base * vp)972 get_scsi_pt_result_category(const struct sg_pt_base * vp)
973 {
974     const struct sg_pt_linux_scsi * ptp = &vp->impl;
975     int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK;
976     int scsi_st = ptp->io_hdr.device_status & 0x7e;
977 
978     if (ptp->os_err)
979         return SCSI_PT_RESULT_OS_ERR;
980     else if (ptp->io_hdr.transport_status)
981         return SCSI_PT_RESULT_TRANSPORT_ERR;
982     else if (dr_st && (SG_LIB_DRIVER_SENSE != dr_st))
983         return SCSI_PT_RESULT_TRANSPORT_ERR;
984     else if ((SG_LIB_DRIVER_SENSE == dr_st) ||
985              (SAM_STAT_CHECK_CONDITION == scsi_st) ||
986              (SAM_STAT_COMMAND_TERMINATED == scsi_st))
987         return SCSI_PT_RESULT_SENSE;
988     else if (scsi_st)
989         return SCSI_PT_RESULT_STATUS;
990     else
991         return SCSI_PT_RESULT_GOOD;
992 }
993 
994 int
get_scsi_pt_os_err(const struct sg_pt_base * vp)995 get_scsi_pt_os_err(const struct sg_pt_base * vp)
996 {
997     const struct sg_pt_linux_scsi * ptp = &vp->impl;
998 
999     return ptp->os_err;
1000 }
1001 
1002 char *
get_scsi_pt_os_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)1003 get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b)
1004 {
1005     const struct sg_pt_linux_scsi * ptp = &vp->impl;
1006     const char * cp;
1007 
1008     cp = safe_strerror(ptp->os_err);
1009     strncpy(b, cp, max_b_len);
1010     if ((int)strlen(cp) >= max_b_len)
1011         b[max_b_len - 1] = '\0';
1012     return b;
1013 }
1014 
1015 bool
pt_device_is_nvme(const struct sg_pt_base * vp)1016 pt_device_is_nvme(const struct sg_pt_base * vp)
1017 {
1018     const struct sg_pt_linux_scsi * ptp = &vp->impl;
1019 
1020     return ptp->is_nvme;
1021 }
1022 
1023 /* If a NVMe block device (which includes the NSID) handle is associated
1024  * with 'vp', then its NSID is returned (values range from 0x1 to
1025  * 0xffffffe). Otherwise 0 is returned. */
1026 uint32_t
get_pt_nvme_nsid(const struct sg_pt_base * vp)1027 get_pt_nvme_nsid(const struct sg_pt_base * vp)
1028 {
1029     const struct sg_pt_linux_scsi * ptp = &vp->impl;
1030 
1031     return ptp->nvme_nsid;
1032 }
1033 
1034 /* Executes SCSI command using sg v3 interface */
1035 static int
do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp,int fd,int time_secs,int verbose)1036 do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
1037               int verbose)
1038 {
1039     struct sg_io_hdr v3_hdr;
1040 
1041     memset(&v3_hdr, 0, sizeof(v3_hdr));
1042     /* convert v4 to v3 header */
1043     v3_hdr.interface_id = 'S';
1044     v3_hdr.dxfer_direction = SG_DXFER_NONE;
1045     v3_hdr.cmdp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.request;
1046     v3_hdr.cmd_len = (uint8_t)ptp->io_hdr.request_len;
1047     if (ptp->io_hdr.din_xfer_len > 0) {
1048         if (ptp->io_hdr.dout_xfer_len > 0) {
1049             if (verbose)
1050                 pr2ws("sgv3 doesn't support bidi\n");
1051             return SCSI_PT_DO_BAD_PARAMS;
1052         }
1053         v3_hdr.dxferp = (void *)(long)ptp->io_hdr.din_xferp;
1054         v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.din_xfer_len;
1055         v3_hdr.dxfer_direction =  SG_DXFER_FROM_DEV;
1056     } else if (ptp->io_hdr.dout_xfer_len > 0) {
1057         v3_hdr.dxferp = (void *)(long)ptp->io_hdr.dout_xferp;
1058         v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.dout_xfer_len;
1059         v3_hdr.dxfer_direction =  SG_DXFER_TO_DEV;
1060     }
1061     if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) {
1062         v3_hdr.sbp = (uint8_t *)(sg_uintptr_t)ptp->io_hdr.response;
1063         v3_hdr.mx_sb_len = (uint8_t)ptp->io_hdr.max_response_len;
1064     }
1065     v3_hdr.pack_id = (int)ptp->io_hdr.request_extra;
1066     if (BSG_FLAG_Q_AT_HEAD & ptp->io_hdr.flags)
1067         v3_hdr.flags |= SG_FLAG_Q_AT_HEAD;      /* favour AT_HEAD */
1068     else if (BSG_FLAG_Q_AT_TAIL & ptp->io_hdr.flags)
1069         v3_hdr.flags |= SG_FLAG_Q_AT_TAIL;
1070 
1071     if (NULL == v3_hdr.cmdp) {
1072         if (verbose)
1073             pr2ws("No SCSI command (cdb) given [v3]\n");
1074         return SCSI_PT_DO_BAD_PARAMS;
1075     }
1076     /* io_hdr.timeout is in milliseconds, if greater than zero */
1077     v3_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT);
1078     /* Finally do the v3 SG_IO ioctl */
1079     if (ioctl(fd, SG_IO, &v3_hdr) < 0) {
1080         ptp->os_err = errno;
1081         if (verbose > 1)
1082             pr2ws("ioctl(SG_IO v3) failed: %s (errno=%d)\n",
1083                   safe_strerror(ptp->os_err), ptp->os_err);
1084         return -ptp->os_err;
1085     }
1086     ptp->io_hdr.device_status = (__u32)v3_hdr.status;
1087     ptp->io_hdr.driver_status = (__u32)v3_hdr.driver_status;
1088     ptp->io_hdr.transport_status = (__u32)v3_hdr.host_status;
1089     ptp->io_hdr.response_len = (__u32)v3_hdr.sb_len_wr;
1090     ptp->io_hdr.duration = (__u32)v3_hdr.duration;
1091     ptp->io_hdr.din_resid = (__s32)v3_hdr.resid;
1092     /* v3_hdr.info not passed back since no mapping defined (yet) */
1093     return 0;
1094 }
1095 
1096 /* Executes SCSI command using sg v4 interface */
1097 static int
do_scsi_pt_v4(struct sg_pt_linux_scsi * ptp,int fd,int time_secs,int verbose)1098 do_scsi_pt_v4(struct sg_pt_linux_scsi * ptp, int fd, int time_secs,
1099               int verbose)
1100 {
1101     if (0 == ptp->io_hdr.request) {
1102         if (verbose)
1103             pr2ws("No SCSI command (cdb) given [v4]\n");
1104         return SCSI_PT_DO_BAD_PARAMS;
1105     }
1106     /* io_hdr.timeout is in milliseconds, if greater than zero */
1107     ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT);
1108     if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) {
1109         ptp->os_err = errno;
1110         if (verbose > 1)
1111             pr2ws("ioctl(SG_IO v4) failed: %s (errno=%d)\n",
1112                   safe_strerror(ptp->os_err), ptp->os_err);
1113         return -ptp->os_err;
1114     }
1115     return 0;
1116 }
1117 
1118 /* Executes SCSI command (or at least forwards it to lower layers).
1119  * Returns 0 for success, negative numbers are negated 'errno' values from
1120  * OS system calls. Positive return values are errors from this package. */
1121 int
do_scsi_pt(struct sg_pt_base * vp,int fd,int time_secs,int verbose)1122 do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose)
1123 {
1124     struct sg_pt_linux_scsi * ptp = &vp->impl;
1125     bool have_checked_for_type = (ptp->dev_fd >= 0);
1126 
1127     if (! sg_bsg_nvme_char_major_checked) {
1128         sg_bsg_nvme_char_major_checked = true;
1129         sg_find_bsg_nvme_char_major(verbose);
1130     }
1131     if (ptp->in_err) {
1132         if (verbose)
1133             pr2ws("Replicated or unused set_scsi_pt... functions\n");
1134         return SCSI_PT_DO_BAD_PARAMS;
1135     }
1136     if (fd >= 0) {
1137         if ((ptp->dev_fd >= 0) && (fd != ptp->dev_fd)) {
1138             if (verbose)
1139                 pr2ws("%s: file descriptor given to create() and here "
1140                       "differ\n", __func__);
1141             return SCSI_PT_DO_BAD_PARAMS;
1142         }
1143         ptp->dev_fd = fd;
1144     } else if (ptp->dev_fd < 0) {
1145         if (verbose)
1146             pr2ws("%s: invalid file descriptors\n", __func__);
1147         return SCSI_PT_DO_BAD_PARAMS;
1148     } else
1149         fd = ptp->dev_fd;
1150     if (! have_checked_for_type) {
1151         int err = set_pt_file_handle(vp, ptp->dev_fd, verbose);
1152 
1153         if (err)
1154             return -ptp->os_err;
1155     }
1156     if (ptp->os_err)
1157         return -ptp->os_err;
1158     if (verbose > 5)
1159         pr2ws("%s:  is_nvme=%d, is_sg=%d, is_bsg=%d\n", __func__,
1160               (int)ptp->is_nvme, (int)ptp->is_sg, (int)ptp->is_bsg);
1161     if (ptp->is_nvme)
1162         return sg_do_nvme_pt(vp, -1, time_secs, verbose);
1163     else if (ptp->is_sg) {
1164 #ifdef IGNORE_LINUX_SGV4
1165         return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
1166 #else
1167         if (ptp->sg_version >= SG_LINUX_SG_VER_V4_BASE)
1168             return do_scsi_pt_v4(ptp, fd, time_secs, verbose);
1169         else
1170             return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
1171 #endif
1172     } else if (sg_bsg_major <= 0)
1173         return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
1174     else if (ptp->is_bsg)
1175         return do_scsi_pt_v4(ptp, fd, time_secs, verbose);
1176     else
1177         return do_scsi_pt_v3(ptp, fd, time_secs, verbose);
1178 
1179     pr2ws("%s: Should never reach this point\n", __func__);
1180     return 0;
1181 }
1182