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