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