xref: /aosp_15_r20/external/sg3_utils/testing/sg_tst_bidi.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche  *  Copyright (C) 2019 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 <string.h>
19*44704f69SBart Van Assche #include <errno.h>
20*44704f69SBart Van Assche #include <sys/ioctl.h>
21*44704f69SBart Van Assche #include <sys/types.h>
22*44704f69SBart Van Assche #include <sys/stat.h>
23*44704f69SBart Van Assche 
24*44704f69SBart Van Assche #ifndef HAVE_LINUX_SG_V4_HDR
25*44704f69SBart Van Assche 
26*44704f69SBart Van Assche /* Kernel uapi header contain __user decorations on user space pointers
27*44704f69SBart Van Assche  * to indicate they are unsafe in the kernel space. However glibc takes
28*44704f69SBart Van Assche  * all those __user decorations out from headers in /usr/include/linux .
29*44704f69SBart Van Assche  * So to stop compile errors when directly importing include/uapi/scsi/sg.h
30*44704f69SBart Van Assche  * undef __user before doing that include. */
31*44704f69SBart Van Assche #define __user
32*44704f69SBart Van Assche 
33*44704f69SBart Van Assche /* Want to block the original sg.h header from also being included. That
34*44704f69SBart Van Assche  * causes lots of multiple definition errors. This will only work if this
35*44704f69SBart Van Assche  * header is included _before_ the original sg.h header.  */
36*44704f69SBart Van Assche #define _SCSI_GENERIC_H         /* original kernel header guard */
37*44704f69SBart Van Assche #define _SCSI_SG_H              /* glibc header guard */
38*44704f69SBart Van Assche 
39*44704f69SBart Van Assche #include "uapi_sg.h"    /* local copy of include/uapi/scsi/sg.h */
40*44704f69SBart Van Assche 
41*44704f69SBart Van Assche #else
42*44704f69SBart Van Assche #define __user
43*44704f69SBart Van Assche #endif  /* end of: ifndef HAVE_LINUX_SG_V4_HDR */
44*44704f69SBart Van Assche 
45*44704f69SBart Van Assche #include "sg_lib.h"
46*44704f69SBart Van Assche #include "sg_io_linux.h"
47*44704f69SBart Van Assche #include "sg_linux_inc.h"
48*44704f69SBart Van Assche #include "sg_pr2serr.h"
49*44704f69SBart Van Assche #include "sg_unaligned.h"
50*44704f69SBart Van Assche 
51*44704f69SBart Van Assche /* This program tests bidirectional (bidi) SCSI command support in version 4.0
52*44704f69SBart Van Assche  * and later of the Linux sg driver. The SBC-3 command XDWRITEREAD(10) that
53*44704f69SBart Van Assche  is implemented by the scsi_debug driver is used.  */
54*44704f69SBart Van Assche 
55*44704f69SBart Van Assche 
56*44704f69SBart Van Assche static const char * version_str = "Version: 1.06  20191021";
57*44704f69SBart Van Assche 
58*44704f69SBart Van Assche #define INQ_REPLY_LEN 96
59*44704f69SBart Van Assche #define INQ_CMD_OP 0x12
60*44704f69SBart Van Assche #define INQ_CMD_LEN 6
61*44704f69SBart Van Assche #define SENSE_BUFFER_LEN 96
62*44704f69SBart Van Assche #define XDWRITEREAD_10_OP 0x53
63*44704f69SBart Van Assche #define XDWRITEREAD_10_LEN 10
64*44704f69SBart Van Assche 
65*44704f69SBart Van Assche #define EBUFF_SZ 256
66*44704f69SBart Van Assche 
67*44704f69SBart Van Assche #ifndef SG_FLAG_Q_AT_TAIL
68*44704f69SBart Van Assche #define SG_FLAG_Q_AT_TAIL 0x10
69*44704f69SBart Van Assche #endif
70*44704f69SBart Van Assche 
71*44704f69SBart Van Assche #ifndef SG_FLAG_Q_AT_HEAD
72*44704f69SBart Van Assche #define SG_FLAG_Q_AT_HEAD 0x20
73*44704f69SBart Van Assche #endif
74*44704f69SBart Van Assche 
75*44704f69SBart Van Assche #define DEF_Q_LEN 16    /* max in sg v3 and earlier */
76*44704f69SBart Van Assche #define MAX_Q_LEN 256
77*44704f69SBart Van Assche 
78*44704f69SBart Van Assche #define DEF_RESERVE_BUFF_SZ (256 * 1024)
79*44704f69SBart Van Assche 
80*44704f69SBart Van Assche 
81*44704f69SBart Van Assche static bool q_at_tail = false;
82*44704f69SBart Van Assche static int q_len = DEF_Q_LEN;
83*44704f69SBart Van Assche static int sleep_secs = 0;
84*44704f69SBart Van Assche static int reserve_buff_sz = DEF_RESERVE_BUFF_SZ;
85*44704f69SBart Van Assche static int verbose = 0;
86*44704f69SBart Van Assche 
87*44704f69SBart Van Assche 
88*44704f69SBart Van Assche static void
usage(void)89*44704f69SBart Van Assche usage(void)
90*44704f69SBart Van Assche {
91*44704f69SBart Van Assche     printf("Usage: sg_tst_bidi [-b=LB_SZ] [-d=DIO_BLKS] [-D] [-h] -l=LBA [-N] "
92*44704f69SBart Van Assche            "[-q=Q_LEN]\n"
93*44704f69SBart Van Assche            "                   [-Q] [-r=SZ] [-R=RC] [-s=SEC] [-t] [-v] [-V] "
94*44704f69SBart Van Assche            "[-w]\n"
95*44704f69SBart Van Assche            "                   <sg_or_bsg_device>\n"
96*44704f69SBart Van Assche            " where:\n"
97*44704f69SBart Van Assche            "      -b=LB_SZ    logical block size (def: 512 bytes)\n"
98*44704f69SBart Van Assche            "      -d=DIO_BLKS    data in and out length (unit: logical "
99*44704f69SBart Van Assche            "blocks; def: 1)\n"
100*44704f69SBart Van Assche            "      -D    do direct IO (def: indirect which is also "
101*44704f69SBart Van Assche            "fallback)\n"
102*44704f69SBart Van Assche            "      -h    help: print usage message then exit\n"
103*44704f69SBart Van Assche            "      -l=LBA    logical block address (LDA) of first modded "
104*44704f69SBart Van Assche            "block\n"
105*44704f69SBart Van Assche            "      -N    durations in nanoseconds (def: milliseconds)\n"
106*44704f69SBart Van Assche            "      -q=Q_LEN    queue length, between 1 and 511 (def: 16). "
107*44704f69SBart Van Assche            " Calls\n"
108*44704f69SBart Van Assche            "                  ioctl(SG_IO) when -q=1 else SG_IOSUBMIT "
109*44704f69SBart Van Assche            "(async)\n"
110*44704f69SBart Van Assche            "      -Q    quiet, suppress usual output\n"
111*44704f69SBart Van Assche            "      -r=SZ     reserve buffer size in KB (def: 256 --> 256 "
112*44704f69SBart Van Assche            "KB)\n"
113*44704f69SBart Van Assche            "      -R=RC     repetition count (def: 0)\n"
114*44704f69SBart Van Assche            "      -s=SEC    sleep between writes and reads (def: 0)\n"
115*44704f69SBart Van Assche            "      -t    queue_at_tail (def: q_at_head)\n"
116*44704f69SBart Van Assche            "      -v    increase verbosity of output\n"
117*44704f69SBart Van Assche            "      -V    print version string then exit\n"
118*44704f69SBart Van Assche            "      -w    sets DISABLE WRITE bit on cdb to 0 (def: 1)\n\n"
119*44704f69SBart Van Assche            "Warning: this test utility writes to location LBA and Q_LEN "
120*44704f69SBart Van Assche            "following\nblocks using the XDWRITEREAD(10) SBC-3 command. "
121*44704f69SBart Van Assche            "When -q=1 does\nioctl(SG_IO) and that is only case when a "
122*44704f69SBart Van Assche            "bsg device can be given.\n");
123*44704f69SBart Van Assche }
124*44704f69SBart Van Assche 
125*44704f69SBart Van Assche static int
ext_ioctl(int sg_fd,bool nanosecs)126*44704f69SBart Van Assche ext_ioctl(int sg_fd, bool nanosecs)
127*44704f69SBart Van Assche {
128*44704f69SBart Van Assche     struct sg_extended_info sei;
129*44704f69SBart Van Assche     struct sg_extended_info * seip;
130*44704f69SBart Van Assche 
131*44704f69SBart Van Assche     seip = &sei;
132*44704f69SBart Van Assche     memset(seip, 0, sizeof(*seip));
133*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_RESERVED_SIZE;
134*44704f69SBart Van Assche     seip->reserved_sz = reserve_buff_sz;
135*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_RESERVED_SIZE;
136*44704f69SBart Van Assche     seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
137*44704f69SBart Van Assche     seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS; /* this or previous optional */
138*44704f69SBart Van Assche     seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
139*44704f69SBart Van Assche     seip->ctl_flags_rd_mask |= SG_CTL_FLAGM_TIME_IN_NS;
140*44704f69SBart Van Assche     if (nanosecs)
141*44704f69SBart Van Assche         seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
142*44704f69SBart Van Assche     else
143*44704f69SBart Van Assche         seip->ctl_flags &= ~SG_CTL_FLAGM_TIME_IN_NS;
144*44704f69SBart Van Assche 
145*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
146*44704f69SBart Van Assche         pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno,
147*44704f69SBart Van Assche                 strerror(errno));
148*44704f69SBart Van Assche         return 1;
149*44704f69SBart Van Assche     }
150*44704f69SBart Van Assche     return 0;
151*44704f69SBart Van Assche }
152*44704f69SBart Van Assche 
153*44704f69SBart Van Assche 
154*44704f69SBart Van Assche int
main(int argc,char * argv[])155*44704f69SBart Van Assche main(int argc, char * argv[])
156*44704f69SBart Van Assche {
157*44704f69SBart Van Assche     bool done;
158*44704f69SBart Van Assche     bool direct_io = false;
159*44704f69SBart Van Assche     bool lba_given = false;
160*44704f69SBart Van Assche     bool nanosecs = false;
161*44704f69SBart Van Assche     bool quiet = false;
162*44704f69SBart Van Assche     bool disable_write = true;
163*44704f69SBart Van Assche     int k, j, ok, ver_num, pack_id, num_waiting, din_len;
164*44704f69SBart Van Assche     int dout_len, cat;
165*44704f69SBart Van Assche     int ret = 0;
166*44704f69SBart Van Assche     int rep_count = 0;
167*44704f69SBart Van Assche     int sg_fd = -1;
168*44704f69SBart Van Assche     int lb_sz = 512;
169*44704f69SBart Van Assche     int dio_blks = 1;
170*44704f69SBart Van Assche     int dirio_count = 0;
171*44704f69SBart Van Assche     int64_t lba = 0;
172*44704f69SBart Van Assche     uint8_t inq_cdb[INQ_CMD_LEN] = {INQ_CMD_OP, 0, 0, 0, INQ_REPLY_LEN, 0};
173*44704f69SBart Van Assche     uint8_t xdwrrd10_cdb[XDWRITEREAD_10_LEN] =
174*44704f69SBart Van Assche                         {XDWRITEREAD_10_OP, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
175*44704f69SBart Van Assche     uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN];
176*44704f69SBart Van Assche     struct sg_io_v4 io_v4[MAX_Q_LEN];
177*44704f69SBart Van Assche     struct sg_io_v4 rio_v4;
178*44704f69SBart Van Assche     struct sg_io_v4 * io_v4p;
179*44704f69SBart Van Assche     char * file_name = 0;
180*44704f69SBart Van Assche     uint8_t * dinp;
181*44704f69SBart Van Assche     uint8_t * free_dinp = NULL;
182*44704f69SBart Van Assche     uint8_t * doutp;
183*44704f69SBart Van Assche     uint8_t * free_doutp = NULL;
184*44704f69SBart Van Assche     char ebuff[EBUFF_SZ];
185*44704f69SBart Van Assche     uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN] SG_C_CPP_ZERO_INIT;
186*44704f69SBart Van Assche 
187*44704f69SBart Van Assche     for (k = 1; k < argc; ++k) {
188*44704f69SBart Van Assche         if (0 == memcmp("-b=", argv[k], 3)) {
189*44704f69SBart Van Assche             lb_sz = atoi(argv[k] + 3);
190*44704f69SBart Van Assche             if (lb_sz < 512 || (0 != (lb_sz % 512))) {
191*44704f69SBart Van Assche                 printf("Expect -b=LB_SZ be 512 or higher and a power of 2\n");
192*44704f69SBart Van Assche                 file_name = 0;
193*44704f69SBart Van Assche                 break;
194*44704f69SBart Van Assche             }
195*44704f69SBart Van Assche         } else if (0 == memcmp("-d=", argv[k], 3)) {
196*44704f69SBart Van Assche             dio_blks = atoi(argv[k] + 3);
197*44704f69SBart Van Assche             if ((dio_blks < 1) || (dio_blks > 0xffff)) {
198*44704f69SBart Van Assche                 fprintf(stderr, "Expect -d=DIO_BLKS to be 1 or greater and "
199*44704f69SBart Van Assche                         "less than 65536\n");
200*44704f69SBart Van Assche                 file_name = 0;
201*44704f69SBart Van Assche                 break;
202*44704f69SBart Van Assche             }
203*44704f69SBart Van Assche         } else if (0 == memcmp("-D", argv[k], 2))
204*44704f69SBart Van Assche             direct_io = true;
205*44704f69SBart Van Assche         else if (0 == memcmp("-h", argv[k], 2)) {
206*44704f69SBart Van Assche             file_name = 0;
207*44704f69SBart Van Assche             break;
208*44704f69SBart Van Assche         } else if (0 == memcmp("-l=", argv[k], 3)) {
209*44704f69SBart Van Assche             if (lba_given) {
210*44704f69SBart Van Assche                 pr2serr("can only give -l=LBA option once\n");
211*44704f69SBart Van Assche                 file_name = 0;
212*44704f69SBart Van Assche                 break;
213*44704f69SBart Van Assche             }
214*44704f69SBart Van Assche             lba = sg_get_llnum(argv[k] + 3);
215*44704f69SBart Van Assche             if ((lba < 0) || (lba > 0xffffffff)) {
216*44704f69SBart Van Assche                 pr2serr("Expect -l= argument (LBA) to be non-negative and "
217*44704f69SBart Van Assche                         "fit in 32 bits\n");
218*44704f69SBart Van Assche                 return -1;
219*44704f69SBart Van Assche             }
220*44704f69SBart Van Assche             lba_given = true;
221*44704f69SBart Van Assche         } else if (0 == memcmp("-N", argv[k], 2))
222*44704f69SBart Van Assche             nanosecs = true;
223*44704f69SBart Van Assche         else if (0 == memcmp("-q=", argv[k], 3)) {
224*44704f69SBart Van Assche             q_len = atoi(argv[k] + 3);
225*44704f69SBart Van Assche             if ((q_len > 511) || (q_len < 1)) {
226*44704f69SBart Van Assche                 printf("Expect -q= to take a number (q length) between 1 "
227*44704f69SBart Van Assche                        "and 511\n");
228*44704f69SBart Van Assche                 file_name = 0;
229*44704f69SBart Van Assche                 break;
230*44704f69SBart Van Assche             }
231*44704f69SBart Van Assche         } else if (0 == memcmp("-Q", argv[k], 2))
232*44704f69SBart Van Assche             quiet = true;
233*44704f69SBart Van Assche         else if (0 == memcmp("-r=", argv[k], 3)) {
234*44704f69SBart Van Assche             reserve_buff_sz = atoi(argv[k] + 3);
235*44704f69SBart Van Assche             if (reserve_buff_sz < 0) {
236*44704f69SBart Van Assche                 printf("Expect -r= to take a number 0 or higher\n");
237*44704f69SBart Van Assche                 file_name = 0;
238*44704f69SBart Van Assche                 break;
239*44704f69SBart Van Assche             }
240*44704f69SBart Van Assche         } else if (0 == memcmp("-R=", argv[k], 3)) {
241*44704f69SBart Van Assche             rep_count = atoi(argv[k] + 3);
242*44704f69SBart Van Assche             if (rep_count < 0) {
243*44704f69SBart Van Assche                 printf("Expect -R= to take a number 0 or higher\n");
244*44704f69SBart Van Assche                 file_name = 0;
245*44704f69SBart Van Assche                 break;
246*44704f69SBart Van Assche             }
247*44704f69SBart Van Assche         } else if (0 == memcmp("-s=", argv[k], 3)) {
248*44704f69SBart Van Assche             sleep_secs = atoi(argv[k] + 3);
249*44704f69SBart Van Assche             if (sleep_secs < 0) {
250*44704f69SBart Van Assche                 printf("Expect -s= to take a number 0 or higher\n");
251*44704f69SBart Van Assche                 file_name = 0;
252*44704f69SBart Van Assche                 break;
253*44704f69SBart Van Assche             }
254*44704f69SBart Van Assche         } else if (0 == memcmp("-t", argv[k], 2))
255*44704f69SBart Van Assche             q_at_tail = true;
256*44704f69SBart Van Assche         else if (0 == memcmp("-vvvvv", argv[k], 5))
257*44704f69SBart Van Assche             verbose += 5;
258*44704f69SBart Van Assche         else if (0 == memcmp("-vvvv", argv[k], 5))
259*44704f69SBart Van Assche             verbose += 4;
260*44704f69SBart Van Assche         else if (0 == memcmp("-vvv", argv[k], 4))
261*44704f69SBart Van Assche             verbose += 3;
262*44704f69SBart Van Assche         else if (0 == memcmp("-vv", argv[k], 3))
263*44704f69SBart Van Assche             verbose += 2;
264*44704f69SBart Van Assche         else if (0 == memcmp("-v", argv[k], 2))
265*44704f69SBart Van Assche             verbose += 1;
266*44704f69SBart Van Assche         else if (0 == memcmp("-V", argv[k], 2)) {
267*44704f69SBart Van Assche             printf("%s\n", version_str);
268*44704f69SBart Van Assche             return 0;
269*44704f69SBart Van Assche         } else if (0 == memcmp("-w", argv[k], 2))
270*44704f69SBart Van Assche             disable_write = false;
271*44704f69SBart Van Assche         else if (*argv[k] == '-') {
272*44704f69SBart Van Assche             printf("Unrecognized switch: %s\n", argv[k]);
273*44704f69SBart Van Assche             file_name = 0;
274*44704f69SBart Van Assche             break;
275*44704f69SBart Van Assche         }
276*44704f69SBart Van Assche         else if (0 == file_name)
277*44704f69SBart Van Assche             file_name = argv[k];
278*44704f69SBart Van Assche         else {
279*44704f69SBart Van Assche             printf("too many arguments\n");
280*44704f69SBart Van Assche             file_name = 0;
281*44704f69SBart Van Assche             break;
282*44704f69SBart Van Assche         }
283*44704f69SBart Van Assche     }
284*44704f69SBart Van Assche     if (0 == file_name) {
285*44704f69SBart Van Assche         printf("No filename (sg device) given\n\n");
286*44704f69SBart Van Assche         usage();
287*44704f69SBart Van Assche         return 1;
288*44704f69SBart Van Assche     }
289*44704f69SBart Van Assche     if (! lba_given) {
290*44704f69SBart Van Assche         pr2serr("Needs the -l=LBA 'option' to be given, hex numbers "
291*44704f69SBart Van Assche                 "prefixed by '0x';\nor with a trailing 'h'\n");
292*44704f69SBart Van Assche         ret = 1;
293*44704f69SBart Van Assche         goto out;
294*44704f69SBart Van Assche     }
295*44704f69SBart Van Assche     din_len = lb_sz * dio_blks;
296*44704f69SBart Van Assche     dout_len = lb_sz * dio_blks;
297*44704f69SBart Van Assche     dinp = sg_memalign(din_len * q_len, 0, &free_dinp, false);
298*44704f69SBart Van Assche     if (NULL == dinp) {
299*44704f69SBart Van Assche         fprintf(stderr, "Unable to allocate %d byte for din buffer\n",
300*44704f69SBart Van Assche                 din_len * q_len);
301*44704f69SBart Van Assche         ret = 1;
302*44704f69SBart Van Assche         goto out;
303*44704f69SBart Van Assche     }
304*44704f69SBart Van Assche     doutp = sg_memalign(dout_len * q_len, 0, &free_doutp, false);
305*44704f69SBart Van Assche     if (NULL == doutp) {
306*44704f69SBart Van Assche         fprintf(stderr, "Unable to allocate %d byte for dout buffer\n",
307*44704f69SBart Van Assche                 dout_len * q_len);
308*44704f69SBart Van Assche         ret = 1;
309*44704f69SBart Van Assche         goto out;
310*44704f69SBart Van Assche     }
311*44704f69SBart Van Assche 
312*44704f69SBart Van Assche     /* An access mode of O_RDWR is required for write()/read() interface */
313*44704f69SBart Van Assche     if ((sg_fd = open(file_name, O_RDWR)) < 0) {
314*44704f69SBart Van Assche         snprintf(ebuff, EBUFF_SZ,
315*44704f69SBart Van Assche                  "error opening file: %s", file_name);
316*44704f69SBart Van Assche         perror(ebuff);
317*44704f69SBart Van Assche         return 1;
318*44704f69SBart Van Assche     }
319*44704f69SBart Van Assche     if (verbose)
320*44704f69SBart Van Assche         fprintf(stderr, "opened given file: %s successfully, fd=%d\n",
321*44704f69SBart Van Assche                 file_name, sg_fd);
322*44704f69SBart Van Assche 
323*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_VERSION_NUM, &ver_num) < 0) {
324*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_VERSION_NUM) failed, errno=%d %s\n", errno,
325*44704f69SBart Van Assche                 strerror(errno));
326*44704f69SBart Van Assche         goto out;
327*44704f69SBart Van Assche     }
328*44704f69SBart Van Assche     if (! quiet)
329*44704f69SBart Van Assche         printf("Linux sg driver version: %d\n", ver_num);
330*44704f69SBart Van Assche     if ((q_len > 1) && ext_ioctl(sg_fd, nanosecs))
331*44704f69SBart Van Assche         goto out;
332*44704f69SBart Van Assche 
333*44704f69SBart Van Assche 
334*44704f69SBart Van Assche     if (1 == q_len) {   /* do sync ioct(SG_IO) */
335*44704f69SBart Van Assche         io_v4p = &io_v4[k];
336*44704f69SBart Van Assche rep_sg_io:
337*44704f69SBart Van Assche         memset(io_v4p, 0, sizeof(*io_v4p));
338*44704f69SBart Van Assche         io_v4p->guard = 'Q';
339*44704f69SBart Van Assche         if (direct_io)
340*44704f69SBart Van Assche             io_v4p->flags |= SG_FLAG_DIRECT_IO;
341*44704f69SBart Van Assche         if (disable_write)
342*44704f69SBart Van Assche             xdwrrd10_cdb[2] |= 0x4;
343*44704f69SBart Van Assche         sg_put_unaligned_be16(dio_blks, xdwrrd10_cdb + 7);
344*44704f69SBart Van Assche         sg_put_unaligned_be32(lba, xdwrrd10_cdb + 2);
345*44704f69SBart Van Assche         if (verbose > 2) {
346*44704f69SBart Van Assche             pr2serr("    %s cdb: ", "XDWRITE(10)");
347*44704f69SBart Van Assche             for (j = 0; j < XDWRITEREAD_10_LEN; ++j)
348*44704f69SBart Van Assche                 pr2serr("%02x ", xdwrrd10_cdb[j]);
349*44704f69SBart Van Assche             pr2serr("\n");
350*44704f69SBart Van Assche         }
351*44704f69SBart Van Assche         io_v4p->request_len = XDWRITEREAD_10_LEN;
352*44704f69SBart Van Assche         io_v4p->request = (uint64_t)(uintptr_t)xdwrrd10_cdb;
353*44704f69SBart Van Assche         io_v4p->din_xfer_len = din_len;
354*44704f69SBart Van Assche         io_v4p->din_xferp = (uint64_t)(uintptr_t)(dinp + (k * din_len));
355*44704f69SBart Van Assche         io_v4p->dout_xfer_len = dout_len;
356*44704f69SBart Van Assche         io_v4p->dout_xferp = (uint64_t)(uintptr_t)(doutp + (k * dout_len));
357*44704f69SBart Van Assche         io_v4p->response = (uint64_t)(uintptr_t)sense_buffer[k];
358*44704f69SBart Van Assche         io_v4p->max_response_len = SENSE_BUFFER_LEN;
359*44704f69SBart Van Assche         io_v4p->timeout = 20000;     /* 20000 millisecs == 20 seconds */
360*44704f69SBart Van Assche         io_v4p->request_extra = 99;  /* so pack_id doesn't start at 0 */
361*44704f69SBart Van Assche         /* default is to queue at head (in SCSI mid level) */
362*44704f69SBart Van Assche         if (q_at_tail)
363*44704f69SBart Van Assche             io_v4p->flags |= SG_FLAG_Q_AT_TAIL;
364*44704f69SBart Van Assche         else
365*44704f69SBart Van Assche             io_v4p->flags |= SG_FLAG_Q_AT_HEAD;
366*44704f69SBart Van Assche         /* io_v4p->usr_ptr = NULL; */
367*44704f69SBart Van Assche 
368*44704f69SBart Van Assche         if (ioctl(sg_fd, SG_IO, io_v4p) < 0) {
369*44704f69SBart Van Assche             pr2serr("sg ioctl(SG_IO) errno=%d [%s]\n", errno,
370*44704f69SBart Van Assche                     strerror(errno));
371*44704f69SBart Van Assche             close(sg_fd);
372*44704f69SBart Van Assche             return 1;
373*44704f69SBart Van Assche         }
374*44704f69SBart Van Assche         /* now for the error processing */
375*44704f69SBart Van Assche         ok = 0;
376*44704f69SBart Van Assche         rio_v4 = *io_v4p;
377*44704f69SBart Van Assche         cat = sg_err_category_new(rio_v4.device_status,
378*44704f69SBart Van Assche                                   rio_v4.transport_status,
379*44704f69SBart Van Assche                                   rio_v4.driver_status,
380*44704f69SBart Van Assche                           (const uint8_t *)(unsigned long)rio_v4.response,
381*44704f69SBart Van Assche                                   rio_v4.response_len);
382*44704f69SBart Van Assche         switch (cat) {
383*44704f69SBart Van Assche         case SG_LIB_CAT_CLEAN:
384*44704f69SBart Van Assche             ok = 1;
385*44704f69SBart Van Assche             break;
386*44704f69SBart Van Assche         case SG_LIB_CAT_RECOVERED:
387*44704f69SBart Van Assche             printf("Recovered error, continuing\n");
388*44704f69SBart Van Assche             ok = 1;
389*44704f69SBart Van Assche             break;
390*44704f69SBart Van Assche         default: /* won't bother decoding other categories */
391*44704f69SBart Van Assche             sg_linux_sense_print(NULL, rio_v4.device_status,
392*44704f69SBart Van Assche                                  rio_v4.transport_status,
393*44704f69SBart Van Assche                                  rio_v4.driver_status,
394*44704f69SBart Van Assche                          (const uint8_t *)(unsigned long)rio_v4.response,
395*44704f69SBart Van Assche                                  rio_v4.response_len, true);
396*44704f69SBart Van Assche             break;
397*44704f69SBart Van Assche         }
398*44704f69SBart Van Assche         if ((rio_v4.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)
399*44704f69SBart Van Assche             ++dirio_count;
400*44704f69SBart Van Assche         if (verbose > 3) {
401*44704f69SBart Van Assche             pr2serr(">> din_resid=%d, dout_resid=%d, info=0x%x\n",
402*44704f69SBart Van Assche                     rio_v4.din_resid, rio_v4.dout_resid, rio_v4.info);
403*44704f69SBart Van Assche             if (rio_v4.response_len > 0) {
404*44704f69SBart Van Assche                 pr2serr("sense buffer: ");
405*44704f69SBart Van Assche                 hex2stderr(sense_buffer[k], rio_v4.response_len, -1);
406*44704f69SBart Van Assche             }
407*44704f69SBart Van Assche         }
408*44704f69SBart Van Assche         if ((! quiet) && ok)  /* output result if it is available */
409*44704f69SBart Van Assche             printf("XDWRITEREAD(10) using ioctl(SG_IO) duration=%u\n",
410*44704f69SBart Van Assche                    rio_v4.duration);
411*44704f69SBart Van Assche         if (rep_count-- > 0)
412*44704f69SBart Van Assche             goto rep_sg_io;
413*44704f69SBart Van Assche         goto out;
414*44704f69SBart Van Assche     }
415*44704f69SBart Van Assche 
416*44704f69SBart Van Assche rep_async:
417*44704f69SBart Van Assche     if (! quiet)
418*44704f69SBart Van Assche         printf("start write() calls\n");
419*44704f69SBart Van Assche     for (k = 0; k < q_len; ++k) {
420*44704f69SBart Van Assche         io_v4p = &io_v4[k];
421*44704f69SBart Van Assche         memset(io_v4p, 0, sizeof(*io_v4p));
422*44704f69SBart Van Assche         io_v4p->guard = 'Q';
423*44704f69SBart Van Assche         if (direct_io)
424*44704f69SBart Van Assche             io_v4p->flags |= SG_FLAG_DIRECT_IO;
425*44704f69SBart Van Assche         /* io_v4p->iovec_count = 0; */  /* memset takes care of this */
426*44704f69SBart Van Assche         if (0 != (k % 64)) {
427*44704f69SBart Van Assche             if (disable_write)
428*44704f69SBart Van Assche                 xdwrrd10_cdb[2] |= 0x4;
429*44704f69SBart Van Assche             sg_put_unaligned_be16(dio_blks, xdwrrd10_cdb + 7);
430*44704f69SBart Van Assche             sg_put_unaligned_be32(lba, xdwrrd10_cdb + 2);
431*44704f69SBart Van Assche             if (verbose > 2) {
432*44704f69SBart Van Assche                 pr2serr("    %s cdb: ", "XDWRITE(10)");
433*44704f69SBart Van Assche                 for (j = 0; j < XDWRITEREAD_10_LEN; ++j)
434*44704f69SBart Van Assche                     pr2serr("%02x ", xdwrrd10_cdb[j]);
435*44704f69SBart Van Assche                 pr2serr("\n");
436*44704f69SBart Van Assche             }
437*44704f69SBart Van Assche             io_v4p->request_len = XDWRITEREAD_10_LEN;
438*44704f69SBart Van Assche             io_v4p->request = (uint64_t)(uintptr_t)xdwrrd10_cdb;
439*44704f69SBart Van Assche             io_v4p->din_xfer_len = din_len;
440*44704f69SBart Van Assche             io_v4p->din_xferp = (uint64_t)(uintptr_t)(dinp + (k * din_len));
441*44704f69SBart Van Assche             io_v4p->dout_xfer_len = dout_len;
442*44704f69SBart Van Assche             io_v4p->dout_xferp = (uint64_t)(uintptr_t)(doutp + (k * dout_len));
443*44704f69SBart Van Assche         } else {
444*44704f69SBart Van Assche             if (verbose > 2) {
445*44704f69SBart Van Assche                 pr2serr("    %s cdb: ", "INQUIRY");
446*44704f69SBart Van Assche                 for (j = 0; j < INQ_CMD_LEN; ++j)
447*44704f69SBart Van Assche                     pr2serr("%02x ", inq_cdb[j]);
448*44704f69SBart Van Assche                 pr2serr("\n");
449*44704f69SBart Van Assche             }
450*44704f69SBart Van Assche             io_v4p->request_len = sizeof(inq_cdb);
451*44704f69SBart Van Assche             io_v4p->request = (uint64_t)(uintptr_t)inq_cdb;
452*44704f69SBart Van Assche             io_v4p->din_xfer_len = INQ_REPLY_LEN;
453*44704f69SBart Van Assche             io_v4p->din_xferp = (uint64_t)(uintptr_t)inqBuff[k];
454*44704f69SBart Van Assche         }
455*44704f69SBart Van Assche         io_v4p->response = (uint64_t)(uintptr_t)sense_buffer[k];
456*44704f69SBart Van Assche         io_v4p->max_response_len = SENSE_BUFFER_LEN;
457*44704f69SBart Van Assche         io_v4p->timeout = 20000;     /* 20000 millisecs == 20 seconds */
458*44704f69SBart Van Assche         io_v4p->request_extra = k + 3;  /* so pack_id doesn't start at 0 */
459*44704f69SBart Van Assche         /* default is to queue at head (in SCSI mid level) */
460*44704f69SBart Van Assche         if (q_at_tail)
461*44704f69SBart Van Assche             io_v4p->flags |= SG_FLAG_Q_AT_TAIL;
462*44704f69SBart Van Assche         else
463*44704f69SBart Van Assche             io_v4p->flags |= SG_FLAG_Q_AT_HEAD;
464*44704f69SBart Van Assche         /* io_v4p->usr_ptr = NULL; */
465*44704f69SBart Van Assche 
466*44704f69SBart Van Assche         if (ioctl(sg_fd, SG_IOSUBMIT, io_v4p) < 0) {
467*44704f69SBart Van Assche             pr2serr("sg ioctl(SG_IOSUBMIT) errno=%d [%s]\n", errno,
468*44704f69SBart Van Assche                     strerror(errno));
469*44704f69SBart Van Assche             close(sg_fd);
470*44704f69SBart Van Assche             return 1;
471*44704f69SBart Van Assche         }
472*44704f69SBart Van Assche     }
473*44704f69SBart Van Assche 
474*44704f69SBart Van Assche #if 0
475*44704f69SBart Van Assche     {
476*44704f69SBart Van Assche         struct sg_scsi_id ssi;
477*44704f69SBart Van Assche 
478*44704f69SBart Van Assche         memset(&ssi, 0, sizeof(ssi));
479*44704f69SBart Van Assche         if (ioctl(sg_fd, SG_GET_SCSI_ID, &ssi) < 0)
480*44704f69SBart Van Assche             pr2serr("ioctl(SG_GET_SCSI_ID) failed, errno=%d %s\n",
481*44704f69SBart Van Assche                     errno, strerror(errno));
482*44704f69SBart Van Assche         else {
483*44704f69SBart Van Assche             printf("host_no: %d\n", ssi.host_no);
484*44704f69SBart Van Assche             printf("  channel: %d\n", ssi.channel);
485*44704f69SBart Van Assche             printf("  scsi_id: %d\n", ssi.scsi_id);
486*44704f69SBart Van Assche             printf("  lun: %d\n", ssi.lun);
487*44704f69SBart Van Assche             printf("  pdt: %d\n", ssi.scsi_type);
488*44704f69SBart Van Assche             printf("  h_cmd_per_lun: %d\n", ssi.h_cmd_per_lun);
489*44704f69SBart Van Assche             printf("  d_queue_depth: %d\n", ssi.d_queue_depth);
490*44704f69SBart Van Assche         }
491*44704f69SBart Van Assche     }
492*44704f69SBart Van Assche #endif
493*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
494*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
495*44704f69SBart Van Assche                 errno, strerror(errno));
496*44704f69SBart Van Assche     else if (! quiet)
497*44704f69SBart Van Assche         printf("first available pack_id: %d\n", pack_id);
498*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
499*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
500*44704f69SBart Van Assche                 errno, strerror(errno));
501*44704f69SBart Van Assche     else if (! quiet)
502*44704f69SBart Van Assche         printf("num_waiting: %d\n", num_waiting);
503*44704f69SBart Van Assche 
504*44704f69SBart Van Assche     if (sleep_secs > 0)
505*44704f69SBart Van Assche         sleep(sleep_secs);
506*44704f69SBart Van Assche 
507*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
508*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
509*44704f69SBart Van Assche                 errno, strerror(errno));
510*44704f69SBart Van Assche     else if (! quiet)
511*44704f69SBart Van Assche         printf("first available pack_id: %d\n", pack_id);
512*44704f69SBart Van Assche     if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
513*44704f69SBart Van Assche         pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
514*44704f69SBart Van Assche                 errno, strerror(errno));
515*44704f69SBart Van Assche     else if (! quiet)
516*44704f69SBart Van Assche         printf("num_waiting: %d\n", num_waiting);
517*44704f69SBart Van Assche 
518*44704f69SBart Van Assche     if (! quiet)
519*44704f69SBart Van Assche         printf("\nstart read() calls\n");
520*44704f69SBart Van Assche     for (k = 0, done = false; k < q_len; ++k) {
521*44704f69SBart Van Assche         if ((! done) && (k == q_len / 2)) {
522*44704f69SBart Van Assche             done = true;
523*44704f69SBart Van Assche             if (! quiet)
524*44704f69SBart Van Assche                 printf("\n>>> half way through read\n");
525*44704f69SBart Van Assche             if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
526*44704f69SBart Van Assche                 pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
527*44704f69SBart Van Assche                         errno, strerror(errno));
528*44704f69SBart Van Assche             else if (! quiet)
529*44704f69SBart Van Assche                 printf("first available pack_id: %d\n", pack_id);
530*44704f69SBart Van Assche             if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
531*44704f69SBart Van Assche                 pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
532*44704f69SBart Van Assche                         errno, strerror(errno));
533*44704f69SBart Van Assche             else if (! quiet)
534*44704f69SBart Van Assche                 printf("num_waiting: %d\n", num_waiting);
535*44704f69SBart Van Assche         }
536*44704f69SBart Van Assche         memset(&rio_v4, 0, sizeof(struct sg_io_v4));
537*44704f69SBart Van Assche         rio_v4.guard = 'Q';
538*44704f69SBart Van Assche         if (ioctl(sg_fd, SG_IORECEIVE, &rio_v4) < 0) {
539*44704f69SBart Van Assche             perror("sg ioctl(SG_IORECEIVE) error");
540*44704f69SBart Van Assche             close(sg_fd);
541*44704f69SBart Van Assche             return 1;
542*44704f69SBart Van Assche         }
543*44704f69SBart Van Assche         /* now for the error processing */
544*44704f69SBart Van Assche         ok = 0;
545*44704f69SBart Van Assche         cat = sg_err_category_new(rio_v4.device_status,
546*44704f69SBart Van Assche                                   rio_v4.transport_status,
547*44704f69SBart Van Assche                                   rio_v4.driver_status,
548*44704f69SBart Van Assche                           (const uint8_t *)(unsigned long)rio_v4.response,
549*44704f69SBart Van Assche                                   rio_v4.response_len);
550*44704f69SBart Van Assche         switch (cat) {
551*44704f69SBart Van Assche         case SG_LIB_CAT_CLEAN:
552*44704f69SBart Van Assche             ok = 1;
553*44704f69SBart Van Assche             break;
554*44704f69SBart Van Assche         case SG_LIB_CAT_RECOVERED:
555*44704f69SBart Van Assche             printf("Recovered error, continuing\n");
556*44704f69SBart Van Assche             ok = 1;
557*44704f69SBart Van Assche             break;
558*44704f69SBart Van Assche         default: /* won't bother decoding other categories */
559*44704f69SBart Van Assche             sg_linux_sense_print(NULL, rio_v4.device_status,
560*44704f69SBart Van Assche                                  rio_v4.transport_status,
561*44704f69SBart Van Assche                                  rio_v4.driver_status,
562*44704f69SBart Van Assche                          (const uint8_t *)(unsigned long)rio_v4.response,
563*44704f69SBart Van Assche                                  rio_v4.response_len, true);
564*44704f69SBart Van Assche             break;
565*44704f69SBart Van Assche         }
566*44704f69SBart Van Assche         if ((rio_v4.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)
567*44704f69SBart Van Assche             ++dirio_count;
568*44704f69SBart Van Assche         if (verbose > 3) {
569*44704f69SBart Van Assche             pr2serr(">> din_resid=%d, dout_resid=%d, info=0x%x\n",
570*44704f69SBart Van Assche                     rio_v4.din_resid, rio_v4.dout_resid, rio_v4.info);
571*44704f69SBart Van Assche             if (rio_v4.response_len > 0) {
572*44704f69SBart Van Assche                 pr2serr("sense buffer: ");
573*44704f69SBart Van Assche                 hex2stderr(sense_buffer[k], rio_v4.response_len, -1);
574*44704f69SBart Van Assche             }
575*44704f69SBart Van Assche         }
576*44704f69SBart Van Assche         if ((! quiet) && ok) { /* output result if it is available */
577*44704f69SBart Van Assche             if (0 != ((rio_v4.request_extra - 3) % 64))
578*44704f69SBart Van Assche                 printf("XDWRITEREAD(10) %d duration=%u\n",
579*44704f69SBart Van Assche                        rio_v4.request_extra, rio_v4.duration);
580*44704f69SBart Van Assche             else
581*44704f69SBart Van Assche                 printf("INQUIRY %d duration=%u\n",
582*44704f69SBart Van Assche                        rio_v4.request_extra,
583*44704f69SBart Van Assche                        rio_v4.duration);
584*44704f69SBart Van Assche         }
585*44704f69SBart Van Assche     }
586*44704f69SBart Van Assche     if (direct_io && (dirio_count < q_len)) {
587*44704f69SBart Van Assche         pr2serr("Direct IO requested %d times, done %d times\nMaybe need "
588*44704f69SBart Van Assche                 "'echo 1 > /sys/module/sg/parameters/allow_dio'\n", q_len, dirio_count);
589*44704f69SBart Van Assche     }
590*44704f69SBart Van Assche     if (rep_count-- > 0)
591*44704f69SBart Van Assche         goto rep_async;
592*44704f69SBart Van Assche     ret = 0;
593*44704f69SBart Van Assche 
594*44704f69SBart Van Assche out:
595*44704f69SBart Van Assche     if (sg_fd >= 0)
596*44704f69SBart Van Assche         close(sg_fd);
597*44704f69SBart Van Assche     if (free_dinp)
598*44704f69SBart Van Assche         free(free_dinp);
599*44704f69SBart Van Assche     if (free_doutp)
600*44704f69SBart Van Assche         free(free_doutp);
601*44704f69SBart Van Assche     return ret;
602*44704f69SBart Van Assche }
603