xref: /aosp_15_r20/external/sg3_utils/testing/sg_tst_ioctl.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  *  Copyright (C) 2018-2022 D. Gilbert
3*44704f69SBart Van Assche  *  This program is free software; you can redistribute it and/or modify
4*44704f69SBart Van Assche  *  it under the terms of the GNU General Public License as published by
5*44704f69SBart Van Assche  *  the Free Software Foundation; either version 2, or (at your option)
6*44704f69SBart Van Assche  *  any later version.
7*44704f69SBart Van Assche  *
8*44704f69SBart Van Assche  * SPDX-License-Identifier: BSD-2-Clause
9*44704f69SBart Van Assche  *
10*44704f69SBart Van Assche  * Invocation: See usage() function below.
11*44704f69SBart Van Assche  *
12*44704f69SBart Van Assche  */
13*44704f69SBart Van Assche 
14*44704f69SBart Van Assche #include <unistd.h>
15*44704f69SBart Van Assche #include <fcntl.h>
16*44704f69SBart Van Assche #include <stdio.h>
17*44704f69SBart Van Assche #include <stdlib.h>
18*44704f69SBart Van Assche #include <stdarg.h>
19*44704f69SBart Van Assche #include <stdbool.h>
20*44704f69SBart Van Assche #include <ctype.h>
21*44704f69SBart Van Assche #include <string.h>
22*44704f69SBart Van Assche #include <errno.h>
23*44704f69SBart Van Assche #include <time.h>
24*44704f69SBart Van Assche #include <sys/ioctl.h>
25*44704f69SBart Van Assche #include <sys/types.h>
26*44704f69SBart Van Assche #include <sys/stat.h>
27*44704f69SBart Van Assche #include <sys/utsname.h>
28*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
29*44704f69SBart Van Assche #include <inttypes.h>
30*44704f69SBart Van Assche 
31*44704f69SBart Van Assche #include <sys/socket.h> /* For passing fd_s via Unix sockets */
32*44704f69SBart Van Assche 
33*44704f69SBart Van Assche #ifndef HAVE_LINUX_SG_V4_HDR
34*44704f69SBart Van Assche 
35*44704f69SBart Van Assche /* Kernel uapi header contain __user decorations on user space pointers
36*44704f69SBart Van Assche  * to indicate they are unsafe in the kernel space. However glibc takes
37*44704f69SBart Van Assche  * all those __user decorations out from headers in /usr/include/linux .
38*44704f69SBart Van Assche  * So to stop compile errors when directly importing include/uapi/scsi/sg.h
39*44704f69SBart Van Assche  * undef __user before doing that include. */
40*44704f69SBart Van Assche #define __user
41*44704f69SBart Van Assche 
42*44704f69SBart Van Assche /* Want to block the original sg.h header from also being included. That
43*44704f69SBart Van Assche  * causes lots of multiple definition errors. This will only work if this
44*44704f69SBart Van Assche  * header is included _before_ the original sg.h header.  */
45*44704f69SBart Van Assche #define _SCSI_GENERIC_H         /* original kernel header guard */
46*44704f69SBart Van Assche #define _SCSI_SG_H              /* glibc header guard */
47*44704f69SBart Van Assche 
48*44704f69SBart Van Assche #include "uapi_sg.h"    /* local copy of include/uapi/scsi/sg.h */
49*44704f69SBart Van Assche 
50*44704f69SBart Van Assche #else
51*44704f69SBart Van Assche #define __user
52*44704f69SBart Van Assche #endif  /* end of: ifndef HAVE_LINUX_SG_V4_HDR */
53*44704f69SBart Van Assche 
54*44704f69SBart Van Assche #include "sg_lib.h"
55*44704f69SBart Van Assche #include "sg_io_linux.h"
56*44704f69SBart Van Assche #include "sg_linux_inc.h"
57*44704f69SBart Van Assche #include "sg_pr2serr.h"
58*44704f69SBart Van Assche 
59*44704f69SBart Van Assche /* This program tests ioctl() calls added and modified in version 4.0 and
60*44704f69SBart Van Assche  * later of the Linux sg driver.  */
61*44704f69SBart Van Assche 
62*44704f69SBart Van Assche 
63*44704f69SBart Van Assche static const char * version_str = "Version: 1.21  20220202";
64*44704f69SBart Van Assche 
65*44704f69SBart Van Assche #define INQ_REPLY_LEN 128
66*44704f69SBart Van Assche #define INQ_CMD_LEN 6
67*44704f69SBart Van Assche #define SDIAG_CMD_LEN 6
68*44704f69SBart Van Assche #define SENSE_BUFFER_LEN 96
69*44704f69SBart Van Assche 
70*44704f69SBart Van Assche #define EBUFF_SZ 512
71*44704f69SBart Van Assche 
72*44704f69SBart Van Assche #ifndef SG_FLAG_Q_AT_TAIL
73*44704f69SBart Van Assche #define SG_FLAG_Q_AT_TAIL 0x10
74*44704f69SBart Van Assche #endif
75*44704f69SBart Van Assche 
76*44704f69SBart Van Assche #ifndef SG_FLAG_Q_AT_HEAD
77*44704f69SBart Van Assche #define SG_FLAG_Q_AT_HEAD 0x20
78*44704f69SBart Van Assche #endif
79*44704f69SBart Van Assche 
80*44704f69SBart Van Assche #define DEF_Q_LEN 16    /* max in sg v3 and earlier */
81*44704f69SBart Van Assche #define MAX_Q_LEN 512
82*44704f69SBart Van Assche 
83*44704f69SBart Van Assche #define DEF_RESERVE_BUFF_SZ (256 * 1024)
84*44704f69SBart Van Assche 
85*44704f69SBart Van Assche static bool create_time = false;
86*44704f69SBart Van Assche static bool is_parent = false;
87*44704f69SBart Van Assche static bool do_fork = false;
88*44704f69SBart Van Assche static bool ioctl_only = false;
89*44704f69SBart Van Assche static bool more_async = false;
90*44704f69SBart Van Assche static bool no_duration = false;
91*44704f69SBart Van Assche static bool q_at_tail = false;
92*44704f69SBart Van Assche static bool write_only = false;
93*44704f69SBart Van Assche static bool mrq_immed = false;  /* if set, also sets mrq_iosubmit */
94*44704f69SBart Van Assche static bool mrq_half_immed = false;
95*44704f69SBart Van Assche static bool mrq_iosubmit = false;
96*44704f69SBart Van Assche static bool show_size_value = false;
97*44704f69SBart Van Assche static bool do_v3_only = false;
98*44704f69SBart Van Assche 
99*44704f69SBart Van Assche static int childs_pid = 0;
100*44704f69SBart Van Assche static int iterator_test = -1;
101*44704f69SBart Van Assche static int object_walk_test = -1;
102*44704f69SBart Van Assche static int sg_drv_ver_num = 0;
103*44704f69SBart Van Assche static int q_len = DEF_Q_LEN;
104*44704f69SBart Van Assche static int sleep_secs = 0;
105*44704f69SBart Van Assche static int reserve_buff_sz = DEF_RESERVE_BUFF_SZ;
106*44704f69SBart Van Assche static int num_mrqs = 0;
107*44704f69SBart Van Assche static int num_sgnw = 0;
108*44704f69SBart Van Assche static int dname_current = 0;
109*44704f69SBart Van Assche static int dname_last = 0;
110*44704f69SBart Van Assche static int dname_pos = 0;
111*44704f69SBart Van Assche static int verbose = 0;
112*44704f69SBart Van Assche 
113*44704f69SBart Van Assche static const char * relative_cp = "";
114*44704f69SBart Van Assche static char * file_name = NULL;
115*44704f69SBart Van Assche 
116*44704f69SBart Van Assche 
117*44704f69SBart Van Assche static void
usage(void)118*44704f69SBart Van Assche usage(void)
119*44704f69SBart Van Assche {
120*44704f69SBart Van Assche     printf("Usage: sg_tst_ioctl [-3] [-c] [-f] [-h] [-I=0|1] [-J=0|1] "
121*44704f69SBart Van Assche            "[-l=Q_LEN]\n"
122*44704f69SBart Van Assche            "                    [-m=MRQS[,I|S]] [-M] [-n] [-o] [-r=SZ] "
123*44704f69SBart Van Assche            "[-s=SEC]\n"
124*44704f69SBart Van Assche            "                    [-S] [-t] [-T=NUM] [-v] [-V] [-w]\n"
125*44704f69SBart Van Assche            "                    <sg_device>[-<num>] [<sg_device2>]\n"
126*44704f69SBart Van Assche            " where:\n"
127*44704f69SBart Van Assche            "      -3      use sg v3 interface (def: sg v4 if available)\n"
128*44704f69SBart Van Assche            "      -c      timestamp when sg driver created <sg_device>\n"
129*44704f69SBart Van Assche            "      -f      fork and test share between processes\n"
130*44704f69SBart Van Assche            "      -h      help: print usage message then exit\n"
131*44704f69SBart Van Assche            "      -I=0|1    iterator test of mid-level; 0: unlocked, 1: "
132*44704f69SBart Van Assche            "locked\n"
133*44704f69SBart Van Assche            "                does test -T=NUM times, outputs duration\n"
134*44704f69SBart Van Assche            "      -J=0|1    object walk up then 2 lookups; 0: no logging; "
135*44704f69SBart Van Assche            "1: log\n"
136*44704f69SBart Van Assche            "                up-scan once per 1000 iterations\n"
137*44704f69SBart Van Assche            "      -l=Q_LEN    queue length, between 1 and 511 (def: 16)\n"
138*44704f69SBart Van Assche            "      -m=MRQS[,I|S]    test multi-req, MRQS number to do; if "
139*44704f69SBart Van Assche            "the letter\n"
140*44704f69SBart Van Assche            "                     'I' is appended after a comma, then do "
141*44704f69SBart Van Assche            "IMMED mrq;\n"
142*44704f69SBart Van Assche            "                     'i' IMMED on submission, non-IMMED on "
143*44704f69SBart Van Assche            "receive;\n"
144*44704f69SBart Van Assche            "                     'S' is appended, then use "
145*44704f69SBart Van Assche            "ioctl(SG_IOSUBMIT)\n"
146*44704f69SBart Van Assche            "      -M      set 'more async' flag\n"
147*44704f69SBart Van Assche            "      -n      do not calculate per command duration (def: do)\n"
148*44704f69SBart Van Assche            "      -o      ioctls only, then exit\n"
149*44704f69SBart Van Assche            "      -r=SZ     reserve buffer size in KB (def: 256 --> 256 "
150*44704f69SBart Van Assche            "KB)\n"
151*44704f69SBart Van Assche            "      -s=SEC    sleep between writes and reads (def: 0)\n"
152*44704f69SBart Van Assche            "      -S        size of interface structures plus ioctl "
153*44704f69SBart Van Assche            "values\n"
154*44704f69SBart Van Assche            "      -t    queue_at_tail (def: q_at_head)\n"
155*44704f69SBart Van Assche            "      -T=NUM    time overhead of NUM invocations of\n"
156*44704f69SBart Van Assche            "                ioctl(SG_GET_NUM_WAITING); then exit\n"
157*44704f69SBart Van Assche            "      -v    increase verbosity of output\n"
158*44704f69SBart Van Assche            "      -V    print version string then exit\n"
159*44704f69SBart Van Assche            "      -w    write (submit) only then exit\n\n");
160*44704f69SBart Van Assche     printf("There are various groups of options for different tests. The "
161*44704f69SBart Van Assche            "get_num_waiting\ngroup needs '-T=NUM' given. When '-I=0|1' is "
162*44704f69SBart Van Assche            "also given then an object tree\niterator test is done NUM "
163*44704f69SBart Van Assche            "times. If instead '-J=0|1' is given then an\nobject tree "
164*44704f69SBart Van Assche            "traversal (up/down) is done 10,000 times (and NUM is\n"
165*44704f69SBart Van Assche            "ignored).\n"
166*44704f69SBart Van Assche           );
167*44704f69SBart Van Assche }
168*44704f69SBart Van Assche 
169*44704f69SBart Van Assche static void
timespec_add(const struct timespec * lhs_p,const struct timespec * rhs_p,struct timespec * res_p)170*44704f69SBart Van Assche timespec_add(const struct timespec *lhs_p, const struct timespec *rhs_p,
171*44704f69SBart Van Assche               struct timespec *res_p)
172*44704f69SBart Van Assche {
173*44704f69SBart Van Assche     if ((lhs_p->tv_nsec + rhs_p->tv_nsec) > 1000000000L) {
174*44704f69SBart Van Assche         res_p->tv_sec = lhs_p->tv_sec + rhs_p->tv_sec + 1;
175*44704f69SBart Van Assche         res_p->tv_nsec = lhs_p->tv_nsec + rhs_p->tv_nsec - 1000000000L;
176*44704f69SBart Van Assche     } else {
177*44704f69SBart Van Assche         res_p->tv_sec = lhs_p->tv_sec + rhs_p->tv_sec;
178*44704f69SBart Van Assche         res_p->tv_nsec = lhs_p->tv_nsec + rhs_p->tv_nsec;
179*44704f69SBart Van Assche     }
180*44704f69SBart Van Assche }
181*44704f69SBart Van Assche 
182*44704f69SBart Van Assche static void
timespec_diff(const struct timespec * lhs_p,const struct timespec * rhs_p,struct timespec * res_p)183*44704f69SBart Van Assche timespec_diff(const struct timespec *lhs_p, const struct timespec *rhs_p,
184*44704f69SBart Van Assche               struct timespec *res_p)
185*44704f69SBart Van Assche {
186*44704f69SBart Van Assche     if ((lhs_p->tv_nsec - rhs_p->tv_nsec) < 0) {
187*44704f69SBart Van Assche         res_p->tv_sec = lhs_p->tv_sec - rhs_p->tv_sec - 1;
188*44704f69SBart Van Assche         res_p->tv_nsec = lhs_p->tv_nsec - rhs_p->tv_nsec + 1000000000L;
189*44704f69SBart Van Assche     } else {
190*44704f69SBart Van Assche         res_p->tv_sec = lhs_p->tv_sec - rhs_p->tv_sec;
191*44704f69SBart Van Assche         res_p->tv_nsec = lhs_p->tv_nsec - rhs_p->tv_nsec;
192*44704f69SBart Van Assche     }
193*44704f69SBart Van Assche }
194*44704f69SBart Van Assche 
195*44704f69SBart Van Assche /* Returns 0 on success. */
timespec2str(char * buf,unsigned int len,struct timespec * ts)196*44704f69SBart Van Assche int timespec2str(char *buf, unsigned int len, struct timespec *ts)
197*44704f69SBart Van Assche {
198*44704f69SBart Van Assche     int ret;
199*44704f69SBart Van Assche     struct tm t;
200*44704f69SBart Van Assche 
201*44704f69SBart Van Assche     tzset();
202*44704f69SBart Van Assche     if (localtime_r(&(ts->tv_sec), &t) == NULL)
203*44704f69SBart Van Assche         return 1;
204*44704f69SBart Van Assche 
205*44704f69SBart Van Assche     ret = strftime(buf, len, "%F %T", &t);
206*44704f69SBart Van Assche     if (ret == 0)
207*44704f69SBart Van Assche         return 2;
208*44704f69SBart Van Assche     len -= ret - 1;
209*44704f69SBart Van Assche 
210*44704f69SBart Van Assche     ret = snprintf(&buf[strlen(buf)], len, ".%09ld", ts->tv_nsec);
211*44704f69SBart Van Assche     if (ret >= (int)len)
212*44704f69SBart Van Assche         return 3;
213*44704f69SBart Van Assche     return 0;
214*44704f69SBart Van Assche }
215*44704f69SBart Van Assche 
216*44704f69SBart Van Assche /* This function taken from Keith Parkard's blog dated 20121005 */
217*44704f69SBart Van Assche static ssize_t
sock_fd_write(int sock,const void * buf,ssize_t buflen,int fd)218*44704f69SBart Van Assche sock_fd_write(int sock, const void *buf, ssize_t buflen, int fd)
219*44704f69SBart Van Assche {
220*44704f69SBart Van Assche     ssize_t     size;
221*44704f69SBart Van Assche     struct msghdr   msg;
222*44704f69SBart Van Assche     struct iovec    iov;
223*44704f69SBart Van Assche     union {
224*44704f69SBart Van Assche         struct cmsghdr  cmsghdr;
225*44704f69SBart Van Assche         char        control[CMSG_SPACE(sizeof (int))];
226*44704f69SBart Van Assche     } cmsgu;
227*44704f69SBart Van Assche     struct cmsghdr  *cmsg;
228*44704f69SBart Van Assche 
229*44704f69SBart Van Assche     iov.iov_base = (void *)buf; /* OS shouldn't write back in this */
230*44704f69SBart Van Assche     iov.iov_len = buflen;
231*44704f69SBart Van Assche 
232*44704f69SBart Van Assche     msg.msg_name = NULL;
233*44704f69SBart Van Assche     msg.msg_namelen = 0;
234*44704f69SBart Van Assche     msg.msg_iov = &iov;
235*44704f69SBart Van Assche     msg.msg_iovlen = 1;
236*44704f69SBart Van Assche 
237*44704f69SBart Van Assche     if (fd != -1) {
238*44704f69SBart Van Assche         msg.msg_control = cmsgu.control;
239*44704f69SBart Van Assche         msg.msg_controllen = sizeof(cmsgu.control);
240*44704f69SBart Van Assche 
241*44704f69SBart Van Assche         cmsg = CMSG_FIRSTHDR(&msg);
242*44704f69SBart Van Assche         cmsg->cmsg_len = CMSG_LEN(sizeof (int));
243*44704f69SBart Van Assche         cmsg->cmsg_level = SOL_SOCKET;
244*44704f69SBart Van Assche         cmsg->cmsg_type = SCM_RIGHTS;
245*44704f69SBart Van Assche 
246*44704f69SBart Van Assche         printf ("passing fd %d\n", fd);
247*44704f69SBart Van Assche         *((int *) CMSG_DATA(cmsg)) = fd;
248*44704f69SBart Van Assche     } else {
249*44704f69SBart Van Assche         msg.msg_control = NULL;
250*44704f69SBart Van Assche         msg.msg_controllen = 0;
251*44704f69SBart Van Assche         printf ("not passing fd\n");
252*44704f69SBart Van Assche     }
253*44704f69SBart Van Assche 
254*44704f69SBart Van Assche     size = sendmsg(sock, &msg, 0);
255*44704f69SBart Van Assche 
256*44704f69SBart Van Assche     if (size < 0)
257*44704f69SBart Van Assche         perror ("sendmsg");
258*44704f69SBart Van Assche     return size;
259*44704f69SBart Van Assche }
260*44704f69SBart Van Assche 
261*44704f69SBart Van Assche /* This function taken from Keith Parkard's blog dated 2101205 */
262*44704f69SBart Van Assche static ssize_t
sock_fd_read(int sock,void * buf,ssize_t bufsize,int * fd)263*44704f69SBart Van Assche sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
264*44704f69SBart Van Assche {
265*44704f69SBart Van Assche     ssize_t     size;
266*44704f69SBart Van Assche 
267*44704f69SBart Van Assche     if (fd) {
268*44704f69SBart Van Assche         struct msghdr   msg;
269*44704f69SBart Van Assche         struct iovec    iov;
270*44704f69SBart Van Assche         union {
271*44704f69SBart Van Assche             struct cmsghdr  cmsghdr;
272*44704f69SBart Van Assche             char        control[CMSG_SPACE(sizeof (int))];
273*44704f69SBart Van Assche         } cmsgu;
274*44704f69SBart Van Assche         struct cmsghdr  *cmsg;
275*44704f69SBart Van Assche 
276*44704f69SBart Van Assche         iov.iov_base = buf;
277*44704f69SBart Van Assche         iov.iov_len = bufsize;
278*44704f69SBart Van Assche 
279*44704f69SBart Van Assche         msg.msg_name = NULL;
280*44704f69SBart Van Assche         msg.msg_namelen = 0;
281*44704f69SBart Van Assche         msg.msg_iov = &iov;
282*44704f69SBart Van Assche         msg.msg_iovlen = 1;
283*44704f69SBart Van Assche         msg.msg_control = cmsgu.control;
284*44704f69SBart Van Assche         msg.msg_controllen = sizeof(cmsgu.control);
285*44704f69SBart Van Assche         size = recvmsg (sock, &msg, 0);
286*44704f69SBart Van Assche         if (size < 0) {
287*44704f69SBart Van Assche             perror ("recvmsg");
288*44704f69SBart Van Assche             exit(1);
289*44704f69SBart Van Assche         }
290*44704f69SBart Van Assche         cmsg = CMSG_FIRSTHDR(&msg);
291*44704f69SBart Van Assche         if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
292*44704f69SBart Van Assche             if (cmsg->cmsg_level != SOL_SOCKET) {
293*44704f69SBart Van Assche                 fprintf (stderr, "invalid cmsg_level %d\n",
294*44704f69SBart Van Assche                      cmsg->cmsg_level);
295*44704f69SBart Van Assche                 exit(1);
296*44704f69SBart Van Assche             }
297*44704f69SBart Van Assche             if (cmsg->cmsg_type != SCM_RIGHTS) {
298*44704f69SBart Van Assche                 fprintf (stderr, "invalid cmsg_type %d\n",
299*44704f69SBart Van Assche                      cmsg->cmsg_type);
300*44704f69SBart Van Assche                 exit(1);
301*44704f69SBart Van Assche             }
302*44704f69SBart Van Assche 
303*44704f69SBart Van Assche             *fd = *((int *) CMSG_DATA(cmsg));
304*44704f69SBart Van Assche             printf ("received fd %d\n", *fd);
305*44704f69SBart Van Assche         } else
306*44704f69SBart Van Assche             *fd = -1;
307*44704f69SBart Van Assche     } else {
308*44704f69SBart Van Assche         size = read (sock, buf, bufsize);
309*44704f69SBart Van Assche         if (size < 0) {
310*44704f69SBart Van Assche             perror("read");
311*44704f69SBart Van Assche             exit(1);
312*44704f69SBart Van Assche         }
313*44704f69SBart Van Assche     }
314*44704f69SBart Van Assche     return size;
315*44704f69SBart Van Assche }
316*44704f69SBart Van Assche 
317*44704f69SBart Van Assche static void
set_more_async(int fd,bool more_asy,bool no_dur)318*44704f69SBart Van Assche set_more_async(int fd, bool more_asy, bool no_dur)
319*44704f69SBart Van Assche {
320*44704f69SBart Van Assche     if (sg_drv_ver_num > 40030) {
321*44704f69SBart Van Assche         struct sg_extended_info sei;
322*44704f69SBart Van Assche         struct sg_extended_info * seip;
323*44704f69SBart Van Assche 
324*44704f69SBart Van Assche         seip = &sei;
325*44704f69SBart Van Assche         memset(seip, 0, sizeof(*seip));
326*44704f69SBart Van Assche         seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
327*44704f69SBart Van Assche         seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
328*44704f69SBart Van Assche         if (more_asy) {
329*44704f69SBart Van Assche            seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC;
330*44704f69SBart Van Assche            seip->ctl_flags = SG_CTL_FLAGM_MORE_ASYNC;
331*44704f69SBart Van Assche         }
332*44704f69SBart Van Assche         if (no_dur) {
333*44704f69SBart Van Assche             seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION;
334*44704f69SBart Van Assche             seip->ctl_flags = SG_CTL_FLAGM_NO_DURATION;
335*44704f69SBart Van Assche         }
336*44704f69SBart Van Assche         if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
337*44704f69SBart Van Assche             pr2serr("ioctl(SG_SET_GET_EXTENDED, MORE_ASYNC(|NO_DUR)) failed, "
338*44704f69SBart Van Assche                     "errno=%d %s\n", errno, strerror(errno));
339*44704f69SBart Van Assche             return;
340*44704f69SBart Van Assche         }
341*44704f69SBart Van Assche     } else
342*44704f69SBart Van Assche         pr2serr("sg driver too old for ioctl(SG_SET_GET_EXTENDED)\n");
343*44704f69SBart Van Assche }
344*44704f69SBart Van Assche 
345*44704f69SBart Van Assche static void
pr_create_dev_time(int sg_fd,const char * dev_name)346*44704f69SBart Van Assche pr_create_dev_time(int sg_fd, const char * dev_name)
347*44704f69SBart Van Assche {
348*44704f69SBart Van Assche     uint32_t u;
349*44704f69SBart Van Assche     uint64_t l;
350*44704f69SBart Van Assche     struct sg_extended_info sei;
351*44704f69SBart Van Assche     struct sg_extended_info * seip;
352*44704f69SBart Van Assche     struct timespec time_up, realtime, boottime, createtime, tmp;
353*44704f69SBart Van Assche     char b[64];
354*44704f69SBart Van Assche 
355*44704f69SBart Van Assche     seip = &sei;
356*44704f69SBart Van Assche         memset(seip, 0, sizeof(*seip));
357*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_READ_VAL;
358*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_READ_VAL;
359*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_DEV_TS_LOWER;
360*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
361*44704f69SBart Van Assche         pr2serr("%s: ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n",
362*44704f69SBart Van Assche                 __func__, errno, strerror(errno));
363*44704f69SBart Van Assche         return;
364*44704f69SBart Van Assche     }
365*44704f69SBart Van Assche     u = seip->read_value;
366*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_DEV_TS_UPPER;
367*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
368*44704f69SBart Van Assche         pr2serr("%s: ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n",
369*44704f69SBart Van Assche                 __func__, errno, strerror(errno));
370*44704f69SBart Van Assche         return;
371*44704f69SBart Van Assche     }
372*44704f69SBart Van Assche     l = seip->read_value;
373*44704f69SBart Van Assche     l <<= 32;
374*44704f69SBart Van Assche     l |= u;
375*44704f69SBart Van Assche     time_up.tv_sec = l / 1000000000UL;
376*44704f69SBart Van Assche     time_up.tv_nsec = l % 1000000000UL;
377*44704f69SBart Van Assche     /* printf("create time nanoseconds=%" PRIu64 "\n", l); */
378*44704f69SBart Van Assche     if (clock_gettime(CLOCK_REALTIME, &realtime) < 0) {
379*44704f69SBart Van Assche         pr2serr("%s: clock_gettime(CLOCK_REALTIME) failed, errno=%d %s\n",
380*44704f69SBart Van Assche                 __func__, errno, strerror(errno));
381*44704f69SBart Van Assche         return;
382*44704f69SBart Van Assche     }
383*44704f69SBart Van Assche     if (clock_gettime(CLOCK_BOOTTIME, &boottime) < 0) {
384*44704f69SBart Van Assche         pr2serr("%s: clock_gettime(CLOCK_REALTIME) failed, errno=%d %s\n",
385*44704f69SBart Van Assche                 __func__, errno, strerror(errno));
386*44704f69SBart Van Assche         return;
387*44704f69SBart Van Assche     }
388*44704f69SBart Van Assche     timespec_diff(&realtime, &boottime, &tmp);
389*44704f69SBart Van Assche     timespec_add(&tmp, &time_up, &createtime);
390*44704f69SBart Van Assche #if 0
391*44704f69SBart Van Assche     printf("real time: %ld,%ld\n", realtime.tv_sec, realtime.tv_nsec);
392*44704f69SBart Van Assche     printf("boot time: %ld,%ld\n", boottime.tv_sec, boottime.tv_nsec);
393*44704f69SBart Van Assche     printf("time up: %ld,%ld\n", time_up.tv_sec, time_up.tv_nsec);
394*44704f69SBart Van Assche     printf("create time: %ld,%ld\n", createtime.tv_sec, createtime.tv_nsec);
395*44704f69SBart Van Assche #endif
396*44704f69SBart Van Assche     timespec2str(b, sizeof(b), &createtime);
397*44704f69SBart Van Assche     printf("Create time of %s was %s\n", dev_name, b);
398*44704f69SBart Van Assche }
399*44704f69SBart Van Assche 
400*44704f69SBart Van Assche static int
tst_extended_ioctl(const char * fnp,int sg_fd,const char * fn2p,int sg_fd2,int sock,const char * cp)401*44704f69SBart Van Assche tst_extended_ioctl(const char * fnp, int sg_fd, const char * fn2p, int sg_fd2,
402*44704f69SBart Van Assche                    int sock, const char * cp)
403*44704f69SBart Van Assche {
404*44704f69SBart Van Assche     uint32_t cflags;
405*44704f69SBart Van Assche     struct sg_extended_info sei;
406*44704f69SBart Van Assche     struct sg_extended_info * seip;
407*44704f69SBart Van Assche 
408*44704f69SBart Van Assche     seip = &sei;
409*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
410*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_RESERVED_SIZE;
411*44704f69SBart Van Assche     seip->reserved_sz = reserve_buff_sz;
412*44704f69SBart Van Assche     seip->sgat_elem_sz = 64 * 1024;
413*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_RESERVED_SIZE;
414*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_TOT_FD_THRESH;
415*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
416*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */
417*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_MINOR_INDEX;
418*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ;
419*44704f69SBart Van Assche     seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
420*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS;
421*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_OTHER_OPENS;
422*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_ORPHANS;
423*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_Q_TAIL;
424*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_IS_SHARE;
425*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_IS_READ_SIDE;
426*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_UNSHARE;
427*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_READ_SIDE_FINI;
428*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_READ_SIDE_ERR;
429*44704f69SBart Van Assche     seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION;
430*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_NO_DURATION;
431*44704f69SBart Van Assche     seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
432*44704f69SBart Van Assche     seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION;
433*44704f69SBart Van Assche 
434*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
435*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
436*44704f69SBart Van Assche                 strerror(errno));
437*44704f69SBart Van Assche         return 1;
438*44704f69SBart Van Assche     }
439*44704f69SBart Van Assche #if 1
440*44704f69SBart Van Assche     printf("%sSG_SET_GET_EXTENDED ioctl ok\n", cp);
441*44704f69SBart Van Assche     if (SG_SEIM_RESERVED_SIZE & seip->sei_rd_mask)
442*44704f69SBart Van Assche         printf("  %sreserved size: %u\n", cp, seip->reserved_sz);
443*44704f69SBart Van Assche     if (SG_SEIM_MINOR_INDEX & seip->sei_rd_mask)
444*44704f69SBart Van Assche         printf("  %sminor index: %u\n", cp, seip->minor_index);
445*44704f69SBart Van Assche     if (SG_SEIM_TOT_FD_THRESH & seip->sei_rd_mask)
446*44704f69SBart Van Assche         printf("  %stot_fd_thresh: %u\n", cp, seip->tot_fd_thresh);
447*44704f69SBart Van Assche     if ((SG_SEIM_CTL_FLAGS & seip->sei_rd_mask) ||
448*44704f69SBart Van Assche          (SG_SEIM_CTL_FLAGS & seip->sei_wr_mask)) {
449*44704f69SBart Van Assche         cflags = seip->ctl_flags;
450*44704f69SBart Van Assche         if (SG_CTL_FLAGM_TIME_IN_NS & seip->ctl_flags_rd_mask)
451*44704f69SBart Van Assche             printf("  %sTIME_IN_NS: %s\n", cp,
452*44704f69SBart Van Assche                    (SG_CTL_FLAGM_TIME_IN_NS & cflags) ? "true" : "false");
453*44704f69SBart Van Assche         if (SG_CTL_FLAGM_OTHER_OPENS & seip->ctl_flags_rd_mask)
454*44704f69SBart Van Assche             printf("  %sOTHER_OPENS: %s\n", cp,
455*44704f69SBart Van Assche                    (SG_CTL_FLAGM_OTHER_OPENS & cflags) ? "true" : "false");
456*44704f69SBart Van Assche         if (SG_CTL_FLAGM_ORPHANS & seip->ctl_flags_rd_mask)
457*44704f69SBart Van Assche             printf("  %sORPHANS: %s\n", cp,
458*44704f69SBart Van Assche                    (SG_CTL_FLAGM_ORPHANS & cflags) ? "true" : "false");
459*44704f69SBart Van Assche         if (SG_CTL_FLAGM_Q_TAIL & seip->ctl_flags_rd_mask)
460*44704f69SBart Van Assche             printf("  %sQ_TAIL: %s\n", cp,
461*44704f69SBart Van Assche                    (SG_CTL_FLAGM_Q_TAIL & cflags) ? "true" : "false");
462*44704f69SBart Van Assche         if (SG_CTL_FLAGM_IS_SHARE & seip->ctl_flags_rd_mask)
463*44704f69SBart Van Assche             printf("  %sIS_SHARE: %s\n", cp,
464*44704f69SBart Van Assche                    (SG_CTL_FLAGM_IS_SHARE & cflags) ? "true" : "false");
465*44704f69SBart Van Assche         if (SG_CTL_FLAGM_IS_READ_SIDE & seip->ctl_flags_rd_mask)
466*44704f69SBart Van Assche             printf("  %sIS_READ_SIDE: %s\n", cp,
467*44704f69SBart Van Assche                    (SG_CTL_FLAGM_IS_READ_SIDE & cflags) ? "true" : "false");
468*44704f69SBart Van Assche         if (SG_CTL_FLAGM_UNSHARE & seip->ctl_flags_rd_mask)
469*44704f69SBart Van Assche             printf("  %sUNSHARE: %s\n", cp,
470*44704f69SBart Van Assche                    (SG_CTL_FLAGM_UNSHARE & cflags) ? "true" : "false");
471*44704f69SBart Van Assche         if (SG_CTL_FLAGM_READ_SIDE_FINI & seip->ctl_flags_rd_mask)
472*44704f69SBart Van Assche             printf("  %sREAD_SIDE_FINI: %s\n", cp,
473*44704f69SBart Van Assche                    (SG_CTL_FLAGM_READ_SIDE_FINI & cflags) ? "true" : "false");
474*44704f69SBart Van Assche         if (SG_CTL_FLAGM_READ_SIDE_ERR & seip->ctl_flags_rd_mask)
475*44704f69SBart Van Assche             printf("  %sREAD_SIDE_ERR: %s\n", cp,
476*44704f69SBart Van Assche                    (SG_CTL_FLAGM_READ_SIDE_ERR & cflags) ? "true" : "false");
477*44704f69SBart Van Assche         if (SG_CTL_FLAGM_NO_DURATION & seip->ctl_flags_rd_mask)
478*44704f69SBart Van Assche             printf("  %sNO_DURATION: %s\n", cp,
479*44704f69SBart Van Assche                    (SG_CTL_FLAGM_NO_DURATION & cflags) ? "true" : "false");
480*44704f69SBart Van Assche     }
481*44704f69SBart Van Assche     if (SG_SEIM_MINOR_INDEX & seip->sei_rd_mask)
482*44704f69SBart Van Assche         printf("  %sminor_index: %u\n", cp, seip->minor_index);
483*44704f69SBart Van Assche     printf("\n");
484*44704f69SBart Van Assche #endif
485*44704f69SBart Van Assche 
486*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
487*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_READ_VAL;
488*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_READ_VAL;
489*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_INT_MASK;
490*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
491*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
492*44704f69SBart Van Assche                 strerror(errno));
493*44704f69SBart Van Assche         return 1;
494*44704f69SBart Van Assche     }
495*44704f69SBart Van Assche     printf("  %sread_value[SG_SEIRV_INT_MASK]= %u\n", cp, seip->read_value);
496*44704f69SBart Van Assche 
497*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
498*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_READ_VAL;
499*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_READ_VAL;
500*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_BOOL_MASK;
501*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
502*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
503*44704f69SBart Van Assche                 strerror(errno));
504*44704f69SBart Van Assche         return 1;
505*44704f69SBart Van Assche     }
506*44704f69SBart Van Assche     printf("  %sread_value[SG_SEIRV_BOOL_MASK]= %u\n", cp, seip->read_value);
507*44704f69SBart Van Assche 
508*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
509*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_READ_VAL;
510*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_READ_VAL;
511*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_VERS_NUM;
512*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
513*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
514*44704f69SBart Van Assche                 strerror(errno));
515*44704f69SBart Van Assche         return 1;
516*44704f69SBart Van Assche     }
517*44704f69SBart Van Assche     printf("  %sread_value[SG_SEIRV_VERS_NUM]= %u\n", cp, seip->read_value);
518*44704f69SBart Van Assche 
519*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
520*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_READ_VAL;
521*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_READ_VAL;
522*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_INACT_RQS;
523*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
524*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
525*44704f69SBart Van Assche                 strerror(errno));
526*44704f69SBart Van Assche         return 1;
527*44704f69SBart Van Assche     }
528*44704f69SBart Van Assche     printf("  %sread_value[SG_SEIRV_INACT_RQS]= %u\n", cp, seip->read_value);
529*44704f69SBart Van Assche 
530*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
531*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_READ_VAL;
532*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_READ_VAL;
533*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_DEV_INACT_RQS;
534*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
535*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
536*44704f69SBart Van Assche                 strerror(errno));
537*44704f69SBart Van Assche         return 1;
538*44704f69SBart Van Assche     }
539*44704f69SBart Van Assche     printf("  %sread_value[SG_SEIRV_DEV_INACT_RQS]= %u\n", cp,
540*44704f69SBart Van Assche            seip->read_value);
541*44704f69SBart Van Assche 
542*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
543*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_READ_VAL;
544*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_READ_VAL;
545*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_SUBMITTED;
546*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
547*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
548*44704f69SBart Van Assche                 strerror(errno));
549*44704f69SBart Van Assche         return 1;
550*44704f69SBart Van Assche     }
551*44704f69SBart Van Assche     printf("  %sread_value[SG_SEIRV_SUBMITTED]= %u\n", cp, seip->read_value);
552*44704f69SBart Van Assche 
553*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
554*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_READ_VAL;
555*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_READ_VAL;
556*44704f69SBart Van Assche     seip->read_value = SG_SEIRV_DEV_SUBMITTED;
557*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
558*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
559*44704f69SBart Van Assche                 strerror(errno));
560*44704f69SBart Van Assche         return 1;
561*44704f69SBart Van Assche     }
562*44704f69SBart Van Assche     printf("  %sread_value[SG_SEIRV_DEV_SUBMITTED]= %u\n", cp,
563*44704f69SBart Van Assche            seip->read_value);
564*44704f69SBart Van Assche 
565*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
566*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_SHARE_FD;
567*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_SHARE_FD;
568*44704f69SBart Van Assche #if 1
569*44704f69SBart Van Assche     seip->share_fd = sg_fd2;
570*44704f69SBart Van Assche #else
571*44704f69SBart Van Assche     seip->share_fd = sg_fd;
572*44704f69SBart Van Assche #endif
573*44704f69SBart Van Assche     if (do_fork && is_parent)
574*44704f69SBart Van Assche         goto bypass_share;
575*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
576*44704f69SBart Van Assche         pr2serr("%sioctl(SG_SET_GET_EXTENDED) shared_fd=%d, failed errno=%d "
577*44704f69SBart Van Assche                 "%s\n", cp, sg_fd2, errno, strerror(errno));
578*44704f69SBart Van Assche     }
579*44704f69SBart Van Assche     printf("  %sshare successful, read back previous shared_fd= %d\n", cp,
580*44704f69SBart Van Assche            (int)seip->share_fd);
581*44704f69SBart Van Assche bypass_share:
582*44704f69SBart Van Assche 
583*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_TRANSFORM, NULL) < 0)
584*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_TRANSFORM) fail expected, errno=%d %s\n",
585*44704f69SBart Van Assche                 errno, strerror(errno));
586*44704f69SBart Van Assche     else
587*44704f69SBart Van Assche         printf("%sSG_GET_TRANSFORM okay (does nothing)\n", cp);
588*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_TRANSFORM, NULL) < 0)
589*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_TRANSFORM) fail expected, errno=%d %s\n",
590*44704f69SBart Van Assche                 errno, strerror(errno));
591*44704f69SBart Van Assche     else
592*44704f69SBart Van Assche         printf("%sSG_SET_TRANSFORM okay (does nothing)\n", cp);
593*44704f69SBart Van Assche     printf("\n");
594*44704f69SBart Van Assche 
595*44704f69SBart Van Assche     /* test sending a sg file descriptor between 2 processes using UNIX
596*44704f69SBart Van Assche      * sockets */
597*44704f69SBart Van Assche     if (do_fork && is_parent && fnp && (sock >= 0)) { /* master/READ side */
598*44704f69SBart Van Assche         int res;
599*44704f69SBart Van Assche         int fd_ma = open(fnp, O_RDWR);
600*44704f69SBart Van Assche 
601*44704f69SBart Van Assche         if (fd_ma < 0) {
602*44704f69SBart Van Assche             pr2serr("%s: opening %s failed: %s\n", __func__, fnp,
603*44704f69SBart Van Assche                     strerror(errno));
604*44704f69SBart Van Assche             return 1;
605*44704f69SBart Van Assche         }
606*44704f69SBart Van Assche         res = sock_fd_write(sock, "boo", 4, fd_ma);
607*44704f69SBart Van Assche         if (res < 0)
608*44704f69SBart Van Assche             pr2serr("%s: sock_fd_write() failed\n", __func__);
609*44704f69SBart Van Assche         else
610*44704f69SBart Van Assche             printf("%s: sock_fd_write() returned: %d\n", __func__, res);
611*44704f69SBart Van Assche     } else if (do_fork && !is_parent && fn2p && (sock >= 0)) {
612*44704f69SBart Van Assche         int res, fd_ma;
613*44704f69SBart Van Assche         /* int fd_sl = open(fn2p, O_RDWR); not needed */
614*44704f69SBart Van Assche         uint8_t b[32];
615*44704f69SBart Van Assche 
616*44704f69SBart Van Assche         fd_ma = -1;
617*44704f69SBart Van Assche         res = sock_fd_read(sock, b, sizeof(b), &fd_ma);
618*44704f69SBart Van Assche         if (res < 0)
619*44704f69SBart Van Assche             pr2serr("%s: sock_fd_read() failed\n", __func__);
620*44704f69SBart Van Assche         else
621*44704f69SBart Van Assche             printf("%s: sock_fd_read() returned: %d, fd_ma=%d\n", __func__,
622*44704f69SBart Van Assche                    res, fd_ma);
623*44704f69SBart Van Assche         /* yes it works! */
624*44704f69SBart Van Assche     }
625*44704f69SBart Van Assche     return 0;
626*44704f69SBart Van Assche }
627*44704f69SBart Van Assche 
628*44704f69SBart Van Assche static int
do_mrqs(int sg_fd,int sg_fd2,int mrqs)629*44704f69SBart Van Assche do_mrqs(int sg_fd, int sg_fd2, int mrqs)
630*44704f69SBart Van Assche {
631*44704f69SBart Van Assche     bool both = (sg_fd2 >= 0);
632*44704f69SBart Van Assche     int k, j, arr_v4_sz, good;
633*44704f69SBart Van Assche     int res = 0;
634*44704f69SBart Van Assche     struct sg_io_v4 * arr_v4;
635*44704f69SBart Van Assche     struct sg_io_v4 * h4p;
636*44704f69SBart Van Assche     struct sg_io_v4 * mrq_h4p;
637*44704f69SBart Van Assche     struct sg_io_v4 mrq_h4;
638*44704f69SBart Van Assche     uint8_t sense_buffer[SENSE_BUFFER_LEN] SG_C_CPP_ZERO_INIT;
639*44704f69SBart Van Assche     uint8_t inq_cdb[INQ_CMD_LEN] =      /* Device Id VPD page */
640*44704f69SBart Van Assche                                 {0x12, 0x1, 0x83, 0, INQ_REPLY_LEN, 0};
641*44704f69SBart Van Assche     uint8_t sdiag_cdb[SDIAG_CMD_LEN] =
642*44704f69SBart Van Assche                                 {0x1d, 0x10 /* PF */, 0, 0, 0, 0};
643*44704f69SBart Van Assche     uint8_t inqBuff[INQ_REPLY_LEN];
644*44704f69SBart Van Assche 
645*44704f69SBart Van Assche     if (both) {
646*44704f69SBart Van Assche         struct sg_extended_info sei;
647*44704f69SBart Van Assche         struct sg_extended_info * seip;
648*44704f69SBart Van Assche 
649*44704f69SBart Van Assche         seip = &sei;
650*44704f69SBart Van Assche         memset(seip, 0, sizeof(*seip));
651*44704f69SBart Van Assche         seip->sei_wr_mask |= SG_SEIM_SHARE_FD;
652*44704f69SBart Van Assche         seip->sei_rd_mask |= SG_SEIM_SHARE_FD;
653*44704f69SBart Van Assche         seip->share_fd = sg_fd;         /* master */
654*44704f69SBart Van Assche         if (ioctl(sg_fd2, SG_SET_GET_EXTENDED, seip) < 0) {
655*44704f69SBart Van Assche             res = errno;
656*44704f69SBart Van Assche             pr2serr("ioctl(sg_fd2, SG_SET_GET_EXTENDED) shared_fd, "
657*44704f69SBart Van Assche                     "failed errno=%d %s\n", res, strerror(res));
658*44704f69SBart Van Assche             return res;
659*44704f69SBart Van Assche         }
660*44704f69SBart Van Assche     }
661*44704f69SBart Van Assche     memset(inqBuff, 0, sizeof(inqBuff));
662*44704f69SBart Van Assche     mrq_h4p = &mrq_h4;
663*44704f69SBart Van Assche     memset(mrq_h4p, 0, sizeof(*mrq_h4p));
664*44704f69SBart Van Assche     mrq_h4p->guard = 'Q';
665*44704f69SBart Van Assche     mrq_h4p->flags = SGV4_FLAG_MULTIPLE_REQS;
666*44704f69SBart Van Assche     if (mrq_immed)
667*44704f69SBart Van Assche         mrq_h4p->flags |= SGV4_FLAG_IMMED;
668*44704f69SBart Van Assche     arr_v4 = (struct sg_io_v4 *)calloc(mrqs, sizeof(struct sg_io_v4));
669*44704f69SBart Van Assche     if (NULL == arr_v4) {
670*44704f69SBart Van Assche         res = ENOMEM;
671*44704f69SBart Van Assche         goto fini;
672*44704f69SBart Van Assche     }
673*44704f69SBart Van Assche     arr_v4_sz = mrqs * sizeof(struct sg_io_v4);
674*44704f69SBart Van Assche 
675*44704f69SBart Van Assche     for (k = 0; k < mrqs; ++k) {
676*44704f69SBart Van Assche         h4p = arr_v4 + k;
677*44704f69SBart Van Assche 
678*44704f69SBart Van Assche         h4p->guard = 'Q';
679*44704f69SBart Van Assche         /* ->protocol and ->subprotocol are already zero */
680*44704f69SBart Van Assche         /* io_hdr[k].iovec_count = 0; */  /* memset takes care of this */
681*44704f69SBart Van Assche         if (0 == (k % 2)) {
682*44704f69SBart Van Assche             h4p->request_len = sizeof(sdiag_cdb);
683*44704f69SBart Van Assche             h4p->request = (uint64_t)(uintptr_t)sdiag_cdb;
684*44704f69SBart Van Assche             /* all din and dout fields are zero */
685*44704f69SBart Van Assche         } else {
686*44704f69SBart Van Assche             h4p->request_len = sizeof(inq_cdb);
687*44704f69SBart Van Assche             h4p->request = (uint64_t)(uintptr_t)inq_cdb;
688*44704f69SBart Van Assche             h4p->din_xfer_len = INQ_REPLY_LEN;
689*44704f69SBart Van Assche             h4p->din_xferp = (uint64_t)(uintptr_t)inqBuff;
690*44704f69SBart Van Assche             if (both)
691*44704f69SBart Van Assche                 h4p->flags |= SGV4_FLAG_DO_ON_OTHER;
692*44704f69SBart Van Assche         }
693*44704f69SBart Van Assche         h4p->response = (uint64_t)(uintptr_t)sense_buffer;
694*44704f69SBart Van Assche         h4p->max_response_len = sizeof(sense_buffer);
695*44704f69SBart Van Assche         h4p->timeout = 20000;     /* 20000 millisecs == 20 seconds */
696*44704f69SBart Van Assche         h4p->request_extra = k + 3;      /* so pack_id doesn't start at 0 */
697*44704f69SBart Van Assche         /* default is to queue at head (in SCSI mid level) */
698*44704f69SBart Van Assche         if (q_at_tail)
699*44704f69SBart Van Assche             h4p->flags |= SG_FLAG_Q_AT_TAIL;
700*44704f69SBart Van Assche         else
701*44704f69SBart Van Assche             h4p->flags |= SG_FLAG_Q_AT_HEAD;
702*44704f69SBart Van Assche     }
703*44704f69SBart Van Assche     mrq_h4p->dout_xferp = (uint64_t)(uintptr_t)arr_v4;
704*44704f69SBart Van Assche     mrq_h4p->dout_xfer_len = arr_v4_sz;
705*44704f69SBart Van Assche     mrq_h4p->din_xferp = mrq_h4p->dout_xferp;
706*44704f69SBart Van Assche     mrq_h4p->din_xfer_len = mrq_h4p->dout_xfer_len;
707*44704f69SBart Van Assche     if (ioctl(sg_fd, (mrq_iosubmit ? SG_IOSUBMIT : SG_IO), mrq_h4p) < 0) {
708*44704f69SBart Van Assche         res = errno;
709*44704f69SBart Van Assche         pr2serr("ioctl(SG_IO%s, mrq) failed, errno=%d %s\n",
710*44704f69SBart Van Assche                 (mrq_iosubmit ? "SUBMIT" : ""), res, strerror(res));
711*44704f69SBart Van Assche         goto fini;
712*44704f69SBart Van Assche     }
713*44704f69SBart Van Assche     if ((mrq_h4p->dout_resid > 0) || ((int)mrq_h4p->info < mrqs))
714*44704f69SBart Van Assche         pr2serr("ioctl(SG_IO%s, mrq) dout_resid=%d, info=%d\n\n",
715*44704f69SBart Van Assche                 (mrq_iosubmit ? "SUBMIT" : ""), mrq_h4p->dout_resid,
716*44704f69SBart Van Assche                 mrq_h4p->info);
717*44704f69SBart Van Assche 
718*44704f69SBart Van Assche     good = 0;
719*44704f69SBart Van Assche     j = 0;
720*44704f69SBart Van Assche     if (mrq_immed) {
721*44704f69SBart Van Assche receive_more:
722*44704f69SBart Van Assche         if (mrq_half_immed)
723*44704f69SBart Van Assche             mrq_h4p->flags = SGV4_FLAG_MULTIPLE_REQS; // zap SGV4_FLAG_IMMED
724*44704f69SBart Van Assche         if (ioctl(sg_fd, SG_IORECEIVE, mrq_h4p) < 0) {
725*44704f69SBart Van Assche             res = errno;
726*44704f69SBart Van Assche             pr2serr("ioctl(SG_IORECEIVE, mrq) failed, errno=%d %s\n",
727*44704f69SBart Van Assche                     res, strerror(res));
728*44704f69SBart Van Assche             goto fini;
729*44704f69SBart Van Assche         }
730*44704f69SBart Van Assche         if ((mrq_h4p->din_resid > 0) || ((int)mrq_h4p->info < mrqs))
731*44704f69SBart Van Assche             pr2serr("ioctl(SG_IORECEIVE, mrq) din_resid=%d, info=%d\n",
732*44704f69SBart Van Assche                     mrq_h4p->din_resid, mrq_h4p->info);
733*44704f69SBart Van Assche     }
734*44704f69SBart Van Assche 
735*44704f69SBart Van Assche     for (k = 0; k < (int)mrq_h4p->info; ++k, ++j) {
736*44704f69SBart Van Assche         h4p = arr_v4 + k;
737*44704f69SBart Van Assche         if (! (h4p->driver_status || h4p->transport_status ||
738*44704f69SBart Van Assche                h4p->device_status)) {
739*44704f69SBart Van Assche             if (h4p->info & SG_INFO_MRQ_FINI)
740*44704f69SBart Van Assche                 ++good;
741*44704f69SBart Van Assche         }
742*44704f69SBart Van Assche         if ((! (h4p->info & SG_INFO_MRQ_FINI)) && (verbose > 1))
743*44704f69SBart Van Assche             pr2serr("%s: k=%d: SG_INFO_MRQ_FINI not set on response\n",
744*44704f69SBart Van Assche                     __func__, k);
745*44704f69SBart Van Assche     }
746*44704f69SBart Van Assche     if (mrq_immed && (j < mrqs))
747*44704f69SBart Van Assche         goto receive_more;
748*44704f69SBart Van Assche 
749*44704f69SBart Van Assche     if (good > 0) {
750*44704f69SBart Van Assche         printf("Final INQUIRY response:\n");
751*44704f69SBart Van Assche         hex2stdout(inqBuff, INQ_REPLY_LEN, 0);
752*44704f69SBart Van Assche     }
753*44704f69SBart Van Assche     printf("Good responses: %d, bad responses: %d\n", good, mrqs - good);
754*44704f69SBart Van Assche     if (mrq_h4p->driver_status != 0)
755*44704f69SBart Van Assche         printf("Master mrq object: driver_status=%d\n",
756*44704f69SBart Van Assche                mrq_h4p->driver_status);
757*44704f69SBart Van Assche     h4p = arr_v4 + mrqs - 1;
758*44704f69SBart Van Assche     if (h4p->driver_status != 0)
759*44704f69SBart Van Assche         printf("Last mrq object: driver_status=%d\n", h4p->driver_status);
760*44704f69SBart Van Assche 
761*44704f69SBart Van Assche fini:
762*44704f69SBart Van Assche     if (arr_v4)
763*44704f69SBart Van Assche         free(arr_v4);
764*44704f69SBart Van Assche     return res;
765*44704f69SBart Van Assche }
766*44704f69SBart Van Assche 
767*44704f69SBart Van Assche 
768*44704f69SBart Van Assche int
main(int argc,char * argv[])769*44704f69SBart Van Assche main(int argc, char * argv[])
770*44704f69SBart Van Assche {
771*44704f69SBart Van Assche     bool done, is_first;
772*44704f69SBart Van Assche     bool nw_given = false;
773*44704f69SBart Van Assche     bool has_dname_range = false;
774*44704f69SBart Van Assche     int k, ok, pack_id, num_waiting;
775*44704f69SBart Van Assche     int res = 0;
776*44704f69SBart Van Assche     int sum_nw = 0;
777*44704f69SBart Van Assche     int sg_fd = -1;
778*44704f69SBart Van Assche     int sg_fd2 = -1;
779*44704f69SBart Van Assche     int sock = -1;
780*44704f69SBart Van Assche     uint8_t inq_cdb[INQ_CMD_LEN] =
781*44704f69SBart Van Assche                                 {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
782*44704f69SBart Van Assche     uint8_t sdiag_cdb[SDIAG_CMD_LEN] =
783*44704f69SBart Van Assche                                 {0x1d, 0x10 /* PF */, 0, 0, 0, 0};
784*44704f69SBart Van Assche     uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN];
785*44704f69SBart Van Assche     sg_io_hdr_t io_hdr[MAX_Q_LEN];
786*44704f69SBart Van Assche     sg_io_hdr_t rio_hdr;
787*44704f69SBart Van Assche     char ebuff[EBUFF_SZ];
788*44704f69SBart Van Assche     char dname[256];
789*44704f69SBart Van Assche     uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN] SG_C_CPP_ZERO_INIT;
790*44704f69SBart Van Assche     const char * second_fname = NULL;
791*44704f69SBart Van Assche     const char * cp;
792*44704f69SBart Van Assche     char * chp;
793*44704f69SBart Van Assche     struct sg_scsi_id ssi;
794*44704f69SBart Van Assche 
795*44704f69SBart Van Assche 
796*44704f69SBart Van Assche     if (sizeof(struct sg_extended_info) != 96)
797*44704f69SBart Van Assche         pr2serr("Warning <<<< sizeof(struct sg_extended_info)=%zu not 96\n",
798*44704f69SBart Van Assche                 sizeof(struct sg_extended_info));
799*44704f69SBart Van Assche     for (k = 1; k < argc; ++k) {
800*44704f69SBart Van Assche         if (0 == memcmp("-3", argv[k], 2))
801*44704f69SBart Van Assche             do_v3_only = true;
802*44704f69SBart Van Assche         else if (0 == memcmp("-c", argv[k], 2))
803*44704f69SBart Van Assche             create_time = true;
804*44704f69SBart Van Assche         else if (0 == memcmp("-f", argv[k], 2))
805*44704f69SBart Van Assche             do_fork = true;
806*44704f69SBart Van Assche         else if (0 == memcmp("-h", argv[k], 2)) {
807*44704f69SBart Van Assche             file_name = 0;
808*44704f69SBart Van Assche             break;
809*44704f69SBart Van Assche         } else if (0 == memcmp("-I=", argv[k], 3)) {
810*44704f69SBart Van Assche             iterator_test = atoi(argv[k] + 3);
811*44704f69SBart Van Assche             if ((iterator_test > 1) || (iterator_test < -1)) {
812*44704f69SBart Van Assche                 printf("Expect -I= to take a number, either 0 or 1\n");
813*44704f69SBart Van Assche                 file_name = 0;
814*44704f69SBart Van Assche                 break;
815*44704f69SBart Van Assche             }
816*44704f69SBart Van Assche         } else if (0 == memcmp("-J=", argv[k], 3)) {
817*44704f69SBart Van Assche             object_walk_test = atoi(argv[k] + 3);
818*44704f69SBart Van Assche             if ((object_walk_test > 1) || (object_walk_test < -1)) {
819*44704f69SBart Van Assche                 printf("Expect -J= to take a number, either 0 or 1\n");
820*44704f69SBart Van Assche                 file_name = 0;
821*44704f69SBart Van Assche                 break;
822*44704f69SBart Van Assche             }
823*44704f69SBart Van Assche         } else if (0 == memcmp("-l=", argv[k], 3)) {
824*44704f69SBart Van Assche             q_len = atoi(argv[k] + 3);
825*44704f69SBart Van Assche             if ((q_len > 511) || (q_len < 1)) {
826*44704f69SBart Van Assche                 printf("Expect -l= to take a number (q length) between 1 "
827*44704f69SBart Van Assche                        "and 511\n");
828*44704f69SBart Van Assche                 file_name = 0;
829*44704f69SBart Van Assche                 break;
830*44704f69SBart Van Assche             }
831*44704f69SBart Van Assche         } else if (0 == memcmp("-m=", argv[k], 3)) {
832*44704f69SBart Van Assche             num_mrqs = sg_get_num(argv[k] + 3);
833*44704f69SBart Van Assche             if (num_mrqs < 1) {
834*44704f69SBart Van Assche                 printf("Expect -m= to take a number greater than 0\n");
835*44704f69SBart Van Assche                 file_name = 0;
836*44704f69SBart Van Assche                 break;
837*44704f69SBart Van Assche             }
838*44704f69SBart Van Assche             if ((cp = strchr(argv[k] + 3, ','))) {
839*44704f69SBart Van Assche                 mrq_iosubmit = true;
840*44704f69SBart Van Assche                 if (cp[1] == 'I')
841*44704f69SBart Van Assche                     mrq_immed = true;
842*44704f69SBart Van Assche                 else if (cp[1] == 'i') {
843*44704f69SBart Van Assche                     mrq_immed = true;
844*44704f69SBart Van Assche                     mrq_half_immed = true;
845*44704f69SBart Van Assche                 } else if (toupper(cp[1]) == 'S')
846*44704f69SBart Van Assche                     ;
847*44704f69SBart Van Assche                 else {
848*44704f69SBart Van Assche                     printf("-m= option expects 'A' or 'a' as a suffix, "
849*44704f69SBart Van Assche                            "after comma\n");
850*44704f69SBart Van Assche                     file_name = 0;
851*44704f69SBart Van Assche                     break;
852*44704f69SBart Van Assche                 }
853*44704f69SBart Van Assche             }
854*44704f69SBart Van Assche         } else if (0 == memcmp("-M", argv[k], 2))
855*44704f69SBart Van Assche             more_async = true;
856*44704f69SBart Van Assche         else if (0 == memcmp("-n", argv[k], 2))
857*44704f69SBart Van Assche             no_duration = true;
858*44704f69SBart Van Assche         else if (0 == memcmp("-o", argv[k], 2))
859*44704f69SBart Van Assche             ioctl_only = true;
860*44704f69SBart Van Assche         else if (0 == memcmp("-r=", argv[k], 3)) {
861*44704f69SBart Van Assche             reserve_buff_sz = atoi(argv[k] + 3);
862*44704f69SBart Van Assche             if (reserve_buff_sz < 0) {
863*44704f69SBart Van Assche                 printf("Expect -r= to take a number 0 or higher\n");
864*44704f69SBart Van Assche                 file_name = 0;
865*44704f69SBart Van Assche                 break;
866*44704f69SBart Van Assche             }
867*44704f69SBart Van Assche         } else if (0 == memcmp("-s=", argv[k], 3)) {
868*44704f69SBart Van Assche             sleep_secs = atoi(argv[k] + 3);
869*44704f69SBart Van Assche             if (sleep_secs < 0) {
870*44704f69SBart Van Assche                 printf("Expect -s= to take a number 0 or higher\n");
871*44704f69SBart Van Assche                 file_name = 0;
872*44704f69SBart Van Assche                 break;
873*44704f69SBart Van Assche             }
874*44704f69SBart Van Assche         } else if (0 == memcmp("-S", argv[k], 2))
875*44704f69SBart Van Assche             show_size_value = true;
876*44704f69SBart Van Assche         else if (0 == memcmp("-t", argv[k], 2))
877*44704f69SBart Van Assche             q_at_tail = true;
878*44704f69SBart Van Assche         else if (0 == memcmp("-T=", argv[k], 3)) {
879*44704f69SBart Van Assche             num_sgnw = sg_get_num(argv[k] + 3);
880*44704f69SBart Van Assche             if (num_sgnw < 0) {
881*44704f69SBart Van Assche                 printf("Expect -T= to take a number >= 0\n");
882*44704f69SBart Van Assche                 file_name = 0;
883*44704f69SBart Van Assche                 break;
884*44704f69SBart Van Assche             }
885*44704f69SBart Van Assche             nw_given = true;
886*44704f69SBart Van Assche         } else if (0 == memcmp("-vvvvvvv", argv[k], 8))
887*44704f69SBart Van Assche             verbose += 7;
888*44704f69SBart Van Assche         else if (0 == memcmp("-vvvvvv", argv[k], 7))
889*44704f69SBart Van Assche             verbose += 6;
890*44704f69SBart Van Assche         else if (0 == memcmp("-vvvvv", argv[k], 6))
891*44704f69SBart Van Assche             verbose += 5;
892*44704f69SBart Van Assche         else if (0 == memcmp("-vvvv", argv[k], 5))
893*44704f69SBart Van Assche             verbose += 4;
894*44704f69SBart Van Assche         else if (0 == memcmp("-vvv", argv[k], 4))
895*44704f69SBart Van Assche             verbose += 3;
896*44704f69SBart Van Assche         else if (0 == memcmp("-vv", argv[k], 3))
897*44704f69SBart Van Assche             verbose += 2;
898*44704f69SBart Van Assche         else if (0 == memcmp("-v", argv[k], 2))
899*44704f69SBart Van Assche             verbose += 1;
900*44704f69SBart Van Assche         else if (0 == memcmp("-V", argv[k], 2)) {
901*44704f69SBart Van Assche             printf("%s\n", version_str);
902*44704f69SBart Van Assche             return 0;
903*44704f69SBart Van Assche         } else if (0 == memcmp("-w", argv[k], 2))
904*44704f69SBart Van Assche             write_only = true;
905*44704f69SBart Van Assche         else if (*argv[k] == '-') {
906*44704f69SBart Van Assche             printf("Unrecognized switch: %s\n", argv[k]);
907*44704f69SBart Van Assche             file_name = 0;
908*44704f69SBart Van Assche             break;
909*44704f69SBart Van Assche         }
910*44704f69SBart Van Assche         else if (0 == file_name)
911*44704f69SBart Van Assche             file_name = argv[k];
912*44704f69SBart Van Assche         else if (NULL == second_fname)
913*44704f69SBart Van Assche             second_fname = argv[k];
914*44704f69SBart Van Assche         else {
915*44704f69SBart Van Assche             printf("too many arguments\n");
916*44704f69SBart Van Assche             file_name = 0;
917*44704f69SBart Van Assche             break;
918*44704f69SBart Van Assche         }
919*44704f69SBart Van Assche     }
920*44704f69SBart Van Assche     if ((iterator_test >= 0) || (object_walk_test >= 0))
921*44704f69SBart Van Assche         nw_given = false;
922*44704f69SBart Van Assche 
923*44704f69SBart Van Assche     if (show_size_value) {
924*44704f69SBart Van Assche         struct utsname unam;
925*44704f69SBart Van Assche 
926*44704f69SBart Van Assche         printf("Size in bytes:\n");
927*44704f69SBart Van Assche         printf("\t%zu\tsizeof(struct sg_header) Version 2 interface "
928*44704f69SBart Van Assche                "structure\n", sizeof(struct sg_header));
929*44704f69SBart Van Assche         printf("\t%zu\tsizeof(struct sg_io_hdr) Version 3 interface "
930*44704f69SBart Van Assche                "structure\n", sizeof(struct sg_io_hdr));
931*44704f69SBart Van Assche         printf("\t%zu\tsizeof(struct sg_io_v4) Version 4 interface "
932*44704f69SBart Van Assche                "structure\n", sizeof(struct sg_io_v4));
933*44704f69SBart Van Assche         printf("\t%zu\tsizeof(struct sg_iovec) scatter gather element\n",
934*44704f69SBart Van Assche                sizeof(struct sg_iovec));
935*44704f69SBart Van Assche         printf("\t%zu\tsizeof(struct sg_scsi_id) topological device id\n",
936*44704f69SBart Van Assche                sizeof(struct sg_scsi_id));
937*44704f69SBart Van Assche         printf("\t%zu\tsizeof(struct sg_req_info) request information\n",
938*44704f69SBart Van Assche                sizeof(struct sg_req_info));
939*44704f69SBart Van Assche         printf("\t%zu\tsizeof(struct sg_extended_info) for "
940*44704f69SBart Van Assche                "SG_SET_GET_EXTENDED\n",
941*44704f69SBart Van Assche                sizeof(struct sg_extended_info));
942*44704f69SBart Van Assche         printf("\nioctl values (i.e. second argument to ioctl()):\n");
943*44704f69SBart Van Assche         printf("\t0x%lx\t\tvalue of SG_GET_NUM_WAITING ioctl\n",
944*44704f69SBart Van Assche                (unsigned long)SG_GET_NUM_WAITING);
945*44704f69SBart Van Assche         printf("\t0x%lx\t\tvalue of SG_IO ioctl\n",
946*44704f69SBart Van Assche                (unsigned long)SG_IO);
947*44704f69SBart Van Assche         printf("\t0x%lx\tvalue of SG_IOABORT ioctl\n",
948*44704f69SBart Van Assche                (unsigned long)SG_IOABORT);
949*44704f69SBart Van Assche         printf("\t0x%lx\tvalue of SG_IORECEIVE ioctl\n",
950*44704f69SBart Van Assche                (unsigned long)SG_IORECEIVE);
951*44704f69SBart Van Assche         printf("\t0x%lx\tvalue of SG_IORECEIVE_V3 ioctl\n",
952*44704f69SBart Van Assche                (unsigned long)SG_IORECEIVE_V3);
953*44704f69SBart Van Assche         printf("\t0x%lx\tvalue of SG_IOSUBMIT ioctl\n",
954*44704f69SBart Van Assche                (unsigned long)SG_IOSUBMIT);
955*44704f69SBart Van Assche         printf("\t0x%lx\tvalue of SG_IOSUBMIT_V3 ioctl\n",
956*44704f69SBart Van Assche                (unsigned long)SG_IOSUBMIT_V3);
957*44704f69SBart Van Assche         printf("\t0x%lx\tvalue of SG_SET_GET_EXTENDED ioctl\n",
958*44704f69SBart Van Assche                (unsigned long)SG_SET_GET_EXTENDED);
959*44704f69SBart Van Assche         printf("\n\t0x%x\t\tbase value of most SG_* ioctls\n",
960*44704f69SBart Van Assche                SG_IOCTL_MAGIC_NUM);
961*44704f69SBart Van Assche         printf("\nsizeof(void *) [a pointer] on this machine: %u bytes\n",
962*44704f69SBart Van Assche                (unsigned)sizeof(void *));
963*44704f69SBart Van Assche         if (0 == uname(&unam))
964*44704f69SBart Van Assche             printf("Machine name: %s\n", unam.machine);
965*44704f69SBart Van Assche 
966*44704f69SBart Van Assche         return 0;
967*44704f69SBart Van Assche     }
968*44704f69SBart Van Assche     if (0 == file_name) {
969*44704f69SBart Van Assche         printf("No filename (sg device) given\n\n");
970*44704f69SBart Van Assche         usage();
971*44704f69SBart Van Assche         return 1;
972*44704f69SBart Van Assche     }
973*44704f69SBart Van Assche     memset(dname, 0, sizeof(dname));
974*44704f69SBart Van Assche     if (strlen(file_name) > 255) {
975*44704f69SBart Van Assche         fprintf(stderr, "file_name too long\n");
976*44704f69SBart Van Assche         goto out;
977*44704f69SBart Van Assche     }
978*44704f69SBart Van Assche     strncpy(dname, file_name, sizeof(dname) - 1);
979*44704f69SBart Van Assche     if ((chp = strchr(dname, '-'))) {
980*44704f69SBart Van Assche         if (1 != sscanf(chp + 1, "%d", &dname_last)) {
981*44704f69SBart Van Assche             fprintf(stderr, "can't code number after '-' in file_name\n");
982*44704f69SBart Van Assche             goto out;
983*44704f69SBart Van Assche         }
984*44704f69SBart Van Assche         *chp = '\0';
985*44704f69SBart Van Assche         --chp;
986*44704f69SBart Van Assche         while (isdigit(*chp))
987*44704f69SBart Van Assche             --chp;
988*44704f69SBart Van Assche         ++chp;
989*44704f69SBart Van Assche         if (1 != sscanf(chp, "%d", &dname_current)) {
990*44704f69SBart Van Assche             fprintf(stderr, "can't code number before '-' in file_name\n");
991*44704f69SBart Van Assche             goto out;
992*44704f69SBart Van Assche         }
993*44704f69SBart Van Assche         *chp = '\0';
994*44704f69SBart Van Assche         has_dname_range = true;
995*44704f69SBart Van Assche         dname_pos = strlen(dname);
996*44704f69SBart Van Assche     }
997*44704f69SBart Van Assche     is_first = true;
998*44704f69SBart Van Assche 
999*44704f69SBart Van Assche dname_range_loop:
1000*44704f69SBart Van Assche     if (has_dname_range)
1001*44704f69SBart Van Assche         sprintf(dname + dname_pos, "%d", dname_current);
1002*44704f69SBart Van Assche 
1003*44704f69SBart Van Assche     /* An access mode of O_RDWR is required for write()/read() interface */
1004*44704f69SBart Van Assche     if ((sg_fd = open(dname, O_RDWR)) < 0) {
1005*44704f69SBart Van Assche         snprintf(ebuff, EBUFF_SZ, "error opening file: %s", dname);
1006*44704f69SBart Van Assche         perror(ebuff);
1007*44704f69SBart Van Assche         return 1;
1008*44704f69SBart Van Assche     }
1009*44704f69SBart Van Assche     if (verbose)
1010*44704f69SBart Van Assche         fprintf(stderr, "opened given file: %s successfully, fd=%d\n",
1011*44704f69SBart Van Assche                 dname, sg_fd);
1012*44704f69SBart Van Assche 
1013*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_VERSION_NUM, &sg_drv_ver_num) < 0) {
1014*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_VERSION_NUM) failed, errno=%d %s\n", errno,
1015*44704f69SBart Van Assche                 strerror(errno));
1016*44704f69SBart Van Assche         goto out;
1017*44704f69SBart Van Assche     }
1018*44704f69SBart Van Assche     if (is_first)
1019*44704f69SBart Van Assche         printf("Linux sg driver version: %d\n", sg_drv_ver_num);
1020*44704f69SBart Van Assche 
1021*44704f69SBart Van Assche     if (create_time && (sg_drv_ver_num > 40030)) {
1022*44704f69SBart Van Assche         pr_create_dev_time(sg_fd, dname);
1023*44704f69SBart Van Assche         goto out;
1024*44704f69SBart Van Assche     }
1025*44704f69SBart Van Assche 
1026*44704f69SBart Van Assche     if (nw_given || (iterator_test >= 0) || (object_walk_test >= 0)) {
1027*44704f69SBart Van Assche         /* -T=NUM and/or -I=0|1 or -j=0|1 */
1028*44704f69SBart Van Assche         /* time ioctl(SG_GET_NUM_WAITING) or do iterator_test */
1029*44704f69SBart Van Assche         int nw;
1030*44704f69SBart Van Assche         struct timespec start_tm, fin_tm, res_tm;
1031*44704f69SBart Van Assche 
1032*44704f69SBart Van Assche         if (is_first) {
1033*44704f69SBart Van Assche             int rang = has_dname_range ? (1 + dname_last - dname_current) : 1;
1034*44704f69SBart Van Assche 
1035*44704f69SBart Van Assche             is_first = false;
1036*44704f69SBart Van Assche             if (nw_given)
1037*44704f69SBart Van Assche                 printf("Timing %d x %d calls to ioctl(SG_GET_NUM_WAITING)\n",
1038*44704f69SBart Van Assche                        rang, num_sgnw);
1039*44704f69SBart Van Assche             else if (iterator_test >= 0) {
1040*44704f69SBart Van Assche                 k = num_sgnw + 1000;
1041*44704f69SBart Van Assche                 printf("Timing %d calls to ioctl(SG_SET_DEBUG, %d)\n",
1042*44704f69SBart Van Assche                        rang, ((0 == iterator_test) ? -k : k));
1043*44704f69SBart Van Assche             } else
1044*44704f69SBart Van Assche                 printf("Timing %d calls to ioctl(SG_SET_DEBUG, %d)\n",
1045*44704f69SBart Van Assche                        rang, (object_walk_test == 0) ? 999 : -999);
1046*44704f69SBart Van Assche             if (0 != clock_gettime(CLOCK_MONOTONIC, &start_tm)) {
1047*44704f69SBart Van Assche                     res = errno;
1048*44704f69SBart Van Assche                     perror("start clock_gettime() failed:");
1049*44704f69SBart Van Assche                     goto out;
1050*44704f69SBart Van Assche             }
1051*44704f69SBart Van Assche         }
1052*44704f69SBart Van Assche         if (nw_given) {
1053*44704f69SBart Van Assche             for (k = 0; k < num_sgnw; ++k, sum_nw += nw) {
1054*44704f69SBart Van Assche                 if (ioctl(sg_fd, SG_GET_NUM_WAITING, &nw) < 0) {
1055*44704f69SBart Van Assche                     res = errno;
1056*44704f69SBart Van Assche                     fprintf(stderr, "%d: ioctl(SG_GET_NUM_WAITING) failed "
1057*44704f69SBart Van Assche                             "errno=%d\n", k, res);
1058*44704f69SBart Van Assche                     goto out;
1059*44704f69SBart Van Assche                 }
1060*44704f69SBart Van Assche             }
1061*44704f69SBart Van Assche         } else if (iterator_test >= 0) {
1062*44704f69SBart Van Assche             int fd, pid;
1063*44704f69SBart Van Assche 
1064*44704f69SBart Van Assche             k = num_sgnw + 1000;
1065*44704f69SBart Van Assche             if (0 == iterator_test)
1066*44704f69SBart Van Assche                 k = -k;
1067*44704f69SBart Van Assche             if (second_fname) {
1068*44704f69SBart Van Assche                 if ((sg_fd2 = open(second_fname, O_RDWR)) < 0) {
1069*44704f69SBart Van Assche                     snprintf(ebuff, EBUFF_SZ, "%s: error opening file: %s",
1070*44704f69SBart Van Assche                              __func__, second_fname);
1071*44704f69SBart Van Assche                     perror(ebuff);
1072*44704f69SBart Van Assche                     return 1;
1073*44704f69SBart Van Assche                 }
1074*44704f69SBart Van Assche                 printf("About to fork due to second filename\n");
1075*44704f69SBart Van Assche                 pid = fork();
1076*44704f69SBart Van Assche                 if (pid < 0) {
1077*44704f69SBart Van Assche                     perror("fork() failed");
1078*44704f69SBart Van Assche                     goto out;
1079*44704f69SBart Van Assche                 } else if (0 == pid) {
1080*44704f69SBart Van Assche                     relative_cp = "child: ";
1081*44704f69SBart Van Assche                     is_parent = false;
1082*44704f69SBart Van Assche                     fd = sg_fd2;
1083*44704f69SBart Van Assche                 } else {
1084*44704f69SBart Van Assche                     relative_cp = "parent: ";
1085*44704f69SBart Van Assche                     is_parent = true;
1086*44704f69SBart Van Assche                     childs_pid = pid;
1087*44704f69SBart Van Assche                     fd = sg_fd;
1088*44704f69SBart Van Assche                 }
1089*44704f69SBart Van Assche             } else {
1090*44704f69SBart Van Assche                 fd = sg_fd;
1091*44704f69SBart Van Assche                 relative_cp = "";
1092*44704f69SBart Van Assche             }
1093*44704f69SBart Van Assche             if (ioctl(fd, SG_SET_DEBUG, &k) < 0) {
1094*44704f69SBart Van Assche                 res = errno;
1095*44704f69SBart Van Assche                 fprintf(stderr, "%s%d: ioctl(SG_SET_DEBUG) failed errno=%d\n",
1096*44704f69SBart Van Assche                         relative_cp, k, res);
1097*44704f69SBart Van Assche                 goto out;
1098*44704f69SBart Van Assche             } else if (verbose)
1099*44704f69SBart Van Assche                 fprintf(stderr, "%siterator_test good ioctl(SG_SET_DEBUG, "
1100*44704f69SBart Van Assche                         "%d)\n", relative_cp, k);
1101*44704f69SBart Van Assche             sum_nw += num_sgnw;
1102*44704f69SBart Van Assche         } else if (object_walk_test >= 0) {
1103*44704f69SBart Van Assche             const char * ccp = "object_walk_test";
1104*44704f69SBart Van Assche 
1105*44704f69SBart Van Assche             relative_cp = "";
1106*44704f69SBart Van Assche             k = (object_walk_test == 0) ? 999 : -999;
1107*44704f69SBart Van Assche             if (ioctl(sg_fd, SG_SET_DEBUG, &k) < 0) {
1108*44704f69SBart Van Assche                 res = errno;
1109*44704f69SBart Van Assche                 fprintf(stderr, "%s: ioctl(SG_SET_DEBUG, %d) failed "
1110*44704f69SBart Van Assche                         "errno=%d\n", ccp, k, res);
1111*44704f69SBart Van Assche             } else if (verbose)
1112*44704f69SBart Van Assche                 fprintf(stderr, "%s: good call to ioctl(SG_SET_DEBUG, %d)\n",
1113*44704f69SBart Van Assche                         ccp, k);
1114*44704f69SBart Van Assche             sum_nw += 10000;    /* (1_up-scan + 2_lookups) * 10,000 times */
1115*44704f69SBart Van Assche         }
1116*44704f69SBart Van Assche 
1117*44704f69SBart Van Assche         if (has_dname_range) {
1118*44704f69SBart Van Assche             ++dname_current;
1119*44704f69SBart Van Assche             if (dname_current <= dname_last) {
1120*44704f69SBart Van Assche                 if (sg_fd >= 0)
1121*44704f69SBart Van Assche                     close(sg_fd);
1122*44704f69SBart Van Assche                 goto dname_range_loop;
1123*44704f69SBart Van Assche             }
1124*44704f69SBart Van Assche         }
1125*44704f69SBart Van Assche         if (0 != clock_gettime(CLOCK_MONOTONIC, &fin_tm)) {
1126*44704f69SBart Van Assche             res = errno;
1127*44704f69SBart Van Assche             perror("finish clock_gettime() failed:");
1128*44704f69SBart Van Assche             goto out;
1129*44704f69SBart Van Assche         }
1130*44704f69SBart Van Assche         res_tm.tv_sec = fin_tm.tv_sec - start_tm.tv_sec;
1131*44704f69SBart Van Assche         res_tm.tv_nsec = fin_tm.tv_nsec - start_tm.tv_nsec;
1132*44704f69SBart Van Assche         if (res_tm.tv_nsec < 0) {
1133*44704f69SBart Van Assche             --res_tm.tv_sec;
1134*44704f69SBart Van Assche             res_tm.tv_nsec += 1000000000;
1135*44704f69SBart Van Assche         }
1136*44704f69SBart Van Assche         if (verbose) {
1137*44704f69SBart Van Assche             if (nw_given && (verbose > 1))
1138*44704f69SBart Van Assche                 printf("sum of num_waiting_s=%d\n", sum_nw);
1139*44704f69SBart Van Assche             printf("%selapsed time (nanosecond precision): %d.%09d secs\n",
1140*44704f69SBart Van Assche                    relative_cp, (int)res_tm.tv_sec, (int)res_tm.tv_nsec);
1141*44704f69SBart Van Assche         } else
1142*44704f69SBart Van Assche             printf("%selapsed time: %d.%06d secs\n", relative_cp,
1143*44704f69SBart Van Assche                    (int)res_tm.tv_sec, (int)(res_tm.tv_nsec / 1000));
1144*44704f69SBart Van Assche         if (num_sgnw >= 100) {
1145*44704f69SBart Van Assche             double m = (double)res_tm.tv_sec +
1146*44704f69SBart Van Assche                        ((double)res_tm.tv_nsec / 1000000000.0);
1147*44704f69SBart Van Assche             double num = num_sgnw;
1148*44704f69SBart Van Assche 
1149*44704f69SBart Van Assche             if (m > 0.000001)
1150*44704f69SBart Van Assche                 printf("%sCalls per second: %.2f\n", relative_cp, num / m);
1151*44704f69SBart Van Assche         }
1152*44704f69SBart Van Assche         res = 0;
1153*44704f69SBart Van Assche         goto out;
1154*44704f69SBart Van Assche     }
1155*44704f69SBart Van Assche     if ((more_async || no_duration) && !do_v3_only)
1156*44704f69SBart Van Assche         set_more_async(sg_fd, more_async, no_duration);
1157*44704f69SBart Van Assche 
1158*44704f69SBart Van Assche     if (second_fname) {
1159*44704f69SBart Van Assche         if ((sg_fd2 = open(second_fname, O_RDWR)) < 0) {
1160*44704f69SBart Van Assche             snprintf(ebuff, EBUFF_SZ,
1161*44704f69SBart Van Assche                      "%s: error opening file: %s", __func__, second_fname);
1162*44704f69SBart Van Assche             perror(ebuff);
1163*44704f69SBart Van Assche             return 1;
1164*44704f69SBart Van Assche         }
1165*44704f69SBart Van Assche         if (verbose)
1166*44704f69SBart Van Assche             fprintf(stderr, "opened second file: %s successfully, fd=%d\n",
1167*44704f69SBart Van Assche                     second_fname, sg_fd2);
1168*44704f69SBart Van Assche         if (more_async && !do_v3_only)
1169*44704f69SBart Van Assche             set_more_async(sg_fd2, more_async, no_duration);
1170*44704f69SBart Van Assche     }
1171*44704f69SBart Van Assche 
1172*44704f69SBart Van Assche     if ((num_mrqs > 0) && !do_v3_only) {
1173*44704f69SBart Van Assche         res = do_mrqs(sg_fd, sg_fd2, num_mrqs);
1174*44704f69SBart Van Assche         goto out;
1175*44704f69SBart Van Assche     }
1176*44704f69SBart Van Assche 
1177*44704f69SBart Van Assche     if (do_fork) {
1178*44704f69SBart Van Assche         int pid;
1179*44704f69SBart Van Assche         int sv[2];
1180*44704f69SBart Van Assche 
1181*44704f69SBart Van Assche         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) {
1182*44704f69SBart Van Assche             perror("socketpair");
1183*44704f69SBart Van Assche             exit(1);
1184*44704f69SBart Van Assche         }
1185*44704f69SBart Van Assche         printf("socketpair: sv[0]=%d, sv[1]=%d sg_fd=%d\n", sv[0], sv[1],
1186*44704f69SBart Van Assche                sg_fd);
1187*44704f69SBart Van Assche         pid = fork();
1188*44704f69SBart Van Assche         if (pid < 0) {
1189*44704f69SBart Van Assche             perror("fork() failed");
1190*44704f69SBart Van Assche             goto out;
1191*44704f69SBart Van Assche         } else if (0 == pid) {
1192*44704f69SBart Van Assche             relative_cp = "child ";
1193*44704f69SBart Van Assche             is_parent = false;
1194*44704f69SBart Van Assche             close(sv[0]);
1195*44704f69SBart Van Assche             sock = sv[1];
1196*44704f69SBart Van Assche         } else {
1197*44704f69SBart Van Assche             relative_cp = "parent ";
1198*44704f69SBart Van Assche             is_parent = true;
1199*44704f69SBart Van Assche             childs_pid = pid;
1200*44704f69SBart Van Assche             close(sv[1]);
1201*44704f69SBart Van Assche             sock = sv[0];
1202*44704f69SBart Van Assche         }
1203*44704f69SBart Van Assche     }
1204*44704f69SBart Van Assche 
1205*44704f69SBart Van Assche     cp = do_fork ? relative_cp : "";
1206*44704f69SBart Van Assche     if (! do_v3_only && (sg_drv_ver_num > 40030)) {
1207*44704f69SBart Van Assche         if (tst_extended_ioctl(dname, sg_fd, second_fname, sg_fd2, sock,
1208*44704f69SBart Van Assche                                cp))
1209*44704f69SBart Van Assche             goto out;
1210*44704f69SBart Van Assche     }
1211*44704f69SBart Van Assche     if (ioctl_only)
1212*44704f69SBart Van Assche         goto out;
1213*44704f69SBart Van Assche 
1214*44704f69SBart Van Assche     if (do_fork && !is_parent)
1215*44704f69SBart Van Assche         return 0;
1216*44704f69SBart Van Assche 
1217*44704f69SBart Van Assche     printf("start write() calls [submits]\n");
1218*44704f69SBart Van Assche     for (k = 0; k < q_len; ++k) {
1219*44704f69SBart Van Assche         /* Prepare INQUIRY command */
1220*44704f69SBart Van Assche         memset(&io_hdr[k], 0, sizeof(sg_io_hdr_t));
1221*44704f69SBart Van Assche         io_hdr[k].interface_id = 'S';
1222*44704f69SBart Van Assche         /* io_hdr[k].iovec_count = 0; */  /* memset takes care of this */
1223*44704f69SBart Van Assche         io_hdr[k].mx_sb_len = (uint8_t)sizeof(sense_buffer);
1224*44704f69SBart Van Assche         if (0 == (k % 3)) {
1225*44704f69SBart Van Assche             io_hdr[k].cmd_len = sizeof(sdiag_cdb);
1226*44704f69SBart Van Assche             io_hdr[k].cmdp = sdiag_cdb;
1227*44704f69SBart Van Assche             io_hdr[k].dxfer_direction = SG_DXFER_NONE;
1228*44704f69SBart Van Assche         } else {
1229*44704f69SBart Van Assche             io_hdr[k].cmd_len = sizeof(inq_cdb);
1230*44704f69SBart Van Assche             io_hdr[k].cmdp = inq_cdb;
1231*44704f69SBart Van Assche             io_hdr[k].dxfer_direction = SG_DXFER_FROM_DEV;
1232*44704f69SBart Van Assche             io_hdr[k].dxfer_len = INQ_REPLY_LEN;
1233*44704f69SBart Van Assche             io_hdr[k].dxferp = inqBuff[k];
1234*44704f69SBart Van Assche         }
1235*44704f69SBart Van Assche         io_hdr[k].sbp = sense_buffer[k];
1236*44704f69SBart Van Assche         io_hdr[k].mx_sb_len = SENSE_BUFFER_LEN;
1237*44704f69SBart Van Assche         io_hdr[k].timeout = 20000;     /* 20000 millisecs == 20 seconds */
1238*44704f69SBart Van Assche         io_hdr[k].pack_id = k + 3;      /* so pack_id doesn't start at 0 */
1239*44704f69SBart Van Assche         /* default is to queue at head (in SCSI mid level) */
1240*44704f69SBart Van Assche         if (q_at_tail)
1241*44704f69SBart Van Assche             io_hdr[k].flags |= SG_FLAG_Q_AT_TAIL;
1242*44704f69SBart Van Assche         else
1243*44704f69SBart Van Assche             io_hdr[k].flags |= SG_FLAG_Q_AT_HEAD;
1244*44704f69SBart Van Assche         /* io_hdr[k].usr_ptr = NULL; */
1245*44704f69SBart Van Assche 
1246*44704f69SBart Van Assche         if (write(sg_fd, &io_hdr[k], sizeof(sg_io_hdr_t)) < 0) {
1247*44704f69SBart Van Assche             pr2serr("%ssg write errno=%d [%s]\n", cp, errno, strerror(errno));
1248*44704f69SBart Van Assche             close(sg_fd);
1249*44704f69SBart Van Assche             return 1;
1250*44704f69SBart Van Assche         }
1251*44704f69SBart Van Assche     }
1252*44704f69SBart Van Assche 
1253*44704f69SBart Van Assche     memset(&ssi, 0, sizeof(ssi));
1254*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_SCSI_ID, &ssi) < 0)
1255*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_SCSI_ID) failed, errno=%d %s\n",
1256*44704f69SBart Van Assche                 errno, strerror(errno));
1257*44704f69SBart Van Assche     else {
1258*44704f69SBart Van Assche         printf("host_no: %d\n", ssi.host_no);
1259*44704f69SBart Van Assche         printf("  channel: %d\n", ssi.channel);
1260*44704f69SBart Van Assche         printf("  scsi_id: %d\n", ssi.scsi_id);
1261*44704f69SBart Van Assche         printf("  lun: %d\n", ssi.lun);
1262*44704f69SBart Van Assche         printf("  pdt: %d\n", ssi.scsi_type);
1263*44704f69SBart Van Assche         printf("  h_cmd_per_lun: %d\n", ssi.h_cmd_per_lun);
1264*44704f69SBart Van Assche         printf("  d_queue_depth: %d\n", ssi.d_queue_depth);
1265*44704f69SBart Van Assche         printf("  SCSI 8 byte LUN: ");
1266*44704f69SBart Van Assche         hex2stdout(ssi.scsi_lun, 8, -1);
1267*44704f69SBart Van Assche     }
1268*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
1269*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
1270*44704f69SBart Van Assche                 errno, strerror(errno));
1271*44704f69SBart Van Assche     else
1272*44704f69SBart Van Assche         printf("first available pack_id: %d\n", pack_id);
1273*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
1274*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
1275*44704f69SBart Van Assche                 errno, strerror(errno));
1276*44704f69SBart Van Assche     else
1277*44704f69SBart Van Assche         printf("num_waiting: %d\n", num_waiting);
1278*44704f69SBart Van Assche 
1279*44704f69SBart Van Assche     sleep(sleep_secs);
1280*44704f69SBart Van Assche 
1281*44704f69SBart Van Assche     if (write_only)
1282*44704f69SBart Van Assche         goto out;
1283*44704f69SBart Van Assche 
1284*44704f69SBart Van Assche     if (do_fork)
1285*44704f69SBart Van Assche         printf("\n\nFollowing starting with get_pack_id are all CHILD\n");
1286*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
1287*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
1288*44704f69SBart Van Assche                 errno, strerror(errno));
1289*44704f69SBart Van Assche     else
1290*44704f69SBart Van Assche         printf("first available pack_id: %d\n", pack_id);
1291*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
1292*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
1293*44704f69SBart Van Assche                 errno, strerror(errno));
1294*44704f69SBart Van Assche     else
1295*44704f69SBart Van Assche         printf("num_waiting: %d\n", num_waiting);
1296*44704f69SBart Van Assche 
1297*44704f69SBart Van Assche     printf("\nstart read() calls [io receive]\n");
1298*44704f69SBart Van Assche     for (k = 0, done = false; k < q_len; ++k) {
1299*44704f69SBart Van Assche         if ((! done) && (k == q_len / 2)) {
1300*44704f69SBart Van Assche             done = true;
1301*44704f69SBart Van Assche             printf("\n>>> half way through read\n");
1302*44704f69SBart Van Assche             if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
1303*44704f69SBart Van Assche                 pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
1304*44704f69SBart Van Assche                         errno, strerror(errno));
1305*44704f69SBart Van Assche             else
1306*44704f69SBart Van Assche                 printf("first available pack_id: %d\n", pack_id);
1307*44704f69SBart Van Assche             if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
1308*44704f69SBart Van Assche                 pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
1309*44704f69SBart Van Assche                         errno, strerror(errno));
1310*44704f69SBart Van Assche             else
1311*44704f69SBart Van Assche                 printf("num_waiting: %d\n", num_waiting);
1312*44704f69SBart Van Assche         }
1313*44704f69SBart Van Assche         memset(&rio_hdr, 0, sizeof(sg_io_hdr_t));
1314*44704f69SBart Van Assche         rio_hdr.interface_id = 'S';
1315*44704f69SBart Van Assche         if (read(sg_fd, &rio_hdr, sizeof(sg_io_hdr_t)) < 0) {
1316*44704f69SBart Van Assche             perror("sg read error");
1317*44704f69SBart Van Assche             close(sg_fd);
1318*44704f69SBart Van Assche             return 1;
1319*44704f69SBart Van Assche         }
1320*44704f69SBart Van Assche         /* now for the error processing */
1321*44704f69SBart Van Assche         ok = 0;
1322*44704f69SBart Van Assche         switch (sg_err_category3(&rio_hdr)) {
1323*44704f69SBart Van Assche         case SG_LIB_CAT_CLEAN:
1324*44704f69SBart Van Assche             ok = 1;
1325*44704f69SBart Van Assche             break;
1326*44704f69SBart Van Assche         case SG_LIB_CAT_RECOVERED:
1327*44704f69SBart Van Assche             printf("Recovered error, continuing\n");
1328*44704f69SBart Van Assche             ok = 1;
1329*44704f69SBart Van Assche             break;
1330*44704f69SBart Van Assche         default: /* won't bother decoding other categories */
1331*44704f69SBart Van Assche             sg_chk_n_print3("command error", &rio_hdr, 1);
1332*44704f69SBart Van Assche             break;
1333*44704f69SBart Van Assche         }
1334*44704f69SBart Van Assche 
1335*44704f69SBart Van Assche         if (ok) { /* output result if it is available */
1336*44704f69SBart Van Assche             if (0 == (rio_hdr.pack_id % 3))
1337*44704f69SBart Van Assche                 printf("SEND DIAGNOSTIC %d duration=%u\n", rio_hdr.pack_id,
1338*44704f69SBart Van Assche                        rio_hdr.duration);
1339*44704f69SBart Van Assche             else
1340*44704f69SBart Van Assche                 printf("INQUIRY %d duration=%u\n", rio_hdr.pack_id,
1341*44704f69SBart Van Assche                        rio_hdr.duration);
1342*44704f69SBart Van Assche         }
1343*44704f69SBart Van Assche     }
1344*44704f69SBart Van Assche 
1345*44704f69SBart Van Assche out:
1346*44704f69SBart Van Assche     if (sg_fd >= 0)
1347*44704f69SBart Van Assche         close(sg_fd);
1348*44704f69SBart Van Assche     if (sg_fd2 >= 0)
1349*44704f69SBart Van Assche         close(sg_fd2);
1350*44704f69SBart Van Assche     return res;
1351*44704f69SBart Van Assche }
1352