• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
pr2ws(const char * fmt,...)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
sg_find_bsg_nvme_char_major(int verbose)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
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)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
check_pt_file_handle(int dev_fd,const char * device_name,int verbose)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
scsi_pt_open_device(const char * device_name,bool read_only,int verbose)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
scsi_pt_open_flags(const char * device_name,int flags,int verbose)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
scsi_pt_close_device(int device_fd)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 *
construct_scsi_pt_obj_with_fd(int dev_fd,int verbose)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 *
construct_scsi_pt_obj()426 construct_scsi_pt_obj()
427 {
428     return construct_scsi_pt_obj_with_fd(-1 /* dev_fd */, 0 /* verbose */);
429 }
430 
431 void
destruct_scsi_pt_obj(struct sg_pt_base * vp)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
clear_scsi_pt_obj(struct sg_pt_base * vp)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
set_pt_file_handle(struct sg_pt_base * vp,int dev_fd,int verbose)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
get_pt_file_handle(const struct sg_pt_base * vp)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
set_scsi_pt_cdb(struct sg_pt_base * vp,const unsigned char * cdb,int cdb_len)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
set_scsi_pt_sense(struct sg_pt_base * vp,unsigned char * sense,int max_sense_len)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
set_scsi_pt_data_in(struct sg_pt_base * vp,unsigned char * dxferp,int dxfer_ilen)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
set_scsi_pt_data_out(struct sg_pt_base * vp,const unsigned char * dxferp,int dxfer_olen)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
set_pt_metadata_xfer(struct sg_pt_base * vp,unsigned char * dxferp,uint32_t dxfer_len,bool out_true)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
set_scsi_pt_packet_id(struct sg_pt_base * vp,int pack_id)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
set_scsi_pt_tag(struct sg_pt_base * vp,uint64_t tag)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
set_scsi_pt_task_management(struct sg_pt_base * vp,int tmf_code)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
set_scsi_pt_task_attr(struct sg_pt_base * vp,int attribute,int priority)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
set_scsi_pt_flags(struct sg_pt_base * vp,int flags)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
get_scsi_pt_resid(const struct sg_pt_base * vp)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
get_scsi_pt_status_response(const struct sg_pt_base * vp)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
get_pt_result(const struct sg_pt_base * vp)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
get_scsi_pt_sense_len(const struct sg_pt_base * vp)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
get_scsi_pt_duration_ms(const struct sg_pt_base * vp)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
get_scsi_pt_transport_err(const struct sg_pt_base * vp)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
set_scsi_pt_transport_err(struct sg_pt_base * vp,int err)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 *
get_scsi_pt_transport_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)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
get_scsi_pt_result_category(const struct sg_pt_base * vp)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
get_scsi_pt_os_err(const struct sg_pt_base * vp)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 *
get_scsi_pt_os_err_str(const struct sg_pt_base * vp,int max_b_len,char * b)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
pt_device_is_nvme(const struct sg_pt_base * vp)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
get_pt_nvme_nsid(const struct sg_pt_base * vp)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
do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp,int fd,int time_secs,int verbose)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
do_scsi_pt(struct sg_pt_base * vp,int fd,int time_secs,int verbose)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