1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * A utility program for copying files. Specialised for "files" that
3*44704f69SBart Van Assche * represent devices that understand the SCSI command set.
4*44704f69SBart Van Assche *
5*44704f69SBart Van Assche * Copyright (C) 2018-2022 D. Gilbert
6*44704f69SBart Van Assche * This program is free software; you can redistribute it and/or modify
7*44704f69SBart Van Assche * it under the terms of the GNU General Public License as published by
8*44704f69SBart Van Assche * the Free Software Foundation; either version 2, or (at your option)
9*44704f69SBart Van Assche * any later version.
10*44704f69SBart Van Assche *
11*44704f69SBart Van Assche * SPDX-License-Identifier: GPL-2.0-or-later
12*44704f69SBart Van Assche *
13*44704f69SBart Van Assche * This program is a specialisation of the Unix "dd" command in which
14*44704f69SBart Van Assche * one or both of the given files is a scsi generic device.
15*44704f69SBart Van Assche * A logical block size ('bs') is assumed to be 512 if not given. This
16*44704f69SBart Van Assche * program complains if 'ibs' or 'obs' are given with some other value
17*44704f69SBart Van Assche * than 'bs'. If 'if' is not given or 'if=-' then stdin is assumed. If
18*44704f69SBart Van Assche * 'of' is not given or 'of=-' then stdout assumed.
19*44704f69SBart Van Assche *
20*44704f69SBart Van Assche * A non-standard argument "bpt" (blocks per transfer) is added to control
21*44704f69SBart Van Assche * the maximum number of blocks in each transfer. The default value is 128.
22*44704f69SBart Van Assche * For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16 KiB
23*44704f69SBart Van Assche * in this case) are transferred to or from the sg device in a single SCSI
24*44704f69SBart Van Assche * command.
25*44704f69SBart Van Assche *
26*44704f69SBart Van Assche * This version is designed for the linux kernel 2.4, 2.6, 3, 4 and 5 series.
27*44704f69SBart Van Assche *
28*44704f69SBart Van Assche * sgp_dd is a Posix threads specialization of the sg_dd utility. Both
29*44704f69SBart Van Assche * sgp_dd and sg_dd only perform special tasks when one or both of the given
30*44704f69SBart Van Assche * devices belong to the Linux sg driver.
31*44704f69SBart Van Assche *
32*44704f69SBart Van Assche * sgh_dd further extends sgp_dd to use the experimental kernel buffer
33*44704f69SBart Van Assche * sharing feature added in 3.9.02 .
34*44704f69SBart Van Assche * N.B. This utility was previously called sgs_dd but there was already an
35*44704f69SBart Van Assche * archived version of a dd variant called sgs_dd so this utility name was
36*44704f69SBart Van Assche * renamed [20181221]
37*44704f69SBart Van Assche */
38*44704f69SBart Van Assche
39*44704f69SBart Van Assche static const char * version_str = "2.22 20221020";
40*44704f69SBart Van Assche
41*44704f69SBart Van Assche #define _XOPEN_SOURCE 600
42*44704f69SBart Van Assche #ifndef _GNU_SOURCE
43*44704f69SBart Van Assche #define _GNU_SOURCE 1
44*44704f69SBart Van Assche #endif
45*44704f69SBart Van Assche
46*44704f69SBart Van Assche #include <unistd.h>
47*44704f69SBart Van Assche #include <fcntl.h>
48*44704f69SBart Van Assche #include <stdio.h>
49*44704f69SBart Van Assche #include <stdlib.h>
50*44704f69SBart Van Assche #include <stdarg.h>
51*44704f69SBart Van Assche #include <stdbool.h>
52*44704f69SBart Van Assche #include <string.h>
53*44704f69SBart Van Assche #include <ctype.h>
54*44704f69SBart Van Assche #include <errno.h>
55*44704f69SBart Van Assche #include <poll.h>
56*44704f69SBart Van Assche #include <limits.h>
57*44704f69SBart Van Assche #include <pthread.h>
58*44704f69SBart Van Assche #include <signal.h>
59*44704f69SBart Van Assche #define __STDC_FORMAT_MACROS 1
60*44704f69SBart Van Assche #include <inttypes.h>
61*44704f69SBart Van Assche #include <sys/ioctl.h>
62*44704f69SBart Van Assche #include <sys/stat.h>
63*44704f69SBart Van Assche #include <sys/sysmacros.h>
64*44704f69SBart Van Assche #ifndef major
65*44704f69SBart Van Assche #include <sys/types.h>
66*44704f69SBart Van Assche #endif
67*44704f69SBart Van Assche #include <sys/time.h>
68*44704f69SBart Van Assche #include <linux/major.h> /* for MEM_MAJOR, SCSI_GENERIC_MAJOR, etc */
69*44704f69SBart Van Assche #include <linux/fs.h> /* for BLKSSZGET and friends */
70*44704f69SBart Van Assche #include <sys/mman.h> /* for mmap() system call */
71*44704f69SBart Van Assche
72*44704f69SBart Van Assche #include <vector>
73*44704f69SBart Van Assche #include <array>
74*44704f69SBart Van Assche #include <atomic> // C++ header replacing <stdatomic.h> also link
75*44704f69SBart Van Assche // needed '-l atomic' . Not anymore??
76*44704f69SBart Van Assche #include <random>
77*44704f69SBart Van Assche #include <thread> // needed for std::this_thread::yield()
78*44704f69SBart Van Assche #include <mutex>
79*44704f69SBart Van Assche #include <chrono>
80*44704f69SBart Van Assche
81*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
82*44704f69SBart Van Assche #include "config.h"
83*44704f69SBart Van Assche #endif
84*44704f69SBart Van Assche
85*44704f69SBart Van Assche #ifdef HAVE_GETRANDOM
86*44704f69SBart Van Assche #include <sys/random.h> /* for getrandom() system call */
87*44704f69SBart Van Assche #endif
88*44704f69SBart Van Assche
89*44704f69SBart Van Assche #ifndef HAVE_LINUX_SG_V4_HDR
90*44704f69SBart Van Assche /* Kernel uapi header contain __user decorations on user space pointers
91*44704f69SBart Van Assche * to indicate they are unsafe in the kernel space. However glibc takes
92*44704f69SBart Van Assche * all those __user decorations out from headers in /usr/include/linux .
93*44704f69SBart Van Assche * So to stop compile errors when directly importing include/uapi/scsi/sg.h
94*44704f69SBart Van Assche * undef __user before doing that include. */
95*44704f69SBart Van Assche #define __user
96*44704f69SBart Van Assche
97*44704f69SBart Van Assche /* Want to block the original sg.h header from also being included. That
98*44704f69SBart Van Assche * causes lots of multiple definition errors. This will only work if this
99*44704f69SBart Van Assche * header is included _before_ the original sg.h header. */
100*44704f69SBart Van Assche #define _SCSI_GENERIC_H /* original kernel header guard */
101*44704f69SBart Van Assche #define _SCSI_SG_H /* glibc header guard */
102*44704f69SBart Van Assche
103*44704f69SBart Van Assche #include "uapi_sg.h" /* local copy of include/uapi/scsi/sg.h */
104*44704f69SBart Van Assche
105*44704f69SBart Van Assche #else
106*44704f69SBart Van Assche #define __user
107*44704f69SBart Van Assche #endif /* end of: ifndef HAVE_LINUX_SG_V4_HDR */
108*44704f69SBart Van Assche
109*44704f69SBart Van Assche #include "sg_lib.h"
110*44704f69SBart Van Assche #include "sg_cmds_basic.h"
111*44704f69SBart Van Assche #include "sg_io_linux.h"
112*44704f69SBart Van Assche #include "sg_unaligned.h"
113*44704f69SBart Van Assche #include "sg_pr2serr.h"
114*44704f69SBart Van Assche
115*44704f69SBart Van Assche
116*44704f69SBart Van Assche using namespace std;
117*44704f69SBart Van Assche
118*44704f69SBart Van Assche #ifdef __GNUC__
119*44704f69SBart Van Assche #ifndef __clang__
120*44704f69SBart Van Assche #pragma GCC diagnostic ignored "-Wclobbered"
121*44704f69SBart Van Assche #endif
122*44704f69SBart Van Assche #endif
123*44704f69SBart Van Assche
124*44704f69SBart Van Assche /* comment out following line to stop ioctl(SG_CTL_FLAGM_SNAP_DEV) */
125*44704f69SBart Van Assche #define SGH_DD_SNAP_DEV 1
126*44704f69SBart Van Assche
127*44704f69SBart Van Assche #ifndef SGV4_FLAG_POLLED
128*44704f69SBart Van Assche #define SGV4_FLAG_POLLED 0x800
129*44704f69SBart Van Assche #endif
130*44704f69SBart Van Assche
131*44704f69SBart Van Assche #define DEF_BLOCK_SIZE 512
132*44704f69SBart Van Assche #define DEF_BLOCKS_PER_TRANSFER 128
133*44704f69SBart Van Assche #define DEF_BLOCKS_PER_2048TRANSFER 32
134*44704f69SBart Van Assche #define DEF_SDT_ICT_MS 300
135*44704f69SBart Van Assche #define DEF_SDT_CRT_SEC 3
136*44704f69SBart Van Assche #define DEF_SCSI_CDBSZ 10
137*44704f69SBart Van Assche #define MAX_SCSI_CDBSZ 16
138*44704f69SBart Van Assche #define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */
139*44704f69SBart Van Assche #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */
140*44704f69SBart Van Assche
141*44704f69SBart Van Assche #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
142*44704f69SBart Van Assche #define READ_CAP_REPLY_LEN 8
143*44704f69SBart Van Assche #define RCAP16_REPLY_LEN 32
144*44704f69SBart Van Assche
145*44704f69SBart Van Assche #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
146*44704f69SBart Van Assche
147*44704f69SBart Van Assche #define SGP_READ10 0x28
148*44704f69SBart Van Assche #define SGP_PRE_FETCH10 0x34
149*44704f69SBart Van Assche #define SGP_PRE_FETCH16 0x90
150*44704f69SBart Van Assche #define SGP_VERIFY10 0x2f
151*44704f69SBart Van Assche #define SGP_WRITE10 0x2a
152*44704f69SBart Van Assche #define DEF_NUM_THREADS 4
153*44704f69SBart Van Assche #define MAX_NUM_THREADS 1024 /* was SG_MAX_QUEUE with v3 driver */
154*44704f69SBart Van Assche #define DEF_NUM_MRQS 0
155*44704f69SBart Van Assche
156*44704f69SBart Van Assche #define FT_OTHER 1 /* filetype other than one of the following */
157*44704f69SBart Van Assche #define FT_SG 2 /* filetype is sg char device */
158*44704f69SBart Van Assche #define FT_DEV_NULL 4 /* either /dev/null, /dev/zero or "." */
159*44704f69SBart Van Assche #define FT_ST 8 /* filetype is st char device (tape) */
160*44704f69SBart Van Assche #define FT_CHAR 16 /* filetype is st char device (tape) */
161*44704f69SBart Van Assche #define FT_BLOCK 32 /* filetype is a block device */
162*44704f69SBart Van Assche #define FT_FIFO 64 /* fifo (named or unnamed pipe (stdout)) */
163*44704f69SBart Van Assche #define FT_RANDOM_0_FF 128 /* iflag=00, iflag=ff and iflag=random
164*44704f69SBart Van Assche override if=IFILE */
165*44704f69SBart Van Assche #define FT_ERROR 256 /* couldn't "stat" file */
166*44704f69SBart Van Assche
167*44704f69SBart Van Assche #define DEV_NULL_MINOR_NUM 3
168*44704f69SBart Van Assche #define DEV_ZERO_MINOR_NUM 5
169*44704f69SBart Van Assche
170*44704f69SBart Van Assche #define EBUFF_SZ 768
171*44704f69SBart Van Assche
172*44704f69SBart Van Assche #define PROC_SCSI_SG_VERSION "/proc/scsi/sg/version"
173*44704f69SBart Van Assche #define SYS_SCSI_SG_VERSION "/sys/module/sg/version"
174*44704f69SBart Van Assche
175*44704f69SBart Van Assche struct flags_t {
176*44704f69SBart Van Assche bool append;
177*44704f69SBart Van Assche bool coe;
178*44704f69SBart Van Assche bool defres; /* without this res_sz==bs*bpt */
179*44704f69SBart Van Assche bool dio;
180*44704f69SBart Van Assche bool direct;
181*44704f69SBart Van Assche bool dpo;
182*44704f69SBart Van Assche bool dsync;
183*44704f69SBart Van Assche bool excl;
184*44704f69SBart Van Assche bool ff;
185*44704f69SBart Van Assche bool fua;
186*44704f69SBart Van Assche bool polled; /* formerly called 'hipri' */
187*44704f69SBart Van Assche bool masync; /* more async sg v4 driver flag */
188*44704f69SBart Van Assche bool mrq_immed; /* mrq submit non-blocking */
189*44704f69SBart Van Assche bool mrq_svb; /* mrq shared_variable_block, for sg->sg copy */
190*44704f69SBart Van Assche bool no_dur;
191*44704f69SBart Van Assche bool nocreat;
192*44704f69SBart Van Assche bool noshare;
193*44704f69SBart Van Assche bool no_thresh;
194*44704f69SBart Van Assche bool no_unshare; /* leave it for driver close/release */
195*44704f69SBart Van Assche bool no_waitq; /* dummy, no longer supported, just warn */
196*44704f69SBart Van Assche bool noxfer;
197*44704f69SBart Van Assche bool qhead;
198*44704f69SBart Van Assche bool qtail;
199*44704f69SBart Van Assche bool random;
200*44704f69SBart Van Assche bool mout_if; /* META_OUT_IF flag at mrq level */
201*44704f69SBart Van Assche bool same_fds;
202*44704f69SBart Van Assche bool swait; /* now ignore; kept for backward compatibility */
203*44704f69SBart Van Assche bool v3;
204*44704f69SBart Van Assche bool v4;
205*44704f69SBart Van Assche bool v4_given;
206*44704f69SBart Van Assche bool wq_excl;
207*44704f69SBart Van Assche bool zero;
208*44704f69SBart Van Assche int mmap;
209*44704f69SBart Van Assche };
210*44704f69SBart Van Assche
211*44704f69SBart Van Assche struct global_collection
212*44704f69SBart Van Assche { /* one instance visible to all threads */
213*44704f69SBart Van Assche int infd;
214*44704f69SBart Van Assche int64_t skip;
215*44704f69SBart Van Assche int in_type;
216*44704f69SBart Van Assche int cdbsz_in;
217*44704f69SBart Van Assche int help;
218*44704f69SBart Van Assche int elem_sz;
219*44704f69SBart Van Assche struct flags_t in_flags;
220*44704f69SBart Van Assche // int64_t in_blk; /* -\ next block address to read */
221*44704f69SBart Van Assche // int64_t in_count; /* | blocks remaining for next read */
222*44704f69SBart Van Assche atomic<int64_t> in_rem_count; /* | count of remaining in blocks */
223*44704f69SBart Van Assche atomic<int> in_partial; /* | */
224*44704f69SBart Van Assche atomic<bool> in_stop; /* | */
225*44704f69SBart Van Assche off_t in_st_size; /* Only for FT_OTHER (regular) file */
226*44704f69SBart Van Assche pthread_mutex_t in_mutex; /* -/ */
227*44704f69SBart Van Assche int nmrqs; /* Number of multi-reqs for sg v4 */
228*44704f69SBart Van Assche int outfd;
229*44704f69SBart Van Assche int64_t seek;
230*44704f69SBart Van Assche int out_type;
231*44704f69SBart Van Assche int out2fd;
232*44704f69SBart Van Assche int out2_type;
233*44704f69SBart Van Assche int cdbsz_out;
234*44704f69SBart Van Assche int aen; /* abort every nth command */
235*44704f69SBart Van Assche int m_aen; /* abort mrq every nth command */
236*44704f69SBart Van Assche struct flags_t out_flags;
237*44704f69SBart Van Assche atomic<int64_t> out_blk; /* -\ next block address to write */
238*44704f69SBart Van Assche atomic<int64_t> out_count; /* | blocks remaining for next write */
239*44704f69SBart Van Assche atomic<int64_t> out_rem_count; /* | count of remaining out blocks */
240*44704f69SBart Van Assche atomic<int> out_partial; /* | */
241*44704f69SBart Van Assche atomic<bool> out_stop; /* | */
242*44704f69SBart Van Assche off_t out_st_size; /* Only for FT_OTHER (regular) file */
243*44704f69SBart Van Assche pthread_mutex_t out_mutex; /* | */
244*44704f69SBart Van Assche pthread_cond_t out_sync_cv; /* | hold writes until "in order" */
245*44704f69SBart Van Assche pthread_mutex_t out2_mutex;
246*44704f69SBart Van Assche int bs;
247*44704f69SBart Van Assche int bpt;
248*44704f69SBart Van Assche int cmd_timeout; /* in milliseconds */
249*44704f69SBart Van Assche int outregfd;
250*44704f69SBart Van Assche int outreg_type;
251*44704f69SBart Van Assche int ofsplit;
252*44704f69SBart Van Assche atomic<int> dio_incomplete_count;
253*44704f69SBart Van Assche atomic<int> sum_of_resids;
254*44704f69SBart Van Assche uint32_t sdt_ict; /* stall detection; initial check time (milliseconds) */
255*44704f69SBart Van Assche uint32_t sdt_crt; /* check repetition time (seconds), after first stall */
256*44704f69SBart Van Assche int fail_mask;
257*44704f69SBart Van Assche int verbose;
258*44704f69SBart Van Assche int dry_run;
259*44704f69SBart Van Assche int chkaddr;
260*44704f69SBart Van Assche bool aen_given;
261*44704f69SBart Van Assche bool cdbsz_given;
262*44704f69SBart Van Assche bool is_mrq_i;
263*44704f69SBart Van Assche bool is_mrq_o;
264*44704f69SBart Van Assche bool m_aen_given;
265*44704f69SBart Van Assche bool ofile_given;
266*44704f69SBart Van Assche bool ofile2_given;
267*44704f69SBart Van Assche bool unit_nanosec; /* default duration unit is millisecond */
268*44704f69SBart Van Assche bool mrq_cmds; /* mrq=<NRQS>,C given */
269*44704f69SBart Van Assche bool mrq_async; /* mrq_immed flag given */
270*44704f69SBart Van Assche bool noshare; /* don't use request sharing */
271*44704f69SBart Van Assche bool unbalanced_mrq; /* so _not_ sg->sg request sharing sync mrq */
272*44704f69SBart Van Assche bool verify; /* don't copy, verify like Unix: cmp */
273*44704f69SBart Van Assche bool prefetch; /* for verify: do PF(b),RD(a),V(b)_a_data */
274*44704f69SBart Van Assche bool unshare; /* let close() do file unshare operation */
275*44704f69SBart Van Assche const char * infp;
276*44704f69SBart Van Assche const char * outfp;
277*44704f69SBart Van Assche const char * out2fp;
278*44704f69SBart Van Assche };
279*44704f69SBart Van Assche
280*44704f69SBart Van Assche typedef struct mrq_abort_info
281*44704f69SBart Van Assche {
282*44704f69SBart Van Assche int from_tid;
283*44704f69SBart Van Assche int fd;
284*44704f69SBart Van Assche int mrq_id;
285*44704f69SBart Van Assche int debug;
286*44704f69SBart Van Assche } Mrq_abort_info;
287*44704f69SBart Van Assche
288*44704f69SBart Van Assche typedef struct request_element
289*44704f69SBart Van Assche { /* one instance per worker thread */
290*44704f69SBart Van Assche struct global_collection *clp;
291*44704f69SBart Van Assche bool wr;
292*44704f69SBart Van Assche bool has_share;
293*44704f69SBart Van Assche bool both_sg;
294*44704f69SBart Van Assche bool same_sg;
295*44704f69SBart Van Assche bool only_in_sg;
296*44704f69SBart Van Assche bool only_out_sg;
297*44704f69SBart Van Assche // bool mrq_abort_thread_active;
298*44704f69SBart Van Assche int id;
299*44704f69SBart Van Assche int bs;
300*44704f69SBart Van Assche int infd;
301*44704f69SBart Van Assche int outfd;
302*44704f69SBart Van Assche int out2fd;
303*44704f69SBart Van Assche int outregfd;
304*44704f69SBart Van Assche int64_t iblk;
305*44704f69SBart Van Assche int64_t oblk;
306*44704f69SBart Van Assche int num_blks;
307*44704f69SBart Van Assche uint8_t * buffp;
308*44704f69SBart Van Assche uint8_t * alloc_bp;
309*44704f69SBart Van Assche struct sg_io_hdr io_hdr;
310*44704f69SBart Van Assche struct sg_io_v4 io_hdr4[2];
311*44704f69SBart Van Assche uint8_t cmd[MAX_SCSI_CDBSZ];
312*44704f69SBart Van Assche uint8_t sb[SENSE_BUFF_LEN];
313*44704f69SBart Van Assche int dio_incomplete_count;
314*44704f69SBart Van Assche int mmap_active;
315*44704f69SBart Van Assche int resid;
316*44704f69SBart Van Assche int rd_p_id;
317*44704f69SBart Van Assche int rep_count;
318*44704f69SBart Van Assche int rq_id;
319*44704f69SBart Van Assche int mmap_len;
320*44704f69SBart Van Assche int mrq_id;
321*44704f69SBart Van Assche int mrq_index;
322*44704f69SBart Van Assche uint32_t in_mrq_q_blks;
323*44704f69SBart Van Assche uint32_t out_mrq_q_blks;
324*44704f69SBart Van Assche long seed;
325*44704f69SBart Van Assche #ifdef HAVE_SRAND48_R /* gcc extension. N.B. non-reentrant version slower */
326*44704f69SBart Van Assche struct drand48_data drand;/* opaque, used by srand48_r and mrand48_r */
327*44704f69SBart Van Assche #endif
328*44704f69SBart Van Assche pthread_t mrq_abort_thread_id;
329*44704f69SBart Van Assche Mrq_abort_info mai;
330*44704f69SBart Van Assche } Rq_elem;
331*44704f69SBart Van Assche
332*44704f69SBart Van Assche typedef struct thread_info
333*44704f69SBart Van Assche {
334*44704f69SBart Van Assche int id;
335*44704f69SBart Van Assche struct global_collection * gcp;
336*44704f69SBart Van Assche pthread_t a_pthr;
337*44704f69SBart Van Assche } Thread_info;
338*44704f69SBart Van Assche
339*44704f69SBart Van Assche /* Additional parameters for sg_start_io() and sg_finish_io() */
340*44704f69SBart Van Assche struct sg_io_extra {
341*44704f69SBart Van Assche bool is_wr2;
342*44704f69SBart Van Assche bool prefetch;
343*44704f69SBart Van Assche bool dout_is_split;
344*44704f69SBart Van Assche int hpv4_ind;
345*44704f69SBart Van Assche int blk_offset;
346*44704f69SBart Van Assche int blks;
347*44704f69SBart Van Assche };
348*44704f69SBart Van Assche
349*44704f69SBart Van Assche #define MONO_MRQ_ID_INIT 0x10000
350*44704f69SBart Van Assche
351*44704f69SBart Van Assche // typedef vector< pair<int, struct sg_io_v4> > mrq_arr_t;
352*44704f69SBart Van Assche typedef array<uint8_t, 32> big_cdb; /* allow up to a 32 byte cdb */
353*44704f69SBart Van Assche typedef pair< vector<struct sg_io_v4>, vector<big_cdb> > mrq_arr_t;
354*44704f69SBart Van Assche
355*44704f69SBart Van Assche
356*44704f69SBart Van Assche /* Use this class to wrap C++11 <random> features to produce uniform random
357*44704f69SBart Van Assche * unsigned ints in the range [lo, hi] (inclusive) given a_seed */
358*44704f69SBart Van Assche class Rand_uint {
359*44704f69SBart Van Assche public:
Rand_uint(unsigned int lo,unsigned int hi,unsigned int a_seed)360*44704f69SBart Van Assche Rand_uint(unsigned int lo, unsigned int hi, unsigned int a_seed)
361*44704f69SBart Van Assche : uid(lo, hi), dre(a_seed) { }
362*44704f69SBart Van Assche /* uid ctor takes inclusive range when integral type */
363*44704f69SBart Van Assche
get()364*44704f69SBart Van Assche unsigned int get() { return uid(dre); }
365*44704f69SBart Van Assche
366*44704f69SBart Van Assche private:
367*44704f69SBart Van Assche uniform_int_distribution<unsigned int> uid;
368*44704f69SBart Van Assche default_random_engine dre;
369*44704f69SBart Van Assche };
370*44704f69SBart Van Assche
371*44704f69SBart Van Assche static atomic<int> mono_pack_id(1);
372*44704f69SBart Van Assche static atomic<int> mono_mrq_id(MONO_MRQ_ID_INIT);
373*44704f69SBart Van Assche static atomic<long int> pos_index(0);
374*44704f69SBart Van Assche
375*44704f69SBart Van Assche static atomic<int> num_ebusy(0);
376*44704f69SBart Van Assche static atomic<int> num_start_eagain(0);
377*44704f69SBart Van Assche static atomic<int> num_fin_eagain(0);
378*44704f69SBart Van Assche static atomic<int> num_abort_req(0);
379*44704f69SBart Van Assche static atomic<int> num_abort_req_success(0);
380*44704f69SBart Van Assche static atomic<int> num_mrq_abort_req(0);
381*44704f69SBart Van Assche static atomic<int> num_mrq_abort_req_success(0);
382*44704f69SBart Van Assche static atomic<int> num_miscompare(0);
383*44704f69SBart Van Assche static atomic<long> num_waiting_calls(0);
384*44704f69SBart Van Assche static atomic<bool> vb_first_time(true);
385*44704f69SBart Van Assche static atomic<bool> shutting_down(false);
386*44704f69SBart Van Assche
387*44704f69SBart Van Assche static sigset_t signal_set;
388*44704f69SBart Van Assche static sigset_t orig_signal_set;
389*44704f69SBart Van Assche static pthread_t sig_listen_thread_id;
390*44704f69SBart Van Assche
391*44704f69SBart Van Assche static const char * sg_allow_dio = "/sys/module/sg/parameters/allow_dio";
392*44704f69SBart Van Assche
393*44704f69SBart Van Assche static void sg_in_rd_cmd(struct global_collection * clp, Rq_elem * rep,
394*44704f69SBart Van Assche mrq_arr_t & def_arr);
395*44704f69SBart Van Assche static void sg_out_wr_cmd(Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2,
396*44704f69SBart Van Assche bool prefetch);
397*44704f69SBart Van Assche static bool normal_in_rd(Rq_elem * rep, int blocks);
398*44704f69SBart Van Assche static void normal_out_wr(Rq_elem * rep, int blocks);
399*44704f69SBart Van Assche static int sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
400*44704f69SBart Van Assche struct sg_io_extra *xtrp);
401*44704f69SBart Van Assche static int sg_finish_io(bool wr, Rq_elem * rep, int pack_id,
402*44704f69SBart Van Assche struct sg_io_extra *xtrp);
403*44704f69SBart Van Assche static int sg_in_open(struct global_collection *clp, const char *inf,
404*44704f69SBart Van Assche uint8_t **mmpp, int *mmap_len);
405*44704f69SBart Van Assche static int sg_out_open(struct global_collection *clp, const char *outf,
406*44704f69SBart Van Assche uint8_t **mmpp, int *mmap_len);
407*44704f69SBart Van Assche static int sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr);
408*44704f69SBart Van Assche
409*44704f69SBart Van Assche #define STRERR_BUFF_LEN 128
410*44704f69SBart Van Assche
411*44704f69SBart Van Assche static pthread_mutex_t strerr_mut = PTHREAD_MUTEX_INITIALIZER;
412*44704f69SBart Van Assche
413*44704f69SBart Van Assche static bool have_sg_version = false;
414*44704f69SBart Van Assche static int sg_version = 0;
415*44704f69SBart Van Assche static bool sg_version_lt_4 = false;
416*44704f69SBart Van Assche static bool sg_version_ge_40045 = false;
417*44704f69SBart Van Assche static bool do_sync = false;
418*44704f69SBart Van Assche static int do_time = 1;
419*44704f69SBart Van Assche static struct global_collection gcoll;
420*44704f69SBart Van Assche static struct timeval start_tm;
421*44704f69SBart Van Assche static int64_t dd_count = -1;
422*44704f69SBart Van Assche static int num_threads = DEF_NUM_THREADS;
423*44704f69SBart Van Assche static int exit_status = 0;
424*44704f69SBart Van Assche static bool after1 = false;
425*44704f69SBart Van Assche
426*44704f69SBart Van Assche static const char * my_name = "sgh_dd: ";
427*44704f69SBart Van Assche
428*44704f69SBart Van Assche static const char * mrq_blk_s = "mrq: ordinary blocking";
429*44704f69SBart Van Assche static const char * mrq_vb_s = "mrq: variable blocking";
430*44704f69SBart Van Assche static const char * mrq_svb_s = "mrq: shared variable blocking (svb)";
431*44704f69SBart Van Assche static const char * mrq_s_nb_s = "mrq: submit of full non-blocking";
432*44704f69SBart Van Assche
433*44704f69SBart Van Assche
434*44704f69SBart Van Assche #ifdef __GNUC__
435*44704f69SBart Van Assche static int pr2serr_lk(const char * fmt, ...)
436*44704f69SBart Van Assche __attribute__ ((format (printf, 1, 2)));
437*44704f69SBart Van Assche #if 0
438*44704f69SBart Van Assche static void pr_errno_lk(int e_no, const char * fmt, ...)
439*44704f69SBart Van Assche __attribute__ ((format (printf, 2, 3)));
440*44704f69SBart Van Assche #endif
441*44704f69SBart Van Assche #else
442*44704f69SBart Van Assche static int pr2serr_lk(const char * fmt, ...);
443*44704f69SBart Van Assche #if 0
444*44704f69SBart Van Assche static void pr_errno_lk(int e_no, const char * fmt, ...);
445*44704f69SBart Van Assche #endif
446*44704f69SBart Van Assche #endif
447*44704f69SBart Van Assche
448*44704f69SBart Van Assche
449*44704f69SBart Van Assche static int
pr2serr_lk(const char * fmt,...)450*44704f69SBart Van Assche pr2serr_lk(const char * fmt, ...)
451*44704f69SBart Van Assche {
452*44704f69SBart Van Assche int n;
453*44704f69SBart Van Assche va_list args;
454*44704f69SBart Van Assche
455*44704f69SBart Van Assche pthread_mutex_lock(&strerr_mut);
456*44704f69SBart Van Assche va_start(args, fmt);
457*44704f69SBart Van Assche n = vfprintf(stderr, fmt, args);
458*44704f69SBart Van Assche va_end(args);
459*44704f69SBart Van Assche pthread_mutex_unlock(&strerr_mut);
460*44704f69SBart Van Assche return n;
461*44704f69SBart Van Assche }
462*44704f69SBart Van Assche
463*44704f69SBart Van Assche static void
usage(int pg_num)464*44704f69SBart Van Assche usage(int pg_num)
465*44704f69SBart Van Assche {
466*44704f69SBart Van Assche if (pg_num > 3)
467*44704f69SBart Van Assche goto page4;
468*44704f69SBart Van Assche else if (pg_num > 2)
469*44704f69SBart Van Assche goto page3;
470*44704f69SBart Van Assche else if (pg_num > 1)
471*44704f69SBart Van Assche goto page2;
472*44704f69SBart Van Assche
473*44704f69SBart Van Assche pr2serr("Usage: sgh_dd [bs=BS] [conv=CONVS] [count=COUNT] [ibs=BS] "
474*44704f69SBart Van Assche "[if=IFILE]\n"
475*44704f69SBart Van Assche " [iflag=FLAGS] [obs=BS] [of=OFILE] [oflag=FLAGS] "
476*44704f69SBart Van Assche "[seek=SEEK]\n"
477*44704f69SBart Van Assche " [skip=SKIP] [--help] [--version]\n\n");
478*44704f69SBart Van Assche pr2serr(" [ae=AEN[,MAEN]] [bpt=BPT] [cdbsz=6|10|12|16] "
479*44704f69SBart Van Assche "[coe=0|1]\n"
480*44704f69SBart Van Assche " [dio=0|1] [elemsz_kb=EKB] [fail_mask=FM] "
481*44704f69SBart Van Assche "[fua=0|1|2|3]\n"
482*44704f69SBart Van Assche " [mrq=[I|O,]NRQS[,C]] [noshare=0|1] "
483*44704f69SBart Van Assche "[of2=OFILE2]\n"
484*44704f69SBart Van Assche " [ofreg=OFREG] [ofsplit=OSP] [sdt=SDT] "
485*44704f69SBart Van Assche "[sync=0|1]\n"
486*44704f69SBart Van Assche " [thr=THR] [time=0|1|2[,TO]] [unshare=1|0] "
487*44704f69SBart Van Assche "[verbose=VERB]\n"
488*44704f69SBart Van Assche " [--dry-run] [--prefetch] [-v|-vv|-vvv] "
489*44704f69SBart Van Assche "[--verbose]\n"
490*44704f69SBart Van Assche " [--verify] [--version]\n\n"
491*44704f69SBart Van Assche " where the main options (shown in first group above) are:\n"
492*44704f69SBart Van Assche " bs must be device logical block size (default "
493*44704f69SBart Van Assche "512)\n"
494*44704f69SBart Van Assche " conv comma separated list from: [nocreat,noerror,"
495*44704f69SBart Van Assche "notrunc,\n"
496*44704f69SBart Van Assche " null,sync]\n"
497*44704f69SBart Van Assche " count number of blocks to copy (def: device size)\n"
498*44704f69SBart Van Assche " if file or device to read from (def: stdin)\n"
499*44704f69SBart Van Assche " iflag comma separated list from: [00,coe,defres,dio,"
500*44704f69SBart Van Assche "direct,dpo,\n"
501*44704f69SBart Van Assche " dsync,excl,ff,fua,masync,mmap,mout_if,"
502*44704f69SBart Van Assche "mrq_immed,mrq_svb,\n"
503*44704f69SBart Van Assche " nocreat,nodur,noxfer,null,polled,qhead,"
504*44704f69SBart Van Assche "qtail,\n"
505*44704f69SBart Van Assche " random,same_fds,v3,v4,wq_excl]\n"
506*44704f69SBart Van Assche " of file or device to write to (def: /dev/null "
507*44704f69SBart Van Assche "N.B. different\n"
508*44704f69SBart Van Assche " from dd it defaults to stdout). If 'of=.' "
509*44704f69SBart Van Assche "uses /dev/null\n"
510*44704f69SBart Van Assche " of2 second file or device to write to (def: "
511*44704f69SBart Van Assche "/dev/null)\n"
512*44704f69SBart Van Assche " oflag comma separated list from: [append,<<list from "
513*44704f69SBart Van Assche "iflag>>]\n"
514*44704f69SBart Van Assche " seek block position to start writing to OFILE\n"
515*44704f69SBart Van Assche " skip block position to start reading from IFILE\n"
516*44704f69SBart Van Assche " --help|-h output this usage message then exit\n"
517*44704f69SBart Van Assche " --verify|-x do a verify (compare) operation [def: do a "
518*44704f69SBart Van Assche "copy]\n"
519*44704f69SBart Van Assche " --version|-V output version string then exit\n\n"
520*44704f69SBart Van Assche "Copy IFILE to OFILE, similar to dd command. This utility is "
521*44704f69SBart Van Assche "specialized for\nSCSI devices and uses multiple POSIX threads. "
522*44704f69SBart Van Assche "It expects one or both IFILE\nand OFILE to be sg devices. With "
523*44704f69SBart Van Assche "--verify option does a verify/compare\noperation instead of a "
524*44704f69SBart Van Assche "copy. This utility is Linux specific and uses the\nv4 sg "
525*44704f69SBart Van Assche "driver 'share' capability if available. Use '-hh', '-hhh' or "
526*44704f69SBart Van Assche "'-hhhh'\nfor more information.\n"
527*44704f69SBart Van Assche );
528*44704f69SBart Van Assche return;
529*44704f69SBart Van Assche page2:
530*44704f69SBart Van Assche pr2serr("Syntax: sgh_dd [operands] [options]\n\n"
531*44704f69SBart Van Assche " where: operands have the form name=value and are pecular to "
532*44704f69SBart Van Assche "'dd'\n"
533*44704f69SBart Van Assche " style commands, and options start with one or "
534*44704f69SBart Van Assche "two hyphens;\n"
535*44704f69SBart Van Assche " the lesser used operands and option are:\n\n"
536*44704f69SBart Van Assche " ae AEN: abort every n commands (def: 0 --> don't "
537*44704f69SBart Van Assche "abort any)\n"
538*44704f69SBart Van Assche " MAEN: abort every n mrq commands (def: 0 --> "
539*44704f69SBart Van Assche "don't)\n"
540*44704f69SBart Van Assche " [requires commands with > 1 ms duration]\n"
541*44704f69SBart Van Assche " bpt is blocks_per_transfer (default is 128)\n"
542*44704f69SBart Van Assche " cdbsz size of SCSI READ, WRITE or VERIFY cdb_s "
543*44704f69SBart Van Assche "(default is 10)\n"
544*44704f69SBart Van Assche " coe continue on error, 0->exit (def), "
545*44704f69SBart Van Assche "1->zero + continue\n"
546*44704f69SBart Van Assche " dio is direct IO, 1->attempt, 0->indirect IO (def)\n"
547*44704f69SBart Van Assche " elemsz_kb scatter gather list element size in kilobytes "
548*44704f69SBart Van Assche "(def: 32[KB])\n"
549*44704f69SBart Van Assche " fail_mask 1: misuse KEEP_SHARE flag; 0: nothing (def)\n"
550*44704f69SBart Van Assche " fua force unit access: 0->don't(def), 1->OFILE, "
551*44704f69SBart Van Assche "2->IFILE,\n"
552*44704f69SBart Van Assche " 3->OFILE+IFILE\n"
553*44704f69SBart Van Assche " mrq number of cmds placed in each sg call "
554*44704f69SBart Van Assche "(def: 0);\n"
555*44704f69SBart Van Assche " may have trailing ',C', to send bulk cdb_s; "
556*44704f69SBart Van Assche "if preceded\n"
557*44704f69SBart Van Assche " by 'I' then mrq only on IFILE, likewise 'O' "
558*44704f69SBart Van Assche "for OFILE\n"
559*44704f69SBart Van Assche " noshare 0->use request sharing(def), 1->don't\n"
560*44704f69SBart Van Assche " ofreg OFREG is regular file or pipe to send what is "
561*44704f69SBart Van Assche "read from\n"
562*44704f69SBart Van Assche " IFILE in the first half of each shared element\n"
563*44704f69SBart Van Assche " ofsplit split ofile write in two at block OSP (def: 0 "
564*44704f69SBart Van Assche "(no split))\n"
565*44704f69SBart Van Assche " sdt stall detection times: CRT[,ICT]. CRT: check "
566*44704f69SBart Van Assche "repetition\n"
567*44704f69SBart Van Assche " time (after first) in seconds; ICT: initial "
568*44704f69SBart Van Assche "check time\n"
569*44704f69SBart Van Assche " in milliseconds. Default: 3,300 . Use CRT=0 "
570*44704f69SBart Van Assche "to disable\n"
571*44704f69SBart Van Assche " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE "
572*44704f69SBart Van Assche "after copy\n"
573*44704f69SBart Van Assche " thr is number of threads, must be > 0, default 4, "
574*44704f69SBart Van Assche "max 1024\n"
575*44704f69SBart Van Assche " time 0->no timing, 1->calc throughput(def), "
576*44704f69SBart Van Assche "2->nanosec\n"
577*44704f69SBart Van Assche " precision; TO is command timeout in seconds "
578*44704f69SBart Van Assche "(def: 60)\n"
579*44704f69SBart Van Assche " unshare 0->don't explicitly unshare after share; 1->let "
580*44704f69SBart Van Assche "close do\n"
581*44704f69SBart Van Assche " file unshare (default)\n"
582*44704f69SBart Van Assche " verbose increase verbosity\n"
583*44704f69SBart Van Assche " --chkaddr|-c exits if read block does not contain "
584*44704f69SBart Van Assche "32 bit block\n"
585*44704f69SBart Van Assche " address, used once only checks first "
586*44704f69SBart Van Assche "address in block\n"
587*44704f69SBart Van Assche " --dry-run|-d prepare but bypass copy/read\n"
588*44704f69SBart Van Assche " --prefetch|-p with verify: do pre-fetch first\n"
589*44704f69SBart Van Assche " --verbose|-v increase verbosity of utility\n\n"
590*44704f69SBart Van Assche "Use '-hhh' or '-hhhh' for more information about flags.\n"
591*44704f69SBart Van Assche );
592*44704f69SBart Van Assche return;
593*44704f69SBart Van Assche page3:
594*44704f69SBart Van Assche pr2serr("Syntax: sgh_dd [operands] [options]\n\n"
595*44704f69SBart Van Assche " where: 'iflag=<arg>' and 'oflag=<arg>' arguments are listed "
596*44704f69SBart Van Assche "below:\n\n"
597*44704f69SBart Van Assche " 00 use all zeros instead of if=IFILE (only in "
598*44704f69SBart Van Assche "iflags)\n"
599*44704f69SBart Van Assche " 00,ff generates blocks that contain own (32 bit be) "
600*44704f69SBart Van Assche "blk address\n"
601*44704f69SBart Van Assche " append append output to OFILE (assumes OFILE is "
602*44704f69SBart Van Assche "regular file)\n"
603*44704f69SBart Van Assche " coe continue of error (reading, fills with zeros)\n"
604*44704f69SBart Van Assche " defres keep default reserve buffer size (else its "
605*44704f69SBart Van Assche "bs*bpt)\n"
606*44704f69SBart Van Assche " dio sets the SG_FLAG_DIRECT_IO in sg requests\n"
607*44704f69SBart Van Assche " direct sets the O_DIRECT flag on open()\n"
608*44704f69SBart Van Assche " dpo sets the DPO (disable page out) in SCSI READs "
609*44704f69SBart Van Assche "and WRITEs\n"
610*44704f69SBart Van Assche " dsync sets the O_SYNC flag on open()\n"
611*44704f69SBart Van Assche " excl sets the O_EXCL flag on open()\n"
612*44704f69SBart Van Assche " ff use all 0xff bytes instead of if=IFILE (only in "
613*44704f69SBart Van Assche "iflags)\n"
614*44704f69SBart Van Assche " fua sets the FUA (force unit access) in SCSI READs "
615*44704f69SBart Van Assche "and WRITEs\n"
616*44704f69SBart Van Assche " hipri same as 'polled'; 'hipri' name is deprecated\n"
617*44704f69SBart Van Assche " masync set 'more async' flag on this sg device\n"
618*44704f69SBart Van Assche " mmap setup mmap IO on IFILE or OFILE; OFILE only "
619*44704f69SBart Van Assche "with noshare\n"
620*44704f69SBart Van Assche " mmap,mmap when used twice, doesn't call munmap()\n"
621*44704f69SBart Van Assche " mout_if set META_OUT_IF flag on each request\n"
622*44704f69SBart Van Assche " mrq_immed if mrq active, do submit non-blocking (def: "
623*44704f69SBart Van Assche "ordered\n"
624*44704f69SBart Van Assche " blocking)\n"
625*44704f69SBart Van Assche " mrq_svb if mrq and sg->sg copy, do shared_variable_"
626*44704f69SBart Van Assche "blocking\n"
627*44704f69SBart Van Assche " nocreat will fail rather than create OFILE\n"
628*44704f69SBart Van Assche " nodur turns off command duration calculations\n"
629*44704f69SBart Van Assche " noxfer no transfer to/from the user space\n"
630*44704f69SBart Van Assche " no_thresh skip checking per fd max data xfer\n"
631*44704f69SBart Van Assche " null does nothing, placeholder\n"
632*44704f69SBart Van Assche " polled set POLLED flag on command, uses blk_poll() to "
633*44704f69SBart Van Assche "complete\n"
634*44704f69SBart Van Assche " qhead queue new request at head of block queue\n"
635*44704f69SBart Van Assche " qtail queue new request at tail of block queue (def: "
636*44704f69SBart Van Assche "q at head)\n"
637*44704f69SBart Van Assche " random use random data instead of if=IFILE (only in "
638*44704f69SBart Van Assche "iflags)\n"
639*44704f69SBart Van Assche " same_fds each thread uses the same IFILE and OFILE(2) "
640*44704f69SBart Van Assche "file\n"
641*44704f69SBart Van Assche " descriptors (def: each threads has own file "
642*44704f69SBart Van Assche "descriptors)\n"
643*44704f69SBart Van Assche " swait this option is now ignored\n"
644*44704f69SBart Van Assche " v3 use v3 sg interface (def: v3 unless sg driver "
645*44704f69SBart Van Assche "is v4)\n"
646*44704f69SBart Van Assche " v4 use v4 sg interface (def: v3 unless sg driver "
647*44704f69SBart Van Assche "is v4)\n"
648*44704f69SBart Van Assche " wq_excl set SG_CTL_FLAGM_EXCL_WAITQ on this sg fd\n"
649*44704f69SBart Van Assche "\n"
650*44704f69SBart Van Assche "Copies IFILE to OFILE (and to OFILE2 if given). If IFILE and "
651*44704f69SBart Van Assche "OFILE are sg\ndevices 'shared' mode is selected unless "
652*44704f69SBart Van Assche "'noshare' is given to 'iflag=' or\n'oflag='. of2=OFILE2 uses "
653*44704f69SBart Van Assche "'oflag=FLAGS'. When sharing, the data stays in a\nsingle "
654*44704f69SBart Van Assche "in-kernel buffer which is copied (or mmap-ed) to the user "
655*44704f69SBart Van Assche "space\nif the 'ofreg=OFREG' is given. Use '-hhhh' for more "
656*44704f69SBart Van Assche "information.\n"
657*44704f69SBart Van Assche );
658*44704f69SBart Van Assche return;
659*44704f69SBart Van Assche page4:
660*44704f69SBart Van Assche pr2serr("pack_id:\n"
661*44704f69SBart Van Assche "These are ascending integers, starting at 1, associated with "
662*44704f69SBart Van Assche "each issued\nSCSI command. When both IFILE and OFILE are sg "
663*44704f69SBart Van Assche "devices, then the READ in\neach read-write pair is issued an "
664*44704f69SBart Van Assche "even pack_id and its WRITE pair is\ngiven the pack_id one "
665*44704f69SBart Van Assche "higher (i.e. an odd number). This enables a\n'dmesg -w' "
666*44704f69SBart Van Assche "user to see that progress is being "
667*44704f69SBart Van Assche "made.\n\n");
668*44704f69SBart Van Assche pr2serr("Debugging:\n"
669*44704f69SBart Van Assche "Apart from using one or more '--verbose' options which gets a "
670*44704f69SBart Van Assche "bit noisy\n'dmesg -w' can give a good overview "
671*44704f69SBart Van Assche "of what is happening.\nThat does a sg driver object tree "
672*44704f69SBart Van Assche "traversal that does minimal locking\nto make sure that each "
673*44704f69SBart Van Assche "traversal is 'safe'. So it is important to note\nthe whole "
674*44704f69SBart Van Assche "tree is not locked. This means for fast devices the overall\n"
675*44704f69SBart Van Assche "tree state may change while the traversal is occurring. For "
676*44704f69SBart Van Assche "example,\nit has been observed that both the read- and write- "
677*44704f69SBart Van Assche "sides of a request\nshare show they are in 'active' state "
678*44704f69SBart Van Assche "which should not be possible.\nIt occurs because the read-"
679*44704f69SBart Van Assche "side probably jumped out of active state and\nthe write-side "
680*44704f69SBart Van Assche "request entered it while some other nodes were being "
681*44704f69SBart Van Assche "printed.\n\n");
682*44704f69SBart Van Assche pr2serr("Busy state:\n"
683*44704f69SBart Van Assche "Busy state (abbreviated to 'bsy' in the dmesg "
684*44704f69SBart Van Assche "output)\nis entered during request setup and completion. It "
685*44704f69SBart Van Assche "is intended to be\na temporary state. It should not block "
686*44704f69SBart Van Assche "but does sometimes (e.g. in\nblock_get_request()). Even so "
687*44704f69SBart Van Assche "that blockage should be short and if not\nthere is a "
688*44704f69SBart Van Assche "problem.\n\n");
689*44704f69SBart Van Assche pr2serr("--verify :\n"
690*44704f69SBart Van Assche "For comparing IFILE with OFILE. Does repeated sequences of: "
691*44704f69SBart Van Assche "READ(ifile)\nand uses data returned to send to VERIFY(ofile, "
692*44704f69SBart Van Assche "BYTCHK=1). So the OFILE\ndevice/disk is doing the actual "
693*44704f69SBart Van Assche "comparison. Stops on first miscompare.\n\n");
694*44704f69SBart Van Assche pr2serr("--prefetch :\n"
695*44704f69SBart Van Assche "Used with --verify option. Prepends a PRE-FETCH(ofile, IMMED) "
696*44704f69SBart Van Assche "to verify\nsequence. This should speed the trailing VERIFY by "
697*44704f69SBart Van Assche "making sure that\nthe data it needs for the comparison is "
698*44704f69SBart Van Assche "already in its cache.\n");
699*44704f69SBart Van Assche return;
700*44704f69SBart Van Assche }
701*44704f69SBart Van Assche
702*44704f69SBart Van Assche static void
lk_print_command_len(const char * prefix,uint8_t * cmdp,int len,bool lock)703*44704f69SBart Van Assche lk_print_command_len(const char *prefix, uint8_t * cmdp, int len, bool lock)
704*44704f69SBart Van Assche {
705*44704f69SBart Van Assche if (lock)
706*44704f69SBart Van Assche pthread_mutex_lock(&strerr_mut);
707*44704f69SBart Van Assche if (prefix && *prefix)
708*44704f69SBart Van Assche fputs(prefix, stderr);
709*44704f69SBart Van Assche sg_print_command_len(cmdp, len);
710*44704f69SBart Van Assche if (lock)
711*44704f69SBart Van Assche pthread_mutex_unlock(&strerr_mut);
712*44704f69SBart Van Assche }
713*44704f69SBart Van Assche
714*44704f69SBart Van Assche static void
lk_chk_n_print3(const char * leadin,struct sg_io_hdr * hp,bool raw_sinfo)715*44704f69SBart Van Assche lk_chk_n_print3(const char * leadin, struct sg_io_hdr * hp, bool raw_sinfo)
716*44704f69SBart Van Assche {
717*44704f69SBart Van Assche pthread_mutex_lock(&strerr_mut);
718*44704f69SBart Van Assche sg_chk_n_print3(leadin, hp, raw_sinfo);
719*44704f69SBart Van Assche pthread_mutex_unlock(&strerr_mut);
720*44704f69SBart Van Assche }
721*44704f69SBart Van Assche
722*44704f69SBart Van Assche static void
lk_chk_n_print4(const char * leadin,const struct sg_io_v4 * h4p,bool raw_sinfo)723*44704f69SBart Van Assche lk_chk_n_print4(const char * leadin, const struct sg_io_v4 * h4p,
724*44704f69SBart Van Assche bool raw_sinfo)
725*44704f69SBart Van Assche {
726*44704f69SBart Van Assche pthread_mutex_lock(&strerr_mut);
727*44704f69SBart Van Assche sg_linux_sense_print(leadin, h4p->device_status, h4p->transport_status,
728*44704f69SBart Van Assche h4p->driver_status, (const uint8_t *)h4p->response,
729*44704f69SBart Van Assche h4p->response_len, raw_sinfo);
730*44704f69SBart Van Assche pthread_mutex_unlock(&strerr_mut);
731*44704f69SBart Van Assche }
732*44704f69SBart Van Assche
733*44704f69SBart Van Assche static void
hex2stderr_lk(const uint8_t * b_str,int len,int no_ascii)734*44704f69SBart Van Assche hex2stderr_lk(const uint8_t * b_str, int len, int no_ascii)
735*44704f69SBart Van Assche {
736*44704f69SBart Van Assche pthread_mutex_lock(&strerr_mut);
737*44704f69SBart Van Assche hex2stderr(b_str, len, no_ascii);
738*44704f69SBart Van Assche pthread_mutex_unlock(&strerr_mut);
739*44704f69SBart Van Assche }
740*44704f69SBart Van Assche
741*44704f69SBart Van Assche /* Flags decoded into abbreviations for those that are set, separated by
742*44704f69SBart Van Assche * '|' . */
743*44704f69SBart Van Assche static char *
sg_flags_str(int flags,int b_len,char * b)744*44704f69SBart Van Assche sg_flags_str(int flags, int b_len, char * b)
745*44704f69SBart Van Assche {
746*44704f69SBart Van Assche int n = 0;
747*44704f69SBart Van Assche
748*44704f69SBart Van Assche if ((b_len < 1) || (! b))
749*44704f69SBart Van Assche return b;
750*44704f69SBart Van Assche b[0] = '\0';
751*44704f69SBart Van Assche if (SG_FLAG_DIRECT_IO & flags) { /* 0x1 */
752*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "DIO|");
753*44704f69SBart Van Assche if (n >= b_len)
754*44704f69SBart Van Assche goto fini;
755*44704f69SBart Van Assche }
756*44704f69SBart Van Assche if (SG_FLAG_MMAP_IO & flags) { /* 0x4 */
757*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "MMAP|");
758*44704f69SBart Van Assche if (n >= b_len)
759*44704f69SBart Van Assche goto fini;
760*44704f69SBart Van Assche }
761*44704f69SBart Van Assche if (SGV4_FLAG_YIELD_TAG & flags) { /* 0x8 */
762*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "YTAG|");
763*44704f69SBart Van Assche if (n >= b_len)
764*44704f69SBart Van Assche goto fini;
765*44704f69SBart Van Assche }
766*44704f69SBart Van Assche if (SG_FLAG_Q_AT_TAIL & flags) { /* 0x10 */
767*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "QTAI|");
768*44704f69SBart Van Assche if (n >= b_len)
769*44704f69SBart Van Assche goto fini;
770*44704f69SBart Van Assche }
771*44704f69SBart Van Assche if (SG_FLAG_Q_AT_HEAD & flags) { /* 0x20 */
772*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "QHEA|");
773*44704f69SBart Van Assche if (n >= b_len)
774*44704f69SBart Van Assche goto fini;
775*44704f69SBart Van Assche }
776*44704f69SBart Van Assche if (SGV4_FLAG_DOUT_OFFSET & flags) { /* 0x40 */
777*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "DOFF|");
778*44704f69SBart Van Assche if (n >= b_len)
779*44704f69SBart Van Assche goto fini;
780*44704f69SBart Van Assche }
781*44704f69SBart Van Assche if (SGV4_FLAG_EVENTFD & flags) { /* 0x80 */
782*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "EVFD|");
783*44704f69SBart Van Assche if (n >= b_len)
784*44704f69SBart Van Assche goto fini;
785*44704f69SBart Van Assche }
786*44704f69SBart Van Assche if (SGV4_FLAG_COMPLETE_B4 & flags) { /* 0x100 */
787*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "CPL_B4|");
788*44704f69SBart Van Assche if (n >= b_len)
789*44704f69SBart Van Assche goto fini;
790*44704f69SBart Van Assche }
791*44704f69SBart Van Assche if (SGV4_FLAG_SIGNAL & flags) { /* 0x200 */
792*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "SIGNAL|");
793*44704f69SBart Van Assche if (n >= b_len)
794*44704f69SBart Van Assche goto fini;
795*44704f69SBart Van Assche }
796*44704f69SBart Van Assche if (SGV4_FLAG_IMMED & flags) { /* 0x400 */
797*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "IMM|");
798*44704f69SBart Van Assche if (n >= b_len)
799*44704f69SBart Van Assche goto fini;
800*44704f69SBart Van Assche }
801*44704f69SBart Van Assche if (SGV4_FLAG_POLLED & flags) { /* 0x800 */
802*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "POLLED|");
803*44704f69SBart Van Assche if (n >= b_len)
804*44704f69SBart Van Assche goto fini;
805*44704f69SBart Van Assche }
806*44704f69SBart Van Assche if (SGV4_FLAG_STOP_IF & flags) { /* 0x1000 */
807*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "STOPIF|");
808*44704f69SBart Van Assche if (n >= b_len)
809*44704f69SBart Van Assche goto fini;
810*44704f69SBart Van Assche }
811*44704f69SBart Van Assche if (SGV4_FLAG_DEV_SCOPE & flags) { /* 0x2000 */
812*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "DEV_SC|");
813*44704f69SBart Van Assche if (n >= b_len)
814*44704f69SBart Van Assche goto fini;
815*44704f69SBart Van Assche }
816*44704f69SBart Van Assche if (SGV4_FLAG_SHARE & flags) { /* 0x4000 */
817*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "SHARE|");
818*44704f69SBart Van Assche if (n >= b_len)
819*44704f69SBart Van Assche goto fini;
820*44704f69SBart Van Assche }
821*44704f69SBart Van Assche if (SGV4_FLAG_DO_ON_OTHER & flags) { /* 0x8000 */
822*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "DO_OTH|");
823*44704f69SBart Van Assche if (n >= b_len)
824*44704f69SBart Van Assche goto fini;
825*44704f69SBart Van Assche }
826*44704f69SBart Van Assche if (SGV4_FLAG_NO_DXFER & flags) { /* 0x10000 */
827*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "NOXFER|");
828*44704f69SBart Van Assche if (n >= b_len)
829*44704f69SBart Van Assche goto fini;
830*44704f69SBart Van Assche }
831*44704f69SBart Van Assche if (SGV4_FLAG_KEEP_SHARE & flags) { /* 0x20000 */
832*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "KEEP_SH|");
833*44704f69SBart Van Assche if (n >= b_len)
834*44704f69SBart Van Assche goto fini;
835*44704f69SBart Van Assche }
836*44704f69SBart Van Assche if (SGV4_FLAG_MULTIPLE_REQS & flags) { /* 0x40000 */
837*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "MRQS|");
838*44704f69SBart Van Assche if (n >= b_len)
839*44704f69SBart Van Assche goto fini;
840*44704f69SBart Van Assche }
841*44704f69SBart Van Assche if (SGV4_FLAG_ORDERED_WR & flags) { /* 0x80000 */
842*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "OWR|");
843*44704f69SBart Van Assche if (n >= b_len)
844*44704f69SBart Van Assche goto fini;
845*44704f69SBart Van Assche }
846*44704f69SBart Van Assche if (SGV4_FLAG_REC_ORDER & flags) { /* 0x100000 */
847*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "REC_O|");
848*44704f69SBart Van Assche if (n >= b_len)
849*44704f69SBart Van Assche goto fini;
850*44704f69SBart Van Assche }
851*44704f69SBart Van Assche if (SGV4_FLAG_META_OUT_IF & flags) { /* 0x200000 */
852*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "MOUT_IF|");
853*44704f69SBart Van Assche if (n >= b_len)
854*44704f69SBart Van Assche goto fini;
855*44704f69SBart Van Assche }
856*44704f69SBart Van Assche if (0 == n)
857*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "<none>");
858*44704f69SBart Van Assche fini:
859*44704f69SBart Van Assche if (n < b_len) { /* trim trailing '\' */
860*44704f69SBart Van Assche if ('|' == b[n - 1])
861*44704f69SBart Van Assche b[n - 1] = '\0';
862*44704f69SBart Van Assche } else if ('|' == b[b_len - 1])
863*44704f69SBart Van Assche b[b_len - 1] = '\0';
864*44704f69SBart Van Assche return b;
865*44704f69SBart Van Assche }
866*44704f69SBart Van Assche
867*44704f69SBart Van Assche /* Info field decoded into abbreviations for those bits that are set,
868*44704f69SBart Van Assche * separated by '|' . */
869*44704f69SBart Van Assche static char *
sg_info_str(int info,int b_len,char * b)870*44704f69SBart Van Assche sg_info_str(int info, int b_len, char * b)
871*44704f69SBart Van Assche {
872*44704f69SBart Van Assche int n = 0;
873*44704f69SBart Van Assche
874*44704f69SBart Van Assche if ((b_len < 1) || (! b))
875*44704f69SBart Van Assche return b;
876*44704f69SBart Van Assche b[0] = '\0';
877*44704f69SBart Van Assche if (SG_INFO_CHECK & info) { /* 0x1 */
878*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "CHK|");
879*44704f69SBart Van Assche if (n >= b_len)
880*44704f69SBart Van Assche goto fini;
881*44704f69SBart Van Assche }
882*44704f69SBart Van Assche if (SG_INFO_DIRECT_IO & info) { /* 0x2 */
883*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "DIO|");
884*44704f69SBart Van Assche if (n >= b_len)
885*44704f69SBart Van Assche goto fini;
886*44704f69SBart Van Assche }
887*44704f69SBart Van Assche if (SG_INFO_MIXED_IO & info) { /* 0x4 */
888*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "MIO|");
889*44704f69SBart Van Assche if (n >= b_len)
890*44704f69SBart Van Assche goto fini;
891*44704f69SBart Van Assche }
892*44704f69SBart Van Assche if (SG_INFO_DEVICE_DETACHING & info) { /* 0x8 */
893*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "DETA|");
894*44704f69SBart Van Assche if (n >= b_len)
895*44704f69SBart Van Assche goto fini;
896*44704f69SBart Van Assche }
897*44704f69SBart Van Assche if (SG_INFO_ABORTED & info) { /* 0x10 */
898*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "ABRT|");
899*44704f69SBart Van Assche if (n >= b_len)
900*44704f69SBart Van Assche goto fini;
901*44704f69SBart Van Assche }
902*44704f69SBart Van Assche if (SG_INFO_MRQ_FINI & info) { /* 0x20 */
903*44704f69SBart Van Assche n += sg_scnpr(b + n, b_len - n, "MRQF|");
904*44704f69SBart Van Assche if (n >= b_len)
905*44704f69SBart Van Assche goto fini;
906*44704f69SBart Van Assche }
907*44704f69SBart Van Assche fini:
908*44704f69SBart Van Assche if (n < b_len) { /* trim trailing '\' */
909*44704f69SBart Van Assche if ('|' == b[n - 1])
910*44704f69SBart Van Assche b[n - 1] = '\0';
911*44704f69SBart Van Assche } else if ('|' == b[b_len - 1])
912*44704f69SBart Van Assche b[b_len - 1] = '\0';
913*44704f69SBart Van Assche return b;
914*44704f69SBart Van Assche }
915*44704f69SBart Van Assche
916*44704f69SBart Van Assche static void
v4hdr_out_lk(const char * leadin,const sg_io_v4 * h4p,int id)917*44704f69SBart Van Assche v4hdr_out_lk(const char * leadin, const sg_io_v4 * h4p, int id)
918*44704f69SBart Van Assche {
919*44704f69SBart Van Assche char b[80];
920*44704f69SBart Van Assche
921*44704f69SBart Van Assche pthread_mutex_lock(&strerr_mut);
922*44704f69SBart Van Assche if (leadin)
923*44704f69SBart Van Assche pr2serr("%s [id=%d]:\n", leadin, id);
924*44704f69SBart Van Assche if (('Q' != h4p->guard) || (0 != h4p->protocol) ||
925*44704f69SBart Van Assche (0 != h4p->subprotocol))
926*44704f69SBart Van Assche pr2serr(" <<<sg_io_v4 _NOT_ properly set>>>\n");
927*44704f69SBart Van Assche pr2serr(" pointers: cdb=%s sense=%s din=%p dout=%p\n",
928*44704f69SBart Van Assche (h4p->request ? "y" : "NULL"), (h4p->response ? "y" : "NULL"),
929*44704f69SBart Van Assche (void *)h4p->din_xferp, (void *)h4p->dout_xferp);
930*44704f69SBart Van Assche pr2serr(" lengths: cdb=%u sense=%u din=%u dout=%u\n",
931*44704f69SBart Van Assche h4p->request_len, h4p->max_response_len, h4p->din_xfer_len,
932*44704f69SBart Van Assche h4p->dout_xfer_len);
933*44704f69SBart Van Assche pr2serr(" flags=0x%x request_extra{pack_id}=%d\n",
934*44704f69SBart Van Assche h4p->flags, h4p->request_extra);
935*44704f69SBart Van Assche pr2serr(" flags set: %s\n", sg_flags_str(h4p->flags, sizeof(b), b));
936*44704f69SBart Van Assche pr2serr(" %s OUT fields:\n", leadin);
937*44704f69SBart Van Assche pr2serr(" response_len=%d driver/transport/device_status="
938*44704f69SBart Van Assche "0x%x/0x%x/0x%x\n", h4p->response_len, h4p->driver_status,
939*44704f69SBart Van Assche h4p->transport_status, h4p->device_status);
940*44704f69SBart Van Assche pr2serr(" info=0x%x din_resid=%u dout_resid=%u spare_out=%u "
941*44704f69SBart Van Assche "dur=%u\n",
942*44704f69SBart Van Assche h4p->info, h4p->din_resid, h4p->dout_resid, h4p->spare_out,
943*44704f69SBart Van Assche h4p->duration);
944*44704f69SBart Van Assche pthread_mutex_unlock(&strerr_mut);
945*44704f69SBart Van Assche }
946*44704f69SBart Van Assche
947*44704f69SBart Van Assche static void
fetch_sg_version(void)948*44704f69SBart Van Assche fetch_sg_version(void)
949*44704f69SBart Van Assche {
950*44704f69SBart Van Assche FILE * fp;
951*44704f69SBart Van Assche char b[96];
952*44704f69SBart Van Assche
953*44704f69SBart Van Assche have_sg_version = false;
954*44704f69SBart Van Assche sg_version = 0;
955*44704f69SBart Van Assche fp = fopen(PROC_SCSI_SG_VERSION, "r");
956*44704f69SBart Van Assche if (fp && fgets(b, sizeof(b) - 1, fp)) {
957*44704f69SBart Van Assche if (1 == sscanf(b, "%d", &sg_version))
958*44704f69SBart Van Assche have_sg_version = !!sg_version;
959*44704f69SBart Van Assche } else {
960*44704f69SBart Van Assche int j, k, l;
961*44704f69SBart Van Assche
962*44704f69SBart Van Assche if (fp)
963*44704f69SBart Van Assche fclose(fp);
964*44704f69SBart Van Assche fp = fopen(SYS_SCSI_SG_VERSION, "r");
965*44704f69SBart Van Assche if (fp && fgets(b, sizeof(b) - 1, fp)) {
966*44704f69SBart Van Assche if (3 == sscanf(b, "%d.%d.%d", &j, &k, &l)) {
967*44704f69SBart Van Assche sg_version = (j * 10000) + (k * 100) + l;
968*44704f69SBart Van Assche have_sg_version = !!sg_version;
969*44704f69SBart Van Assche }
970*44704f69SBart Van Assche }
971*44704f69SBart Van Assche }
972*44704f69SBart Van Assche if (fp)
973*44704f69SBart Van Assche fclose(fp);
974*44704f69SBart Van Assche }
975*44704f69SBart Van Assche
976*44704f69SBart Van Assche static void
calc_duration_throughput(int contin)977*44704f69SBart Van Assche calc_duration_throughput(int contin)
978*44704f69SBart Van Assche {
979*44704f69SBart Van Assche struct timeval end_tm, res_tm;
980*44704f69SBart Van Assche double a, b;
981*44704f69SBart Van Assche
982*44704f69SBart Van Assche gettimeofday(&end_tm, NULL);
983*44704f69SBart Van Assche res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
984*44704f69SBart Van Assche res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
985*44704f69SBart Van Assche if (res_tm.tv_usec < 0) {
986*44704f69SBart Van Assche --res_tm.tv_sec;
987*44704f69SBart Van Assche res_tm.tv_usec += 1000000;
988*44704f69SBart Van Assche }
989*44704f69SBart Van Assche a = res_tm.tv_sec;
990*44704f69SBart Van Assche a += (0.000001 * res_tm.tv_usec);
991*44704f69SBart Van Assche b = (double)gcoll.bs * (dd_count - gcoll.out_rem_count.load());
992*44704f69SBart Van Assche pr2serr("time to %s data %s %d.%06d secs",
993*44704f69SBart Van Assche (gcoll.verify ? "verify" : "copy"), (contin ? "so far" : "was"),
994*44704f69SBart Van Assche (int)res_tm.tv_sec, (int)res_tm.tv_usec);
995*44704f69SBart Van Assche if ((a > 0.00001) && (b > 511))
996*44704f69SBart Van Assche pr2serr(", %.2f MB/sec\n", b / (a * 1000000.0));
997*44704f69SBart Van Assche else
998*44704f69SBart Van Assche pr2serr("\n");
999*44704f69SBart Van Assche }
1000*44704f69SBart Van Assche
1001*44704f69SBart Van Assche static void
print_stats(const char * str)1002*44704f69SBart Van Assche print_stats(const char * str)
1003*44704f69SBart Van Assche {
1004*44704f69SBart Van Assche int64_t infull;
1005*44704f69SBart Van Assche
1006*44704f69SBart Van Assche if (0 != gcoll.out_rem_count.load())
1007*44704f69SBart Van Assche pr2serr(" remaining block count=%" PRId64 "\n",
1008*44704f69SBart Van Assche gcoll.out_rem_count.load());
1009*44704f69SBart Van Assche infull = dd_count - gcoll.in_rem_count.load();
1010*44704f69SBart Van Assche pr2serr("%s%" PRId64 "+%d records in\n", str,
1011*44704f69SBart Van Assche infull - gcoll.in_partial.load(), gcoll.in_partial.load());
1012*44704f69SBart Van Assche
1013*44704f69SBart Van Assche if (gcoll.out_type == FT_DEV_NULL)
1014*44704f69SBart Van Assche pr2serr("%s0+0 records out\n", str);
1015*44704f69SBart Van Assche else {
1016*44704f69SBart Van Assche int64_t outfull = dd_count - gcoll.out_rem_count.load();
1017*44704f69SBart Van Assche
1018*44704f69SBart Van Assche pr2serr("%s%" PRId64 "+%d records %s\n", str,
1019*44704f69SBart Van Assche outfull - gcoll.out_partial.load(), gcoll.out_partial.load(),
1020*44704f69SBart Van Assche (gcoll.verify ? "verified" : "out"));
1021*44704f69SBart Van Assche }
1022*44704f69SBart Van Assche }
1023*44704f69SBart Van Assche
1024*44704f69SBart Van Assche static void
interrupt_handler(int sig)1025*44704f69SBart Van Assche interrupt_handler(int sig)
1026*44704f69SBart Van Assche {
1027*44704f69SBart Van Assche struct sigaction sigact;
1028*44704f69SBart Van Assche
1029*44704f69SBart Van Assche sigact.sa_handler = SIG_DFL;
1030*44704f69SBart Van Assche sigemptyset(&sigact.sa_mask);
1031*44704f69SBart Van Assche sigact.sa_flags = 0;
1032*44704f69SBart Van Assche sigaction(sig, &sigact, NULL);
1033*44704f69SBart Van Assche pr2serr("Interrupted by signal,");
1034*44704f69SBart Van Assche if (do_time > 0)
1035*44704f69SBart Van Assche calc_duration_throughput(0);
1036*44704f69SBart Van Assche print_stats("");
1037*44704f69SBart Van Assche kill(getpid (), sig);
1038*44704f69SBart Van Assche }
1039*44704f69SBart Van Assche
1040*44704f69SBart Van Assche static void
siginfo_handler(int sig)1041*44704f69SBart Van Assche siginfo_handler(int sig)
1042*44704f69SBart Van Assche {
1043*44704f69SBart Van Assche if (sig) { ; } /* unused, dummy to suppress warning */
1044*44704f69SBart Van Assche pr2serr("Progress report, continuing ...\n");
1045*44704f69SBart Van Assche if (do_time > 0)
1046*44704f69SBart Van Assche calc_duration_throughput(1);
1047*44704f69SBart Van Assche print_stats(" ");
1048*44704f69SBart Van Assche }
1049*44704f69SBart Van Assche
1050*44704f69SBart Van Assche static void
siginfo2_handler(int sig)1051*44704f69SBart Van Assche siginfo2_handler(int sig)
1052*44704f69SBart Van Assche {
1053*44704f69SBart Van Assche struct global_collection * clp = &gcoll;
1054*44704f69SBart Van Assche
1055*44704f69SBart Van Assche if (sig) { ; } /* unused, dummy to suppress warning */
1056*44704f69SBart Van Assche pr2serr("Progress report, continuing ...\n");
1057*44704f69SBart Van Assche if (do_time > 0)
1058*44704f69SBart Van Assche calc_duration_throughput(1);
1059*44704f69SBart Van Assche print_stats(" ");
1060*44704f69SBart Van Assche pr2serr("Send broadcast on out_sync_cv condition variable\n");
1061*44704f69SBart Van Assche pthread_cond_broadcast(&clp->out_sync_cv);
1062*44704f69SBart Van Assche }
1063*44704f69SBart Van Assche
1064*44704f69SBart Van Assche static void
install_handler(int sig_num,void (* sig_handler)(int sig))1065*44704f69SBart Van Assche install_handler(int sig_num, void (*sig_handler) (int sig))
1066*44704f69SBart Van Assche {
1067*44704f69SBart Van Assche struct sigaction sigact;
1068*44704f69SBart Van Assche sigaction (sig_num, NULL, &sigact);
1069*44704f69SBart Van Assche if (sigact.sa_handler != SIG_IGN)
1070*44704f69SBart Van Assche {
1071*44704f69SBart Van Assche sigact.sa_handler = sig_handler;
1072*44704f69SBart Van Assche sigemptyset (&sigact.sa_mask);
1073*44704f69SBart Van Assche sigact.sa_flags = 0;
1074*44704f69SBart Van Assche sigaction (sig_num, &sigact, NULL);
1075*44704f69SBart Van Assche }
1076*44704f69SBart Van Assche }
1077*44704f69SBart Van Assche
1078*44704f69SBart Van Assche #ifdef SG_LIB_ANDROID
1079*44704f69SBart Van Assche static void
thread_exit_handler(int sig)1080*44704f69SBart Van Assche thread_exit_handler(int sig)
1081*44704f69SBart Van Assche {
1082*44704f69SBart Van Assche pthread_exit(0);
1083*44704f69SBart Van Assche }
1084*44704f69SBart Van Assche #endif
1085*44704f69SBart Van Assche
1086*44704f69SBart Van Assche /* Make safe_strerror() thread safe */
1087*44704f69SBart Van Assche static char *
tsafe_strerror(int code,char * ebp)1088*44704f69SBart Van Assche tsafe_strerror(int code, char * ebp)
1089*44704f69SBart Van Assche {
1090*44704f69SBart Van Assche char * cp;
1091*44704f69SBart Van Assche
1092*44704f69SBart Van Assche pthread_mutex_lock(&strerr_mut);
1093*44704f69SBart Van Assche cp = safe_strerror(code);
1094*44704f69SBart Van Assche strncpy(ebp, cp, STRERR_BUFF_LEN);
1095*44704f69SBart Van Assche pthread_mutex_unlock(&strerr_mut);
1096*44704f69SBart Van Assche
1097*44704f69SBart Van Assche ebp[strlen(ebp)] = '\0';
1098*44704f69SBart Van Assche return ebp;
1099*44704f69SBart Van Assche }
1100*44704f69SBart Van Assche
1101*44704f69SBart Van Assche
1102*44704f69SBart Van Assche /* Following macro from D.R. Butenhof's POSIX threads book:
1103*44704f69SBart Van Assche * ISBN 0-201-63392-2 . [Highly recommended book.] Changed __FILE__
1104*44704f69SBart Van Assche * to __func__ */
1105*44704f69SBart Van Assche #define err_exit(code,text) do { \
1106*44704f69SBart Van Assche char strerr_buff[STRERR_BUFF_LEN + 1]; \
1107*44704f69SBart Van Assche pr2serr("%s at \"%s\":%d: %s\n", \
1108*44704f69SBart Van Assche text, __func__, __LINE__, tsafe_strerror(code, strerr_buff)); \
1109*44704f69SBart Van Assche exit(1); \
1110*44704f69SBart Van Assche } while (0)
1111*44704f69SBart Van Assche
1112*44704f69SBart Van Assche
1113*44704f69SBart Van Assche static int
dd_filetype(const char * filename,off_t & st_size)1114*44704f69SBart Van Assche dd_filetype(const char * filename, off_t & st_size)
1115*44704f69SBart Van Assche {
1116*44704f69SBart Van Assche struct stat st;
1117*44704f69SBart Van Assche size_t len = strlen(filename);
1118*44704f69SBart Van Assche
1119*44704f69SBart Van Assche if ((1 == len) && ('.' == filename[0]))
1120*44704f69SBart Van Assche return FT_DEV_NULL;
1121*44704f69SBart Van Assche if (stat(filename, &st) < 0)
1122*44704f69SBart Van Assche return FT_ERROR;
1123*44704f69SBart Van Assche if (S_ISCHR(st.st_mode)) {
1124*44704f69SBart Van Assche if ((MEM_MAJOR == major(st.st_rdev)) &&
1125*44704f69SBart Van Assche ((DEV_NULL_MINOR_NUM == minor(st.st_rdev)) ||
1126*44704f69SBart Van Assche (DEV_ZERO_MINOR_NUM == minor(st.st_rdev))))
1127*44704f69SBart Van Assche return FT_DEV_NULL; /* treat /dev/null + /dev/zero the same */
1128*44704f69SBart Van Assche if (SCSI_GENERIC_MAJOR == major(st.st_rdev))
1129*44704f69SBart Van Assche return FT_SG;
1130*44704f69SBart Van Assche if (SCSI_TAPE_MAJOR == major(st.st_rdev))
1131*44704f69SBart Van Assche return FT_ST;
1132*44704f69SBart Van Assche return FT_CHAR;
1133*44704f69SBart Van Assche } else if (S_ISBLK(st.st_mode))
1134*44704f69SBart Van Assche return FT_BLOCK;
1135*44704f69SBart Van Assche else if (S_ISFIFO(st.st_mode))
1136*44704f69SBart Van Assche return FT_FIFO;
1137*44704f69SBart Van Assche st_size = st.st_size;
1138*44704f69SBart Van Assche return FT_OTHER;
1139*44704f69SBart Van Assche }
1140*44704f69SBart Van Assche
1141*44704f69SBart Van Assche static inline void
stop_both(struct global_collection * clp)1142*44704f69SBart Van Assche stop_both(struct global_collection * clp)
1143*44704f69SBart Van Assche {
1144*44704f69SBart Van Assche clp->in_stop = true;
1145*44704f69SBart Van Assche clp->out_stop = true;
1146*44704f69SBart Van Assche }
1147*44704f69SBart Van Assche
1148*44704f69SBart Van Assche /* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */
1149*44704f69SBart Van Assche static int
scsi_read_capacity(int sg_fd,int64_t * num_sect,int * sect_sz)1150*44704f69SBart Van Assche scsi_read_capacity(int sg_fd, int64_t * num_sect, int * sect_sz)
1151*44704f69SBart Van Assche {
1152*44704f69SBart Van Assche int res;
1153*44704f69SBart Van Assche uint8_t rcBuff[RCAP16_REPLY_LEN] = {};
1154*44704f69SBart Van Assche
1155*44704f69SBart Van Assche res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, false, 0);
1156*44704f69SBart Van Assche if (0 != res)
1157*44704f69SBart Van Assche return res;
1158*44704f69SBart Van Assche
1159*44704f69SBart Van Assche if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) &&
1160*44704f69SBart Van Assche (0xff == rcBuff[3])) {
1161*44704f69SBart Van Assche
1162*44704f69SBart Van Assche res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, false,
1163*44704f69SBart Van Assche 0);
1164*44704f69SBart Van Assche if (0 != res)
1165*44704f69SBart Van Assche return res;
1166*44704f69SBart Van Assche *num_sect = sg_get_unaligned_be64(rcBuff + 0) + 1;
1167*44704f69SBart Van Assche *sect_sz = sg_get_unaligned_be32(rcBuff + 8);
1168*44704f69SBart Van Assche } else {
1169*44704f69SBart Van Assche /* take care not to sign extend values > 0x7fffffff */
1170*44704f69SBart Van Assche *num_sect = (int64_t)sg_get_unaligned_be32(rcBuff + 0) + 1;
1171*44704f69SBart Van Assche *sect_sz = sg_get_unaligned_be32(rcBuff + 4);
1172*44704f69SBart Van Assche }
1173*44704f69SBart Van Assche return 0;
1174*44704f69SBart Van Assche }
1175*44704f69SBart Van Assche
1176*44704f69SBart Van Assche /* Return of 0 -> success, -1 -> failure. BLKGETSIZE64, BLKGETSIZE and */
1177*44704f69SBart Van Assche /* BLKSSZGET macros problematic (from <linux/fs.h> or <sys/mount.h>). */
1178*44704f69SBart Van Assche static int
read_blkdev_capacity(int sg_fd,int64_t * num_sect,int * sect_sz)1179*44704f69SBart Van Assche read_blkdev_capacity(int sg_fd, int64_t * num_sect, int * sect_sz)
1180*44704f69SBart Van Assche {
1181*44704f69SBart Van Assche #ifdef BLKSSZGET
1182*44704f69SBart Van Assche if ((ioctl(sg_fd, BLKSSZGET, sect_sz) < 0) && (*sect_sz > 0)) {
1183*44704f69SBart Van Assche perror("BLKSSZGET ioctl error");
1184*44704f69SBart Van Assche return -1;
1185*44704f69SBart Van Assche } else {
1186*44704f69SBart Van Assche #ifdef BLKGETSIZE64
1187*44704f69SBart Van Assche uint64_t ull;
1188*44704f69SBart Van Assche
1189*44704f69SBart Van Assche if (ioctl(sg_fd, BLKGETSIZE64, &ull) < 0) {
1190*44704f69SBart Van Assche
1191*44704f69SBart Van Assche perror("BLKGETSIZE64 ioctl error");
1192*44704f69SBart Van Assche return -1;
1193*44704f69SBart Van Assche }
1194*44704f69SBart Van Assche *num_sect = ((int64_t)ull / (int64_t)*sect_sz);
1195*44704f69SBart Van Assche #else
1196*44704f69SBart Van Assche unsigned long ul;
1197*44704f69SBart Van Assche
1198*44704f69SBart Van Assche if (ioctl(sg_fd, BLKGETSIZE, &ul) < 0) {
1199*44704f69SBart Van Assche perror("BLKGETSIZE ioctl error");
1200*44704f69SBart Van Assche return -1;
1201*44704f69SBart Van Assche }
1202*44704f69SBart Van Assche *num_sect = (int64_t)ul;
1203*44704f69SBart Van Assche #endif
1204*44704f69SBart Van Assche }
1205*44704f69SBart Van Assche return 0;
1206*44704f69SBart Van Assche #else
1207*44704f69SBart Van Assche *num_sect = 0;
1208*44704f69SBart Van Assche *sect_sz = 0;
1209*44704f69SBart Van Assche return -1;
1210*44704f69SBart Van Assche #endif
1211*44704f69SBart Van Assche }
1212*44704f69SBart Van Assche
1213*44704f69SBart Van Assche static int
system_wrapper(const char * cmd)1214*44704f69SBart Van Assche system_wrapper(const char * cmd)
1215*44704f69SBart Van Assche {
1216*44704f69SBart Van Assche int res;
1217*44704f69SBart Van Assche
1218*44704f69SBart Van Assche res = system(cmd);
1219*44704f69SBart Van Assche if (WIFSIGNALED(res) &&
1220*44704f69SBart Van Assche (WTERMSIG(res) == SIGINT || WTERMSIG(res) == SIGQUIT))
1221*44704f69SBart Van Assche raise(WTERMSIG(res));
1222*44704f69SBart Van Assche return WEXITSTATUS(res);
1223*44704f69SBart Van Assche }
1224*44704f69SBart Van Assche
1225*44704f69SBart Van Assche /* Has an infinite loop doing a timed wait for any signals in sig_set. After
1226*44704f69SBart Van Assche * each timeout (300 ms) checks if the most_recent_pack_id atomic integer
1227*44704f69SBart Van Assche * has changed. If not after another two timeouts announces a stall has
1228*44704f69SBart Van Assche * been detected. If shutting down atomic is true breaks out of loop and
1229*44704f69SBart Van Assche * shuts down this thread. Other than that, this thread is normally cancelled
1230*44704f69SBart Van Assche * by the main thread, after other threads have exited. */
1231*44704f69SBart Van Assche static void *
sig_listen_thread(void * v_clp)1232*44704f69SBart Van Assche sig_listen_thread(void * v_clp)
1233*44704f69SBart Van Assche {
1234*44704f69SBart Van Assche bool stall_reported = false;
1235*44704f69SBart Van Assche int prev_pack_id = 0;
1236*44704f69SBart Van Assche struct timespec ts;
1237*44704f69SBart Van Assche struct timespec * tsp = &ts;
1238*44704f69SBart Van Assche struct global_collection * clp = (struct global_collection *)v_clp;
1239*44704f69SBart Van Assche uint32_t ict_ms = (clp->sdt_ict ? clp->sdt_ict : DEF_SDT_ICT_MS);
1240*44704f69SBart Van Assche
1241*44704f69SBart Van Assche tsp->tv_sec = ict_ms / 1000;
1242*44704f69SBart Van Assche tsp->tv_nsec = (ict_ms % 1000) * 1000 * 1000; /* DEF_SDT_ICT_MS */
1243*44704f69SBart Van Assche while (1) {
1244*44704f69SBart Van Assche int sig_number = sigtimedwait(&signal_set, NULL, tsp);
1245*44704f69SBart Van Assche
1246*44704f69SBart Van Assche if (sig_number < 0) {
1247*44704f69SBart Van Assche int err = errno;
1248*44704f69SBart Van Assche
1249*44704f69SBart Van Assche /* EAGAIN implies a timeout */
1250*44704f69SBart Van Assche if ((EAGAIN == err) && (clp->sdt_crt > 0)) {
1251*44704f69SBart Van Assche int pack_id = mono_pack_id.load();
1252*44704f69SBart Van Assche
1253*44704f69SBart Van Assche if ((pack_id > 0) && (pack_id == prev_pack_id)) {
1254*44704f69SBart Van Assche if (! stall_reported) {
1255*44704f69SBart Van Assche stall_reported = true;
1256*44704f69SBart Van Assche tsp->tv_sec = clp->sdt_crt;
1257*44704f69SBart Van Assche tsp->tv_nsec = 0;
1258*44704f69SBart Van Assche pr2serr_lk("%s: first stall at pack_id=%d detected\n",
1259*44704f69SBart Van Assche __func__, pack_id);
1260*44704f69SBart Van Assche } else
1261*44704f69SBart Van Assche pr2serr_lk("%s: subsequent stall at pack_id=%d\n",
1262*44704f69SBart Van Assche __func__, pack_id);
1263*44704f69SBart Van Assche // following command assumes linux bash or similar shell
1264*44704f69SBart Van Assche system_wrapper("cat /proc/scsi/sg/debug >> /dev/stderr\n");
1265*44704f69SBart Van Assche // system_wrapper("/usr/bin/dmesg\n");
1266*44704f69SBart Van Assche } else
1267*44704f69SBart Van Assche prev_pack_id = pack_id;
1268*44704f69SBart Van Assche } else if (EAGAIN != err)
1269*44704f69SBart Van Assche pr2serr_lk("%s: sigtimedwait() errno=%d\n", __func__, err);
1270*44704f69SBart Van Assche }
1271*44704f69SBart Van Assche if (SIGINT == sig_number) {
1272*44704f69SBart Van Assche pr2serr_lk("%sinterrupted by SIGINT\n", my_name);
1273*44704f69SBart Van Assche stop_both(clp);
1274*44704f69SBart Van Assche pthread_cond_broadcast(&clp->out_sync_cv);
1275*44704f69SBart Van Assche sigprocmask(SIG_SETMASK, &orig_signal_set, NULL);
1276*44704f69SBart Van Assche raise(SIGINT);
1277*44704f69SBart Van Assche break;
1278*44704f69SBart Van Assche }
1279*44704f69SBart Van Assche if (SIGUSR2 == sig_number) {
1280*44704f69SBart Van Assche if (clp->verbose > 2)
1281*44704f69SBart Van Assche pr2serr_lk("%s: interrupted by SIGUSR2\n", __func__);
1282*44704f69SBart Van Assche break;
1283*44704f69SBart Van Assche }
1284*44704f69SBart Van Assche if (shutting_down)
1285*44704f69SBart Van Assche break;
1286*44704f69SBart Van Assche } /* end of while loop */
1287*44704f69SBart Van Assche if (clp->verbose > 3)
1288*44704f69SBart Van Assche pr2serr_lk("%s: exiting\n", __func__);
1289*44704f69SBart Van Assche
1290*44704f69SBart Van Assche return NULL;
1291*44704f69SBart Van Assche }
1292*44704f69SBart Van Assche
1293*44704f69SBart Van Assche static void *
mrq_abort_thread(void * v_maip)1294*44704f69SBart Van Assche mrq_abort_thread(void * v_maip)
1295*44704f69SBart Van Assche {
1296*44704f69SBart Van Assche int res, err;
1297*44704f69SBart Van Assche int n = 0;
1298*44704f69SBart Van Assche int seed;
1299*44704f69SBart Van Assche unsigned int rn;
1300*44704f69SBart Van Assche Mrq_abort_info l_mai = *(Mrq_abort_info *)v_maip;
1301*44704f69SBart Van Assche struct sg_io_v4 ctl_v4 {};
1302*44704f69SBart Van Assche
1303*44704f69SBart Van Assche #ifdef HAVE_GETRANDOM
1304*44704f69SBart Van Assche {
1305*44704f69SBart Van Assche ssize_t ssz = getrandom(&seed, sizeof(seed), GRND_NONBLOCK);
1306*44704f69SBart Van Assche
1307*44704f69SBart Van Assche if (ssz < (ssize_t)sizeof(seed)) {
1308*44704f69SBart Van Assche pr2serr("getrandom() failed, ret=%d\n", (int)ssz);
1309*44704f69SBart Van Assche seed = (int)time(NULL);
1310*44704f69SBart Van Assche }
1311*44704f69SBart Van Assche }
1312*44704f69SBart Van Assche #else
1313*44704f69SBart Van Assche seed = (int)time(NULL); /* use seconds since epoch as proxy */
1314*44704f69SBart Van Assche #endif
1315*44704f69SBart Van Assche if (l_mai.debug)
1316*44704f69SBart Van Assche pr2serr_lk("%s: from_id=%d: to abort mrq_pack_id=%d\n", __func__,
1317*44704f69SBart Van Assche l_mai.from_tid, l_mai.mrq_id);
1318*44704f69SBart Van Assche res = ioctl(l_mai.fd, SG_GET_NUM_WAITING, &n);
1319*44704f69SBart Van Assche ++num_waiting_calls;
1320*44704f69SBart Van Assche if (res < 0) {
1321*44704f69SBart Van Assche err = errno;
1322*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_GET_NUM_WAITING) failed: %s [%d]\n",
1323*44704f69SBart Van Assche __func__, safe_strerror(err), err);
1324*44704f69SBart Van Assche } else if (l_mai.debug)
1325*44704f69SBart Van Assche pr2serr_lk("%s: num_waiting=%d\n", __func__, n);
1326*44704f69SBart Van Assche
1327*44704f69SBart Van Assche Rand_uint * ruip = new Rand_uint(5, 500, seed);
1328*44704f69SBart Van Assche struct timespec tspec = {0, 4000 /* 4 usecs */};
1329*44704f69SBart Van Assche rn = ruip->get();
1330*44704f69SBart Van Assche tspec.tv_nsec = rn * 1000;
1331*44704f69SBart Van Assche if (l_mai.debug > 1)
1332*44704f69SBart Van Assche pr2serr_lk("%s: /dev/urandom seed=0x%x delay=%u microsecs\n",
1333*44704f69SBart Van Assche __func__, seed, rn);
1334*44704f69SBart Van Assche if (rn >= 20)
1335*44704f69SBart Van Assche nanosleep(&tspec, NULL);
1336*44704f69SBart Van Assche else if (l_mai.debug > 1)
1337*44704f69SBart Van Assche pr2serr_lk("%s: skipping nanosleep cause delay < 20 usecs\n",
1338*44704f69SBart Van Assche __func__);
1339*44704f69SBart Van Assche
1340*44704f69SBart Van Assche ctl_v4.guard = 'Q';
1341*44704f69SBart Van Assche ctl_v4.flags = SGV4_FLAG_MULTIPLE_REQS;
1342*44704f69SBart Van Assche ctl_v4.request_extra = l_mai.mrq_id;
1343*44704f69SBart Van Assche ++num_mrq_abort_req;
1344*44704f69SBart Van Assche res = ioctl(l_mai.fd, SG_IOABORT, &ctl_v4);
1345*44704f69SBart Van Assche if (res < 0) {
1346*44704f69SBart Van Assche err = errno;
1347*44704f69SBart Van Assche if (ENODATA == err)
1348*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_IOABORT) no match on "
1349*44704f69SBart Van Assche "MRQ pack_id=%d\n", __func__, l_mai.mrq_id);
1350*44704f69SBart Van Assche else
1351*44704f69SBart Van Assche pr2serr_lk("%s: MRQ ioctl(SG_IOABORT) failed: %s [%d]\n",
1352*44704f69SBart Van Assche __func__, safe_strerror(err), err);
1353*44704f69SBart Van Assche } else {
1354*44704f69SBart Van Assche ++num_mrq_abort_req_success;
1355*44704f69SBart Van Assche if (l_mai.debug > 1)
1356*44704f69SBart Van Assche pr2serr_lk("%s: from_id=%d sent ioctl(SG_IOABORT) on MRQ rq_id="
1357*44704f69SBart Van Assche "%d, success\n", __func__, l_mai.from_tid,
1358*44704f69SBart Van Assche l_mai.mrq_id);
1359*44704f69SBart Van Assche }
1360*44704f69SBart Van Assche delete ruip;
1361*44704f69SBart Van Assche return NULL;
1362*44704f69SBart Van Assche }
1363*44704f69SBart Van Assche
1364*44704f69SBart Van Assche static bool
sg_share_prepare(int write_side_fd,int read_side_fd,int id,bool vb_b)1365*44704f69SBart Van Assche sg_share_prepare(int write_side_fd, int read_side_fd, int id, bool vb_b)
1366*44704f69SBart Van Assche {
1367*44704f69SBart Van Assche struct sg_extended_info sei {};
1368*44704f69SBart Van Assche struct sg_extended_info * seip = &sei;
1369*44704f69SBart Van Assche
1370*44704f69SBart Van Assche seip->sei_wr_mask |= SG_SEIM_SHARE_FD;
1371*44704f69SBart Van Assche seip->sei_rd_mask |= SG_SEIM_SHARE_FD;
1372*44704f69SBart Van Assche seip->share_fd = read_side_fd;
1373*44704f69SBart Van Assche if (ioctl(write_side_fd, SG_SET_GET_EXTENDED, seip) < 0) {
1374*44704f69SBart Van Assche pr2serr_lk("tid=%d: ioctl(EXTENDED(shared_fd=%d), failed "
1375*44704f69SBart Van Assche "errno=%d %s\n", id, read_side_fd, errno,
1376*44704f69SBart Van Assche strerror(errno));
1377*44704f69SBart Van Assche return false;
1378*44704f69SBart Van Assche }
1379*44704f69SBart Van Assche if (vb_b)
1380*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: ioctl(EXTENDED(shared_fd)) ok, "
1381*44704f69SBart Van Assche "read_side_fd=%d, write_side_fd=%d\n", __func__,
1382*44704f69SBart Van Assche id, read_side_fd, write_side_fd);
1383*44704f69SBart Van Assche return true;
1384*44704f69SBart Van Assche }
1385*44704f69SBart Van Assche
1386*44704f69SBart Van Assche static void
sg_unshare(int sg_fd,int id,bool vb_b)1387*44704f69SBart Van Assche sg_unshare(int sg_fd, int id, bool vb_b)
1388*44704f69SBart Van Assche {
1389*44704f69SBart Van Assche struct sg_extended_info sei {};
1390*44704f69SBart Van Assche struct sg_extended_info * seip = &sei;
1391*44704f69SBart Van Assche
1392*44704f69SBart Van Assche seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
1393*44704f69SBart Van Assche seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
1394*44704f69SBart Van Assche seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_UNSHARE;
1395*44704f69SBart Van Assche seip->ctl_flags |= SG_CTL_FLAGM_UNSHARE; /* needs to be set to unshare */
1396*44704f69SBart Van Assche if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
1397*44704f69SBart Van Assche pr2serr_lk("tid=%d: ioctl(EXTENDED(UNSHARE), failed errno=%d %s\n",
1398*44704f69SBart Van Assche id, errno, strerror(errno));
1399*44704f69SBart Van Assche return;
1400*44704f69SBart Van Assche }
1401*44704f69SBart Van Assche if (vb_b)
1402*44704f69SBart Van Assche pr2serr_lk("tid=%d: ioctl(UNSHARE) ok\n", id);
1403*44704f69SBart Van Assche }
1404*44704f69SBart Van Assche
1405*44704f69SBart Van Assche static void
sg_noshare_enlarge(int sg_fd,bool vb_b)1406*44704f69SBart Van Assche sg_noshare_enlarge(int sg_fd, bool vb_b)
1407*44704f69SBart Van Assche {
1408*44704f69SBart Van Assche if (sg_version_ge_40045) {
1409*44704f69SBart Van Assche struct sg_extended_info sei {};
1410*44704f69SBart Van Assche struct sg_extended_info * seip = &sei;
1411*44704f69SBart Van Assche
1412*44704f69SBart Van Assche sei.sei_wr_mask |= SG_SEIM_TOT_FD_THRESH;
1413*44704f69SBart Van Assche seip->tot_fd_thresh = 96 * 1024 * 1024;
1414*44704f69SBart Van Assche if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
1415*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(EXTENDED(TOT_FD_THRESH), failed errno=%d "
1416*44704f69SBart Van Assche "%s\n", __func__, errno, strerror(errno));
1417*44704f69SBart Van Assche return;
1418*44704f69SBart Van Assche }
1419*44704f69SBart Van Assche if (vb_b)
1420*44704f69SBart Van Assche pr2serr_lk("ioctl(TOT_FD_THRESH) ok\n");
1421*44704f69SBart Van Assche }
1422*44704f69SBart Van Assche }
1423*44704f69SBart Van Assche
1424*44704f69SBart Van Assche static void
sg_take_snap(int sg_fd,int id,bool vb_b)1425*44704f69SBart Van Assche sg_take_snap(int sg_fd, int id, bool vb_b)
1426*44704f69SBart Van Assche {
1427*44704f69SBart Van Assche struct sg_extended_info sei {};
1428*44704f69SBart Van Assche struct sg_extended_info * seip = &sei;
1429*44704f69SBart Van Assche
1430*44704f69SBart Van Assche seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
1431*44704f69SBart Van Assche seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
1432*44704f69SBart Van Assche seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_SNAP_DEV;
1433*44704f69SBart Van Assche seip->ctl_flags &= ~SG_CTL_FLAGM_SNAP_DEV; /* 0 --> append */
1434*44704f69SBart Van Assche if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) {
1435*44704f69SBart Van Assche pr2serr_lk("tid=%d: ioctl(EXTENDED(SNAP_DEV), failed errno=%d %s\n",
1436*44704f69SBart Van Assche id, errno, strerror(errno));
1437*44704f69SBart Van Assche return;
1438*44704f69SBart Van Assche }
1439*44704f69SBart Van Assche if (vb_b)
1440*44704f69SBart Van Assche pr2serr_lk("tid=%d: ioctl(SNAP_DEV) ok\n", id);
1441*44704f69SBart Van Assche }
1442*44704f69SBart Van Assche
1443*44704f69SBart Van Assche static void
cleanup_in(void * v_clp)1444*44704f69SBart Van Assche cleanup_in(void * v_clp)
1445*44704f69SBart Van Assche {
1446*44704f69SBart Van Assche struct global_collection * clp = (struct global_collection *)v_clp;
1447*44704f69SBart Van Assche
1448*44704f69SBart Van Assche pr2serr("thread cancelled while in mutex held\n");
1449*44704f69SBart Van Assche stop_both(clp);
1450*44704f69SBart Van Assche pthread_mutex_unlock(&clp->in_mutex);
1451*44704f69SBart Van Assche pthread_cond_broadcast(&clp->out_sync_cv);
1452*44704f69SBart Van Assche }
1453*44704f69SBart Van Assche
1454*44704f69SBart Van Assche static void
cleanup_out(void * v_clp)1455*44704f69SBart Van Assche cleanup_out(void * v_clp)
1456*44704f69SBart Van Assche {
1457*44704f69SBart Van Assche struct global_collection * clp = (struct global_collection *)v_clp;
1458*44704f69SBart Van Assche
1459*44704f69SBart Van Assche pr2serr("thread cancelled while out_mutex held\n");
1460*44704f69SBart Van Assche stop_both(clp);
1461*44704f69SBart Van Assche pthread_mutex_unlock(&clp->out_mutex);
1462*44704f69SBart Van Assche pthread_cond_broadcast(&clp->out_sync_cv);
1463*44704f69SBart Van Assche }
1464*44704f69SBart Van Assche
buffp_onto_next(Rq_elem * rep)1465*44704f69SBart Van Assche static void inline buffp_onto_next(Rq_elem * rep)
1466*44704f69SBart Van Assche {
1467*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
1468*44704f69SBart Van Assche
1469*44704f69SBart Van Assche if ((clp->nmrqs > 0) && clp->unbalanced_mrq) {
1470*44704f69SBart Van Assche ++rep->mrq_index;
1471*44704f69SBart Van Assche if (rep->mrq_index >= clp->nmrqs)
1472*44704f69SBart Van Assche rep->mrq_index = 0; /* wrap */
1473*44704f69SBart Van Assche }
1474*44704f69SBart Van Assche }
1475*44704f69SBart Van Assche
1476*44704f69SBart Van Assche static inline uint8_t *
get_buffp(Rq_elem * rep)1477*44704f69SBart Van Assche get_buffp(Rq_elem * rep)
1478*44704f69SBart Van Assche {
1479*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
1480*44704f69SBart Van Assche
1481*44704f69SBart Van Assche if ((clp->nmrqs > 0) && clp->unbalanced_mrq && (rep->mrq_index > 0))
1482*44704f69SBart Van Assche return rep->buffp + (rep->mrq_index * clp->bs * clp->bpt);
1483*44704f69SBart Van Assche else
1484*44704f69SBart Van Assche return rep->buffp;
1485*44704f69SBart Van Assche }
1486*44704f69SBart Van Assche
1487*44704f69SBart Van Assche static void *
read_write_thread(void * v_tip)1488*44704f69SBart Van Assche read_write_thread(void * v_tip)
1489*44704f69SBart Van Assche {
1490*44704f69SBart Van Assche Thread_info * tip;
1491*44704f69SBart Van Assche struct global_collection * clp;
1492*44704f69SBart Van Assche Rq_elem rel {};
1493*44704f69SBart Van Assche Rq_elem * rep = &rel;
1494*44704f69SBart Van Assche int n, sz, blocks, status, vb, err, res, wr_blks, c_addr;
1495*44704f69SBart Van Assche int num_sg = 0;
1496*44704f69SBart Van Assche int64_t my_index;
1497*44704f69SBart Van Assche volatile bool stop_after_write = false;
1498*44704f69SBart Van Assche bool own_infd = false;
1499*44704f69SBart Van Assche bool in_is_sg, in_mmap, out_is_sg, out_mmap;
1500*44704f69SBart Van Assche bool own_outfd = false;
1501*44704f69SBart Van Assche bool own_out2fd = false;
1502*44704f69SBart Van Assche bool share_and_ofreg;
1503*44704f69SBart Van Assche mrq_arr_t deferred_arr; /* MRQ deferred array (vector) */
1504*44704f69SBart Van Assche
1505*44704f69SBart Van Assche tip = (Thread_info *)v_tip;
1506*44704f69SBart Van Assche clp = tip->gcp;
1507*44704f69SBart Van Assche vb = clp->verbose;
1508*44704f69SBart Van Assche rep->bs = clp->bs;
1509*44704f69SBart Van Assche sz = clp->bpt * rep->bs;
1510*44704f69SBart Van Assche c_addr = clp->chkaddr;
1511*44704f69SBart Van Assche in_is_sg = (FT_SG == clp->in_type);
1512*44704f69SBart Van Assche in_mmap = (in_is_sg && (clp->in_flags.mmap > 0));
1513*44704f69SBart Van Assche out_is_sg = (FT_SG == clp->out_type);
1514*44704f69SBart Van Assche out_mmap = (out_is_sg && (clp->out_flags.mmap > 0));
1515*44704f69SBart Van Assche /* Following clp members are constant during lifetime of thread */
1516*44704f69SBart Van Assche rep->clp = clp;
1517*44704f69SBart Van Assche rep->id = tip->id;
1518*44704f69SBart Van Assche if (vb > 2)
1519*44704f69SBart Van Assche pr2serr_lk("%d <-- Starting worker thread\n", rep->id);
1520*44704f69SBart Van Assche if (! (in_mmap || out_mmap)) {
1521*44704f69SBart Van Assche n = sz;
1522*44704f69SBart Van Assche if (clp->unbalanced_mrq)
1523*44704f69SBart Van Assche n *= clp->nmrqs;
1524*44704f69SBart Van Assche rep->buffp = sg_memalign(n, 0 /* page align */, &rep->alloc_bp,
1525*44704f69SBart Van Assche false);
1526*44704f69SBart Van Assche if (NULL == rep->buffp)
1527*44704f69SBart Van Assche err_exit(ENOMEM, "out of memory creating user buffers\n");
1528*44704f69SBart Van Assche }
1529*44704f69SBart Van Assche rep->infd = clp->infd;
1530*44704f69SBart Van Assche rep->outfd = clp->outfd;
1531*44704f69SBart Van Assche rep->out2fd = clp->out2fd;
1532*44704f69SBart Van Assche rep->outregfd = clp->outregfd;
1533*44704f69SBart Van Assche rep->rep_count = 0;
1534*44704f69SBart Van Assche if (clp->unbalanced_mrq && (clp->nmrqs > 0))
1535*44704f69SBart Van Assche rep->mrq_index = clp->nmrqs - 1;
1536*44704f69SBart Van Assche
1537*44704f69SBart Van Assche if (rep->infd == rep->outfd) {
1538*44704f69SBart Van Assche if (in_is_sg)
1539*44704f69SBart Van Assche rep->same_sg = true;
1540*44704f69SBart Van Assche } else if (in_is_sg && out_is_sg)
1541*44704f69SBart Van Assche rep->both_sg = true;
1542*44704f69SBart Van Assche else if (in_is_sg)
1543*44704f69SBart Van Assche rep->only_in_sg = true;
1544*44704f69SBart Van Assche else if (out_is_sg)
1545*44704f69SBart Van Assche rep->only_out_sg = true;
1546*44704f69SBart Van Assche
1547*44704f69SBart Van Assche if (clp->in_flags.random) {
1548*44704f69SBart Van Assche #ifdef HAVE_GETRANDOM
1549*44704f69SBart Van Assche ssize_t ssz = getrandom(&rep->seed, sizeof(rep->seed), GRND_NONBLOCK);
1550*44704f69SBart Van Assche
1551*44704f69SBart Van Assche if (ssz < (ssize_t)sizeof(rep->seed)) {
1552*44704f69SBart Van Assche pr2serr_lk("thread=%d: getrandom() failed, ret=%d\n",
1553*44704f69SBart Van Assche rep->id, (int)ssz);
1554*44704f69SBart Van Assche rep->seed = (long)time(NULL);
1555*44704f69SBart Van Assche }
1556*44704f69SBart Van Assche #else
1557*44704f69SBart Van Assche rep->seed = (long)time(NULL); /* use seconds since epoch as proxy */
1558*44704f69SBart Van Assche #endif
1559*44704f69SBart Van Assche if (vb > 1)
1560*44704f69SBart Van Assche pr2serr_lk("thread=%d: seed=%ld\n", rep->id, rep->seed);
1561*44704f69SBart Van Assche #ifdef HAVE_SRAND48_R
1562*44704f69SBart Van Assche srand48_r(rep->seed, &rep->drand);
1563*44704f69SBart Van Assche #else
1564*44704f69SBart Van Assche srand48(rep->seed);
1565*44704f69SBart Van Assche #endif
1566*44704f69SBart Van Assche }
1567*44704f69SBart Van Assche if (clp->in_flags.same_fds || clp->out_flags.same_fds)
1568*44704f69SBart Van Assche ;
1569*44704f69SBart Van Assche else {
1570*44704f69SBart Van Assche int fd;
1571*44704f69SBart Van Assche
1572*44704f69SBart Van Assche if (in_is_sg && clp->infp) {
1573*44704f69SBart Van Assche fd = sg_in_open(clp, clp->infp, (in_mmap ? &rep->buffp : NULL),
1574*44704f69SBart Van Assche (in_mmap ? &rep->mmap_len : NULL));
1575*44704f69SBart Van Assche if (fd < 0)
1576*44704f69SBart Van Assche goto fini;
1577*44704f69SBart Van Assche rep->infd = fd;
1578*44704f69SBart Van Assche rep->mmap_active = in_mmap ? clp->in_flags.mmap : 0;
1579*44704f69SBart Van Assche if (in_mmap && (vb > 4))
1580*44704f69SBart Van Assche pr2serr_lk("thread=%d: mmap buffp=%p\n", rep->id, rep->buffp);
1581*44704f69SBart Van Assche own_infd = true;
1582*44704f69SBart Van Assche ++num_sg;
1583*44704f69SBart Van Assche if (vb > 2)
1584*44704f69SBart Van Assche pr2serr_lk("thread=%d: opened local sg IFILE\n", rep->id);
1585*44704f69SBart Van Assche }
1586*44704f69SBart Van Assche if (out_is_sg && clp->outfp) {
1587*44704f69SBart Van Assche fd = sg_out_open(clp, clp->outfp, (out_mmap ? &rep->buffp : NULL),
1588*44704f69SBart Van Assche (out_mmap ? &rep->mmap_len : NULL));
1589*44704f69SBart Van Assche if (fd < 0)
1590*44704f69SBart Van Assche goto fini;
1591*44704f69SBart Van Assche rep->outfd = fd;
1592*44704f69SBart Van Assche if (! rep->mmap_active)
1593*44704f69SBart Van Assche rep->mmap_active = out_mmap ? clp->out_flags.mmap : 0;
1594*44704f69SBart Van Assche if (out_mmap && (vb > 4))
1595*44704f69SBart Van Assche pr2serr_lk("thread=%d: mmap buffp=%p\n", rep->id, rep->buffp);
1596*44704f69SBart Van Assche own_outfd = true;
1597*44704f69SBart Van Assche ++num_sg;
1598*44704f69SBart Van Assche if (vb > 2)
1599*44704f69SBart Van Assche pr2serr_lk("thread=%d: opened local sg OFILE\n", rep->id);
1600*44704f69SBart Van Assche }
1601*44704f69SBart Van Assche if ((FT_SG == clp->out2_type) && clp->out2fp) {
1602*44704f69SBart Van Assche fd = sg_out_open(clp, clp->out2fp,
1603*44704f69SBart Van Assche (out_mmap ? &rep->buffp : NULL),
1604*44704f69SBart Van Assche (out_mmap ? &rep->mmap_len : NULL));
1605*44704f69SBart Van Assche if (fd < 0)
1606*44704f69SBart Van Assche goto fini;
1607*44704f69SBart Van Assche rep->out2fd = fd;
1608*44704f69SBart Van Assche own_out2fd = true;
1609*44704f69SBart Van Assche if (vb > 2)
1610*44704f69SBart Van Assche pr2serr_lk("thread=%d: opened local sg OFILE2\n", rep->id);
1611*44704f69SBart Van Assche }
1612*44704f69SBart Van Assche }
1613*44704f69SBart Van Assche if (vb > 2) {
1614*44704f69SBart Van Assche if (in_is_sg && (! own_infd))
1615*44704f69SBart Van Assche pr2serr_lk("thread=%d: using global sg IFILE, fd=%d\n", rep->id,
1616*44704f69SBart Van Assche rep->infd);
1617*44704f69SBart Van Assche if (out_is_sg && (! own_outfd))
1618*44704f69SBart Van Assche pr2serr_lk("thread=%d: using global sg OFILE, fd=%d\n", rep->id,
1619*44704f69SBart Van Assche rep->outfd);
1620*44704f69SBart Van Assche if ((FT_SG == clp->out2_type) && (! own_out2fd))
1621*44704f69SBart Van Assche pr2serr_lk("thread=%d: using global sg OFILE2, fd=%d\n", rep->id,
1622*44704f69SBart Van Assche rep->out2fd);
1623*44704f69SBart Van Assche }
1624*44704f69SBart Van Assche if (!sg_version_ge_40045) {
1625*44704f69SBart Van Assche if (vb > 4)
1626*44704f69SBart Van Assche pr2serr_lk("thread=%d: Skipping share because driver too old\n",
1627*44704f69SBart Van Assche rep->id);
1628*44704f69SBart Van Assche } else if (clp->noshare) {
1629*44704f69SBart Van Assche if (vb > 4)
1630*44704f69SBart Van Assche pr2serr_lk("thread=%d: Skipping IFILE share with OFILE due to "
1631*44704f69SBart Van Assche "noshare=1\n", rep->id);
1632*44704f69SBart Van Assche } else if (sg_version_ge_40045 && in_is_sg && out_is_sg)
1633*44704f69SBart Van Assche rep->has_share = sg_share_prepare(rep->outfd, rep->infd, rep->id,
1634*44704f69SBart Van Assche vb > 9);
1635*44704f69SBart Van Assche if (vb > 9)
1636*44704f69SBart Van Assche pr2serr_lk("tid=%d, has_share=%s\n", rep->id,
1637*44704f69SBart Van Assche (rep->has_share ? "true" : "false"));
1638*44704f69SBart Van Assche share_and_ofreg = (rep->has_share && (rep->outregfd >= 0));
1639*44704f69SBart Van Assche
1640*44704f69SBart Van Assche /* vvvvvvvvvvvvvv Main segment copy loop vvvvvvvvvvvvvvvvvvvvvvv */
1641*44704f69SBart Van Assche while (1) {
1642*44704f69SBart Van Assche rep->wr = false;
1643*44704f69SBart Van Assche my_index = atomic_fetch_add(&pos_index, (long int)clp->bpt);
1644*44704f69SBart Van Assche /* Start of READ half of a segment */
1645*44704f69SBart Van Assche buffp_onto_next(rep);
1646*44704f69SBart Van Assche status = pthread_mutex_lock(&clp->in_mutex);
1647*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock in_mutex");
1648*44704f69SBart Van Assche
1649*44704f69SBart Van Assche if (dd_count >= 0) {
1650*44704f69SBart Van Assche if (my_index >= dd_count) {
1651*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->in_mutex);
1652*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock in_mutex");
1653*44704f69SBart Van Assche if ((clp->nmrqs > 0) && (deferred_arr.first.size() > 0)) {
1654*44704f69SBart Van Assche if (vb > 2)
1655*44704f69SBart Van Assche pr2serr_lk("thread=%d: tail-end my_index>=dd_count, "
1656*44704f69SBart Van Assche "to_do=%u\n", rep->id,
1657*44704f69SBart Van Assche (uint32_t)deferred_arr.first.size());
1658*44704f69SBart Van Assche res = sgh_do_deferred_mrq(rep, deferred_arr);
1659*44704f69SBart Van Assche if (res)
1660*44704f69SBart Van Assche pr2serr_lk("%s tid=%d: sgh_do_deferred_mrq failed\n",
1661*44704f69SBart Van Assche __func__, rep->id);
1662*44704f69SBart Van Assche }
1663*44704f69SBart Van Assche break; /* at or beyond end, so leave loop >>>>>>>>>> */
1664*44704f69SBart Van Assche } else if ((my_index + clp->bpt) > dd_count)
1665*44704f69SBart Van Assche blocks = dd_count - my_index;
1666*44704f69SBart Van Assche else
1667*44704f69SBart Van Assche blocks = clp->bpt;
1668*44704f69SBart Van Assche } else
1669*44704f69SBart Van Assche blocks = clp->bpt;
1670*44704f69SBart Van Assche
1671*44704f69SBart Van Assche rep->iblk = clp->skip + my_index;
1672*44704f69SBart Van Assche rep->oblk = clp->seek + my_index;
1673*44704f69SBart Van Assche rep->num_blks = blocks;
1674*44704f69SBart Van Assche
1675*44704f69SBart Van Assche // clp->in_blk += blocks;
1676*44704f69SBart Van Assche // clp->in_count -= blocks;
1677*44704f69SBart Van Assche
1678*44704f69SBart Van Assche pthread_cleanup_push(cleanup_in, (void *)clp);
1679*44704f69SBart Van Assche if (in_is_sg)
1680*44704f69SBart Van Assche sg_in_rd_cmd(clp, rep, deferred_arr);
1681*44704f69SBart Van Assche else {
1682*44704f69SBart Van Assche stop_after_write = normal_in_rd(rep, blocks);
1683*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->in_mutex);
1684*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock in_mutex");
1685*44704f69SBart Van Assche }
1686*44704f69SBart Van Assche if (c_addr && (rep->bs > 3)) {
1687*44704f69SBart Van Assche int k, j, off, num;
1688*44704f69SBart Van Assche uint32_t addr = (uint32_t)rep->iblk;
1689*44704f69SBart Van Assche
1690*44704f69SBart Van Assche num = (1 == c_addr) ? 4 : (rep->bs - 3);
1691*44704f69SBart Van Assche for (k = 0, off = 0; k < blocks; ++k, ++addr, off += rep->bs) {
1692*44704f69SBart Van Assche for (j = 0; j < num; j += 4) {
1693*44704f69SBart Van Assche if (addr != sg_get_unaligned_be32(rep->buffp + off + j))
1694*44704f69SBart Van Assche break;
1695*44704f69SBart Van Assche }
1696*44704f69SBart Van Assche if (j < num)
1697*44704f69SBart Van Assche break;
1698*44704f69SBart Van Assche }
1699*44704f69SBart Van Assche if (k < blocks) {
1700*44704f69SBart Van Assche pr2serr("%s: chkaddr failure at addr=0x%x\n", __func__, addr);
1701*44704f69SBart Van Assche exit_status = SG_LIB_CAT_MISCOMPARE;
1702*44704f69SBart Van Assche ++num_miscompare;
1703*44704f69SBart Van Assche stop_both(clp);
1704*44704f69SBart Van Assche }
1705*44704f69SBart Van Assche }
1706*44704f69SBart Van Assche pthread_cleanup_pop(0);
1707*44704f69SBart Van Assche ++rep->rep_count;
1708*44704f69SBart Van Assche
1709*44704f69SBart Van Assche /* Start of WRITE part of a segment */
1710*44704f69SBart Van Assche rep->wr = true;
1711*44704f69SBart Van Assche status = pthread_mutex_lock(&clp->out_mutex);
1712*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock out_mutex");
1713*44704f69SBart Van Assche
1714*44704f69SBart Van Assche /* Make sure the OFILE (+ OFREG) are in same sequence as IFILE */
1715*44704f69SBart Van Assche if (clp->in_flags.random)
1716*44704f69SBart Van Assche goto skip_force_out_sequence;
1717*44704f69SBart Van Assche if ((rep->outregfd < 0) && in_is_sg && out_is_sg)
1718*44704f69SBart Van Assche goto skip_force_out_sequence;
1719*44704f69SBart Van Assche if (share_and_ofreg || (FT_DEV_NULL != clp->out_type)) {
1720*44704f69SBart Van Assche while ((! clp->out_stop.load()) &&
1721*44704f69SBart Van Assche (rep->oblk != clp->out_blk.load())) {
1722*44704f69SBart Van Assche /* if write would be out of sequence then wait */
1723*44704f69SBart Van Assche pthread_cleanup_push(cleanup_out, (void *)clp);
1724*44704f69SBart Van Assche status = pthread_cond_wait(&clp->out_sync_cv, &clp->out_mutex);
1725*44704f69SBart Van Assche if (0 != status) err_exit(status, "cond out_sync_cv");
1726*44704f69SBart Van Assche pthread_cleanup_pop(0);
1727*44704f69SBart Van Assche }
1728*44704f69SBart Van Assche }
1729*44704f69SBart Van Assche
1730*44704f69SBart Van Assche skip_force_out_sequence:
1731*44704f69SBart Van Assche if (clp->out_stop.load() || (clp->out_count.load() <= 0)) {
1732*44704f69SBart Van Assche if (! clp->out_stop.load())
1733*44704f69SBart Van Assche clp->out_stop = true;
1734*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->out_mutex);
1735*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
1736*44704f69SBart Van Assche break; /* stop requested so leave loop >>>>>>>>>> */
1737*44704f69SBart Van Assche }
1738*44704f69SBart Van Assche if (stop_after_write)
1739*44704f69SBart Van Assche clp->out_stop = true;
1740*44704f69SBart Van Assche
1741*44704f69SBart Van Assche clp->out_count -= blocks;
1742*44704f69SBart Van Assche clp->out_blk += blocks;
1743*44704f69SBart Van Assche
1744*44704f69SBart Van Assche pthread_cleanup_push(cleanup_out, (void *)clp);
1745*44704f69SBart Van Assche if (rep->outregfd >= 0) {
1746*44704f69SBart Van Assche res = write(rep->outregfd, get_buffp(rep),
1747*44704f69SBart Van Assche rep->bs * rep->num_blks);
1748*44704f69SBart Van Assche err = errno;
1749*44704f69SBart Van Assche if (res < 0)
1750*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: write(outregfd) failed: %s\n",
1751*44704f69SBart Van Assche __func__, rep->id, strerror(err));
1752*44704f69SBart Van Assche else if (vb > 9)
1753*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: write(outregfd), fd=%d, num_blks=%d"
1754*44704f69SBart Van Assche "\n", __func__, rep->id, rep->outregfd,
1755*44704f69SBart Van Assche rep->num_blks);
1756*44704f69SBart Van Assche }
1757*44704f69SBart Van Assche /* Output to OFILE */
1758*44704f69SBart Van Assche wr_blks = rep->num_blks;
1759*44704f69SBart Van Assche if (out_is_sg) {
1760*44704f69SBart Van Assche sg_out_wr_cmd(rep, deferred_arr, false, clp->prefetch);
1761*44704f69SBart Van Assche ++rep->rep_count;
1762*44704f69SBart Van Assche } else if (FT_DEV_NULL == clp->out_type) {
1763*44704f69SBart Van Assche /* skip actual write operation */
1764*44704f69SBart Van Assche wr_blks = 0;
1765*44704f69SBart Van Assche clp->out_rem_count -= blocks;
1766*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->out_mutex);
1767*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
1768*44704f69SBart Van Assche } else {
1769*44704f69SBart Van Assche normal_out_wr(rep, blocks);
1770*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->out_mutex);
1771*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
1772*44704f69SBart Van Assche ++rep->rep_count;
1773*44704f69SBart Van Assche }
1774*44704f69SBart Van Assche pthread_cleanup_pop(0);
1775*44704f69SBart Van Assche
1776*44704f69SBart Van Assche /* Output to OFILE2 if sg device */
1777*44704f69SBart Van Assche if ((clp->out2fd >= 0) && (FT_SG == clp->out2_type)) {
1778*44704f69SBart Van Assche pthread_cleanup_push(cleanup_out, (void *)clp);
1779*44704f69SBart Van Assche status = pthread_mutex_lock(&clp->out2_mutex);
1780*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock out2_mutex");
1781*44704f69SBart Van Assche /* releases out2_mutex mid operation */
1782*44704f69SBart Van Assche sg_out_wr_cmd(rep, deferred_arr, true, false);
1783*44704f69SBart Van Assche
1784*44704f69SBart Van Assche pthread_cleanup_pop(0);
1785*44704f69SBart Van Assche }
1786*44704f69SBart Van Assche if (0 == rep->num_blks) {
1787*44704f69SBart Van Assche if ((clp->nmrqs > 0) && (deferred_arr.first.size() > 0)) {
1788*44704f69SBart Van Assche if (wr_blks > 0)
1789*44704f69SBart Van Assche rep->out_mrq_q_blks += wr_blks;
1790*44704f69SBart Van Assche if (vb > 2)
1791*44704f69SBart Van Assche pr2serr_lk("thread=%d: tail-end, to_do=%u\n", rep->id,
1792*44704f69SBart Van Assche (uint32_t)deferred_arr.first.size());
1793*44704f69SBart Van Assche res = sgh_do_deferred_mrq(rep, deferred_arr);
1794*44704f69SBart Van Assche if (res)
1795*44704f69SBart Van Assche pr2serr_lk("%s tid=%d: sgh_do_deferred_mrq failed\n",
1796*44704f69SBart Van Assche __func__, rep->id);
1797*44704f69SBart Van Assche }
1798*44704f69SBart Van Assche clp->out_stop = true;
1799*44704f69SBart Van Assche stop_after_write = true;
1800*44704f69SBart Van Assche break; /* read nothing so leave loop >>>>>>>>>> */
1801*44704f69SBart Van Assche }
1802*44704f69SBart Van Assche // if ((! rep->has_share) && (FT_DEV_NULL != clp->out_type))
1803*44704f69SBart Van Assche pthread_cond_broadcast(&clp->out_sync_cv);
1804*44704f69SBart Van Assche if (stop_after_write)
1805*44704f69SBart Van Assche break; /* leaving main loop >>>>>>>>> */
1806*44704f69SBart Van Assche } /* ^^^^^^^^^^ end of main while loop which copies segments ^^^^^^ */
1807*44704f69SBart Van Assche
1808*44704f69SBart Van Assche status = pthread_mutex_lock(&clp->in_mutex);
1809*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock in_mutex");
1810*44704f69SBart Van Assche if (! clp->in_stop.load())
1811*44704f69SBart Van Assche clp->in_stop = true; /* flag other workers to stop */
1812*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->in_mutex);
1813*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock in_mutex");
1814*44704f69SBart Van Assche
1815*44704f69SBart Van Assche fini:
1816*44704f69SBart Van Assche if ((1 == rep->mmap_active) && (rep->mmap_len > 0)) {
1817*44704f69SBart Van Assche if (munmap(rep->buffp, rep->mmap_len) < 0) {
1818*44704f69SBart Van Assche err = errno;
1819*44704f69SBart Van Assche char bb[STRERR_BUFF_LEN + 1];
1820*44704f69SBart Van Assche
1821*44704f69SBart Van Assche pr2serr_lk("thread=%d: munmap() failed: %s\n", rep->id,
1822*44704f69SBart Van Assche tsafe_strerror(err, bb));
1823*44704f69SBart Van Assche }
1824*44704f69SBart Van Assche if (vb > 4)
1825*44704f69SBart Van Assche pr2serr_lk("thread=%d: munmap(%p, %d)\n", rep->id, rep->buffp,
1826*44704f69SBart Van Assche rep->mmap_len);
1827*44704f69SBart Van Assche rep->mmap_active = 0;
1828*44704f69SBart Van Assche }
1829*44704f69SBart Van Assche if (rep->alloc_bp) {
1830*44704f69SBart Van Assche free(rep->alloc_bp);
1831*44704f69SBart Van Assche rep->alloc_bp = NULL;
1832*44704f69SBart Van Assche rep->buffp = NULL;
1833*44704f69SBart Van Assche }
1834*44704f69SBart Van Assche
1835*44704f69SBart Van Assche if (sg_version_ge_40045) {
1836*44704f69SBart Van Assche if (clp->noshare) {
1837*44704f69SBart Van Assche if ((clp->nmrqs > 0) && clp->unshare)
1838*44704f69SBart Van Assche sg_unshare(rep->infd, rep->id, vb > 9);
1839*44704f69SBart Van Assche } else if (in_is_sg && out_is_sg)
1840*44704f69SBart Van Assche if (clp->unshare)
1841*44704f69SBart Van Assche sg_unshare(rep->infd, rep->id, vb > 9);
1842*44704f69SBart Van Assche }
1843*44704f69SBart Van Assche if (own_infd && (rep->infd >= 0)) {
1844*44704f69SBart Van Assche if (vb && in_is_sg) {
1845*44704f69SBart Van Assche ++num_waiting_calls;
1846*44704f69SBart Van Assche if (ioctl(rep->infd, SG_GET_NUM_WAITING, &n) >= 0) {
1847*44704f69SBart Van Assche if (n > 0)
1848*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: num_waiting=%d prior close(in)\n",
1849*44704f69SBart Van Assche __func__, rep->id, n);
1850*44704f69SBart Van Assche } else {
1851*44704f69SBart Van Assche err = errno;
1852*44704f69SBart Van Assche pr2serr_lk("%s: [%d] ioctl(SG_GET_NUM_WAITING) errno=%d: "
1853*44704f69SBart Van Assche "%s\n", __func__, rep->id, err, strerror(err));
1854*44704f69SBart Van Assche }
1855*44704f69SBart Van Assche }
1856*44704f69SBart Van Assche close(rep->infd);
1857*44704f69SBart Van Assche }
1858*44704f69SBart Van Assche if (own_outfd && (rep->outfd >= 0)) {
1859*44704f69SBart Van Assche if (vb && out_is_sg) {
1860*44704f69SBart Van Assche ++num_waiting_calls;
1861*44704f69SBart Van Assche if (ioctl(rep->outfd, SG_GET_NUM_WAITING, &n) >= 0) {
1862*44704f69SBart Van Assche if (n > 0)
1863*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: num_waiting=%d prior "
1864*44704f69SBart Van Assche "close(out)\n", __func__, rep->id, n);
1865*44704f69SBart Van Assche } else {
1866*44704f69SBart Van Assche err = errno;
1867*44704f69SBart Van Assche pr2serr_lk("%s: [%d] ioctl(SG_GET_NUM_WAITING) errno=%d: "
1868*44704f69SBart Van Assche "%s\n", __func__, rep->id, err, strerror(err));
1869*44704f69SBart Van Assche }
1870*44704f69SBart Van Assche }
1871*44704f69SBart Van Assche close(rep->outfd);
1872*44704f69SBart Van Assche }
1873*44704f69SBart Van Assche if (own_out2fd && (rep->out2fd >= 0))
1874*44704f69SBart Van Assche close(rep->out2fd);
1875*44704f69SBart Van Assche pthread_cond_broadcast(&clp->out_sync_cv);
1876*44704f69SBart Van Assche return stop_after_write ? NULL : clp;
1877*44704f69SBart Van Assche }
1878*44704f69SBart Van Assche
1879*44704f69SBart Van Assche /* N.B. A return of true means it wants to stop the copy. So false is the
1880*44704f69SBart Van Assche * 'good' reply (i.e. keep going). */
1881*44704f69SBart Van Assche static bool
normal_in_rd(Rq_elem * rep,int blocks)1882*44704f69SBart Van Assche normal_in_rd(Rq_elem * rep, int blocks)
1883*44704f69SBart Van Assche {
1884*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
1885*44704f69SBart Van Assche bool stop_after_write = false;
1886*44704f69SBart Van Assche bool same_fds = clp->in_flags.same_fds || clp->out_flags.same_fds;
1887*44704f69SBart Van Assche int res;
1888*44704f69SBart Van Assche
1889*44704f69SBart Van Assche if (clp->verbose > 4)
1890*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: iblk=%" PRIu64 ", blocks=%d\n", __func__,
1891*44704f69SBart Van Assche rep->id, rep->iblk, blocks);
1892*44704f69SBart Van Assche if (FT_RANDOM_0_FF == clp->in_type) {
1893*44704f69SBart Van Assche int k, j;
1894*44704f69SBart Van Assche const int jbump = sizeof(uint32_t);
1895*44704f69SBart Van Assche long rn;
1896*44704f69SBart Van Assche uint8_t * bp;
1897*44704f69SBart Van Assche
1898*44704f69SBart Van Assche if (clp->in_flags.zero && clp->in_flags.ff && (rep->bs >= 4)) {
1899*44704f69SBart Van Assche uint32_t pos = (uint32_t)rep->iblk;
1900*44704f69SBart Van Assche uint32_t off;
1901*44704f69SBart Van Assche
1902*44704f69SBart Van Assche for (k = 0, off = 0; k < blocks; ++k, off += rep->bs, ++pos) {
1903*44704f69SBart Van Assche for (j = 0; j < (rep->bs - 3); j += 4)
1904*44704f69SBart Van Assche sg_put_unaligned_be32(pos, rep->buffp + off + j);
1905*44704f69SBart Van Assche }
1906*44704f69SBart Van Assche } else if (clp->in_flags.zero)
1907*44704f69SBart Van Assche memset(rep->buffp, 0, blocks * rep->bs);
1908*44704f69SBart Van Assche else if (clp->in_flags.ff)
1909*44704f69SBart Van Assche memset(rep->buffp, 0xff, blocks * rep->bs);
1910*44704f69SBart Van Assche else {
1911*44704f69SBart Van Assche for (k = 0, bp = rep->buffp; k < blocks; ++k, bp += rep->bs) {
1912*44704f69SBart Van Assche for (j = 0; j < rep->bs; j += jbump) {
1913*44704f69SBart Van Assche /* mrand48 takes uniformly from [-2^31, 2^31) */
1914*44704f69SBart Van Assche #ifdef HAVE_SRAND48_R
1915*44704f69SBart Van Assche mrand48_r(&rep->drand, &rn);
1916*44704f69SBart Van Assche #else
1917*44704f69SBart Van Assche rn = mrand48();
1918*44704f69SBart Van Assche #endif
1919*44704f69SBart Van Assche *((uint32_t *)(bp + j)) = (uint32_t)rn;
1920*44704f69SBart Van Assche }
1921*44704f69SBart Van Assche }
1922*44704f69SBart Van Assche }
1923*44704f69SBart Van Assche clp->in_rem_count -= blocks;
1924*44704f69SBart Van Assche return stop_after_write;
1925*44704f69SBart Van Assche }
1926*44704f69SBart Van Assche if (! same_fds) { /* each has own file pointer, so we need to move it */
1927*44704f69SBart Van Assche int64_t pos = rep->iblk * rep->bs;
1928*44704f69SBart Van Assche
1929*44704f69SBart Van Assche if (lseek64(rep->infd, pos, SEEK_SET) < 0) { /* problem if pipe! */
1930*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: >> lseek64(%" PRId64 "): %s\n", __func__,
1931*44704f69SBart Van Assche rep->id, pos, safe_strerror(errno));
1932*44704f69SBart Van Assche stop_both(clp);
1933*44704f69SBart Van Assche return true;
1934*44704f69SBart Van Assche }
1935*44704f69SBart Van Assche }
1936*44704f69SBart Van Assche /* enters holding in_mutex */
1937*44704f69SBart Van Assche while (((res = read(clp->infd, rep->buffp, blocks * rep->bs)) < 0) &&
1938*44704f69SBart Van Assche ((EINTR == errno) || (EAGAIN == errno)))
1939*44704f69SBart Van Assche std::this_thread::yield();/* another thread may be able to progress */
1940*44704f69SBart Van Assche if (res < 0) {
1941*44704f69SBart Van Assche char strerr_buff[STRERR_BUFF_LEN + 1];
1942*44704f69SBart Van Assche
1943*44704f69SBart Van Assche if (clp->in_flags.coe) {
1944*44704f69SBart Van Assche memset(rep->buffp, 0, rep->num_blks * rep->bs);
1945*44704f69SBart Van Assche pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64
1946*44704f69SBart Van Assche " for %d bytes, %s\n", rep->id, rep->iblk,
1947*44704f69SBart Van Assche rep->num_blks * rep->bs,
1948*44704f69SBart Van Assche tsafe_strerror(errno, strerr_buff));
1949*44704f69SBart Van Assche res = rep->num_blks * rep->bs;
1950*44704f69SBart Van Assche }
1951*44704f69SBart Van Assche else {
1952*44704f69SBart Van Assche pr2serr_lk("tid=%d: error in normal read, %s\n", rep->id,
1953*44704f69SBart Van Assche tsafe_strerror(errno, strerr_buff));
1954*44704f69SBart Van Assche stop_both(clp);
1955*44704f69SBart Van Assche return true;
1956*44704f69SBart Van Assche }
1957*44704f69SBart Van Assche }
1958*44704f69SBart Van Assche if (res < blocks * rep->bs) {
1959*44704f69SBart Van Assche // int o_blocks = blocks;
1960*44704f69SBart Van Assche
1961*44704f69SBart Van Assche stop_after_write = true;
1962*44704f69SBart Van Assche blocks = res / rep->bs;
1963*44704f69SBart Van Assche if ((res % rep->bs) > 0) {
1964*44704f69SBart Van Assche blocks++;
1965*44704f69SBart Van Assche clp->in_partial++;
1966*44704f69SBart Van Assche }
1967*44704f69SBart Van Assche /* Reverse out + re-apply blocks on clp */
1968*44704f69SBart Van Assche // clp->in_blk -= o_blocks;
1969*44704f69SBart Van Assche // clp->in_count += o_blocks;
1970*44704f69SBart Van Assche rep->num_blks = blocks;
1971*44704f69SBart Van Assche // clp->in_blk += blocks;
1972*44704f69SBart Van Assche // clp->in_count -= blocks;
1973*44704f69SBart Van Assche }
1974*44704f69SBart Van Assche clp->in_rem_count -= blocks;
1975*44704f69SBart Van Assche return stop_after_write;
1976*44704f69SBart Van Assche }
1977*44704f69SBart Van Assche
1978*44704f69SBart Van Assche static void
normal_out_wr(Rq_elem * rep,int blocks)1979*44704f69SBart Van Assche normal_out_wr(Rq_elem * rep, int blocks)
1980*44704f69SBart Van Assche {
1981*44704f69SBart Van Assche int res;
1982*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
1983*44704f69SBart Van Assche
1984*44704f69SBart Van Assche /* enters holding out_mutex */
1985*44704f69SBart Van Assche if (clp->verbose > 4)
1986*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: oblk=%" PRIu64 ", blocks=%d\n", __func__,
1987*44704f69SBart Van Assche rep->id, rep->oblk, blocks);
1988*44704f69SBart Van Assche while (((res = write(clp->outfd, rep->buffp, blocks * rep->bs))
1989*44704f69SBart Van Assche < 0) && ((EINTR == errno) || (EAGAIN == errno)))
1990*44704f69SBart Van Assche std::this_thread::yield();/* another thread may be able to progress */
1991*44704f69SBart Van Assche if (res < 0) {
1992*44704f69SBart Van Assche char strerr_buff[STRERR_BUFF_LEN + 1];
1993*44704f69SBart Van Assche
1994*44704f69SBart Van Assche if (clp->out_flags.coe) {
1995*44704f69SBart Van Assche pr2serr_lk("tid=%d: >> ignored error for out blk=%" PRId64
1996*44704f69SBart Van Assche " for %d bytes, %s\n", rep->id, rep->oblk,
1997*44704f69SBart Van Assche rep->num_blks * rep->bs,
1998*44704f69SBart Van Assche tsafe_strerror(errno, strerr_buff));
1999*44704f69SBart Van Assche res = rep->num_blks * rep->bs;
2000*44704f69SBart Van Assche }
2001*44704f69SBart Van Assche else {
2002*44704f69SBart Van Assche pr2serr_lk("tid=%d: error normal write, %s\n", rep->id,
2003*44704f69SBart Van Assche tsafe_strerror(errno, strerr_buff));
2004*44704f69SBart Van Assche stop_both(clp);
2005*44704f69SBart Van Assche return;
2006*44704f69SBart Van Assche }
2007*44704f69SBart Van Assche }
2008*44704f69SBart Van Assche if (res < blocks * rep->bs) {
2009*44704f69SBart Van Assche blocks = res / rep->bs;
2010*44704f69SBart Van Assche if ((res % rep->bs) > 0) {
2011*44704f69SBart Van Assche blocks++;
2012*44704f69SBart Van Assche clp->out_partial++;
2013*44704f69SBart Van Assche }
2014*44704f69SBart Van Assche rep->num_blks = blocks;
2015*44704f69SBart Van Assche }
2016*44704f69SBart Van Assche clp->out_rem_count -= blocks;
2017*44704f69SBart Van Assche }
2018*44704f69SBart Van Assche
2019*44704f69SBart Van Assche static int
sg_build_scsi_cdb(uint8_t * cdbp,int cdb_sz,unsigned int blocks,int64_t start_block,bool ver_true,bool write_true,bool fua,bool dpo)2020*44704f69SBart Van Assche sg_build_scsi_cdb(uint8_t * cdbp, int cdb_sz, unsigned int blocks,
2021*44704f69SBart Van Assche int64_t start_block, bool ver_true, bool write_true,
2022*44704f69SBart Van Assche bool fua, bool dpo)
2023*44704f69SBart Van Assche {
2024*44704f69SBart Van Assche int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
2025*44704f69SBart Van Assche int ve_opcode[] = {0xff /* no VER(6) */, 0x2f, 0xaf, 0x8f};
2026*44704f69SBart Van Assche int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a};
2027*44704f69SBart Van Assche int sz_ind;
2028*44704f69SBart Van Assche
2029*44704f69SBart Van Assche memset(cdbp, 0, cdb_sz);
2030*44704f69SBart Van Assche if (ver_true) { /* only support VERIFY(10) */
2031*44704f69SBart Van Assche if (cdb_sz < 10) {
2032*44704f69SBart Van Assche pr2serr_lk("%sonly support VERIFY(10)\n", my_name);
2033*44704f69SBart Van Assche return 1;
2034*44704f69SBart Van Assche }
2035*44704f69SBart Van Assche cdb_sz = 10;
2036*44704f69SBart Van Assche fua = false;
2037*44704f69SBart Van Assche cdbp[1] |= 0x2; /* BYTCHK=1 --> sending dout for comparison */
2038*44704f69SBart Van Assche cdbp[0] = ve_opcode[1];
2039*44704f69SBart Van Assche }
2040*44704f69SBart Van Assche if (dpo)
2041*44704f69SBart Van Assche cdbp[1] |= 0x10;
2042*44704f69SBart Van Assche if (fua)
2043*44704f69SBart Van Assche cdbp[1] |= 0x8;
2044*44704f69SBart Van Assche switch (cdb_sz) {
2045*44704f69SBart Van Assche case 6:
2046*44704f69SBart Van Assche sz_ind = 0;
2047*44704f69SBart Van Assche cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] :
2048*44704f69SBart Van Assche rd_opcode[sz_ind]);
2049*44704f69SBart Van Assche sg_put_unaligned_be24(0x1fffff & start_block, cdbp + 1);
2050*44704f69SBart Van Assche cdbp[4] = (256 == blocks) ? 0 : (uint8_t)blocks;
2051*44704f69SBart Van Assche if (blocks > 256) {
2052*44704f69SBart Van Assche pr2serr_lk("%sfor 6 byte commands, maximum number of blocks is "
2053*44704f69SBart Van Assche "256\n", my_name);
2054*44704f69SBart Van Assche return 1;
2055*44704f69SBart Van Assche }
2056*44704f69SBart Van Assche if ((start_block + blocks - 1) & (~0x1fffff)) {
2057*44704f69SBart Van Assche pr2serr_lk("%sfor 6 byte commands, can't address blocks beyond "
2058*44704f69SBart Van Assche "%d\n", my_name, 0x1fffff);
2059*44704f69SBart Van Assche return 1;
2060*44704f69SBart Van Assche }
2061*44704f69SBart Van Assche if (dpo || fua) {
2062*44704f69SBart Van Assche pr2serr_lk("%sfor 6 byte commands, neither dpo nor fua bits "
2063*44704f69SBart Van Assche "supported\n", my_name);
2064*44704f69SBart Van Assche return 1;
2065*44704f69SBart Van Assche }
2066*44704f69SBart Van Assche break;
2067*44704f69SBart Van Assche case 10:
2068*44704f69SBart Van Assche if (! ver_true) {
2069*44704f69SBart Van Assche sz_ind = 1;
2070*44704f69SBart Van Assche cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] :
2071*44704f69SBart Van Assche rd_opcode[sz_ind]);
2072*44704f69SBart Van Assche }
2073*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2);
2074*44704f69SBart Van Assche sg_put_unaligned_be16((uint16_t)blocks, cdbp + 7);
2075*44704f69SBart Van Assche if (blocks & (~0xffff)) {
2076*44704f69SBart Van Assche pr2serr_lk("%sfor 10 byte commands, maximum number of blocks is "
2077*44704f69SBart Van Assche "%d\n", my_name, 0xffff);
2078*44704f69SBart Van Assche return 1;
2079*44704f69SBart Van Assche }
2080*44704f69SBart Van Assche break;
2081*44704f69SBart Van Assche case 12:
2082*44704f69SBart Van Assche sz_ind = 2;
2083*44704f69SBart Van Assche cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] :
2084*44704f69SBart Van Assche rd_opcode[sz_ind]);
2085*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)start_block, cdbp + 2);
2086*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)blocks, cdbp + 6);
2087*44704f69SBart Van Assche break;
2088*44704f69SBart Van Assche case 16:
2089*44704f69SBart Van Assche sz_ind = 3;
2090*44704f69SBart Van Assche cdbp[0] = (uint8_t)(write_true ? wr_opcode[sz_ind] :
2091*44704f69SBart Van Assche rd_opcode[sz_ind]);
2092*44704f69SBart Van Assche sg_put_unaligned_be64((uint64_t)start_block, cdbp + 2);
2093*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)blocks, cdbp + 10);
2094*44704f69SBart Van Assche break;
2095*44704f69SBart Van Assche default:
2096*44704f69SBart Van Assche pr2serr_lk("%sexpected cdb size of 6, 10, 12, or 16 but got %d\n",
2097*44704f69SBart Van Assche my_name, cdb_sz);
2098*44704f69SBart Van Assche return 1;
2099*44704f69SBart Van Assche }
2100*44704f69SBart Van Assche return 0;
2101*44704f69SBart Van Assche }
2102*44704f69SBart Van Assche
2103*44704f69SBart Van Assche /* Enters this function holding in_mutex */
2104*44704f69SBart Van Assche static void
sg_in_rd_cmd(struct global_collection * clp,Rq_elem * rep,mrq_arr_t & def_arr)2105*44704f69SBart Van Assche sg_in_rd_cmd(struct global_collection * clp, Rq_elem * rep,
2106*44704f69SBart Van Assche mrq_arr_t & def_arr)
2107*44704f69SBart Van Assche {
2108*44704f69SBart Van Assche int status, pack_id;
2109*44704f69SBart Van Assche
2110*44704f69SBart Van Assche while (1) {
2111*44704f69SBart Van Assche int res = sg_start_io(rep, def_arr, pack_id, NULL);
2112*44704f69SBart Van Assche
2113*44704f69SBart Van Assche if (1 == res)
2114*44704f69SBart Van Assche err_exit(ENOMEM, "sg starting in command");
2115*44704f69SBart Van Assche else if (res < 0) {
2116*44704f69SBart Van Assche pr2serr_lk("tid=%d: inputting to sg failed, blk=%" PRId64 "\n",
2117*44704f69SBart Van Assche rep->id, rep->iblk);
2118*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->in_mutex);
2119*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock in_mutex");
2120*44704f69SBart Van Assche stop_both(clp);
2121*44704f69SBart Van Assche return;
2122*44704f69SBart Van Assche }
2123*44704f69SBart Van Assche /* Now release in mutex to let other reads run in parallel */
2124*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->in_mutex);
2125*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock in_mutex");
2126*44704f69SBart Van Assche
2127*44704f69SBart Van Assche res = sg_finish_io(rep->wr, rep, pack_id, NULL);
2128*44704f69SBart Van Assche switch (res) {
2129*44704f69SBart Van Assche case SG_LIB_CAT_ABORTED_COMMAND:
2130*44704f69SBart Van Assche case SG_LIB_CAT_UNIT_ATTENTION:
2131*44704f69SBart Van Assche /* try again with same addr, count info */
2132*44704f69SBart Van Assche /* now re-acquire in mutex for balance */
2133*44704f69SBart Van Assche /* N.B. This re-read could now be out of read sequence */
2134*44704f69SBart Van Assche status = pthread_mutex_lock(&clp->in_mutex);
2135*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock in_mutex");
2136*44704f69SBart Van Assche break; /* will loop again */
2137*44704f69SBart Van Assche case SG_LIB_CAT_MEDIUM_HARD:
2138*44704f69SBart Van Assche if (0 == clp->in_flags.coe) {
2139*44704f69SBart Van Assche pr2serr_lk("error finishing sg in command (medium)\n");
2140*44704f69SBart Van Assche if (exit_status <= 0)
2141*44704f69SBart Van Assche exit_status = res;
2142*44704f69SBart Van Assche stop_both(clp);
2143*44704f69SBart Van Assche return;
2144*44704f69SBart Van Assche } else {
2145*44704f69SBart Van Assche memset(get_buffp(rep), 0, rep->num_blks * rep->bs);
2146*44704f69SBart Van Assche pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64
2147*44704f69SBart Van Assche " for %d bytes\n", rep->id, rep->iblk,
2148*44704f69SBart Van Assche rep->num_blks * rep->bs);
2149*44704f69SBart Van Assche }
2150*44704f69SBart Van Assche #if defined(__GNUC__)
2151*44704f69SBart Van Assche #if (__GNUC__ >= 7)
2152*44704f69SBart Van Assche __attribute__((fallthrough));
2153*44704f69SBart Van Assche /* FALL THROUGH */
2154*44704f69SBart Van Assche #endif
2155*44704f69SBart Van Assche #endif
2156*44704f69SBart Van Assche case 0:
2157*44704f69SBart Van Assche status = pthread_mutex_lock(&clp->in_mutex);
2158*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock in_mutex");
2159*44704f69SBart Van Assche if (rep->dio_incomplete_count || rep->resid) {
2160*44704f69SBart Van Assche clp->dio_incomplete_count += rep->dio_incomplete_count;
2161*44704f69SBart Van Assche clp->sum_of_resids += rep->resid;
2162*44704f69SBart Van Assche }
2163*44704f69SBart Van Assche clp->in_rem_count -= rep->num_blks;
2164*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->in_mutex);
2165*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock in_mutex");
2166*44704f69SBart Van Assche return;
2167*44704f69SBart Van Assche default:
2168*44704f69SBart Van Assche pr2serr_lk("tid=%d: error finishing sg in command (%d)\n",
2169*44704f69SBart Van Assche rep->id, res);
2170*44704f69SBart Van Assche if (exit_status <= 0)
2171*44704f69SBart Van Assche exit_status = res;
2172*44704f69SBart Van Assche stop_both(clp);
2173*44704f69SBart Van Assche return;
2174*44704f69SBart Van Assche }
2175*44704f69SBart Van Assche } /* end of while (1) loop */
2176*44704f69SBart Van Assche }
2177*44704f69SBart Van Assche
2178*44704f69SBart Van Assche static bool
sg_wr_swap_share(Rq_elem * rep,int to_fd,bool before)2179*44704f69SBart Van Assche sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before)
2180*44704f69SBart Van Assche {
2181*44704f69SBart Van Assche bool not_first = false;
2182*44704f69SBart Van Assche int err = 0;
2183*44704f69SBart Van Assche int k;
2184*44704f69SBart Van Assche int read_side_fd = rep->infd;
2185*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
2186*44704f69SBart Van Assche struct sg_extended_info sei {};
2187*44704f69SBart Van Assche struct sg_extended_info * seip = &sei;
2188*44704f69SBart Van Assche
2189*44704f69SBart Van Assche if (rep->clp->verbose > 2)
2190*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: to_fd=%d, before=%d\n", __func__, rep->id,
2191*44704f69SBart Van Assche to_fd, (int)before);
2192*44704f69SBart Van Assche seip->sei_wr_mask |= SG_SEIM_CHG_SHARE_FD;
2193*44704f69SBart Van Assche seip->sei_rd_mask |= SG_SEIM_CHG_SHARE_FD;
2194*44704f69SBart Van Assche seip->share_fd = to_fd;
2195*44704f69SBart Van Assche if (before) {
2196*44704f69SBart Van Assche /* clear READ_SIDE_FINI bit: puts read-side in SG_RQ_SHR_SWAP state */
2197*44704f69SBart Van Assche seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
2198*44704f69SBart Van Assche seip->sei_rd_mask |= SG_SEIM_CTL_FLAGS;
2199*44704f69SBart Van Assche seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_READ_SIDE_FINI;
2200*44704f69SBart Van Assche seip->ctl_flags &= ~SG_CTL_FLAGM_READ_SIDE_FINI;/* would be 0 anyway */
2201*44704f69SBart Van Assche }
2202*44704f69SBart Van Assche for (k = 0; (ioctl(read_side_fd, SG_SET_GET_EXTENDED, seip) < 0) &&
2203*44704f69SBart Van Assche (EBUSY == errno); ++k) {
2204*44704f69SBart Van Assche err = errno;
2205*44704f69SBart Van Assche if (k > 10000)
2206*44704f69SBart Van Assche break;
2207*44704f69SBart Van Assche if (! not_first) {
2208*44704f69SBart Van Assche if (clp->verbose > 3)
2209*44704f69SBart Van Assche pr2serr_lk("tid=%d: ioctl(EXTENDED(change_shared_fd=%d), "
2210*44704f69SBart Van Assche "failed errno=%d %s\n", rep->id, read_side_fd, err,
2211*44704f69SBart Van Assche strerror(err));
2212*44704f69SBart Van Assche not_first = true;
2213*44704f69SBart Van Assche }
2214*44704f69SBart Van Assche err = 0;
2215*44704f69SBart Van Assche std::this_thread::yield();/* another thread may be able to progress */
2216*44704f69SBart Van Assche }
2217*44704f69SBart Van Assche if (err) {
2218*44704f69SBart Van Assche pr2serr_lk("tid=%d: ioctl(EXTENDED(change_shared_fd=%d), failed "
2219*44704f69SBart Van Assche "errno=%d %s\n", rep->id, read_side_fd, err, strerror(err));
2220*44704f69SBart Van Assche return false;
2221*44704f69SBart Van Assche }
2222*44704f69SBart Van Assche if (clp->verbose > 15)
2223*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: ioctl(EXTENDED(change_shared_fd)) ok, "
2224*44704f69SBart Van Assche "read_side_fd=%d, to_write_side_fd=%d\n", __func__, rep->id,
2225*44704f69SBart Van Assche read_side_fd, to_fd);
2226*44704f69SBart Van Assche return true;
2227*44704f69SBart Van Assche }
2228*44704f69SBart Van Assche
2229*44704f69SBart Van Assche /* Enters this function holding out_mutex */
2230*44704f69SBart Van Assche static void
sg_out_wr_cmd(Rq_elem * rep,mrq_arr_t & def_arr,bool is_wr2,bool prefetch)2231*44704f69SBart Van Assche sg_out_wr_cmd(Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2, bool prefetch)
2232*44704f69SBart Van Assche {
2233*44704f69SBart Van Assche int res, status, pack_id, nblks;
2234*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
2235*44704f69SBart Van Assche uint32_t ofsplit = clp->ofsplit;
2236*44704f69SBart Van Assche pthread_mutex_t * mutexp = is_wr2 ? &clp->out2_mutex : &clp->out_mutex;
2237*44704f69SBart Van Assche struct sg_io_extra xtr {};
2238*44704f69SBart Van Assche struct sg_io_extra * xtrp = &xtr;
2239*44704f69SBart Van Assche const char * wr_or_ver = clp->verify ? "verify" : "out";
2240*44704f69SBart Van Assche
2241*44704f69SBart Van Assche xtrp->is_wr2 = is_wr2;
2242*44704f69SBart Van Assche xtrp->prefetch = prefetch;
2243*44704f69SBart Van Assche nblks = rep->num_blks;
2244*44704f69SBart Van Assche if (rep->has_share && is_wr2)
2245*44704f69SBart Van Assche sg_wr_swap_share(rep, rep->out2fd, true);
2246*44704f69SBart Van Assche
2247*44704f69SBart Van Assche if (prefetch) {
2248*44704f69SBart Van Assche again:
2249*44704f69SBart Van Assche res = sg_start_io(rep, def_arr, pack_id, xtrp);
2250*44704f69SBart Van Assche if (1 == res)
2251*44704f69SBart Van Assche err_exit(ENOMEM, "sg starting out command");
2252*44704f69SBart Van Assche else if (res < 0) {
2253*44704f69SBart Van Assche pr2serr_lk("%ssg %s failed, blk=%" PRId64 "\n",
2254*44704f69SBart Van Assche my_name, wr_or_ver, rep->oblk);
2255*44704f69SBart Van Assche status = pthread_mutex_unlock(mutexp);
2256*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
2257*44704f69SBart Van Assche stop_both(clp);
2258*44704f69SBart Van Assche goto fini;
2259*44704f69SBart Van Assche }
2260*44704f69SBart Van Assche /* Now release in mutex to let other reads run in parallel */
2261*44704f69SBart Van Assche status = pthread_mutex_unlock(mutexp);
2262*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
2263*44704f69SBart Van Assche
2264*44704f69SBart Van Assche res = sg_finish_io(rep->wr, rep, pack_id, xtrp);
2265*44704f69SBart Van Assche switch (res) {
2266*44704f69SBart Van Assche case SG_LIB_CAT_ABORTED_COMMAND:
2267*44704f69SBart Van Assche case SG_LIB_CAT_UNIT_ATTENTION:
2268*44704f69SBart Van Assche /* try again with same addr, count info */
2269*44704f69SBart Van Assche /* now re-acquire out mutex for balance */
2270*44704f69SBart Van Assche /* N.B. This re-write could now be out of write sequence */
2271*44704f69SBart Van Assche status = pthread_mutex_lock(mutexp);
2272*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock out_mutex");
2273*44704f69SBart Van Assche goto again;
2274*44704f69SBart Van Assche case SG_LIB_CAT_CONDITION_MET:
2275*44704f69SBart Van Assche case 0:
2276*44704f69SBart Van Assche status = pthread_mutex_lock(mutexp);
2277*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
2278*44704f69SBart Van Assche break;
2279*44704f69SBart Van Assche default:
2280*44704f69SBart Van Assche pr2serr_lk("error finishing sg prefetch command (%d)\n", res);
2281*44704f69SBart Van Assche if (exit_status <= 0)
2282*44704f69SBart Van Assche exit_status = res;
2283*44704f69SBart Van Assche stop_both(clp);
2284*44704f69SBart Van Assche goto fini;
2285*44704f69SBart Van Assche }
2286*44704f69SBart Van Assche }
2287*44704f69SBart Van Assche
2288*44704f69SBart Van Assche /* start write (or verify) on current segment on sg device */
2289*44704f69SBart Van Assche xtrp->prefetch = false;
2290*44704f69SBart Van Assche if ((ofsplit > 0) && (rep->num_blks > (int)ofsplit)) {
2291*44704f69SBart Van Assche xtrp->dout_is_split = true;
2292*44704f69SBart Van Assche xtrp->blk_offset = 0;
2293*44704f69SBart Van Assche xtrp->blks = ofsplit;
2294*44704f69SBart Van Assche nblks = ofsplit;
2295*44704f69SBart Van Assche xtrp->hpv4_ind = 0;
2296*44704f69SBart Van Assche }
2297*44704f69SBart Van Assche split_upper:
2298*44704f69SBart Van Assche while (1) {
2299*44704f69SBart Van Assche res = sg_start_io(rep, def_arr, pack_id, xtrp);
2300*44704f69SBart Van Assche if (1 == res)
2301*44704f69SBart Van Assche err_exit(ENOMEM, "sg starting out command");
2302*44704f69SBart Van Assche else if (res < 0) {
2303*44704f69SBart Van Assche pr2serr_lk("%ssg %s failed, blk=%" PRId64 "\n", my_name,
2304*44704f69SBart Van Assche wr_or_ver, rep->oblk);
2305*44704f69SBart Van Assche status = pthread_mutex_unlock(mutexp);
2306*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
2307*44704f69SBart Van Assche stop_both(clp);
2308*44704f69SBart Van Assche goto fini;
2309*44704f69SBart Van Assche }
2310*44704f69SBart Van Assche /* Now release in mutex to let other reads run in parallel */
2311*44704f69SBart Van Assche status = pthread_mutex_unlock(mutexp);
2312*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
2313*44704f69SBart Van Assche
2314*44704f69SBart Van Assche res = sg_finish_io(rep->wr, rep, pack_id, xtrp);
2315*44704f69SBart Van Assche switch (res) {
2316*44704f69SBart Van Assche case SG_LIB_CAT_ABORTED_COMMAND:
2317*44704f69SBart Van Assche case SG_LIB_CAT_UNIT_ATTENTION:
2318*44704f69SBart Van Assche /* try again with same addr, count info */
2319*44704f69SBart Van Assche /* now re-acquire out mutex for balance */
2320*44704f69SBart Van Assche /* N.B. This re-write could now be out of write sequence */
2321*44704f69SBart Van Assche status = pthread_mutex_lock(mutexp);
2322*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock out_mutex");
2323*44704f69SBart Van Assche break; /* loops around */
2324*44704f69SBart Van Assche case SG_LIB_CAT_MEDIUM_HARD:
2325*44704f69SBart Van Assche if (0 == clp->out_flags.coe) {
2326*44704f69SBart Van Assche pr2serr_lk("error finishing sg %s command (medium)\n",
2327*44704f69SBart Van Assche wr_or_ver);
2328*44704f69SBart Van Assche if (exit_status <= 0)
2329*44704f69SBart Van Assche exit_status = res;
2330*44704f69SBart Van Assche stop_both(clp);
2331*44704f69SBart Van Assche goto fini;
2332*44704f69SBart Van Assche } else
2333*44704f69SBart Van Assche pr2serr_lk(">> ignored error for %s blk=%" PRId64 " for %d "
2334*44704f69SBart Van Assche "bytes\n", wr_or_ver, rep->oblk, nblks * rep->bs);
2335*44704f69SBart Van Assche #if defined(__GNUC__)
2336*44704f69SBart Van Assche #if (__GNUC__ >= 7)
2337*44704f69SBart Van Assche __attribute__((fallthrough));
2338*44704f69SBart Van Assche /* FALL THROUGH */
2339*44704f69SBart Van Assche #endif
2340*44704f69SBart Van Assche #endif
2341*44704f69SBart Van Assche case SG_LIB_CAT_CONDITION_MET:
2342*44704f69SBart Van Assche case 0:
2343*44704f69SBart Van Assche if (! is_wr2) {
2344*44704f69SBart Van Assche status = pthread_mutex_lock(mutexp);
2345*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock out_mutex");
2346*44704f69SBart Van Assche if (rep->dio_incomplete_count || rep->resid) {
2347*44704f69SBart Van Assche clp->dio_incomplete_count += rep->dio_incomplete_count;
2348*44704f69SBart Van Assche clp->sum_of_resids += rep->resid;
2349*44704f69SBart Van Assche }
2350*44704f69SBart Van Assche clp->out_rem_count -= nblks;
2351*44704f69SBart Van Assche status = pthread_mutex_unlock(mutexp);
2352*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
2353*44704f69SBart Van Assche }
2354*44704f69SBart Van Assche goto fini;
2355*44704f69SBart Van Assche case SG_LIB_CAT_MISCOMPARE:
2356*44704f69SBart Van Assche ++num_miscompare;
2357*44704f69SBart Van Assche // fall through
2358*44704f69SBart Van Assche default:
2359*44704f69SBart Van Assche pr2serr_lk("error finishing sg %s command (%d)\n", wr_or_ver,
2360*44704f69SBart Van Assche res);
2361*44704f69SBart Van Assche if (exit_status <= 0)
2362*44704f69SBart Van Assche exit_status = res;
2363*44704f69SBart Van Assche stop_both(clp);
2364*44704f69SBart Van Assche goto fini;
2365*44704f69SBart Van Assche }
2366*44704f69SBart Van Assche } /* end of while (1) loop */
2367*44704f69SBart Van Assche fini:
2368*44704f69SBart Van Assche if (xtrp->dout_is_split) { /* set up upper half of split */
2369*44704f69SBart Van Assche if ((0 == xtrp->hpv4_ind) && (rep->num_blks > (int)ofsplit)) {
2370*44704f69SBart Van Assche xtrp->hpv4_ind = 1;
2371*44704f69SBart Van Assche xtrp->blk_offset = ofsplit;
2372*44704f69SBart Van Assche xtrp->blks = rep->num_blks - ofsplit;
2373*44704f69SBart Van Assche nblks = xtrp->blks;
2374*44704f69SBart Van Assche status = pthread_mutex_lock(mutexp);
2375*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock out_mutex");
2376*44704f69SBart Van Assche goto split_upper;
2377*44704f69SBart Van Assche }
2378*44704f69SBart Van Assche }
2379*44704f69SBart Van Assche if (rep->has_share && is_wr2)
2380*44704f69SBart Van Assche sg_wr_swap_share(rep, rep->outfd, false);
2381*44704f69SBart Van Assche }
2382*44704f69SBart Van Assche
2383*44704f69SBart Van Assche static int
process_mrq_response(Rq_elem * rep,const struct sg_io_v4 * ctl_v4p,const struct sg_io_v4 * a_v4p,int num_mrq,uint32_t & good_inblks,uint32_t & good_outblks)2384*44704f69SBart Van Assche process_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
2385*44704f69SBart Van Assche const struct sg_io_v4 * a_v4p, int num_mrq,
2386*44704f69SBart Van Assche uint32_t & good_inblks, uint32_t & good_outblks)
2387*44704f69SBart Van Assche {
2388*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
2389*44704f69SBart Van Assche bool ok, all_good;
2390*44704f69SBart Van Assche bool sb_in_co = !!(ctl_v4p->response);
2391*44704f69SBart Van Assche int id = rep->id;
2392*44704f69SBart Van Assche int resid = ctl_v4p->din_resid;
2393*44704f69SBart Van Assche int sres = ctl_v4p->spare_out;
2394*44704f69SBart Van Assche int n_subm = num_mrq - ctl_v4p->dout_resid;
2395*44704f69SBart Van Assche int n_cmpl = ctl_v4p->info;
2396*44704f69SBart Van Assche int n_good = 0;
2397*44704f69SBart Van Assche int hole_count = 0;
2398*44704f69SBart Van Assche int vb = clp->verbose;
2399*44704f69SBart Van Assche int k, j, f1, slen, blen;
2400*44704f69SBart Van Assche char b[160];
2401*44704f69SBart Van Assche
2402*44704f69SBart Van Assche blen = sizeof(b);
2403*44704f69SBart Van Assche good_inblks = 0;
2404*44704f69SBart Van Assche good_outblks = 0;
2405*44704f69SBart Van Assche if (vb > 2)
2406*44704f69SBart Van Assche pr2serr_lk("[thread_id=%d] %s: num_mrq=%d, n_subm=%d, n_cmpl=%d\n",
2407*44704f69SBart Van Assche id, __func__, num_mrq, n_subm, n_cmpl);
2408*44704f69SBart Van Assche if (n_subm < 0) {
2409*44704f69SBart Van Assche pr2serr_lk("[%d] co.dout_resid(%d) > num_mrq(%d)\n", id,
2410*44704f69SBart Van Assche ctl_v4p->dout_resid, num_mrq);
2411*44704f69SBart Van Assche return -1;
2412*44704f69SBart Van Assche }
2413*44704f69SBart Van Assche if (n_cmpl != (num_mrq - resid))
2414*44704f69SBart Van Assche pr2serr_lk("[%d] co.info(%d) != (num_mrq(%d) - co.din_resid(%d))\n"
2415*44704f69SBart Van Assche "will use co.info\n", id, n_cmpl, num_mrq, resid);
2416*44704f69SBart Van Assche if (n_cmpl > n_subm) {
2417*44704f69SBart Van Assche pr2serr_lk("[%d] n_cmpl(%d) > n_subm(%d), use n_subm for both\n",
2418*44704f69SBart Van Assche id, n_cmpl, n_subm);
2419*44704f69SBart Van Assche n_cmpl = n_subm;
2420*44704f69SBart Van Assche }
2421*44704f69SBart Van Assche if (sres) {
2422*44704f69SBart Van Assche pr2serr_lk("[%d] secondary error: %s [%d], info=0x%x\n", id,
2423*44704f69SBart Van Assche strerror(sres), sres, ctl_v4p->info);
2424*44704f69SBart Van Assche if (E2BIG == sres) {
2425*44704f69SBart Van Assche sg_take_snap(rep->infd, id, true);
2426*44704f69SBart Van Assche sg_take_snap(rep->outfd, id, true);
2427*44704f69SBart Van Assche }
2428*44704f69SBart Van Assche }
2429*44704f69SBart Van Assche /* Check if those submitted have finished or not. N.B. If there has been
2430*44704f69SBart Van Assche * an error then there may be "holes" (i.e. info=0x0) in the array due
2431*44704f69SBart Van Assche * to completions being out-of-order. */
2432*44704f69SBart Van Assche for (k = 0, j = 0; ((k < num_mrq) && (j < n_subm));
2433*44704f69SBart Van Assche ++k, j += f1, ++a_v4p) {
2434*44704f69SBart Van Assche slen = a_v4p->response_len;
2435*44704f69SBart Van Assche if (! (SG_INFO_MRQ_FINI & a_v4p->info))
2436*44704f69SBart Van Assche ++hole_count;
2437*44704f69SBart Van Assche ok = true;
2438*44704f69SBart Van Assche f1 = !!(a_v4p->info); /* want to skip n_subm count if info is 0x0 */
2439*44704f69SBart Van Assche if (SG_INFO_CHECK & a_v4p->info) {
2440*44704f69SBart Van Assche ok = false;
2441*44704f69SBart Van Assche pr2serr_lk("[%d] a_v4[%d]: SG_INFO_CHECK set [%s]\n", id, k,
2442*44704f69SBart Van Assche sg_info_str(a_v4p->info, sizeof(b), b));
2443*44704f69SBart Van Assche }
2444*44704f69SBart Van Assche if (sg_scsi_status_is_bad(a_v4p->device_status) ||
2445*44704f69SBart Van Assche a_v4p->transport_status || a_v4p->driver_status) {
2446*44704f69SBart Van Assche ok = false;
2447*44704f69SBart Van Assche if (SAM_STAT_CHECK_CONDITION != a_v4p->device_status) {
2448*44704f69SBart Van Assche pr2serr_lk("[%d] a_v4[%d]:\n", id, k);
2449*44704f69SBart Van Assche if (vb)
2450*44704f69SBart Van Assche lk_chk_n_print4(" >>", a_v4p, vb > 4);
2451*44704f69SBart Van Assche }
2452*44704f69SBart Van Assche }
2453*44704f69SBart Van Assche if (slen > 0) {
2454*44704f69SBart Van Assche struct sg_scsi_sense_hdr ssh;
2455*44704f69SBart Van Assche const uint8_t *sbp = (const uint8_t *)
2456*44704f69SBart Van Assche (sb_in_co ? ctl_v4p->response : a_v4p->response);
2457*44704f69SBart Van Assche
2458*44704f69SBart Van Assche if (sg_scsi_normalize_sense(sbp, slen, &ssh) &&
2459*44704f69SBart Van Assche (ssh.response_code >= 0x70)) {
2460*44704f69SBart Van Assche if (ssh.response_code & 0x1)
2461*44704f69SBart Van Assche ok = true;
2462*44704f69SBart Van Assche if (vb) {
2463*44704f69SBart Van Assche sg_get_sense_str(" ", sbp, slen, false, blen, b);
2464*44704f69SBart Van Assche pr2serr_lk("[%d] a_v4[%d]:\n%s\n", id, k, b);
2465*44704f69SBart Van Assche }
2466*44704f69SBart Van Assche }
2467*44704f69SBart Van Assche }
2468*44704f69SBart Van Assche if (ok && f1) {
2469*44704f69SBart Van Assche ++n_good;
2470*44704f69SBart Van Assche if (a_v4p->dout_xfer_len >= (uint32_t)rep->bs)
2471*44704f69SBart Van Assche good_outblks += (a_v4p->dout_xfer_len - a_v4p->dout_resid) /
2472*44704f69SBart Van Assche rep->bs;
2473*44704f69SBart Van Assche if (a_v4p->din_xfer_len >= (uint32_t)rep->bs)
2474*44704f69SBart Van Assche good_inblks += (a_v4p->din_xfer_len - a_v4p->din_resid) /
2475*44704f69SBart Van Assche rep->bs;
2476*44704f69SBart Van Assche }
2477*44704f69SBart Van Assche } /* end of request array scan loop */
2478*44704f69SBart Van Assche if ((n_subm == num_mrq) || (vb < 3))
2479*44704f69SBart Van Assche goto fini;
2480*44704f69SBart Van Assche pr2serr_lk("[%d] checking response array _beyond_ number of "
2481*44704f69SBart Van Assche "submissions [%d] to num_mrq:\n", id, k);
2482*44704f69SBart Van Assche for (all_good = true; k < num_mrq; ++k, ++a_v4p) {
2483*44704f69SBart Van Assche if (SG_INFO_MRQ_FINI & a_v4p->info) {
2484*44704f69SBart Van Assche pr2serr_lk("[%d] a_v4[%d]: unexpected SG_INFO_MRQ_FINI set [%s]\n",
2485*44704f69SBart Van Assche id, k, sg_info_str(a_v4p->info, sizeof(b), b));
2486*44704f69SBart Van Assche all_good = false;
2487*44704f69SBart Van Assche }
2488*44704f69SBart Van Assche if (a_v4p->device_status || a_v4p->transport_status ||
2489*44704f69SBart Van Assche a_v4p->driver_status) {
2490*44704f69SBart Van Assche pr2serr_lk("[%d] a_v4[%d]:\n", id, k);
2491*44704f69SBart Van Assche lk_chk_n_print4(" ", a_v4p, vb > 4);
2492*44704f69SBart Van Assche all_good = false;
2493*44704f69SBart Van Assche }
2494*44704f69SBart Van Assche }
2495*44704f69SBart Van Assche if (all_good)
2496*44704f69SBart Van Assche pr2serr_lk(" ... all good\n");
2497*44704f69SBart Van Assche fini:
2498*44704f69SBart Van Assche return n_good;
2499*44704f69SBart Van Assche }
2500*44704f69SBart Van Assche
2501*44704f69SBart Van Assche #if 0
2502*44704f69SBart Van Assche static int
2503*44704f69SBart Van Assche chk_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p,
2504*44704f69SBart Van Assche const struct sg_io_v4 * a_v4p, int nrq,
2505*44704f69SBart Van Assche uint32_t * good_inblksp, uint32_t * good_outblksp)
2506*44704f69SBart Van Assche {
2507*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
2508*44704f69SBart Van Assche bool ok;
2509*44704f69SBart Van Assche int id = rep->id;
2510*44704f69SBart Van Assche int resid = ctl_v4p->din_resid;
2511*44704f69SBart Van Assche int sres = ctl_v4p->spare_out;
2512*44704f69SBart Van Assche int n_subm = nrq - ctl_v4p->dout_resid;
2513*44704f69SBart Van Assche int n_cmpl = ctl_v4p->info;
2514*44704f69SBart Van Assche int n_good = 0;
2515*44704f69SBart Van Assche int vb = clp->verbose;
2516*44704f69SBart Van Assche int k, slen, blen;
2517*44704f69SBart Van Assche uint32_t good_inblks = 0;
2518*44704f69SBart Van Assche uint32_t good_outblks = 0;
2519*44704f69SBart Van Assche const struct sg_io_v4 * a_np = a_v4p;
2520*44704f69SBart Van Assche char b[80];
2521*44704f69SBart Van Assche
2522*44704f69SBart Van Assche blen = sizeof(b);
2523*44704f69SBart Van Assche if (n_subm < 0) {
2524*44704f69SBart Van Assche pr2serr_lk("[%d] %s: co.dout_resid(%d) > nrq(%d)\n", id, __func__,
2525*44704f69SBart Van Assche ctl_v4p->dout_resid, nrq);
2526*44704f69SBart Van Assche return -1;
2527*44704f69SBart Van Assche }
2528*44704f69SBart Van Assche if (n_cmpl != (nrq - resid))
2529*44704f69SBart Van Assche pr2serr_lk("[%d] %s: co.info(%d) != (nrq(%d) - co.din_resid(%d))\n"
2530*44704f69SBart Van Assche "will use co.info\n", id, __func__, n_cmpl, nrq, resid);
2531*44704f69SBart Van Assche if (n_cmpl > n_subm) {
2532*44704f69SBart Van Assche pr2serr_lk("[%d] %s: n_cmpl(%d) > n_subm(%d), use n_subm for both\n",
2533*44704f69SBart Van Assche id, __func__, n_cmpl, n_subm);
2534*44704f69SBart Van Assche n_cmpl = n_subm;
2535*44704f69SBart Van Assche }
2536*44704f69SBart Van Assche if (sres) {
2537*44704f69SBart Van Assche pr2serr_lk("[%d] %s: secondary error: %s [%d], info=0x%x\n", id,
2538*44704f69SBart Van Assche __func__, strerror(sres), sres, ctl_v4p->info);
2539*44704f69SBart Van Assche if (E2BIG == sres) {
2540*44704f69SBart Van Assche sg_take_snap(rep->infd, id, true);
2541*44704f69SBart Van Assche sg_take_snap(rep->outfd, id, true);
2542*44704f69SBart Van Assche }
2543*44704f69SBart Van Assche }
2544*44704f69SBart Van Assche /* Check if those submitted have finished or not */
2545*44704f69SBart Van Assche for (k = 0; k < n_subm; ++k, ++a_np) {
2546*44704f69SBart Van Assche slen = a_np->response_len;
2547*44704f69SBart Van Assche if (! (SG_INFO_MRQ_FINI & a_np->info)) {
2548*44704f69SBart Van Assche pr2serr_lk("[%d] %s, a_n[%d]: missing SG_INFO_MRQ_FINI [%s]\n",
2549*44704f69SBart Van Assche id, __func__, k, sg_info_str(a_np->info, blen, b));
2550*44704f69SBart Van Assche v4hdr_out_lk("a_np", a_np, id);
2551*44704f69SBart Van Assche v4hdr_out_lk("cop", ctl_v4p, id);
2552*44704f69SBart Van Assche }
2553*44704f69SBart Van Assche ok = true;
2554*44704f69SBart Van Assche if (SG_INFO_CHECK & a_np->info) {
2555*44704f69SBart Van Assche ok = false;
2556*44704f69SBart Van Assche pr2serr_lk("[%d] a_n[%d]: SG_INFO_CHECK set [%s]\n", id, k,
2557*44704f69SBart Van Assche sg_info_str(a_np->info, sizeof(b), b));
2558*44704f69SBart Van Assche }
2559*44704f69SBart Van Assche if (sg_scsi_status_is_bad(a_np->device_status) ||
2560*44704f69SBart Van Assche a_np->transport_status || a_np->driver_status) {
2561*44704f69SBart Van Assche ok = false;
2562*44704f69SBart Van Assche if (SAM_STAT_CHECK_CONDITION != a_np->device_status) {
2563*44704f69SBart Van Assche pr2serr_lk("[%d] %s, a_n[%d]:\n", id, __func__, k);
2564*44704f69SBart Van Assche if (vb)
2565*44704f69SBart Van Assche lk_chk_n_print4(" >>", a_np, false);
2566*44704f69SBart Van Assche }
2567*44704f69SBart Van Assche }
2568*44704f69SBart Van Assche if (slen > 0) {
2569*44704f69SBart Van Assche struct sg_scsi_sense_hdr ssh;
2570*44704f69SBart Van Assche const uint8_t *sbp = (const uint8_t *)a_np->response;
2571*44704f69SBart Van Assche
2572*44704f69SBart Van Assche if (sg_scsi_normalize_sense(sbp, slen, &ssh) &&
2573*44704f69SBart Van Assche (ssh.response_code >= 0x70)) {
2574*44704f69SBart Van Assche char b[256];
2575*44704f69SBart Van Assche
2576*44704f69SBart Van Assche if (ssh.response_code & 0x1)
2577*44704f69SBart Van Assche ok = true;
2578*44704f69SBart Van Assche if (vb) {
2579*44704f69SBart Van Assche sg_get_sense_str(" ", sbp, slen, false, sizeof(b), b);
2580*44704f69SBart Van Assche pr2serr_lk("[%d] %s, a_n[%d]:\n%s\n", id, __func__, k, b);
2581*44704f69SBart Van Assche }
2582*44704f69SBart Van Assche }
2583*44704f69SBart Van Assche }
2584*44704f69SBart Van Assche if (ok) {
2585*44704f69SBart Van Assche ++n_good;
2586*44704f69SBart Van Assche if (a_np->dout_xfer_len >= (uint32_t)rep->bs)
2587*44704f69SBart Van Assche good_outblks += (a_np->dout_xfer_len - a_np->dout_resid) /
2588*44704f69SBart Van Assche rep->bs;
2589*44704f69SBart Van Assche if (a_np->din_xfer_len >= (uint32_t)rep->bs)
2590*44704f69SBart Van Assche good_inblks += (a_np->din_xfer_len - a_np->din_resid) /
2591*44704f69SBart Van Assche rep->bs;
2592*44704f69SBart Van Assche }
2593*44704f69SBart Van Assche }
2594*44704f69SBart Van Assche if ((n_subm == nrq) || (vb < 3))
2595*44704f69SBart Van Assche goto fini;
2596*44704f69SBart Van Assche pr2serr_lk("[%d] %s: checking response array beyond number of "
2597*44704f69SBart Van Assche "submissions:\n", id, __func__);
2598*44704f69SBart Van Assche for (k = n_subm; k < nrq; ++k, ++a_np) {
2599*44704f69SBart Van Assche if (SG_INFO_MRQ_FINI & a_np->info)
2600*44704f69SBart Van Assche pr2serr_lk("[%d] %s, a_n[%d]: unexpected SG_INFO_MRQ_FINI set\n",
2601*44704f69SBart Van Assche id, __func__, k);
2602*44704f69SBart Van Assche if (a_np->device_status || a_np->transport_status ||
2603*44704f69SBart Van Assche a_np->driver_status) {
2604*44704f69SBart Van Assche pr2serr_lk("[%d] %s, a_n[%d]:\n", id, __func__, k);
2605*44704f69SBart Van Assche lk_chk_n_print4(" ", a_np, vb > 4);
2606*44704f69SBart Van Assche }
2607*44704f69SBart Van Assche }
2608*44704f69SBart Van Assche fini:
2609*44704f69SBart Van Assche if (good_inblksp)
2610*44704f69SBart Van Assche *good_inblksp = good_inblks;
2611*44704f69SBart Van Assche if (good_outblksp)
2612*44704f69SBart Van Assche *good_outblksp = good_outblks;
2613*44704f69SBart Van Assche return n_good;
2614*44704f69SBart Van Assche }
2615*44704f69SBart Van Assche #endif
2616*44704f69SBart Van Assche
2617*44704f69SBart Van Assche /* do mrq 'full non-blocking' invocation so both submission and completion
2618*44704f69SBart Van Assche * is async (i.e. uses SGV4_FLAG_IMMED flag). This type of mrq is
2619*44704f69SBart Van Assche * restricted to a single file descriptor (i.e. the 'fd' argument). */
2620*44704f69SBart Van Assche static int
sgh_do_async_mrq(Rq_elem * rep,mrq_arr_t & def_arr,int fd,struct sg_io_v4 * ctlop,int nrq)2621*44704f69SBart Van Assche sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd,
2622*44704f69SBart Van Assche struct sg_io_v4 * ctlop, int nrq)
2623*44704f69SBart Van Assche {
2624*44704f69SBart Van Assche int half = nrq / 2;
2625*44704f69SBart Van Assche int k, res, nwait, half_num, rest, err, num_good, b_len;
2626*44704f69SBart Van Assche const int64_t wait_us = 10;
2627*44704f69SBart Van Assche uint32_t in_fin_blks, out_fin_blks;
2628*44704f69SBart Van Assche struct sg_io_v4 * a_v4p;
2629*44704f69SBart Van Assche struct sg_io_v4 hold_ctlo;
2630*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
2631*44704f69SBart Van Assche char b[80];
2632*44704f69SBart Van Assche
2633*44704f69SBart Van Assche hold_ctlo = *ctlop;
2634*44704f69SBart Van Assche b_len = sizeof(b);
2635*44704f69SBart Van Assche a_v4p = def_arr.first.data();
2636*44704f69SBart Van Assche ctlop->flags = SGV4_FLAG_MULTIPLE_REQS;
2637*44704f69SBart Van Assche if (clp->in_flags.polled || clp->out_flags.polled) {
2638*44704f69SBart Van Assche /* submit of full non-blocking with POLLED */
2639*44704f69SBart Van Assche ctlop->flags |= (SGV4_FLAG_IMMED | SGV4_FLAG_POLLED);
2640*44704f69SBart Van Assche if (!after1 && (clp->verbose > 1)) {
2641*44704f69SBart Van Assche after1 = true;
2642*44704f69SBart Van Assche pr2serr_lk("%s: %s\n", __func__, mrq_s_nb_s);
2643*44704f69SBart Van Assche }
2644*44704f69SBart Van Assche } else {
2645*44704f69SBart Van Assche ctlop->flags |= SGV4_FLAG_IMMED; /* submit non-blocking */
2646*44704f69SBart Van Assche if (!after1 && (clp->verbose > 1)) {
2647*44704f69SBart Van Assche after1 = true;
2648*44704f69SBart Van Assche pr2serr_lk("%s: %s\n", __func__, mrq_s_nb_s);
2649*44704f69SBart Van Assche }
2650*44704f69SBart Van Assche }
2651*44704f69SBart Van Assche if (clp->verbose > 4) {
2652*44704f69SBart Van Assche pr2serr_lk("%s: Controlling object _before_ ioctl(SG_IOSUBMIT):\n",
2653*44704f69SBart Van Assche __func__);
2654*44704f69SBart Van Assche if (clp->verbose > 5)
2655*44704f69SBart Van Assche hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1);
2656*44704f69SBart Van Assche v4hdr_out_lk("Controlling object before", ctlop, rep->id);
2657*44704f69SBart Van Assche }
2658*44704f69SBart Van Assche res = ioctl(fd, SG_IOSUBMIT, ctlop);
2659*44704f69SBart Van Assche if (res < 0) {
2660*44704f69SBart Van Assche err = errno;
2661*44704f69SBart Van Assche if (E2BIG == err)
2662*44704f69SBart Van Assche sg_take_snap(fd, rep->id, true);
2663*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_IOSUBMIT, %s)-->%d, errno=%d: %s\n", __func__,
2664*44704f69SBart Van Assche sg_flags_str(ctlop->flags, b_len, b), res, err,
2665*44704f69SBart Van Assche strerror(err));
2666*44704f69SBart Van Assche return -1;
2667*44704f69SBart Van Assche }
2668*44704f69SBart Van Assche /* fetch first half */
2669*44704f69SBart Van Assche for (k = 0; k < 100000; ++k) {
2670*44704f69SBart Van Assche ++num_waiting_calls;
2671*44704f69SBart Van Assche res = ioctl(fd, SG_GET_NUM_WAITING, &nwait);
2672*44704f69SBart Van Assche if (res < 0) {
2673*44704f69SBart Van Assche err = errno;
2674*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_GET_NUM_WAITING)-->%d, errno=%d: %s\n",
2675*44704f69SBart Van Assche __func__, res, err, strerror(err));
2676*44704f69SBart Van Assche return -1;
2677*44704f69SBart Van Assche }
2678*44704f69SBart Van Assche if (nwait >= half)
2679*44704f69SBart Van Assche break;
2680*44704f69SBart Van Assche this_thread::sleep_for(chrono::microseconds{wait_us});
2681*44704f69SBart Van Assche }
2682*44704f69SBart Van Assche ctlop->flags = (SGV4_FLAG_MULTIPLE_REQS | SGV4_FLAG_IMMED);
2683*44704f69SBart Van Assche res = ioctl(fd, SG_IORECEIVE, ctlop);
2684*44704f69SBart Van Assche if (res < 0) {
2685*44704f69SBart Van Assche err = errno;
2686*44704f69SBart Van Assche if (ENODATA != err) {
2687*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_IORECEIVE, %s),1-->%d, errno=%d: %s\n",
2688*44704f69SBart Van Assche __func__, sg_flags_str(ctlop->flags, b_len, b), res,
2689*44704f69SBart Van Assche err, strerror(err));
2690*44704f69SBart Van Assche return -1;
2691*44704f69SBart Van Assche }
2692*44704f69SBart Van Assche half_num = 0;
2693*44704f69SBart Van Assche } else
2694*44704f69SBart Van Assche half_num = ctlop->info;
2695*44704f69SBart Van Assche if (clp->verbose > 4) {
2696*44704f69SBart Van Assche pr2serr_lk("%s: Controlling object output by ioctl(SG_IORECEIVE),1: "
2697*44704f69SBart Van Assche "num_received=%d\n", __func__, half_num);
2698*44704f69SBart Van Assche if (clp->verbose > 5)
2699*44704f69SBart Van Assche hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1);
2700*44704f69SBart Van Assche v4hdr_out_lk("Controlling object after", ctlop, rep->id);
2701*44704f69SBart Van Assche if (clp->verbose > 5) {
2702*44704f69SBart Van Assche for (k = 0; k < half_num; ++k) {
2703*44704f69SBart Van Assche pr2serr_lk("AFTER: def_arr[%d]:\n", k);
2704*44704f69SBart Van Assche v4hdr_out_lk("normal v4 object", (a_v4p + k), rep->id);
2705*44704f69SBart Van Assche // hex2stderr_lk((const uint8_t *)(a_v4p + k), sizeof(*a_v4p),
2706*44704f69SBart Van Assche // 1);
2707*44704f69SBart Van Assche }
2708*44704f69SBart Van Assche }
2709*44704f69SBart Van Assche }
2710*44704f69SBart Van Assche in_fin_blks = 0;
2711*44704f69SBart Van Assche out_fin_blks = 0;
2712*44704f69SBart Van Assche num_good = process_mrq_response(rep, ctlop, a_v4p, half_num, in_fin_blks,
2713*44704f69SBart Van Assche out_fin_blks);
2714*44704f69SBart Van Assche if (clp->verbose > 2)
2715*44704f69SBart Van Assche pr2serr_lk("%s: >>>1 num_good=%d, in_q/fin blks=%u/%u; out_q/fin "
2716*44704f69SBart Van Assche "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks,
2717*44704f69SBart Van Assche in_fin_blks, rep->out_mrq_q_blks, out_fin_blks);
2718*44704f69SBart Van Assche
2719*44704f69SBart Van Assche if (num_good < 0)
2720*44704f69SBart Van Assche res = -1;
2721*44704f69SBart Van Assche else if (num_good < half_num) {
2722*44704f69SBart Van Assche int resid_blks = rep->in_mrq_q_blks - in_fin_blks;
2723*44704f69SBart Van Assche
2724*44704f69SBart Van Assche if (resid_blks > 0)
2725*44704f69SBart Van Assche gcoll.in_rem_count += resid_blks;
2726*44704f69SBart Van Assche resid_blks = rep->out_mrq_q_blks - out_fin_blks;
2727*44704f69SBart Van Assche if (resid_blks > 0)
2728*44704f69SBart Van Assche gcoll.out_rem_count += resid_blks;
2729*44704f69SBart Van Assche
2730*44704f69SBart Van Assche return -1;
2731*44704f69SBart Van Assche }
2732*44704f69SBart Van Assche
2733*44704f69SBart Van Assche rest = nrq - half_num;
2734*44704f69SBart Van Assche if (rest < 1)
2735*44704f69SBart Van Assche goto fini;
2736*44704f69SBart Van Assche /* fetch remaining */
2737*44704f69SBart Van Assche for (k = 0; k < 100000; ++k) {
2738*44704f69SBart Van Assche ++num_waiting_calls;
2739*44704f69SBart Van Assche res = ioctl(fd, SG_GET_NUM_WAITING, &nwait);
2740*44704f69SBart Van Assche if (res < 0) {
2741*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_GET_NUM_WAITING)-->%d, errno=%d: %s\n",
2742*44704f69SBart Van Assche __func__, res, errno, strerror(errno));
2743*44704f69SBart Van Assche return -1;
2744*44704f69SBart Van Assche }
2745*44704f69SBart Van Assche if (nwait >= rest)
2746*44704f69SBart Van Assche break;
2747*44704f69SBart Van Assche this_thread::sleep_for(chrono::microseconds{wait_us});
2748*44704f69SBart Van Assche }
2749*44704f69SBart Van Assche ctlop = &hold_ctlo;
2750*44704f69SBart Van Assche ctlop->din_xferp += (half_num * sizeof(struct sg_io_v4));
2751*44704f69SBart Van Assche ctlop->din_xfer_len -= (half_num * sizeof(struct sg_io_v4));
2752*44704f69SBart Van Assche ctlop->dout_xferp = ctlop->din_xferp;
2753*44704f69SBart Van Assche ctlop->dout_xfer_len = ctlop->din_xfer_len;
2754*44704f69SBart Van Assche ctlop->flags = (SGV4_FLAG_MULTIPLE_REQS | SGV4_FLAG_IMMED);
2755*44704f69SBart Van Assche res = ioctl(fd, SG_IORECEIVE, ctlop);
2756*44704f69SBart Van Assche if (res < 0) {
2757*44704f69SBart Van Assche err = errno;
2758*44704f69SBart Van Assche if (ENODATA != err) {
2759*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_IORECEIVE, %s),2-->%d, errno=%d: %s\n",
2760*44704f69SBart Van Assche __func__, sg_flags_str(ctlop->flags, b_len, b), res,
2761*44704f69SBart Van Assche err, strerror(err));
2762*44704f69SBart Van Assche return -1;
2763*44704f69SBart Van Assche }
2764*44704f69SBart Van Assche half_num = 0;
2765*44704f69SBart Van Assche } else
2766*44704f69SBart Van Assche half_num = ctlop->info;
2767*44704f69SBart Van Assche if (clp->verbose > 4) {
2768*44704f69SBart Van Assche pr2serr_lk("%s: Controlling object output by ioctl(SG_IORECEIVE),2: "
2769*44704f69SBart Van Assche "num_received=%d\n", __func__, half_num);
2770*44704f69SBart Van Assche if (clp->verbose > 5)
2771*44704f69SBart Van Assche hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1);
2772*44704f69SBart Van Assche v4hdr_out_lk("Controlling object after", ctlop, rep->id);
2773*44704f69SBart Van Assche if (clp->verbose > 5) {
2774*44704f69SBart Van Assche for (k = 0; k < half_num; ++k) {
2775*44704f69SBart Van Assche pr2serr_lk("AFTER: def_arr[%d]:\n", k);
2776*44704f69SBart Van Assche v4hdr_out_lk("normal v4 object", (a_v4p + k), rep->id);
2777*44704f69SBart Van Assche // hex2stderr_lk((const uint8_t *)(a_v4p + k), sizeof(*a_v4p),
2778*44704f69SBart Van Assche // 1);
2779*44704f69SBart Van Assche }
2780*44704f69SBart Van Assche }
2781*44704f69SBart Van Assche }
2782*44704f69SBart Van Assche in_fin_blks = 0;
2783*44704f69SBart Van Assche out_fin_blks = 0;
2784*44704f69SBart Van Assche num_good = process_mrq_response(rep, ctlop, a_v4p, half_num, in_fin_blks,
2785*44704f69SBart Van Assche out_fin_blks);
2786*44704f69SBart Van Assche if (clp->verbose > 2)
2787*44704f69SBart Van Assche pr2serr_lk("%s: >>>2 num_good=%d, in_q/fin blks=%u/%u; out_q/fin "
2788*44704f69SBart Van Assche "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks,
2789*44704f69SBart Van Assche in_fin_blks, rep->out_mrq_q_blks, out_fin_blks);
2790*44704f69SBart Van Assche
2791*44704f69SBart Van Assche if (num_good < 0)
2792*44704f69SBart Van Assche res = -1;
2793*44704f69SBart Van Assche else if (num_good < half_num) {
2794*44704f69SBart Van Assche int resid_blks = rep->in_mrq_q_blks - in_fin_blks;
2795*44704f69SBart Van Assche
2796*44704f69SBart Van Assche if (resid_blks > 0)
2797*44704f69SBart Van Assche gcoll.in_rem_count += resid_blks;
2798*44704f69SBart Van Assche resid_blks = rep->out_mrq_q_blks - out_fin_blks;
2799*44704f69SBart Van Assche if (resid_blks > 0)
2800*44704f69SBart Van Assche gcoll.out_rem_count += resid_blks;
2801*44704f69SBart Van Assche
2802*44704f69SBart Van Assche res = -1;
2803*44704f69SBart Van Assche }
2804*44704f69SBart Van Assche
2805*44704f69SBart Van Assche fini:
2806*44704f69SBart Van Assche return res;
2807*44704f69SBart Van Assche }
2808*44704f69SBart Van Assche
2809*44704f69SBart Van Assche /* Split def_arr into fd_def_arr and o_fd_arr based on whether each element's
2810*44704f69SBart Van Assche * flags field has SGV4_FLAG_DO_ON_OTHER set. If it is set place in
2811*44704f69SBart Van Assche * o_fd_def_arr and mask out SGV4_DO_ON_OTHER. Returns number of elements
2812*44704f69SBart Van Assche * in o_fd_def_arr. */
2813*44704f69SBart Van Assche static int
split_def_arr(const mrq_arr_t & def_arr,mrq_arr_t & fd_def_arr,mrq_arr_t & o_fd_def_arr)2814*44704f69SBart Van Assche split_def_arr(const mrq_arr_t & def_arr, mrq_arr_t & fd_def_arr,
2815*44704f69SBart Van Assche mrq_arr_t & o_fd_def_arr)
2816*44704f69SBart Van Assche {
2817*44704f69SBart Van Assche int nrq, k;
2818*44704f69SBart Van Assche int res = 0;
2819*44704f69SBart Van Assche const struct sg_io_v4 * a_v4p;
2820*44704f69SBart Van Assche
2821*44704f69SBart Van Assche a_v4p = def_arr.first.data();
2822*44704f69SBart Van Assche nrq = def_arr.first.size();
2823*44704f69SBart Van Assche
2824*44704f69SBart Van Assche for (k = 0; k < nrq; ++k) {
2825*44704f69SBart Van Assche int flags;
2826*44704f69SBart Van Assche const struct sg_io_v4 * h4p = a_v4p + k;
2827*44704f69SBart Van Assche
2828*44704f69SBart Van Assche flags = h4p->flags;
2829*44704f69SBart Van Assche if (flags & SGV4_FLAG_DO_ON_OTHER) {
2830*44704f69SBart Van Assche o_fd_def_arr.first.push_back(def_arr.first[k]);
2831*44704f69SBart Van Assche o_fd_def_arr.second.push_back(def_arr.second[k]);
2832*44704f69SBart Van Assche flags &= ~SGV4_FLAG_DO_ON_OTHER; /* mask out DO_ON_OTHER */
2833*44704f69SBart Van Assche o_fd_def_arr.first[res].flags = flags;
2834*44704f69SBart Van Assche ++res;
2835*44704f69SBart Van Assche } else {
2836*44704f69SBart Van Assche fd_def_arr.first.push_back(def_arr.first[k]);
2837*44704f69SBart Van Assche fd_def_arr.second.push_back(def_arr.second[k]);
2838*44704f69SBart Van Assche }
2839*44704f69SBart Van Assche }
2840*44704f69SBart Van Assche return res;
2841*44704f69SBart Van Assche }
2842*44704f69SBart Van Assche
2843*44704f69SBart Van Assche /* This function sets up a multiple request (mrq) transaction and sends it
2844*44704f69SBart Van Assche * to the pass-through. Returns 0 on success, 1 if ENOMEM error else -1 for
2845*44704f69SBart Van Assche * other errors. */
2846*44704f69SBart Van Assche static int
sgh_do_deferred_mrq(Rq_elem * rep,mrq_arr_t & def_arr)2847*44704f69SBart Van Assche sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr)
2848*44704f69SBart Van Assche {
2849*44704f69SBart Van Assche bool launch_mrq_abort = false;
2850*44704f69SBart Van Assche int nrq, k, res, fd, mrq_pack_id, status, id, num_good, b_len;
2851*44704f69SBart Van Assche uint32_t in_fin_blks, out_fin_blks;
2852*44704f69SBart Van Assche const int max_cdb_sz = 16;
2853*44704f69SBart Van Assche struct sg_io_v4 * a_v4p;
2854*44704f69SBart Van Assche struct sg_io_v4 ctl_v4 {};
2855*44704f69SBart Van Assche uint8_t * cmd_ap = NULL;
2856*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
2857*44704f69SBart Van Assche const char * iosub_str = "iosub_str";
2858*44704f69SBart Van Assche char b[80];
2859*44704f69SBart Van Assche
2860*44704f69SBart Van Assche id = rep->id;
2861*44704f69SBart Van Assche b_len = sizeof(b);
2862*44704f69SBart Van Assche ctl_v4.guard = 'Q';
2863*44704f69SBart Van Assche a_v4p = def_arr.first.data();
2864*44704f69SBart Van Assche nrq = def_arr.first.size();
2865*44704f69SBart Van Assche if (nrq < 1) {
2866*44704f69SBart Van Assche pr2serr_lk("[%d] %s: strange nrq=0, nothing to do\n", id, __func__);
2867*44704f69SBart Van Assche return 0;
2868*44704f69SBart Van Assche }
2869*44704f69SBart Van Assche if (clp->mrq_cmds) {
2870*44704f69SBart Van Assche cmd_ap = (uint8_t *)calloc(nrq, max_cdb_sz);
2871*44704f69SBart Van Assche if (NULL == cmd_ap) {
2872*44704f69SBart Van Assche pr2serr_lk("[%d] %s: no memory for calloc(%d * 16)\n", id,
2873*44704f69SBart Van Assche __func__, nrq);
2874*44704f69SBart Van Assche return 1;
2875*44704f69SBart Van Assche }
2876*44704f69SBart Van Assche }
2877*44704f69SBart Van Assche for (k = 0; k < nrq; ++k) {
2878*44704f69SBart Van Assche struct sg_io_v4 * h4p = a_v4p + k;
2879*44704f69SBart Van Assche uint8_t *cmdp = &def_arr.second[k].front();
2880*44704f69SBart Van Assche
2881*44704f69SBart Van Assche if (clp->mrq_cmds) {
2882*44704f69SBart Van Assche memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len);
2883*44704f69SBart Van Assche h4p->request = 0;
2884*44704f69SBart Van Assche } else
2885*44704f69SBart Van Assche h4p->request = (uint64_t)cmdp;
2886*44704f69SBart Van Assche if (clp->verbose > 5) {
2887*44704f69SBart Van Assche pr2serr_lk("%s%s[%d] def_arr[%d]", ((0 == k) ? __func__ : ""),
2888*44704f69SBart Van Assche ((0 == k) ? ": " : ""), id, k);
2889*44704f69SBart Van Assche if (h4p->din_xferp)
2890*44704f69SBart Van Assche pr2serr_lk(" [din=0x%p]:\n", (void *)h4p->din_xferp);
2891*44704f69SBart Van Assche else if (h4p->dout_xferp)
2892*44704f69SBart Van Assche pr2serr_lk(" [dout=0x%p]:\n", (void *)h4p->dout_xferp);
2893*44704f69SBart Van Assche else
2894*44704f69SBart Van Assche pr2serr_lk(":\n");
2895*44704f69SBart Van Assche hex2stderr_lk((const uint8_t *)h4p, sizeof(*h4p), 1);
2896*44704f69SBart Van Assche }
2897*44704f69SBart Van Assche }
2898*44704f69SBart Van Assche if (rep->both_sg || rep->same_sg)
2899*44704f69SBart Van Assche fd = rep->infd; /* assume share to rep->outfd */
2900*44704f69SBart Van Assche else if (rep->only_in_sg)
2901*44704f69SBart Van Assche fd = rep->infd;
2902*44704f69SBart Van Assche else if (rep->only_out_sg)
2903*44704f69SBart Van Assche fd = rep->outfd;
2904*44704f69SBart Van Assche else {
2905*44704f69SBart Van Assche pr2serr_lk("[%d] %s: why am I here? No sg devices\n", id, __func__);
2906*44704f69SBart Van Assche res = -1;
2907*44704f69SBart Van Assche goto fini;
2908*44704f69SBart Van Assche }
2909*44704f69SBart Van Assche res = 0;
2910*44704f69SBart Van Assche if (clp->mrq_cmds) {
2911*44704f69SBart Van Assche ctl_v4.request_len = nrq * max_cdb_sz;
2912*44704f69SBart Van Assche ctl_v4.request = (uint64_t)cmd_ap;
2913*44704f69SBart Van Assche }
2914*44704f69SBart Van Assche ctl_v4.flags = SGV4_FLAG_MULTIPLE_REQS;
2915*44704f69SBart Van Assche if (! clp->mrq_async) {
2916*44704f69SBart Van Assche ctl_v4.flags |= SGV4_FLAG_STOP_IF;
2917*44704f69SBart Van Assche if (clp->in_flags.mrq_svb || clp->out_flags.mrq_svb)
2918*44704f69SBart Van Assche ctl_v4.flags |= SGV4_FLAG_SHARE;
2919*44704f69SBart Van Assche }
2920*44704f69SBart Van Assche ctl_v4.dout_xferp = (uint64_t)a_v4p; /* request array */
2921*44704f69SBart Van Assche ctl_v4.dout_xfer_len = nrq * sizeof(*a_v4p);
2922*44704f69SBart Van Assche ctl_v4.din_xferp = (uint64_t)a_v4p; /* response array */
2923*44704f69SBart Van Assche ctl_v4.din_xfer_len = nrq * sizeof(*a_v4p);
2924*44704f69SBart Van Assche mrq_pack_id = atomic_fetch_add(&mono_mrq_id, 1);
2925*44704f69SBart Van Assche if ((clp->m_aen > 0) && (MONO_MRQ_ID_INIT != mrq_pack_id) &&
2926*44704f69SBart Van Assche (0 == ((mrq_pack_id - MONO_MRQ_ID_INIT) % clp->m_aen))) {
2927*44704f69SBart Van Assche launch_mrq_abort = true;
2928*44704f69SBart Van Assche if (clp->verbose > 2)
2929*44704f69SBart Van Assche pr2serr_lk("[%d] %s: Decide to launch MRQ abort thread, "
2930*44704f69SBart Van Assche "mrq_id=%d\n", id, __func__, mrq_pack_id);
2931*44704f69SBart Van Assche memset(&rep->mai, 0, sizeof(rep->mai));
2932*44704f69SBart Van Assche rep->mai.from_tid = id;
2933*44704f69SBart Van Assche rep->mai.mrq_id = mrq_pack_id;
2934*44704f69SBart Van Assche rep->mai.fd = fd;
2935*44704f69SBart Van Assche rep->mai.debug = clp->verbose;
2936*44704f69SBart Van Assche
2937*44704f69SBart Van Assche status = pthread_create(&rep->mrq_abort_thread_id, NULL,
2938*44704f69SBart Van Assche mrq_abort_thread, (void *)&rep->mai);
2939*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_create, sig...");
2940*44704f69SBart Van Assche }
2941*44704f69SBart Van Assche ctl_v4.request_extra = launch_mrq_abort ? mrq_pack_id : 0;
2942*44704f69SBart Van Assche rep->mrq_id = mrq_pack_id;
2943*44704f69SBart Van Assche if (clp->verbose && rep->both_sg && clp->mrq_async)
2944*44704f69SBart Van Assche iosub_str = "SG_IOSUBMIT(variable)";
2945*44704f69SBart Van Assche if (clp->verbose > 4) {
2946*44704f69SBart Van Assche pr2serr_lk("%s: Controlling object _before_ ioctl(%s):\n",
2947*44704f69SBart Van Assche __func__, iosub_str);
2948*44704f69SBart Van Assche if (clp->verbose > 5)
2949*44704f69SBart Van Assche hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1);
2950*44704f69SBart Van Assche v4hdr_out_lk("Controlling object before", &ctl_v4, id);
2951*44704f69SBart Van Assche }
2952*44704f69SBart Van Assche if (clp->mrq_async && (! rep->both_sg)) {
2953*44704f69SBart Van Assche /* do 'submit non-blocking' or 'full non-blocking' mrq */
2954*44704f69SBart Van Assche mrq_arr_t fd_def_arr;
2955*44704f69SBart Van Assche mrq_arr_t o_fd_def_arr;
2956*44704f69SBart Van Assche
2957*44704f69SBart Van Assche /* need to deconstruct def_arr[] into two separate lists, one for
2958*44704f69SBart Van Assche * the source, the other for the destination. */
2959*44704f69SBart Van Assche int o_num_fd = split_def_arr(def_arr, fd_def_arr, o_fd_def_arr);
2960*44704f69SBart Van Assche int num_fd = fd_def_arr.first.size();
2961*44704f69SBart Van Assche if (num_fd > 0) {
2962*44704f69SBart Van Assche struct sg_io_v4 fd_ctl = ctl_v4;
2963*44704f69SBart Van Assche struct sg_io_v4 * aa_v4p = fd_def_arr.first.data();
2964*44704f69SBart Van Assche
2965*44704f69SBart Van Assche for (k = 0; k < num_fd; ++k) {
2966*44704f69SBart Van Assche struct sg_io_v4 * h4p = aa_v4p + k;
2967*44704f69SBart Van Assche uint8_t *cmdp = &fd_def_arr.second[k].front();
2968*44704f69SBart Van Assche
2969*44704f69SBart Van Assche if (clp->mrq_cmds) {
2970*44704f69SBart Van Assche memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len);
2971*44704f69SBart Van Assche h4p->request = 0;
2972*44704f69SBart Van Assche } else
2973*44704f69SBart Van Assche h4p->request = (uint64_t)cmdp;
2974*44704f69SBart Van Assche if (clp->verbose > 5) {
2975*44704f69SBart Van Assche pr2serr_lk("[%d] df_def_arr[%d]:\n", id, k);
2976*44704f69SBart Van Assche hex2stderr_lk((const uint8_t *)(aa_v4p + k),
2977*44704f69SBart Van Assche sizeof(*aa_v4p), 1);
2978*44704f69SBart Van Assche }
2979*44704f69SBart Van Assche }
2980*44704f69SBart Van Assche fd_ctl.dout_xferp = (uint64_t)aa_v4p; /* request array */
2981*44704f69SBart Van Assche fd_ctl.dout_xfer_len = num_fd * sizeof(*aa_v4p);
2982*44704f69SBart Van Assche fd_ctl.din_xferp = (uint64_t)aa_v4p; /* response array */
2983*44704f69SBart Van Assche fd_ctl.din_xfer_len = num_fd * sizeof(*aa_v4p);
2984*44704f69SBart Van Assche fd_ctl.request_extra = launch_mrq_abort ? mrq_pack_id : 0;
2985*44704f69SBart Van Assche /* this is the source side mrq command */
2986*44704f69SBart Van Assche res = sgh_do_async_mrq(rep, fd_def_arr, fd, &fd_ctl, num_fd);
2987*44704f69SBart Van Assche rep->in_mrq_q_blks = 0;
2988*44704f69SBart Van Assche if (res)
2989*44704f69SBart Van Assche goto fini;
2990*44704f69SBart Van Assche }
2991*44704f69SBart Van Assche if (o_num_fd > 0) {
2992*44704f69SBart Van Assche struct sg_io_v4 o_fd_ctl = ctl_v4;
2993*44704f69SBart Van Assche struct sg_io_v4 * aa_v4p = o_fd_def_arr.first.data();
2994*44704f69SBart Van Assche
2995*44704f69SBart Van Assche for (k = 0; k < o_num_fd; ++k) {
2996*44704f69SBart Van Assche struct sg_io_v4 * h4p = aa_v4p + k;
2997*44704f69SBart Van Assche uint8_t *cmdp = &o_fd_def_arr.second[k].front();
2998*44704f69SBart Van Assche
2999*44704f69SBart Van Assche if (clp->mrq_cmds) {
3000*44704f69SBart Van Assche memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len);
3001*44704f69SBart Van Assche h4p->request = 0;
3002*44704f69SBart Van Assche } else
3003*44704f69SBart Van Assche h4p->request = (uint64_t)cmdp;
3004*44704f69SBart Van Assche if (clp->verbose > 5) {
3005*44704f69SBart Van Assche pr2serr_lk("[%d] o_fd_def_arr[%d]:\n", id, k);
3006*44704f69SBart Van Assche hex2stderr_lk((const uint8_t *)(aa_v4p + k),
3007*44704f69SBart Van Assche sizeof(*aa_v4p), 1);
3008*44704f69SBart Van Assche }
3009*44704f69SBart Van Assche }
3010*44704f69SBart Van Assche o_fd_ctl.dout_xferp = (uint64_t)aa_v4p; /* request array */
3011*44704f69SBart Van Assche o_fd_ctl.dout_xfer_len = o_num_fd * sizeof(*aa_v4p);
3012*44704f69SBart Van Assche o_fd_ctl.din_xferp = (uint64_t)aa_v4p; /* response array */
3013*44704f69SBart Van Assche o_fd_ctl.din_xfer_len = o_num_fd * sizeof(*aa_v4p);
3014*44704f69SBart Van Assche o_fd_ctl.request_extra = launch_mrq_abort ? mrq_pack_id : 0;
3015*44704f69SBart Van Assche /* this is the destination side mrq command */
3016*44704f69SBart Van Assche res = sgh_do_async_mrq(rep, o_fd_def_arr, rep->outfd, &o_fd_ctl,
3017*44704f69SBart Van Assche o_num_fd);
3018*44704f69SBart Van Assche rep->out_mrq_q_blks = 0;
3019*44704f69SBart Van Assche }
3020*44704f69SBart Van Assche goto fini;
3021*44704f69SBart Van Assche }
3022*44704f69SBart Van Assche
3023*44704f69SBart Van Assche try_again:
3024*44704f69SBart Van Assche if (clp->unbalanced_mrq) {
3025*44704f69SBart Van Assche iosub_str = "SG_IOSUBMIT(variable_blocking)";
3026*44704f69SBart Van Assche if (!after1 && (clp->verbose > 1)) {
3027*44704f69SBart Van Assche after1 = true;
3028*44704f69SBart Van Assche pr2serr_lk("%s: unbalanced %s\n", __func__, mrq_vb_s);
3029*44704f69SBart Van Assche }
3030*44704f69SBart Van Assche res = ioctl(fd, SG_IOSUBMIT, &ctl_v4);
3031*44704f69SBart Van Assche } else {
3032*44704f69SBart Van Assche if (clp->mrq_async) {
3033*44704f69SBart Van Assche iosub_str = "SG_IOSUBMIT(variable_blocking)";
3034*44704f69SBart Van Assche if (!after1 && (clp->verbose > 1)) {
3035*44704f69SBart Van Assche after1 = true;
3036*44704f69SBart Van Assche pr2serr_lk("%s: %s\n", __func__, mrq_vb_s);
3037*44704f69SBart Van Assche }
3038*44704f69SBart Van Assche res = ioctl(fd, SG_IOSUBMIT, &ctl_v4);
3039*44704f69SBart Van Assche } else if (clp->in_flags.mrq_svb || clp->out_flags.mrq_svb) {
3040*44704f69SBart Van Assche iosub_str = "SG_IOSUBMIT(shared_variable_blocking)";
3041*44704f69SBart Van Assche if (!after1 && (clp->verbose > 1)) {
3042*44704f69SBart Van Assche after1 = true;
3043*44704f69SBart Van Assche pr2serr_lk("%s: %s\n", __func__, mrq_svb_s);
3044*44704f69SBart Van Assche }
3045*44704f69SBart Van Assche res = ioctl(fd, SG_IOSUBMIT, &ctl_v4);
3046*44704f69SBart Van Assche } else {
3047*44704f69SBart Van Assche iosub_str = "SG_IO(ordered_blocking)";
3048*44704f69SBart Van Assche if (!after1 && (clp->verbose > 1)) {
3049*44704f69SBart Van Assche after1 = true;
3050*44704f69SBart Van Assche pr2serr_lk("%s: %s\n", __func__, mrq_blk_s);
3051*44704f69SBart Van Assche }
3052*44704f69SBart Van Assche res = ioctl(fd, SG_IO, &ctl_v4);
3053*44704f69SBart Van Assche }
3054*44704f69SBart Van Assche }
3055*44704f69SBart Van Assche if (res < 0) {
3056*44704f69SBart Van Assche int err = errno;
3057*44704f69SBart Van Assche
3058*44704f69SBart Van Assche if (E2BIG == err)
3059*44704f69SBart Van Assche sg_take_snap(fd, id, true);
3060*44704f69SBart Van Assche else if (EBUSY == err) {
3061*44704f69SBart Van Assche ++num_ebusy;
3062*44704f69SBart Van Assche std::this_thread::yield();/* allow another thread to progress */
3063*44704f69SBart Van Assche goto try_again;
3064*44704f69SBart Van Assche }
3065*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(%s, %s)-->%d, errno=%d: %s\n",
3066*44704f69SBart Van Assche __func__, iosub_str, sg_flags_str(ctl_v4.flags, b_len, b),
3067*44704f69SBart Van Assche res, err, strerror(err));
3068*44704f69SBart Van Assche res = -1;
3069*44704f69SBart Van Assche goto fini;
3070*44704f69SBart Van Assche }
3071*44704f69SBart Van Assche if (clp->verbose && vb_first_time.load()) {
3072*44704f69SBart Van Assche pr2serr_lk("First controlling object output by ioctl(%s), flags: "
3073*44704f69SBart Van Assche "%s\n", iosub_str, sg_flags_str(ctl_v4.flags, b_len, b));
3074*44704f69SBart Van Assche vb_first_time.store(false);
3075*44704f69SBart Van Assche } else if (clp->verbose > 4)
3076*44704f69SBart Van Assche pr2serr_lk("%s: Controlling object output by ioctl(%s):\n",
3077*44704f69SBart Van Assche __func__, iosub_str);
3078*44704f69SBart Van Assche if (clp->verbose > 4) {
3079*44704f69SBart Van Assche if (clp->verbose > 5)
3080*44704f69SBart Van Assche hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1);
3081*44704f69SBart Van Assche v4hdr_out_lk("Controlling object after", &ctl_v4, id);
3082*44704f69SBart Van Assche if (clp->verbose > 5) {
3083*44704f69SBart Van Assche for (k = 0; k < nrq; ++k) {
3084*44704f69SBart Van Assche pr2serr_lk("AFTER: def_arr[%d]:\n", k);
3085*44704f69SBart Van Assche v4hdr_out_lk("normal v4 object", (a_v4p + k), id);
3086*44704f69SBart Van Assche // hex2stderr_lk((const uint8_t *)(a_v4p + k), sizeof(*a_v4p),
3087*44704f69SBart Van Assche // 1);
3088*44704f69SBart Van Assche }
3089*44704f69SBart Van Assche }
3090*44704f69SBart Van Assche }
3091*44704f69SBart Van Assche in_fin_blks = 0;
3092*44704f69SBart Van Assche out_fin_blks = 0;
3093*44704f69SBart Van Assche num_good = process_mrq_response(rep, &ctl_v4, a_v4p, nrq, in_fin_blks,
3094*44704f69SBart Van Assche out_fin_blks);
3095*44704f69SBart Van Assche if (clp->verbose > 2)
3096*44704f69SBart Van Assche pr2serr_lk("%s: >>> num_good=%d, in_q/fin blks=%u/%u; out_q/fin "
3097*44704f69SBart Van Assche "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks,
3098*44704f69SBart Van Assche in_fin_blks, rep->out_mrq_q_blks, out_fin_blks);
3099*44704f69SBart Van Assche
3100*44704f69SBart Van Assche if (num_good < 0)
3101*44704f69SBart Van Assche res = -1;
3102*44704f69SBart Van Assche else if (num_good < nrq) {
3103*44704f69SBart Van Assche int resid_blks = rep->in_mrq_q_blks - in_fin_blks;
3104*44704f69SBart Van Assche
3105*44704f69SBart Van Assche if (resid_blks > 0)
3106*44704f69SBart Van Assche gcoll.in_rem_count += resid_blks;
3107*44704f69SBart Van Assche resid_blks = rep->out_mrq_q_blks - out_fin_blks;
3108*44704f69SBart Van Assche if (resid_blks > 0)
3109*44704f69SBart Van Assche gcoll.out_rem_count += resid_blks;
3110*44704f69SBart Van Assche
3111*44704f69SBart Van Assche res = -1;
3112*44704f69SBart Van Assche }
3113*44704f69SBart Van Assche rep->in_mrq_q_blks = 0;
3114*44704f69SBart Van Assche rep->out_mrq_q_blks = 0;
3115*44704f69SBart Van Assche fini:
3116*44704f69SBart Van Assche def_arr.first.clear();
3117*44704f69SBart Van Assche def_arr.second.clear();
3118*44704f69SBart Van Assche if (cmd_ap)
3119*44704f69SBart Van Assche free(cmd_ap);
3120*44704f69SBart Van Assche if (launch_mrq_abort) {
3121*44704f69SBart Van Assche if (clp->verbose > 1)
3122*44704f69SBart Van Assche pr2serr_lk("[%d] %s: About to join MRQ abort thread, "
3123*44704f69SBart Van Assche "mrq_id=%d\n", id, __func__, mrq_pack_id);
3124*44704f69SBart Van Assche
3125*44704f69SBart Van Assche void * vp; /* not used */
3126*44704f69SBart Van Assche status = pthread_join(rep->mrq_abort_thread_id, &vp);
3127*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_join");
3128*44704f69SBart Van Assche }
3129*44704f69SBart Van Assche return res;
3130*44704f69SBart Van Assche }
3131*44704f69SBart Van Assche
3132*44704f69SBart Van Assche /* Returns 0 on success, 1 if ENOMEM error else -1 for other errors. */
3133*44704f69SBart Van Assche static int
sg_start_io(Rq_elem * rep,mrq_arr_t & def_arr,int & pack_id,struct sg_io_extra * xtrp)3134*44704f69SBart Van Assche sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id,
3135*44704f69SBart Van Assche struct sg_io_extra *xtrp)
3136*44704f69SBart Van Assche {
3137*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
3138*44704f69SBart Van Assche bool wr = rep->wr;
3139*44704f69SBart Van Assche bool fua = wr ? clp->out_flags.fua : clp->in_flags.fua;
3140*44704f69SBart Van Assche bool dpo = wr ? clp->out_flags.dpo : clp->in_flags.dpo;
3141*44704f69SBart Van Assche bool dio = wr ? clp->out_flags.dio : clp->in_flags.dio;
3142*44704f69SBart Van Assche bool mmap = wr ? clp->out_flags.mmap : clp->in_flags.mmap;
3143*44704f69SBart Van Assche bool noxfer = wr ? clp->out_flags.noxfer : clp->in_flags.noxfer;
3144*44704f69SBart Van Assche bool v4 = wr ? clp->out_flags.v4 : clp->in_flags.v4;
3145*44704f69SBart Van Assche bool qhead = wr ? clp->out_flags.qhead : clp->in_flags.qhead;
3146*44704f69SBart Van Assche bool qtail = wr ? clp->out_flags.qtail : clp->in_flags.qtail;
3147*44704f69SBart Van Assche bool polled = wr ? clp->out_flags.polled : clp->in_flags.polled;
3148*44704f69SBart Van Assche bool mout_if = wr ? clp->out_flags.mout_if : clp->in_flags.mout_if;
3149*44704f69SBart Van Assche bool prefetch = xtrp ? xtrp->prefetch : false;
3150*44704f69SBart Van Assche bool is_wr2 = xtrp ? xtrp->is_wr2 : false;
3151*44704f69SBart Van Assche int cdbsz = wr ? clp->cdbsz_out : clp->cdbsz_in;
3152*44704f69SBart Van Assche int flags = 0;
3153*44704f69SBart Van Assche int res, err, fd, b_len, nblks, blk_off;
3154*44704f69SBart Van Assche int64_t blk = wr ? rep->oblk : rep->iblk;
3155*44704f69SBart Van Assche struct sg_io_hdr * hp = &rep->io_hdr;
3156*44704f69SBart Van Assche struct sg_io_v4 * h4p = &rep->io_hdr4[xtrp ? xtrp->hpv4_ind : 0];
3157*44704f69SBart Van Assche const char * cp = "";
3158*44704f69SBart Van Assche const char * crwp;
3159*44704f69SBart Van Assche char b[80];
3160*44704f69SBart Van Assche
3161*44704f69SBart Van Assche b_len = sizeof(b);
3162*44704f69SBart Van Assche if (wr) {
3163*44704f69SBart Van Assche fd = is_wr2 ? rep->out2fd : rep->outfd;
3164*44704f69SBart Van Assche if (clp->verify) {
3165*44704f69SBart Van Assche crwp = is_wr2 ? "verifying2" : "verifying";
3166*44704f69SBart Van Assche if (prefetch)
3167*44704f69SBart Van Assche crwp = is_wr2 ? "prefetch2" : "prefetch";
3168*44704f69SBart Van Assche } else
3169*44704f69SBart Van Assche crwp = is_wr2 ? "writing2" : "writing";
3170*44704f69SBart Van Assche } else {
3171*44704f69SBart Van Assche fd = rep->infd;
3172*44704f69SBart Van Assche crwp = "reading";
3173*44704f69SBart Van Assche }
3174*44704f69SBart Van Assche if (qhead)
3175*44704f69SBart Van Assche qtail = false; /* qhead takes precedence */
3176*44704f69SBart Van Assche
3177*44704f69SBart Van Assche if (v4 && xtrp && xtrp->dout_is_split) {
3178*44704f69SBart Van Assche res = sg_build_scsi_cdb(rep->cmd, cdbsz, xtrp->blks,
3179*44704f69SBart Van Assche blk + (unsigned int)xtrp->blk_offset,
3180*44704f69SBart Van Assche clp->verify, true, fua, dpo);
3181*44704f69SBart Van Assche } else
3182*44704f69SBart Van Assche res = sg_build_scsi_cdb(rep->cmd, cdbsz, rep->num_blks, blk,
3183*44704f69SBart Van Assche wr ? clp->verify : false, wr, fua, dpo);
3184*44704f69SBart Van Assche if (res) {
3185*44704f69SBart Van Assche pr2serr_lk("%sbad cdb build, start_blk=%" PRId64 ", blocks=%d\n",
3186*44704f69SBart Van Assche my_name, blk, rep->num_blks);
3187*44704f69SBart Van Assche return -1;
3188*44704f69SBart Van Assche }
3189*44704f69SBart Van Assche if (prefetch) {
3190*44704f69SBart Van Assche if (cdbsz == 10)
3191*44704f69SBart Van Assche rep->cmd[0] = SGP_PRE_FETCH10;
3192*44704f69SBart Van Assche else if (cdbsz == 16)
3193*44704f69SBart Van Assche rep->cmd[0] = SGP_PRE_FETCH16;
3194*44704f69SBart Van Assche else {
3195*44704f69SBart Van Assche pr2serr_lk("%sbad PRE-FETCH build, start_blk=%" PRId64 ", "
3196*44704f69SBart Van Assche "blocks=%d\n", my_name, blk, rep->num_blks);
3197*44704f69SBart Van Assche return -1;
3198*44704f69SBart Van Assche }
3199*44704f69SBart Van Assche rep->cmd[1] = 0x2; /* set IMMED (no fua or dpo) */
3200*44704f69SBart Van Assche }
3201*44704f69SBart Van Assche if (mmap && (clp->noshare || (rep->outregfd >= 0)))
3202*44704f69SBart Van Assche flags |= SG_FLAG_MMAP_IO;
3203*44704f69SBart Van Assche if (noxfer)
3204*44704f69SBart Van Assche flags |= SG_FLAG_NO_DXFER;
3205*44704f69SBart Van Assche if (dio)
3206*44704f69SBart Van Assche flags |= SG_FLAG_DIRECT_IO;
3207*44704f69SBart Van Assche if (polled)
3208*44704f69SBart Van Assche flags |= SGV4_FLAG_POLLED;
3209*44704f69SBart Van Assche if (qhead)
3210*44704f69SBart Van Assche flags |= SG_FLAG_Q_AT_HEAD;
3211*44704f69SBart Van Assche if (qtail)
3212*44704f69SBart Van Assche flags |= SG_FLAG_Q_AT_TAIL;
3213*44704f69SBart Van Assche if (mout_if)
3214*44704f69SBart Van Assche flags |= SGV4_FLAG_META_OUT_IF;
3215*44704f69SBart Van Assche if (rep->has_share) {
3216*44704f69SBart Van Assche flags |= SGV4_FLAG_SHARE;
3217*44704f69SBart Van Assche if (wr)
3218*44704f69SBart Van Assche flags |= SGV4_FLAG_NO_DXFER;
3219*44704f69SBart Van Assche else if (rep->outregfd < 0)
3220*44704f69SBart Van Assche flags |= SGV4_FLAG_NO_DXFER;
3221*44704f69SBart Van Assche
3222*44704f69SBart Van Assche cp = (wr ? " write_side active" : " read_side active");
3223*44704f69SBart Van Assche } else
3224*44704f69SBart Van Assche cp = (wr ? " write-side not sharing" : " read_side not sharing");
3225*44704f69SBart Van Assche if (rep->both_sg) {
3226*44704f69SBart Van Assche if (wr)
3227*44704f69SBart Van Assche pack_id = rep->rd_p_id + 1;
3228*44704f69SBart Van Assche else {
3229*44704f69SBart Van Assche pack_id = 2 * atomic_fetch_add(&mono_pack_id, 1);
3230*44704f69SBart Van Assche rep->rd_p_id = pack_id;
3231*44704f69SBart Van Assche }
3232*44704f69SBart Van Assche } else
3233*44704f69SBart Van Assche pack_id = atomic_fetch_add(&mono_pack_id, 1); /* fetch before */
3234*44704f69SBart Van Assche rep->rq_id = pack_id;
3235*44704f69SBart Van Assche nblks = rep->num_blks;
3236*44704f69SBart Van Assche blk_off = 0;
3237*44704f69SBart Van Assche if (clp->verbose && 0 == clp->nmrqs && vb_first_time.load()) {
3238*44704f69SBart Van Assche vb_first_time.store(false);
3239*44704f69SBart Van Assche pr2serr("First normal IO: %s, flags: %s\n", cp,
3240*44704f69SBart Van Assche sg_flags_str(flags, b_len, b));
3241*44704f69SBart Van Assche }
3242*44704f69SBart Van Assche if (v4) {
3243*44704f69SBart Van Assche memset(h4p, 0, sizeof(struct sg_io_v4));
3244*44704f69SBart Van Assche if (clp->nmrqs > 0) {
3245*44704f69SBart Van Assche if (rep->both_sg && (rep->outfd == fd))
3246*44704f69SBart Van Assche flags |= SGV4_FLAG_DO_ON_OTHER;
3247*44704f69SBart Van Assche }
3248*44704f69SBart Van Assche if (xtrp && xtrp->dout_is_split && (nblks > 0)) {
3249*44704f69SBart Van Assche if (1 == xtrp->hpv4_ind) {
3250*44704f69SBart Van Assche flags |= SGV4_FLAG_DOUT_OFFSET;
3251*44704f69SBart Van Assche blk_off = xtrp->blk_offset;
3252*44704f69SBart Van Assche h4p->spare_in = clp->bs * blk_off;
3253*44704f69SBart Van Assche }
3254*44704f69SBart Van Assche nblks = xtrp->blks;
3255*44704f69SBart Van Assche if ((0 == xtrp->hpv4_ind) && (nblks < rep->num_blks))
3256*44704f69SBart Van Assche flags |= SGV4_FLAG_KEEP_SHARE;
3257*44704f69SBart Van Assche }
3258*44704f69SBart Van Assche if (clp->ofile2_given && wr && rep->has_share && ! is_wr2)
3259*44704f69SBart Van Assche flags |= SGV4_FLAG_KEEP_SHARE; /* set on first write only */
3260*44704f69SBart Van Assche else if (clp->fail_mask & 1)
3261*44704f69SBart Van Assche flags |= SGV4_FLAG_KEEP_SHARE; /* troublemaking .... */
3262*44704f69SBart Van Assche } else
3263*44704f69SBart Van Assche memset(hp, 0, sizeof(struct sg_io_hdr));
3264*44704f69SBart Van Assche if (clp->verbose > 3) {
3265*44704f69SBart Van Assche bool lock = true;
3266*44704f69SBart Van Assche char prefix[128];
3267*44704f69SBart Van Assche
3268*44704f69SBart Van Assche if (4 == clp->verbose) {
3269*44704f69SBart Van Assche snprintf(prefix, sizeof(prefix), "tid,rq_id=%d,%d: ", rep->id,
3270*44704f69SBart Van Assche pack_id);
3271*44704f69SBart Van Assche lock = false;
3272*44704f69SBart Van Assche } else {
3273*44704f69SBart Van Assche prefix[0] = '\0';
3274*44704f69SBart Van Assche pr2serr_lk("%s tid,rq_id=%d,%d: SCSI %s%s %s, blk=%" PRId64
3275*44704f69SBart Van Assche " num_blks=%d\n", __func__, rep->id, pack_id, crwp, cp,
3276*44704f69SBart Van Assche sg_flags_str(flags, b_len, b), blk + blk_off, nblks);
3277*44704f69SBart Van Assche }
3278*44704f69SBart Van Assche lk_print_command_len(prefix, rep->cmd, cdbsz, lock);
3279*44704f69SBart Van Assche }
3280*44704f69SBart Van Assche if (v4)
3281*44704f69SBart Van Assche goto do_v4; // <<<<<<<<<<<<<<< look further down
3282*44704f69SBart Van Assche
3283*44704f69SBart Van Assche hp->interface_id = 'S';
3284*44704f69SBart Van Assche hp->cmd_len = cdbsz;
3285*44704f69SBart Van Assche hp->cmdp = rep->cmd;
3286*44704f69SBart Van Assche hp->dxferp = get_buffp(rep);
3287*44704f69SBart Van Assche hp->dxfer_len = clp->bs * rep->num_blks;
3288*44704f69SBart Van Assche if (!wr)
3289*44704f69SBart Van Assche hp->dxfer_direction = SG_DXFER_FROM_DEV;
3290*44704f69SBart Van Assche else if (prefetch) {
3291*44704f69SBart Van Assche hp->dxfer_direction = SG_DXFER_NONE;
3292*44704f69SBart Van Assche hp->dxfer_len = 0;
3293*44704f69SBart Van Assche hp->dxferp = NULL;
3294*44704f69SBart Van Assche } else
3295*44704f69SBart Van Assche hp->dxfer_direction = SG_DXFER_TO_DEV;
3296*44704f69SBart Van Assche hp->mx_sb_len = sizeof(rep->sb);
3297*44704f69SBart Van Assche hp->sbp = rep->sb;
3298*44704f69SBart Van Assche hp->timeout = clp->cmd_timeout;
3299*44704f69SBart Van Assche hp->usr_ptr = rep;
3300*44704f69SBart Van Assche hp->pack_id = pack_id;
3301*44704f69SBart Van Assche hp->flags = flags;
3302*44704f69SBart Van Assche
3303*44704f69SBart Van Assche while (((res = write(fd, hp, sizeof(struct sg_io_hdr))) < 0) &&
3304*44704f69SBart Van Assche ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
3305*44704f69SBart Van Assche if (EAGAIN == errno) {
3306*44704f69SBart Van Assche ++num_start_eagain;
3307*44704f69SBart Van Assche #ifdef SGH_DD_SNAP_DEV
3308*44704f69SBart Van Assche if (0 == (num_ebusy % 1000))
3309*44704f69SBart Van Assche sg_take_snap(fd, rep->id, (clp->verbose > 2));
3310*44704f69SBart Van Assche #endif
3311*44704f69SBart Van Assche } else if (EBUSY == errno) {
3312*44704f69SBart Van Assche ++num_ebusy;
3313*44704f69SBart Van Assche #ifdef SGH_DD_SNAP_DEV
3314*44704f69SBart Van Assche if (0 == (num_ebusy % 1000))
3315*44704f69SBart Van Assche sg_take_snap(fd, rep->id, (clp->verbose > 2));
3316*44704f69SBart Van Assche #endif
3317*44704f69SBart Van Assche }
3318*44704f69SBart Van Assche std::this_thread::yield();/* another thread may be able to progress */
3319*44704f69SBart Van Assche }
3320*44704f69SBart Van Assche err = errno;
3321*44704f69SBart Van Assche if (res < 0) {
3322*44704f69SBart Van Assche if (ENOMEM == err)
3323*44704f69SBart Van Assche return 1;
3324*44704f69SBart Van Assche pr2serr_lk("%s tid=%d: %s %s write(2) failed: %s\n", __func__,
3325*44704f69SBart Van Assche rep->id, cp, sg_flags_str(hp->flags, b_len, b),
3326*44704f69SBart Van Assche strerror(err));
3327*44704f69SBart Van Assche return -1;
3328*44704f69SBart Van Assche }
3329*44704f69SBart Van Assche return 0;
3330*44704f69SBart Van Assche
3331*44704f69SBart Van Assche do_v4:
3332*44704f69SBart Van Assche h4p->guard = 'Q';
3333*44704f69SBart Van Assche h4p->request_len = cdbsz;
3334*44704f69SBart Van Assche h4p->request = (uint64_t)rep->cmd;
3335*44704f69SBart Van Assche if (wr) {
3336*44704f69SBart Van Assche if (prefetch) {
3337*44704f69SBart Van Assche h4p->dout_xfer_len = 0; // din_xfer_len is also 0
3338*44704f69SBart Van Assche h4p->dout_xferp = 0;
3339*44704f69SBart Van Assche } else {
3340*44704f69SBart Van Assche h4p->dout_xfer_len = clp->bs * nblks;
3341*44704f69SBart Van Assche h4p->dout_xferp = (uint64_t)get_buffp(rep);
3342*44704f69SBart Van Assche }
3343*44704f69SBart Van Assche } else if (nblks > 0) {
3344*44704f69SBart Van Assche h4p->din_xfer_len = clp->bs * nblks;
3345*44704f69SBart Van Assche h4p->din_xferp = (uint64_t)get_buffp(rep);
3346*44704f69SBart Van Assche }
3347*44704f69SBart Van Assche h4p->max_response_len = sizeof(rep->sb);
3348*44704f69SBart Van Assche h4p->response = (uint64_t)rep->sb;
3349*44704f69SBart Van Assche h4p->timeout = clp->cmd_timeout;
3350*44704f69SBart Van Assche h4p->usr_ptr = (uint64_t)rep;
3351*44704f69SBart Van Assche h4p->request_extra = pack_id; /* this is the pack_id */
3352*44704f69SBart Van Assche h4p->flags = flags;
3353*44704f69SBart Van Assche if (clp->nmrqs > 0) {
3354*44704f69SBart Van Assche big_cdb cdb_arr;
3355*44704f69SBart Van Assche uint8_t * cmdp = &(cdb_arr[0]);
3356*44704f69SBart Van Assche
3357*44704f69SBart Van Assche if (wr)
3358*44704f69SBart Van Assche rep->out_mrq_q_blks += nblks;
3359*44704f69SBart Van Assche else
3360*44704f69SBart Van Assche rep->in_mrq_q_blks += nblks;
3361*44704f69SBart Van Assche memcpy(cmdp, rep->cmd, cdbsz);
3362*44704f69SBart Van Assche def_arr.first.push_back(*h4p);
3363*44704f69SBart Van Assche def_arr.second.push_back(cdb_arr);
3364*44704f69SBart Van Assche res = 0;
3365*44704f69SBart Van Assche if ((int)def_arr.first.size() >= clp->nmrqs) {
3366*44704f69SBart Van Assche res = sgh_do_deferred_mrq(rep, def_arr);
3367*44704f69SBart Van Assche if (res)
3368*44704f69SBart Van Assche pr2serr_lk("%s tid=%d: sgh_do_deferred_mrq failed\n",
3369*44704f69SBart Van Assche __func__, rep->id);
3370*44704f69SBart Van Assche }
3371*44704f69SBart Van Assche return res;
3372*44704f69SBart Van Assche }
3373*44704f69SBart Van Assche while (((res = ioctl(fd, SG_IOSUBMIT, h4p)) < 0) &&
3374*44704f69SBart Van Assche ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
3375*44704f69SBart Van Assche if (EAGAIN == errno) {
3376*44704f69SBart Van Assche ++num_start_eagain;
3377*44704f69SBart Van Assche #ifdef SGH_DD_SNAP_DEV
3378*44704f69SBart Van Assche if (0 == (num_ebusy % 1000))
3379*44704f69SBart Van Assche sg_take_snap(fd, rep->id, (clp->verbose > 2));
3380*44704f69SBart Van Assche #endif
3381*44704f69SBart Van Assche } else if (EBUSY == errno) {
3382*44704f69SBart Van Assche ++num_ebusy;
3383*44704f69SBart Van Assche #ifdef SGH_DD_SNAP_DEV
3384*44704f69SBart Van Assche if (0 == (num_ebusy % 1000))
3385*44704f69SBart Van Assche sg_take_snap(fd, rep->id, (clp->verbose > 2));
3386*44704f69SBart Van Assche #endif
3387*44704f69SBart Van Assche }
3388*44704f69SBart Van Assche std::this_thread::yield();/* another thread may be able to progress */
3389*44704f69SBart Van Assche }
3390*44704f69SBart Van Assche err = errno;
3391*44704f69SBart Van Assche if (res < 0) {
3392*44704f69SBart Van Assche if (ENOMEM == err)
3393*44704f69SBart Van Assche return 1;
3394*44704f69SBart Van Assche if (E2BIG == err)
3395*44704f69SBart Van Assche sg_take_snap(fd, rep->id, true);
3396*44704f69SBart Van Assche pr2serr_lk("%s tid=%d: %s %s ioctl(2) failed: %s\n", __func__,
3397*44704f69SBart Van Assche rep->id, cp, sg_flags_str(h4p->flags, b_len, b),
3398*44704f69SBart Van Assche strerror(err));
3399*44704f69SBart Van Assche // v4hdr_out_lk("leadin", h4p, rep->id);
3400*44704f69SBart Van Assche return -1;
3401*44704f69SBart Van Assche }
3402*44704f69SBart Van Assche if ((clp->aen > 0) && (rep->rep_count > 0)) {
3403*44704f69SBart Van Assche if (0 == (rep->rq_id % clp->aen)) {
3404*44704f69SBart Van Assche struct timespec tspec = {0, 4000 /* 4 usecs */};
3405*44704f69SBart Van Assche
3406*44704f69SBart Van Assche nanosleep(&tspec, NULL);
3407*44704f69SBart Van Assche #if 0
3408*44704f69SBart Van Assche struct pollfd a_poll;
3409*44704f69SBart Van Assche
3410*44704f69SBart Van Assche a_poll.fd = fd;
3411*44704f69SBart Van Assche a_poll.events = POLL_IN;
3412*44704f69SBart Van Assche a_poll.revents = 0;
3413*44704f69SBart Van Assche res = poll(&a_poll, 1 /* element */, 1 /* millisecond */);
3414*44704f69SBart Van Assche if (res < 0)
3415*44704f69SBart Van Assche pr2serr_lk("%s: poll() failed: %s [%d]\n",
3416*44704f69SBart Van Assche __func__, safe_strerror(errno), errno);
3417*44704f69SBart Van Assche else if (0 == res) { /* timeout, cmd still inflight, so abort */
3418*44704f69SBart Van Assche }
3419*44704f69SBart Van Assche #endif
3420*44704f69SBart Van Assche ++num_abort_req;
3421*44704f69SBart Van Assche res = ioctl(fd, SG_IOABORT, h4p);
3422*44704f69SBart Van Assche if (res < 0) {
3423*44704f69SBart Van Assche err = errno;
3424*44704f69SBart Van Assche if (ENODATA == err) {
3425*44704f69SBart Van Assche if (clp->verbose > 2)
3426*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_IOABORT) no match on "
3427*44704f69SBart Van Assche "pack_id=%d\n", __func__, pack_id);
3428*44704f69SBart Van Assche } else
3429*44704f69SBart Van Assche pr2serr_lk("%s: ioctl(SG_IOABORT) failed: %s [%d]\n",
3430*44704f69SBart Van Assche __func__, safe_strerror(err), err);
3431*44704f69SBart Van Assche } else {
3432*44704f69SBart Van Assche ++num_abort_req_success;
3433*44704f69SBart Van Assche if (clp->verbose > 2)
3434*44704f69SBart Van Assche pr2serr_lk("%s: sent ioctl(SG_IOABORT) on rq_id=%d, "
3435*44704f69SBart Van Assche "success\n", __func__, pack_id);
3436*44704f69SBart Van Assche }
3437*44704f69SBart Van Assche } /* else got response, too late for timeout, so skip */
3438*44704f69SBart Van Assche }
3439*44704f69SBart Van Assche return 0;
3440*44704f69SBart Van Assche }
3441*44704f69SBart Van Assche
3442*44704f69SBart Van Assche /* 0 -> successful, SG_LIB_CAT_UNIT_ATTENTION or SG_LIB_CAT_ABORTED_COMMAND
3443*44704f69SBart Van Assche -> try again, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_MEDIUM_HARD,
3444*44704f69SBart Van Assche -1 other errors */
3445*44704f69SBart Van Assche static int
sg_finish_io(bool wr,Rq_elem * rep,int pack_id,struct sg_io_extra * xtrp)3446*44704f69SBart Van Assche sg_finish_io(bool wr, Rq_elem * rep, int pack_id, struct sg_io_extra *xtrp)
3447*44704f69SBart Van Assche {
3448*44704f69SBart Van Assche struct global_collection * clp = rep->clp;
3449*44704f69SBart Van Assche bool v4 = wr ? clp->out_flags.v4 : clp->in_flags.v4;
3450*44704f69SBart Van Assche bool mout_if = wr ? clp->out_flags.mout_if : clp->in_flags.mout_if;
3451*44704f69SBart Van Assche bool is_wr2 = xtrp ? xtrp->is_wr2 : false;
3452*44704f69SBart Van Assche bool prefetch = xtrp ? xtrp->prefetch : false;
3453*44704f69SBart Van Assche int res, fd;
3454*44704f69SBart Van Assche int64_t blk = wr ? rep->oblk : rep->iblk;
3455*44704f69SBart Van Assche struct sg_io_hdr io_hdr;
3456*44704f69SBart Van Assche struct sg_io_hdr * hp;
3457*44704f69SBart Van Assche struct sg_io_v4 * h4p;
3458*44704f69SBart Van Assche const char *cp;
3459*44704f69SBart Van Assche
3460*44704f69SBart Van Assche if (wr) {
3461*44704f69SBart Van Assche fd = is_wr2 ? rep->out2fd : rep->outfd;
3462*44704f69SBart Van Assche cp = is_wr2 ? "writing2" : "writing";
3463*44704f69SBart Van Assche if (clp->verify) {
3464*44704f69SBart Van Assche cp = is_wr2 ? "verifying2" : "verifying";
3465*44704f69SBart Van Assche if (prefetch)
3466*44704f69SBart Van Assche cp = is_wr2 ? "prefetch2" : "prefetch";
3467*44704f69SBart Van Assche }
3468*44704f69SBart Van Assche } else {
3469*44704f69SBart Van Assche fd = rep->infd;
3470*44704f69SBart Van Assche cp = "reading";
3471*44704f69SBart Van Assche }
3472*44704f69SBart Van Assche if (v4)
3473*44704f69SBart Van Assche goto do_v4;
3474*44704f69SBart Van Assche memset(&io_hdr, 0 , sizeof(struct sg_io_hdr));
3475*44704f69SBart Van Assche /* FORCE_PACK_ID active set only read packet with matching pack_id */
3476*44704f69SBart Van Assche io_hdr.interface_id = 'S';
3477*44704f69SBart Van Assche io_hdr.dxfer_direction = wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
3478*44704f69SBart Van Assche io_hdr.pack_id = pack_id;
3479*44704f69SBart Van Assche
3480*44704f69SBart Van Assche while (((res = read(fd, &io_hdr, sizeof(struct sg_io_hdr))) < 0) &&
3481*44704f69SBart Van Assche ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
3482*44704f69SBart Van Assche if (EAGAIN == errno) {
3483*44704f69SBart Van Assche ++num_fin_eagain;
3484*44704f69SBart Van Assche #ifdef SGH_DD_SNAP_DEV
3485*44704f69SBart Van Assche if (0 == (num_ebusy % 1000))
3486*44704f69SBart Van Assche sg_take_snap(fd, rep->id, (clp->verbose > 2));
3487*44704f69SBart Van Assche #endif
3488*44704f69SBart Van Assche } else if (EBUSY == errno) {
3489*44704f69SBart Van Assche ++num_ebusy;
3490*44704f69SBart Van Assche #ifdef SGH_DD_SNAP_DEV
3491*44704f69SBart Van Assche if (0 == (num_ebusy % 1000))
3492*44704f69SBart Van Assche sg_take_snap(fd, rep->id, (clp->verbose > 2));
3493*44704f69SBart Van Assche #endif
3494*44704f69SBart Van Assche }
3495*44704f69SBart Van Assche std::this_thread::yield();/* another thread may be able to progress */
3496*44704f69SBart Van Assche }
3497*44704f69SBart Van Assche if (res < 0) {
3498*44704f69SBart Van Assche perror("finishing io [read(2)] on sg device, error");
3499*44704f69SBart Van Assche return -1;
3500*44704f69SBart Van Assche }
3501*44704f69SBart Van Assche if (rep != (Rq_elem *)io_hdr.usr_ptr)
3502*44704f69SBart Van Assche err_exit(0, "sg_finish_io: bad usr_ptr, request-response mismatch\n");
3503*44704f69SBart Van Assche memcpy(&rep->io_hdr, &io_hdr, sizeof(struct sg_io_hdr));
3504*44704f69SBart Van Assche hp = &rep->io_hdr;
3505*44704f69SBart Van Assche
3506*44704f69SBart Van Assche res = sg_err_category3(hp);
3507*44704f69SBart Van Assche switch (res) {
3508*44704f69SBart Van Assche case SG_LIB_CAT_CLEAN:
3509*44704f69SBart Van Assche case SG_LIB_CAT_CONDITION_MET:
3510*44704f69SBart Van Assche break;
3511*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
3512*44704f69SBart Van Assche lk_chk_n_print3(cp, hp, false);
3513*44704f69SBart Van Assche break;
3514*44704f69SBart Van Assche case SG_LIB_CAT_ABORTED_COMMAND:
3515*44704f69SBart Van Assche case SG_LIB_CAT_UNIT_ATTENTION:
3516*44704f69SBart Van Assche if (clp->verbose > 3)
3517*44704f69SBart Van Assche lk_chk_n_print3(cp, hp, false);
3518*44704f69SBart Van Assche return res;
3519*44704f69SBart Van Assche case SG_LIB_CAT_MISCOMPARE:
3520*44704f69SBart Van Assche ++num_miscompare;
3521*44704f69SBart Van Assche // fall through
3522*44704f69SBart Van Assche case SG_LIB_CAT_NOT_READY:
3523*44704f69SBart Van Assche default:
3524*44704f69SBart Van Assche {
3525*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
3526*44704f69SBart Van Assche
3527*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64, cp, blk);
3528*44704f69SBart Van Assche lk_chk_n_print3(ebuff, hp, clp->verbose > 1);
3529*44704f69SBart Van Assche return res;
3530*44704f69SBart Van Assche }
3531*44704f69SBart Van Assche }
3532*44704f69SBart Van Assche if ((wr ? clp->out_flags.dio : clp->in_flags.dio) &&
3533*44704f69SBart Van Assche (! (hp->info & SG_INFO_DIRECT_IO_MASK)))
3534*44704f69SBart Van Assche rep->dio_incomplete_count = 1; /* count dios done as indirect IO */
3535*44704f69SBart Van Assche else
3536*44704f69SBart Van Assche rep->dio_incomplete_count = 0;
3537*44704f69SBart Van Assche rep->resid = hp->resid;
3538*44704f69SBart Van Assche if (clp->verbose > 3)
3539*44704f69SBart Van Assche pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id, cp);
3540*44704f69SBart Van Assche return 0;
3541*44704f69SBart Van Assche
3542*44704f69SBart Van Assche do_v4:
3543*44704f69SBart Van Assche if (clp->nmrqs > 0) {
3544*44704f69SBart Van Assche rep->resid = 0;
3545*44704f69SBart Van Assche return 0;
3546*44704f69SBart Van Assche }
3547*44704f69SBart Van Assche h4p = &rep->io_hdr4[xtrp ? xtrp->hpv4_ind : 0];
3548*44704f69SBart Van Assche h4p->request_extra = pack_id;
3549*44704f69SBart Van Assche if (mout_if) {
3550*44704f69SBart Van Assche h4p->info = 0;
3551*44704f69SBart Van Assche h4p->din_resid = 0;
3552*44704f69SBart Van Assche }
3553*44704f69SBart Van Assche while (((res = ioctl(fd, SG_IORECEIVE, h4p)) < 0) &&
3554*44704f69SBart Van Assche ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno))) {
3555*44704f69SBart Van Assche if (EAGAIN == errno) {
3556*44704f69SBart Van Assche ++num_fin_eagain;
3557*44704f69SBart Van Assche #ifdef SGH_DD_SNAP_DEV
3558*44704f69SBart Van Assche if (0 == (num_ebusy % 1000))
3559*44704f69SBart Van Assche sg_take_snap(fd, rep->id, (clp->verbose > 2));
3560*44704f69SBart Van Assche #endif
3561*44704f69SBart Van Assche } else if (EBUSY == errno) {
3562*44704f69SBart Van Assche ++num_ebusy;
3563*44704f69SBart Van Assche #ifdef SGH_DD_SNAP_DEV
3564*44704f69SBart Van Assche if (0 == (num_ebusy % 1000))
3565*44704f69SBart Van Assche sg_take_snap(fd, rep->id, (clp->verbose > 2));
3566*44704f69SBart Van Assche #endif
3567*44704f69SBart Van Assche }
3568*44704f69SBart Van Assche std::this_thread::yield();/* another thread may be able to progress */
3569*44704f69SBart Van Assche }
3570*44704f69SBart Van Assche if (res < 0) {
3571*44704f69SBart Van Assche perror("finishing io [SG_IORECEIVE] on sg device, error");
3572*44704f69SBart Van Assche return -1;
3573*44704f69SBart Van Assche }
3574*44704f69SBart Van Assche if (mout_if && (0 == h4p->info) && (0 == h4p->din_resid))
3575*44704f69SBart Van Assche goto all_good;
3576*44704f69SBart Van Assche if (rep != (Rq_elem *)h4p->usr_ptr)
3577*44704f69SBart Van Assche err_exit(0, "sg_finish_io: bad usr_ptr, request-response mismatch\n");
3578*44704f69SBart Van Assche res = sg_err_category_new(h4p->device_status, h4p->transport_status,
3579*44704f69SBart Van Assche h4p->driver_status,
3580*44704f69SBart Van Assche (const uint8_t *)h4p->response,
3581*44704f69SBart Van Assche h4p->response_len);
3582*44704f69SBart Van Assche switch (res) {
3583*44704f69SBart Van Assche case SG_LIB_CAT_CLEAN:
3584*44704f69SBart Van Assche case SG_LIB_CAT_CONDITION_MET:
3585*44704f69SBart Van Assche break;
3586*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
3587*44704f69SBart Van Assche lk_chk_n_print4(cp, h4p, false);
3588*44704f69SBart Van Assche break;
3589*44704f69SBart Van Assche case SG_LIB_CAT_ABORTED_COMMAND:
3590*44704f69SBart Van Assche case SG_LIB_CAT_UNIT_ATTENTION:
3591*44704f69SBart Van Assche if (clp->verbose > 3)
3592*44704f69SBart Van Assche lk_chk_n_print4(cp, h4p, false);
3593*44704f69SBart Van Assche return res;
3594*44704f69SBart Van Assche case SG_LIB_CAT_MISCOMPARE:
3595*44704f69SBart Van Assche ++num_miscompare;
3596*44704f69SBart Van Assche // fall through
3597*44704f69SBart Van Assche case SG_LIB_CAT_NOT_READY:
3598*44704f69SBart Van Assche default:
3599*44704f69SBart Van Assche {
3600*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
3601*44704f69SBart Van Assche
3602*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%s rq_id=%d, blk=%" PRId64, cp,
3603*44704f69SBart Van Assche pack_id, blk);
3604*44704f69SBart Van Assche lk_chk_n_print4(ebuff, h4p, clp->verbose > 1);
3605*44704f69SBart Van Assche if ((clp->verbose > 4) && h4p->info)
3606*44704f69SBart Van Assche pr2serr_lk(" info=0x%x sg_info_check=%d direct=%d "
3607*44704f69SBart Van Assche "detaching=%d aborted=%d\n", h4p->info,
3608*44704f69SBart Van Assche !!(h4p->info & SG_INFO_CHECK),
3609*44704f69SBart Van Assche !!(h4p->info & SG_INFO_DIRECT_IO),
3610*44704f69SBart Van Assche !!(h4p->info & SG_INFO_DEVICE_DETACHING),
3611*44704f69SBart Van Assche !!(h4p->info & SG_INFO_ABORTED));
3612*44704f69SBart Van Assche return res;
3613*44704f69SBart Van Assche }
3614*44704f69SBart Van Assche }
3615*44704f69SBart Van Assche if ((wr ? clp->out_flags.dio : clp->in_flags.dio) &&
3616*44704f69SBart Van Assche ! (h4p->info & SG_INFO_DIRECT_IO))
3617*44704f69SBart Van Assche rep->dio_incomplete_count = 1; /* count dios done as indirect IO */
3618*44704f69SBart Van Assche else
3619*44704f69SBart Van Assche rep->dio_incomplete_count = 0;
3620*44704f69SBart Van Assche rep->resid = h4p->din_resid;
3621*44704f69SBart Van Assche if (clp->verbose > 4) {
3622*44704f69SBart Van Assche pr2serr_lk("%s: tid,rq_id=%d,%d: completed %s\n", __func__, rep->id,
3623*44704f69SBart Van Assche pack_id, cp);
3624*44704f69SBart Van Assche if ((clp->verbose > 4) && h4p->info)
3625*44704f69SBart Van Assche pr2serr_lk(" info=0x%x sg_info_check=%d direct=%d "
3626*44704f69SBart Van Assche "detaching=%d aborted=%d\n", h4p->info,
3627*44704f69SBart Van Assche !!(h4p->info & SG_INFO_CHECK),
3628*44704f69SBart Van Assche !!(h4p->info & SG_INFO_DIRECT_IO),
3629*44704f69SBart Van Assche !!(h4p->info & SG_INFO_DEVICE_DETACHING),
3630*44704f69SBart Van Assche !!(h4p->info & SG_INFO_ABORTED));
3631*44704f69SBart Van Assche }
3632*44704f69SBart Van Assche all_good:
3633*44704f69SBart Van Assche return 0;
3634*44704f69SBart Van Assche }
3635*44704f69SBart Van Assche
3636*44704f69SBart Van Assche /* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */
3637*44704f69SBart Van Assche static int
sg_prepare_resbuf(int fd,bool is_in,struct global_collection * clp,uint8_t ** mmpp)3638*44704f69SBart Van Assche sg_prepare_resbuf(int fd, bool is_in, struct global_collection *clp,
3639*44704f69SBart Van Assche uint8_t **mmpp)
3640*44704f69SBart Van Assche {
3641*44704f69SBart Van Assche static bool done = false;
3642*44704f69SBart Van Assche bool def_res = is_in ? clp->in_flags.defres : clp->out_flags.defres;
3643*44704f69SBart Van Assche bool no_dur = is_in ? clp->in_flags.no_dur : clp->out_flags.no_dur;
3644*44704f69SBart Van Assche bool masync = is_in ? clp->in_flags.masync : clp->out_flags.masync;
3645*44704f69SBart Van Assche bool wq_excl = is_in ? clp->in_flags.wq_excl : clp->out_flags.wq_excl;
3646*44704f69SBart Van Assche bool skip_thresh = is_in ? clp->in_flags.no_thresh :
3647*44704f69SBart Van Assche clp->out_flags.no_thresh;
3648*44704f69SBart Van Assche int res, t;
3649*44704f69SBart Van Assche int num = 0;
3650*44704f69SBart Van Assche uint8_t *mmp;
3651*44704f69SBart Van Assche struct sg_extended_info sei {};
3652*44704f69SBart Van Assche struct sg_extended_info * seip = &sei;
3653*44704f69SBart Van Assche
3654*44704f69SBart Van Assche res = ioctl(fd, SG_GET_VERSION_NUM, &t);
3655*44704f69SBart Van Assche if ((res < 0) || (t < 40000)) {
3656*44704f69SBart Van Assche if (ioctl(fd, SG_GET_RESERVED_SIZE, &num) < 0) {
3657*44704f69SBart Van Assche perror("SG_GET_RESERVED_SIZE ioctl failed");
3658*44704f69SBart Van Assche return 0;
3659*44704f69SBart Van Assche }
3660*44704f69SBart Van Assche if (! done) {
3661*44704f69SBart Van Assche done = true;
3662*44704f69SBart Van Assche sg_version_lt_4 = true;
3663*44704f69SBart Van Assche pr2serr_lk("%ssg driver prior to 4.0.00, reduced functionality\n",
3664*44704f69SBart Van Assche my_name);
3665*44704f69SBart Van Assche }
3666*44704f69SBart Van Assche goto bypass;
3667*44704f69SBart Van Assche }
3668*44704f69SBart Van Assche if (! sg_version_ge_40045)
3669*44704f69SBart Van Assche goto bypass;
3670*44704f69SBart Van Assche if (clp->elem_sz >= 4096) {
3671*44704f69SBart Van Assche seip->sei_rd_mask |= SG_SEIM_SGAT_ELEM_SZ;
3672*44704f69SBart Van Assche res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
3673*44704f69SBart Van Assche if (res < 0)
3674*44704f69SBart Van Assche pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) rd "
3675*44704f69SBart Van Assche "error: %s\n", my_name, __func__, strerror(errno));
3676*44704f69SBart Van Assche if (clp->elem_sz != (int)seip->sgat_elem_sz) {
3677*44704f69SBart Van Assche memset(seip, 0, sizeof(*seip));
3678*44704f69SBart Van Assche seip->sei_wr_mask |= SG_SEIM_SGAT_ELEM_SZ;
3679*44704f69SBart Van Assche seip->sgat_elem_sz = clp->elem_sz;
3680*44704f69SBart Van Assche res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
3681*44704f69SBart Van Assche if (res < 0)
3682*44704f69SBart Van Assche pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(SGAT_ELEM_SZ) wr "
3683*44704f69SBart Van Assche "error: %s\n", my_name, __func__, strerror(errno));
3684*44704f69SBart Van Assche }
3685*44704f69SBart Van Assche }
3686*44704f69SBart Van Assche if (no_dur || masync || skip_thresh) {
3687*44704f69SBart Van Assche memset(seip, 0, sizeof(*seip));
3688*44704f69SBart Van Assche seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
3689*44704f69SBart Van Assche if (no_dur) {
3690*44704f69SBart Van Assche seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_NO_DURATION;
3691*44704f69SBart Van Assche seip->ctl_flags |= SG_CTL_FLAGM_NO_DURATION;
3692*44704f69SBart Van Assche }
3693*44704f69SBart Van Assche if (masync) {
3694*44704f69SBart Van Assche seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_MORE_ASYNC;
3695*44704f69SBart Van Assche seip->ctl_flags |= SG_CTL_FLAGM_MORE_ASYNC;
3696*44704f69SBart Van Assche }
3697*44704f69SBart Van Assche if (wq_excl) {
3698*44704f69SBart Van Assche seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_EXCL_WAITQ;
3699*44704f69SBart Van Assche seip->ctl_flags |= SG_CTL_FLAGM_EXCL_WAITQ;
3700*44704f69SBart Van Assche }
3701*44704f69SBart Van Assche if (skip_thresh) {
3702*44704f69SBart Van Assche seip->tot_fd_thresh = 0;
3703*44704f69SBart Van Assche sei.sei_wr_mask |= SG_SEIM_TOT_FD_THRESH;
3704*44704f69SBart Van Assche }
3705*44704f69SBart Van Assche res = ioctl(fd, SG_SET_GET_EXTENDED, seip);
3706*44704f69SBart Van Assche if (res < 0)
3707*44704f69SBart Van Assche pr2serr_lk("%s%s: SG_SET_GET_EXTENDED(NO_DURATION) error: %s\n",
3708*44704f69SBart Van Assche my_name, __func__, strerror(errno));
3709*44704f69SBart Van Assche }
3710*44704f69SBart Van Assche bypass:
3711*44704f69SBart Van Assche if (! def_res) {
3712*44704f69SBart Van Assche num = clp->bs * clp->bpt;
3713*44704f69SBart Van Assche res = ioctl(fd, SG_SET_RESERVED_SIZE, &num);
3714*44704f69SBart Van Assche if (res < 0) {
3715*44704f69SBart Van Assche perror("sgh_dd: SG_SET_RESERVED_SIZE error");
3716*44704f69SBart Van Assche return 0;
3717*44704f69SBart Van Assche } else {
3718*44704f69SBart Van Assche int nn;
3719*44704f69SBart Van Assche
3720*44704f69SBart Van Assche res = ioctl(fd, SG_GET_RESERVED_SIZE, &nn);
3721*44704f69SBart Van Assche if (res < 0) {
3722*44704f69SBart Van Assche perror("sgh_dd: SG_GET_RESERVED_SIZE error");
3723*44704f69SBart Van Assche return 0;
3724*44704f69SBart Van Assche }
3725*44704f69SBart Van Assche if (nn < num) {
3726*44704f69SBart Van Assche pr2serr_lk("%s: SG_GET_RESERVED_SIZE shows size truncated, "
3727*44704f69SBart Van Assche "wanted %d got %d\n", __func__, num, nn);
3728*44704f69SBart Van Assche return 0;
3729*44704f69SBart Van Assche }
3730*44704f69SBart Van Assche }
3731*44704f69SBart Van Assche if (mmpp) {
3732*44704f69SBart Van Assche mmp = (uint8_t *)mmap(NULL, num, PROT_READ | PROT_WRITE,
3733*44704f69SBart Van Assche MAP_SHARED, fd, 0);
3734*44704f69SBart Van Assche if (MAP_FAILED == mmp) {
3735*44704f69SBart Van Assche int err = errno;
3736*44704f69SBart Van Assche
3737*44704f69SBart Van Assche pr2serr_lk("%s%s: sz=%d, fd=%d, mmap() failed: %s\n",
3738*44704f69SBart Van Assche my_name, __func__, num, fd, strerror(err));
3739*44704f69SBart Van Assche return 0;
3740*44704f69SBart Van Assche }
3741*44704f69SBart Van Assche *mmpp = mmp;
3742*44704f69SBart Van Assche }
3743*44704f69SBart Van Assche }
3744*44704f69SBart Van Assche t = 1;
3745*44704f69SBart Van Assche res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t);
3746*44704f69SBart Van Assche if (res < 0)
3747*44704f69SBart Van Assche perror("sgh_dd: SG_SET_FORCE_PACK_ID error");
3748*44704f69SBart Van Assche if (clp->unit_nanosec && sg_version_ge_40045) {
3749*44704f69SBart Van Assche memset(seip, 0, sizeof(*seip));
3750*44704f69SBart Van Assche seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
3751*44704f69SBart Van Assche seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
3752*44704f69SBart Van Assche seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
3753*44704f69SBart Van Assche if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
3754*44704f69SBart Van Assche pr2serr_lk("ioctl(EXTENDED(TIME_IN_NS)) failed, errno=%d %s\n",
3755*44704f69SBart Van Assche errno, strerror(errno));
3756*44704f69SBart Van Assche }
3757*44704f69SBart Van Assche }
3758*44704f69SBart Van Assche t = 1;
3759*44704f69SBart Van Assche res = ioctl(fd, SG_SET_DEBUG, &t); /* more info in the kernel log */
3760*44704f69SBart Van Assche if (res < 0)
3761*44704f69SBart Van Assche perror("sgs_dd: SG_SET_DEBUG error");
3762*44704f69SBart Van Assche return (res < 0) ? 0 : num;
3763*44704f69SBart Van Assche }
3764*44704f69SBart Van Assche
3765*44704f69SBart Van Assche static bool
process_flags(const char * arg,struct flags_t * fp)3766*44704f69SBart Van Assche process_flags(const char * arg, struct flags_t * fp)
3767*44704f69SBart Van Assche {
3768*44704f69SBart Van Assche char buff[256];
3769*44704f69SBart Van Assche char * cp;
3770*44704f69SBart Van Assche char * np;
3771*44704f69SBart Van Assche
3772*44704f69SBart Van Assche strncpy(buff, arg, sizeof(buff));
3773*44704f69SBart Van Assche buff[sizeof(buff) - 1] = '\0';
3774*44704f69SBart Van Assche if ('\0' == buff[0]) {
3775*44704f69SBart Van Assche pr2serr("no flag found\n");
3776*44704f69SBart Van Assche return false;
3777*44704f69SBart Van Assche }
3778*44704f69SBart Van Assche cp = buff;
3779*44704f69SBart Van Assche do {
3780*44704f69SBart Van Assche np = strchr(cp, ',');
3781*44704f69SBart Van Assche if (np)
3782*44704f69SBart Van Assche *np++ = '\0';
3783*44704f69SBart Van Assche if (0 == strcmp(cp, "00"))
3784*44704f69SBart Van Assche fp->zero = true;
3785*44704f69SBart Van Assche else if (0 == strcmp(cp, "append"))
3786*44704f69SBart Van Assche fp->append = true;
3787*44704f69SBart Van Assche else if (0 == strcmp(cp, "coe"))
3788*44704f69SBart Van Assche fp->coe = true;
3789*44704f69SBart Van Assche else if (0 == strcmp(cp, "defres"))
3790*44704f69SBart Van Assche fp->defres = true;
3791*44704f69SBart Van Assche else if (0 == strcmp(cp, "dio"))
3792*44704f69SBart Van Assche fp->dio = true;
3793*44704f69SBart Van Assche else if (0 == strcmp(cp, "direct"))
3794*44704f69SBart Van Assche fp->direct = true;
3795*44704f69SBart Van Assche else if (0 == strcmp(cp, "dpo"))
3796*44704f69SBart Van Assche fp->dpo = true;
3797*44704f69SBart Van Assche else if (0 == strcmp(cp, "dsync"))
3798*44704f69SBart Van Assche fp->dsync = true;
3799*44704f69SBart Van Assche else if (0 == strcmp(cp, "excl"))
3800*44704f69SBart Van Assche fp->excl = true;
3801*44704f69SBart Van Assche else if (0 == strcmp(cp, "ff"))
3802*44704f69SBart Van Assche fp->ff = true;
3803*44704f69SBart Van Assche else if (0 == strcmp(cp, "fua"))
3804*44704f69SBart Van Assche fp->fua = true;
3805*44704f69SBart Van Assche else if (0 == strcmp(cp, "hipri"))
3806*44704f69SBart Van Assche fp->polled = true;
3807*44704f69SBart Van Assche else if (0 == strcmp(cp, "masync"))
3808*44704f69SBart Van Assche fp->masync = true;
3809*44704f69SBart Van Assche else if (0 == strcmp(cp, "mmap"))
3810*44704f69SBart Van Assche ++fp->mmap; /* mmap > 1 stops munmap() being called */
3811*44704f69SBart Van Assche else if (0 == strcmp(cp, "mrq_imm"))
3812*44704f69SBart Van Assche fp->mrq_immed = true;
3813*44704f69SBart Van Assche else if (0 == strcmp(cp, "mrq_immed"))
3814*44704f69SBart Van Assche fp->mrq_immed = true;
3815*44704f69SBart Van Assche else if (0 == strcmp(cp, "mrq_svb"))
3816*44704f69SBart Van Assche fp->mrq_svb = true;
3817*44704f69SBart Van Assche else if (0 == strcmp(cp, "nodur"))
3818*44704f69SBart Van Assche fp->no_dur = true;
3819*44704f69SBart Van Assche else if (0 == strcmp(cp, "no_dur"))
3820*44704f69SBart Van Assche fp->no_dur = true;
3821*44704f69SBart Van Assche else if (0 == strcmp(cp, "nocreat"))
3822*44704f69SBart Van Assche fp->nocreat = true;
3823*44704f69SBart Van Assche else if (0 == strcmp(cp, "noshare"))
3824*44704f69SBart Van Assche fp->noshare = true;
3825*44704f69SBart Van Assche else if (0 == strcmp(cp, "no_share"))
3826*44704f69SBart Van Assche fp->noshare = true;
3827*44704f69SBart Van Assche else if (0 == strcmp(cp, "no_thresh"))
3828*44704f69SBart Van Assche fp->no_thresh = true;
3829*44704f69SBart Van Assche else if (0 == strcmp(cp, "no-thresh"))
3830*44704f69SBart Van Assche fp->no_thresh = true;
3831*44704f69SBart Van Assche else if (0 == strcmp(cp, "nothresh"))
3832*44704f69SBart Van Assche fp->no_thresh = true;
3833*44704f69SBart Van Assche else if (0 == strcmp(cp, "no_unshare"))
3834*44704f69SBart Van Assche fp->no_unshare = true;
3835*44704f69SBart Van Assche else if (0 == strcmp(cp, "no-unshare"))
3836*44704f69SBart Van Assche fp->no_unshare = true;
3837*44704f69SBart Van Assche else if (0 == strcmp(cp, "no_waitq"))
3838*44704f69SBart Van Assche fp->no_waitq = true;
3839*44704f69SBart Van Assche else if (0 == strcmp(cp, "no-waitq"))
3840*44704f69SBart Van Assche fp->no_waitq = true;
3841*44704f69SBart Van Assche else if (0 == strcmp(cp, "nowaitq"))
3842*44704f69SBart Van Assche fp->no_waitq = true;
3843*44704f69SBart Van Assche else if (0 == strcmp(cp, "noxfer"))
3844*44704f69SBart Van Assche fp->noxfer = true;
3845*44704f69SBart Van Assche else if (0 == strcmp(cp, "no_xfer"))
3846*44704f69SBart Van Assche fp->noxfer = true;
3847*44704f69SBart Van Assche else if (0 == strcmp(cp, "null"))
3848*44704f69SBart Van Assche ;
3849*44704f69SBart Van Assche else if (0 == strcmp(cp, "polled"))
3850*44704f69SBart Van Assche fp->polled = true;
3851*44704f69SBart Van Assche else if (0 == strcmp(cp, "qhead"))
3852*44704f69SBart Van Assche fp->qhead = true;
3853*44704f69SBart Van Assche else if (0 == strcmp(cp, "qtail"))
3854*44704f69SBart Van Assche fp->qtail = true;
3855*44704f69SBart Van Assche else if (0 == strcmp(cp, "random"))
3856*44704f69SBart Van Assche fp->random = true;
3857*44704f69SBart Van Assche else if ((0 == strcmp(cp, "mout_if")) || (0 == strcmp(cp, "mout-if")))
3858*44704f69SBart Van Assche fp->mout_if = true;
3859*44704f69SBart Van Assche else if (0 == strcmp(cp, "same_fds"))
3860*44704f69SBart Van Assche fp->same_fds = true;
3861*44704f69SBart Van Assche else if (0 == strcmp(cp, "swait"))
3862*44704f69SBart Van Assche fp->swait = true;
3863*44704f69SBart Van Assche else if (0 == strcmp(cp, "v3"))
3864*44704f69SBart Van Assche fp->v3 = true;
3865*44704f69SBart Van Assche else if (0 == strcmp(cp, "v4")) {
3866*44704f69SBart Van Assche fp->v4 = true;
3867*44704f69SBart Van Assche fp->v4_given = true;
3868*44704f69SBart Van Assche } else if (0 == strcmp(cp, "wq_excl"))
3869*44704f69SBart Van Assche fp->wq_excl = true;
3870*44704f69SBart Van Assche else {
3871*44704f69SBart Van Assche pr2serr("unrecognised flag: %s\n", cp);
3872*44704f69SBart Van Assche return false;
3873*44704f69SBart Van Assche }
3874*44704f69SBart Van Assche cp = np;
3875*44704f69SBart Van Assche } while (cp);
3876*44704f69SBart Van Assche return true;
3877*44704f69SBart Van Assche }
3878*44704f69SBart Van Assche
3879*44704f69SBart Van Assche /* Returns the number of times 'ch' is found in string 's' given the
3880*44704f69SBart Van Assche * string's length. */
3881*44704f69SBart Van Assche static int
num_chs_in_str(const char * s,int slen,int ch)3882*44704f69SBart Van Assche num_chs_in_str(const char * s, int slen, int ch)
3883*44704f69SBart Van Assche {
3884*44704f69SBart Van Assche int res = 0;
3885*44704f69SBart Van Assche
3886*44704f69SBart Van Assche while (--slen >= 0) {
3887*44704f69SBart Van Assche if (ch == s[slen])
3888*44704f69SBart Van Assche ++res;
3889*44704f69SBart Van Assche }
3890*44704f69SBart Van Assche return res;
3891*44704f69SBart Van Assche }
3892*44704f69SBart Van Assche
3893*44704f69SBart Van Assche static int
sg_in_open(struct global_collection * clp,const char * inf,uint8_t ** mmpp,int * mmap_lenp)3894*44704f69SBart Van Assche sg_in_open(struct global_collection *clp, const char *inf, uint8_t **mmpp,
3895*44704f69SBart Van Assche int * mmap_lenp)
3896*44704f69SBart Van Assche {
3897*44704f69SBart Van Assche int fd, n;
3898*44704f69SBart Van Assche int flags = O_RDWR;
3899*44704f69SBart Van Assche
3900*44704f69SBart Van Assche if (clp->in_flags.direct)
3901*44704f69SBart Van Assche flags |= O_DIRECT;
3902*44704f69SBart Van Assche if (clp->in_flags.excl)
3903*44704f69SBart Van Assche flags |= O_EXCL;
3904*44704f69SBart Van Assche if (clp->in_flags.dsync)
3905*44704f69SBart Van Assche flags |= O_SYNC;
3906*44704f69SBart Van Assche
3907*44704f69SBart Van Assche if ((fd = open(inf, flags)) < 0) {
3908*44704f69SBart Van Assche int err = errno;
3909*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
3910*44704f69SBart Van Assche
3911*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for sg reading",
3912*44704f69SBart Van Assche __func__, inf);
3913*44704f69SBart Van Assche perror(ebuff);
3914*44704f69SBart Van Assche return -sg_convert_errno(err);
3915*44704f69SBart Van Assche }
3916*44704f69SBart Van Assche n = sg_prepare_resbuf(fd, true, clp, mmpp);
3917*44704f69SBart Van Assche if (n <= 0) {
3918*44704f69SBart Van Assche close(fd);
3919*44704f69SBart Van Assche return -SG_LIB_FILE_ERROR;
3920*44704f69SBart Van Assche }
3921*44704f69SBart Van Assche if (clp->noshare)
3922*44704f69SBart Van Assche sg_noshare_enlarge(fd, clp->verbose > 3);
3923*44704f69SBart Van Assche if (mmap_lenp)
3924*44704f69SBart Van Assche *mmap_lenp = n;
3925*44704f69SBart Van Assche return fd;
3926*44704f69SBart Van Assche }
3927*44704f69SBart Van Assche
3928*44704f69SBart Van Assche static int
sg_out_open(struct global_collection * clp,const char * outf,uint8_t ** mmpp,int * mmap_lenp)3929*44704f69SBart Van Assche sg_out_open(struct global_collection *clp, const char *outf, uint8_t **mmpp,
3930*44704f69SBart Van Assche int * mmap_lenp)
3931*44704f69SBart Van Assche {
3932*44704f69SBart Van Assche int fd, n;
3933*44704f69SBart Van Assche int flags = O_RDWR;
3934*44704f69SBart Van Assche
3935*44704f69SBart Van Assche if (clp->out_flags.direct)
3936*44704f69SBart Van Assche flags |= O_DIRECT;
3937*44704f69SBart Van Assche if (clp->out_flags.excl)
3938*44704f69SBart Van Assche flags |= O_EXCL;
3939*44704f69SBart Van Assche if (clp->out_flags.dsync)
3940*44704f69SBart Van Assche flags |= O_SYNC;
3941*44704f69SBart Van Assche
3942*44704f69SBart Van Assche if ((fd = open(outf, flags)) < 0) {
3943*44704f69SBart Van Assche int err = errno;
3944*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
3945*44704f69SBart Van Assche
3946*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for sg %s",
3947*44704f69SBart Van Assche __func__, outf, (clp->verify ? "verifying" : "writing"));
3948*44704f69SBart Van Assche perror(ebuff);
3949*44704f69SBart Van Assche return -sg_convert_errno(err);
3950*44704f69SBart Van Assche }
3951*44704f69SBart Van Assche n = sg_prepare_resbuf(fd, false, clp, mmpp);
3952*44704f69SBart Van Assche if (n <= 0) {
3953*44704f69SBart Van Assche close(fd);
3954*44704f69SBart Van Assche return -SG_LIB_FILE_ERROR;
3955*44704f69SBart Van Assche }
3956*44704f69SBart Van Assche if (clp->noshare)
3957*44704f69SBart Van Assche sg_noshare_enlarge(fd, clp->verbose > 3);
3958*44704f69SBart Van Assche if (mmap_lenp)
3959*44704f69SBart Van Assche *mmap_lenp = n;
3960*44704f69SBart Van Assche return fd;
3961*44704f69SBart Van Assche }
3962*44704f69SBart Van Assche
3963*44704f69SBart Van Assche /* Process arguments given to 'conv=" option. Returns 0 on success,
3964*44704f69SBart Van Assche * 1 on error. */
3965*44704f69SBart Van Assche static int
process_conv(const char * arg,struct flags_t * ifp,struct flags_t * ofp)3966*44704f69SBart Van Assche process_conv(const char * arg, struct flags_t * ifp, struct flags_t * ofp)
3967*44704f69SBart Van Assche {
3968*44704f69SBart Van Assche char buff[256];
3969*44704f69SBart Van Assche char * cp;
3970*44704f69SBart Van Assche char * np;
3971*44704f69SBart Van Assche
3972*44704f69SBart Van Assche strncpy(buff, arg, sizeof(buff));
3973*44704f69SBart Van Assche buff[sizeof(buff) - 1] = '\0';
3974*44704f69SBart Van Assche if ('\0' == buff[0]) {
3975*44704f69SBart Van Assche pr2serr("no conversions found\n");
3976*44704f69SBart Van Assche return 1;
3977*44704f69SBart Van Assche }
3978*44704f69SBart Van Assche cp = buff;
3979*44704f69SBart Van Assche do {
3980*44704f69SBart Van Assche np = strchr(cp, ',');
3981*44704f69SBart Van Assche if (np)
3982*44704f69SBart Van Assche *np++ = '\0';
3983*44704f69SBart Van Assche if (0 == strcmp(cp, "nocreat"))
3984*44704f69SBart Van Assche ofp->nocreat = true;
3985*44704f69SBart Van Assche else if (0 == strcmp(cp, "noerror"))
3986*44704f69SBart Van Assche ifp->coe = true; /* will still fail on write error */
3987*44704f69SBart Van Assche else if (0 == strcmp(cp, "notrunc"))
3988*44704f69SBart Van Assche ; /* this is the default action of sg_dd so ignore */
3989*44704f69SBart Van Assche else if (0 == strcmp(cp, "null"))
3990*44704f69SBart Van Assche ;
3991*44704f69SBart Van Assche else if (0 == strcmp(cp, "sync"))
3992*44704f69SBart Van Assche ; /* dd(susv4): pad errored block(s) with zeros but sg_dd does
3993*44704f69SBart Van Assche * that by default. Typical dd use: 'conv=noerror,sync' */
3994*44704f69SBart Van Assche else {
3995*44704f69SBart Van Assche pr2serr("unrecognised flag: %s\n", cp);
3996*44704f69SBart Van Assche return 1;
3997*44704f69SBart Van Assche }
3998*44704f69SBart Van Assche cp = np;
3999*44704f69SBart Van Assche } while (cp);
4000*44704f69SBart Van Assche return 0;
4001*44704f69SBart Van Assche }
4002*44704f69SBart Van Assche
4003*44704f69SBart Van Assche #define STR_SZ 1024
4004*44704f69SBart Van Assche #define INOUTF_SZ 512
4005*44704f69SBart Van Assche
4006*44704f69SBart Van Assche static int
parse_cmdline_sanity(int argc,char * argv[],struct global_collection * clp,char * inf,char * outf,char * out2f,char * outregf)4007*44704f69SBart Van Assche parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp,
4008*44704f69SBart Van Assche char * inf, char * outf, char * out2f, char * outregf)
4009*44704f69SBart Van Assche {
4010*44704f69SBart Van Assche bool verbose_given = false;
4011*44704f69SBart Van Assche bool version_given = false;
4012*44704f69SBart Van Assche bool verify_given = false;
4013*44704f69SBart Van Assche bool bpt_given = false;
4014*44704f69SBart Van Assche int ibs = 0;
4015*44704f69SBart Van Assche int obs = 0;
4016*44704f69SBart Van Assche int k, keylen, n, res;
4017*44704f69SBart Van Assche char str[STR_SZ];
4018*44704f69SBart Van Assche char * key;
4019*44704f69SBart Van Assche char * buf;
4020*44704f69SBart Van Assche const char * cp;
4021*44704f69SBart Van Assche
4022*44704f69SBart Van Assche for (k = 1; k < argc; k++) {
4023*44704f69SBart Van Assche if (argv[k]) {
4024*44704f69SBart Van Assche strncpy(str, argv[k], STR_SZ);
4025*44704f69SBart Van Assche str[STR_SZ - 1] = '\0';
4026*44704f69SBart Van Assche }
4027*44704f69SBart Van Assche else
4028*44704f69SBart Van Assche continue;
4029*44704f69SBart Van Assche for (key = str, buf = key; *buf && *buf != '=';)
4030*44704f69SBart Van Assche buf++;
4031*44704f69SBart Van Assche if (*buf)
4032*44704f69SBart Van Assche *buf++ = '\0';
4033*44704f69SBart Van Assche keylen = strlen(key);
4034*44704f69SBart Van Assche if (0 == strcmp(key, "ae")) {
4035*44704f69SBart Van Assche clp->aen = sg_get_num(buf);
4036*44704f69SBart Van Assche if (clp->aen < 0) {
4037*44704f69SBart Van Assche pr2serr("%sbad AEN argument to 'ae=', want 0 or higher\n",
4038*44704f69SBart Van Assche my_name);
4039*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4040*44704f69SBart Van Assche }
4041*44704f69SBart Van Assche cp = strchr(buf, ',');
4042*44704f69SBart Van Assche if (cp) {
4043*44704f69SBart Van Assche clp->m_aen = sg_get_num(cp + 1);
4044*44704f69SBart Van Assche if (clp->m_aen < 0) {
4045*44704f69SBart Van Assche pr2serr("%sbad MAEN argument to 'ae=', want 0 or "
4046*44704f69SBart Van Assche "higher\n", my_name);
4047*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4048*44704f69SBart Van Assche }
4049*44704f69SBart Van Assche clp->m_aen_given = true;
4050*44704f69SBart Van Assche }
4051*44704f69SBart Van Assche clp->aen_given = true;
4052*44704f69SBart Van Assche } else if (0 == strcmp(key, "bpt")) {
4053*44704f69SBart Van Assche clp->bpt = sg_get_num(buf);
4054*44704f69SBart Van Assche if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) {
4055*44704f69SBart Van Assche pr2serr("%sbad argument to 'bpt='\n", my_name);
4056*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4057*44704f69SBart Van Assche }
4058*44704f69SBart Van Assche bpt_given = true;
4059*44704f69SBart Van Assche } else if (0 == strcmp(key, "bs")) {
4060*44704f69SBart Van Assche clp->bs = sg_get_num(buf);
4061*44704f69SBart Van Assche if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) {
4062*44704f69SBart Van Assche pr2serr("%sbad argument to 'bs='\n", my_name);
4063*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4064*44704f69SBart Van Assche }
4065*44704f69SBart Van Assche } else if (0 == strcmp(key, "cdbsz")) {
4066*44704f69SBart Van Assche clp->cdbsz_in = sg_get_num(buf);
4067*44704f69SBart Van Assche if ((clp->cdbsz_in < 6) || (clp->cdbsz_in > 32)) {
4068*44704f69SBart Van Assche pr2serr("%s'cdbsz' expects 6, 10, 12, 16 or 32\n", my_name);
4069*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4070*44704f69SBart Van Assche }
4071*44704f69SBart Van Assche clp->cdbsz_out = clp->cdbsz_in;
4072*44704f69SBart Van Assche clp->cdbsz_given = true;
4073*44704f69SBart Van Assche } else if (0 == strcmp(key, "coe")) {
4074*44704f69SBart Van Assche clp->in_flags.coe = !! sg_get_num(buf);
4075*44704f69SBart Van Assche clp->out_flags.coe = clp->in_flags.coe;
4076*44704f69SBart Van Assche } else if (0 == strcmp(key, "conv")) {
4077*44704f69SBart Van Assche if (process_conv(buf, &clp->in_flags, &clp->out_flags)) {
4078*44704f69SBart Van Assche pr2serr("%s: bad argument to 'conv='\n", my_name);
4079*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4080*44704f69SBart Van Assche }
4081*44704f69SBart Van Assche } else if (0 == strcmp(key, "count")) {
4082*44704f69SBart Van Assche if (0 != strcmp("-1", buf)) {
4083*44704f69SBart Van Assche dd_count = sg_get_llnum(buf);
4084*44704f69SBart Van Assche if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) {
4085*44704f69SBart Van Assche pr2serr("%sbad argument to 'count='\n", my_name);
4086*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4087*44704f69SBart Van Assche }
4088*44704f69SBart Van Assche } /* treat 'count=-1' as calculate count (same as not given) */
4089*44704f69SBart Van Assche } else if (0 == strcmp(key, "dio")) {
4090*44704f69SBart Van Assche clp->in_flags.dio = !! sg_get_num(buf);
4091*44704f69SBart Van Assche clp->out_flags.dio = clp->in_flags.dio;
4092*44704f69SBart Van Assche } else if (0 == strcmp(key, "elemsz_kb")) {
4093*44704f69SBart Van Assche n = sg_get_num(buf);
4094*44704f69SBart Van Assche if (n < 1) {
4095*44704f69SBart Van Assche pr2serr("elemsz_kb=EKB wants an integer > 0\n");
4096*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4097*44704f69SBart Van Assche }
4098*44704f69SBart Van Assche if (n & (n - 1)) {
4099*44704f69SBart Van Assche pr2serr("elemsz_kb=EKB wants EKB to be power of 2\n");
4100*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4101*44704f69SBart Van Assche }
4102*44704f69SBart Van Assche clp->elem_sz = n * 1024;
4103*44704f69SBart Van Assche } else if ((0 == strcmp(key, "fail_mask")) ||
4104*44704f69SBart Van Assche (0 == strcmp(key, "fail-mask"))) {
4105*44704f69SBart Van Assche clp->fail_mask = sg_get_num(buf);
4106*44704f69SBart Van Assche if (clp->fail_mask < 0) {
4107*44704f69SBart Van Assche pr2serr("fail_mask: couldn't decode argument\n");
4108*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4109*44704f69SBart Van Assche }
4110*44704f69SBart Van Assche } else if (0 == strcmp(key, "fua")) {
4111*44704f69SBart Van Assche n = sg_get_num(buf);
4112*44704f69SBart Van Assche if (n & 1)
4113*44704f69SBart Van Assche clp->out_flags.fua = true;
4114*44704f69SBart Van Assche if (n & 2)
4115*44704f69SBart Van Assche clp->in_flags.fua = true;
4116*44704f69SBart Van Assche } else if (0 == strcmp(key, "ibs")) {
4117*44704f69SBart Van Assche ibs = sg_get_num(buf);
4118*44704f69SBart Van Assche if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) {
4119*44704f69SBart Van Assche pr2serr("%sbad argument to 'ibs='\n", my_name);
4120*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4121*44704f69SBart Van Assche }
4122*44704f69SBart Van Assche } else if (0 == strcmp(key, "if")) {
4123*44704f69SBart Van Assche if ('\0' != inf[0]) {
4124*44704f69SBart Van Assche pr2serr("Second 'if=' argument??\n");
4125*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4126*44704f69SBart Van Assche } else {
4127*44704f69SBart Van Assche memcpy(inf, buf, INOUTF_SZ);
4128*44704f69SBart Van Assche inf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */
4129*44704f69SBart Van Assche }
4130*44704f69SBart Van Assche } else if (0 == strcmp(key, "iflag")) {
4131*44704f69SBart Van Assche if (! process_flags(buf, &clp->in_flags)) {
4132*44704f69SBart Van Assche pr2serr("%sbad argument to 'iflag='\n", my_name);
4133*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4134*44704f69SBart Van Assche }
4135*44704f69SBart Van Assche } else if (0 == strcmp(key, "mrq")) {
4136*44704f69SBart Van Assche if (isdigit(buf[0]))
4137*44704f69SBart Van Assche cp = buf;
4138*44704f69SBart Van Assche else {
4139*44704f69SBart Van Assche if ('I' == isupper(buf[0]))
4140*44704f69SBart Van Assche clp->is_mrq_i = true;
4141*44704f69SBart Van Assche else if ('O' == isupper(buf[0]))
4142*44704f69SBart Van Assche clp->is_mrq_o = true;
4143*44704f69SBart Van Assche else {
4144*44704f69SBart Van Assche pr2serr("%sonly mrq=i,NRQS or mrq=o,NRQS allowed here\n",
4145*44704f69SBart Van Assche my_name);
4146*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4147*44704f69SBart Van Assche }
4148*44704f69SBart Van Assche cp = strchr(buf, ',');
4149*44704f69SBart Van Assche ++cp;
4150*44704f69SBart Van Assche }
4151*44704f69SBart Van Assche clp->nmrqs = sg_get_num(cp);
4152*44704f69SBart Van Assche if (clp->nmrqs < 0) {
4153*44704f69SBart Van Assche pr2serr("%sbad argument to 'mrq='\n", my_name);
4154*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4155*44704f69SBart Van Assche }
4156*44704f69SBart Van Assche cp = strchr(cp, ',');
4157*44704f69SBart Van Assche if (cp && ('C' == toupper(cp[1])))
4158*44704f69SBart Van Assche clp->mrq_cmds = true;
4159*44704f69SBart Van Assche } else if (0 == strcmp(key, "noshare")) {
4160*44704f69SBart Van Assche clp->noshare = !! sg_get_num(buf);
4161*44704f69SBart Van Assche } else if (0 == strcmp(key, "obs")) {
4162*44704f69SBart Van Assche obs = sg_get_num(buf);
4163*44704f69SBart Van Assche if ((obs < 0) || (obs > MAX_BPT_VALUE)) {
4164*44704f69SBart Van Assche pr2serr("%sbad argument to 'obs='\n", my_name);
4165*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4166*44704f69SBart Van Assche }
4167*44704f69SBart Van Assche } else if (strcmp(key, "of2") == 0) {
4168*44704f69SBart Van Assche if ('\0' != out2f[0]) {
4169*44704f69SBart Van Assche pr2serr("Second OFILE2 argument??\n");
4170*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
4171*44704f69SBart Van Assche } else {
4172*44704f69SBart Van Assche memcpy(out2f, buf, INOUTF_SZ);
4173*44704f69SBart Van Assche out2f[INOUTF_SZ - 1] = '\0'; /* noisy compiler */
4174*44704f69SBart Van Assche }
4175*44704f69SBart Van Assche } else if (strcmp(key, "ofreg") == 0) {
4176*44704f69SBart Van Assche if ('\0' != outregf[0]) {
4177*44704f69SBart Van Assche pr2serr("Second OFREG argument??\n");
4178*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
4179*44704f69SBart Van Assche } else {
4180*44704f69SBart Van Assche memcpy(outregf, buf, INOUTF_SZ);
4181*44704f69SBart Van Assche outregf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */
4182*44704f69SBart Van Assche }
4183*44704f69SBart Van Assche } else if (0 == strcmp(key, "ofsplit")) {
4184*44704f69SBart Van Assche clp->ofsplit = sg_get_num(buf);
4185*44704f69SBart Van Assche if (-1 == clp->ofsplit) {
4186*44704f69SBart Van Assche pr2serr("%sbad argument to 'ofsplit='\n", my_name);
4187*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4188*44704f69SBart Van Assche }
4189*44704f69SBart Van Assche } else if (strcmp(key, "of") == 0) {
4190*44704f69SBart Van Assche if ('\0' != outf[0]) {
4191*44704f69SBart Van Assche pr2serr("Second 'of=' argument??\n");
4192*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4193*44704f69SBart Van Assche } else {
4194*44704f69SBart Van Assche memcpy(outf, buf, INOUTF_SZ);
4195*44704f69SBart Van Assche outf[INOUTF_SZ - 1] = '\0'; /* noisy compiler */
4196*44704f69SBart Van Assche }
4197*44704f69SBart Van Assche } else if (0 == strcmp(key, "oflag")) {
4198*44704f69SBart Van Assche if (! process_flags(buf, &clp->out_flags)) {
4199*44704f69SBart Van Assche pr2serr("%sbad argument to 'oflag='\n", my_name);
4200*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4201*44704f69SBart Van Assche }
4202*44704f69SBart Van Assche } else if (0 == strcmp(key, "sdt")) {
4203*44704f69SBart Van Assche cp = strchr(buf, ',');
4204*44704f69SBart Van Assche n = sg_get_num(buf);
4205*44704f69SBart Van Assche if (n < 0) {
4206*44704f69SBart Van Assche pr2serr("%sbad argument to 'sdt=CRT[,ICT]'\n", my_name);
4207*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4208*44704f69SBart Van Assche }
4209*44704f69SBart Van Assche clp->sdt_crt = n;
4210*44704f69SBart Van Assche if (cp) {
4211*44704f69SBart Van Assche n = sg_get_num(cp + 1);
4212*44704f69SBart Van Assche if (n < 0) {
4213*44704f69SBart Van Assche pr2serr("%sbad 2nd argument to 'sdt=CRT,ICT'\n",
4214*44704f69SBart Van Assche my_name);
4215*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4216*44704f69SBart Van Assche }
4217*44704f69SBart Van Assche clp->sdt_ict = n;
4218*44704f69SBart Van Assche }
4219*44704f69SBart Van Assche } else if (0 == strcmp(key, "seek")) {
4220*44704f69SBart Van Assche clp->seek = sg_get_llnum(buf);
4221*44704f69SBart Van Assche if (clp->seek < 0) {
4222*44704f69SBart Van Assche pr2serr("%sbad argument to 'seek='\n", my_name);
4223*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4224*44704f69SBart Van Assche }
4225*44704f69SBart Van Assche } else if (0 == strcmp(key, "skip")) {
4226*44704f69SBart Van Assche clp->skip = sg_get_llnum(buf);
4227*44704f69SBart Van Assche if (clp->skip < 0) {
4228*44704f69SBart Van Assche pr2serr("%sbad argument to 'skip='\n", my_name);
4229*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4230*44704f69SBart Van Assche }
4231*44704f69SBart Van Assche } else if (0 == strcmp(key, "sync"))
4232*44704f69SBart Van Assche do_sync = !! sg_get_num(buf);
4233*44704f69SBart Van Assche else if (0 == strcmp(key, "thr"))
4234*44704f69SBart Van Assche num_threads = sg_get_num(buf);
4235*44704f69SBart Van Assche else if (0 == strcmp(key, "time")) {
4236*44704f69SBart Van Assche do_time = sg_get_num(buf);
4237*44704f69SBart Van Assche if (do_time < 0) {
4238*44704f69SBart Van Assche pr2serr("%sbad argument to 'time=0|1|2'\n", my_name);
4239*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4240*44704f69SBart Van Assche }
4241*44704f69SBart Van Assche cp = strchr(buf, ',');
4242*44704f69SBart Van Assche if (cp) {
4243*44704f69SBart Van Assche n = sg_get_num(cp + 1);
4244*44704f69SBart Van Assche if (n < 0) {
4245*44704f69SBart Van Assche pr2serr("%sbad argument to 'time=0|1|2,TO'\n", my_name);
4246*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4247*44704f69SBart Van Assche }
4248*44704f69SBart Van Assche clp->cmd_timeout = n ? (n * 1000) : DEF_TIMEOUT;
4249*44704f69SBart Van Assche }
4250*44704f69SBart Van Assche } else if (0 == strcmp(key, "unshare"))
4251*44704f69SBart Van Assche clp->unshare = !! sg_get_num(buf); /* default: true */
4252*44704f69SBart Van Assche else if (0 == strncmp(key, "verb", 4))
4253*44704f69SBart Van Assche clp->verbose = sg_get_num(buf);
4254*44704f69SBart Van Assche else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
4255*44704f69SBart Van Assche res = 0;
4256*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'c');
4257*44704f69SBart Van Assche clp->chkaddr += n;
4258*44704f69SBart Van Assche res += n;
4259*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'd');
4260*44704f69SBart Van Assche clp->dry_run += n;
4261*44704f69SBart Van Assche res += n;
4262*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'h');
4263*44704f69SBart Van Assche clp->help += n;
4264*44704f69SBart Van Assche res += n;
4265*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'p');
4266*44704f69SBart Van Assche if (n > 0)
4267*44704f69SBart Van Assche clp->prefetch = true;
4268*44704f69SBart Van Assche res += n;
4269*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'v');
4270*44704f69SBart Van Assche if (n > 0)
4271*44704f69SBart Van Assche verbose_given = true;
4272*44704f69SBart Van Assche clp->verbose += n; /* -v ---> --verbose */
4273*44704f69SBart Van Assche res += n;
4274*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'V');
4275*44704f69SBart Van Assche if (n > 0)
4276*44704f69SBart Van Assche version_given = true;
4277*44704f69SBart Van Assche res += n;
4278*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'x');
4279*44704f69SBart Van Assche if (n > 0)
4280*44704f69SBart Van Assche verify_given = true;
4281*44704f69SBart Van Assche res += n;
4282*44704f69SBart Van Assche
4283*44704f69SBart Van Assche if (res < (keylen - 1)) {
4284*44704f69SBart Van Assche pr2serr("Unrecognised short option in '%s', try '--help'\n",
4285*44704f69SBart Van Assche key);
4286*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4287*44704f69SBart Van Assche }
4288*44704f69SBart Van Assche } else if (0 == strncmp(key, "--chkaddr", 9))
4289*44704f69SBart Van Assche ++clp->chkaddr;
4290*44704f69SBart Van Assche else if ((0 == strncmp(key, "--dry-run", 9)) ||
4291*44704f69SBart Van Assche (0 == strncmp(key, "--dry_run", 9)))
4292*44704f69SBart Van Assche ++clp->dry_run;
4293*44704f69SBart Van Assche else if ((0 == strncmp(key, "--help", 6)) ||
4294*44704f69SBart Van Assche (0 == strcmp(key, "-?")))
4295*44704f69SBart Van Assche ++clp->help;
4296*44704f69SBart Van Assche else if ((0 == strncmp(key, "--prefetch", 10)) ||
4297*44704f69SBart Van Assche (0 == strncmp(key, "--pre-fetch", 11)))
4298*44704f69SBart Van Assche clp->prefetch = true;
4299*44704f69SBart Van Assche else if (0 == strncmp(key, "--verb", 6)) {
4300*44704f69SBart Van Assche verbose_given = true;
4301*44704f69SBart Van Assche ++clp->verbose; /* --verbose */
4302*44704f69SBart Van Assche } else if (0 == strncmp(key, "--veri", 6))
4303*44704f69SBart Van Assche verify_given = true;
4304*44704f69SBart Van Assche else if (0 == strncmp(key, "--vers", 6))
4305*44704f69SBart Van Assche version_given = true;
4306*44704f69SBart Van Assche else {
4307*44704f69SBart Van Assche pr2serr("Unrecognized option '%s'\n", key);
4308*44704f69SBart Van Assche pr2serr("For more information use '--help' or '-h'\n");
4309*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4310*44704f69SBart Van Assche }
4311*44704f69SBart Van Assche }
4312*44704f69SBart Van Assche
4313*44704f69SBart Van Assche #ifdef DEBUG
4314*44704f69SBart Van Assche pr2serr("In DEBUG mode, ");
4315*44704f69SBart Van Assche if (verbose_given && version_given) {
4316*44704f69SBart Van Assche pr2serr("but override: '-vV' given, zero verbose and continue\n");
4317*44704f69SBart Van Assche verbose_given = false;
4318*44704f69SBart Van Assche version_given = false;
4319*44704f69SBart Van Assche clp->verbose = 0;
4320*44704f69SBart Van Assche } else if (! verbose_given) {
4321*44704f69SBart Van Assche pr2serr("set '-vv'\n");
4322*44704f69SBart Van Assche clp->verbose = 2;
4323*44704f69SBart Van Assche } else
4324*44704f69SBart Van Assche pr2serr("keep verbose=%d\n", clp->verbose);
4325*44704f69SBart Van Assche #else
4326*44704f69SBart Van Assche if (verbose_given && version_given)
4327*44704f69SBart Van Assche pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
4328*44704f69SBart Van Assche #endif
4329*44704f69SBart Van Assche if (version_given) {
4330*44704f69SBart Van Assche pr2serr("%s%s\n", my_name, version_str);
4331*44704f69SBart Van Assche return SG_LIB_OK_FALSE;
4332*44704f69SBart Van Assche }
4333*44704f69SBart Van Assche if (clp->help > 0) {
4334*44704f69SBart Van Assche usage(clp->help);
4335*44704f69SBart Van Assche return SG_LIB_OK_FALSE;
4336*44704f69SBart Van Assche }
4337*44704f69SBart Van Assche if (clp->bs <= 0) {
4338*44704f69SBart Van Assche clp->bs = DEF_BLOCK_SIZE;
4339*44704f69SBart Van Assche pr2serr("Assume default 'bs' ((logical) block size) of %d bytes\n",
4340*44704f69SBart Van Assche clp->bs);
4341*44704f69SBart Van Assche }
4342*44704f69SBart Van Assche if (verify_given) {
4343*44704f69SBart Van Assche pr2serr("Doing verify/cmp rather than copy\n");
4344*44704f69SBart Van Assche clp->verify = true;
4345*44704f69SBart Van Assche }
4346*44704f69SBart Van Assche if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) {
4347*44704f69SBart Van Assche pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
4348*44704f69SBart Van Assche usage(0);
4349*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4350*44704f69SBart Van Assche }
4351*44704f69SBart Van Assche if ((clp->skip < 0) || (clp->seek < 0)) {
4352*44704f69SBart Van Assche pr2serr("skip and seek cannot be negative\n");
4353*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4354*44704f69SBart Van Assche }
4355*44704f69SBart Van Assche if (clp->out_flags.append) {
4356*44704f69SBart Van Assche if (clp->seek > 0) {
4357*44704f69SBart Van Assche pr2serr("Can't use both append and seek switches\n");
4358*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4359*44704f69SBart Van Assche }
4360*44704f69SBart Van Assche if (verify_given) {
4361*44704f69SBart Van Assche pr2serr("Can't use both append and verify switches\n");
4362*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4363*44704f69SBart Van Assche }
4364*44704f69SBart Van Assche }
4365*44704f69SBart Van Assche if (clp->bpt < 1) {
4366*44704f69SBart Van Assche pr2serr("bpt must be greater than 0\n");
4367*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4368*44704f69SBart Van Assche }
4369*44704f69SBart Van Assche if (clp->in_flags.mmap && clp->out_flags.mmap) {
4370*44704f69SBart Van Assche pr2serr("mmap flag on both IFILE and OFILE doesn't work\n");
4371*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4372*44704f69SBart Van Assche }
4373*44704f69SBart Van Assche if (! clp->noshare) {
4374*44704f69SBart Van Assche if (clp->in_flags.noshare || clp->out_flags.noshare)
4375*44704f69SBart Van Assche clp->noshare = true;
4376*44704f69SBart Van Assche }
4377*44704f69SBart Van Assche if (clp->unshare) {
4378*44704f69SBart Van Assche if (clp->in_flags.no_unshare || clp->out_flags.no_unshare)
4379*44704f69SBart Van Assche clp->unshare = false;
4380*44704f69SBart Van Assche }
4381*44704f69SBart Van Assche if (clp->out_flags.mmap && ! clp->noshare) {
4382*44704f69SBart Van Assche pr2serr("oflag=mmap needs either noshare=1\n");
4383*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4384*44704f69SBart Van Assche }
4385*44704f69SBart Van Assche if ((clp->in_flags.mmap || clp->out_flags.mmap) &&
4386*44704f69SBart Van Assche (clp->in_flags.same_fds || clp->out_flags.same_fds)) {
4387*44704f69SBart Van Assche pr2serr("can't have both 'mmap' and 'same_fds' flags\n");
4388*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4389*44704f69SBart Van Assche }
4390*44704f69SBart Van Assche if ((! clp->noshare) && (clp->in_flags.dio || clp->out_flags.dio)) {
4391*44704f69SBart Van Assche pr2serr("dio flag can only be used with noshare=1\n");
4392*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4393*44704f69SBart Van Assche }
4394*44704f69SBart Van Assche if (clp->nmrqs > 0) {
4395*44704f69SBart Van Assche if (clp->in_flags.mrq_immed || clp->out_flags.mrq_immed)
4396*44704f69SBart Van Assche clp->mrq_async = true;
4397*44704f69SBart Van Assche }
4398*44704f69SBart Van Assche /* defaulting transfer size to 128*2048 for CD/DVDs is too large
4399*44704f69SBart Van Assche for the block layer in lk 2.6 and results in an EIO on the
4400*44704f69SBart Van Assche SG_IO ioctl. So reduce it in that case. */
4401*44704f69SBart Van Assche if ((clp->bs >= 2048) && (! bpt_given))
4402*44704f69SBart Van Assche clp->bpt = DEF_BLOCKS_PER_2048TRANSFER;
4403*44704f69SBart Van Assche if (clp->ofsplit >= clp->bpt) {
4404*44704f69SBart Van Assche pr2serr("ofsplit when given must be less than BPT\n");
4405*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4406*44704f69SBart Van Assche }
4407*44704f69SBart Van Assche if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) {
4408*44704f69SBart Van Assche pr2serr("too few or too many threads requested\n");
4409*44704f69SBart Van Assche usage(1);
4410*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4411*44704f69SBart Van Assche }
4412*44704f69SBart Van Assche if (clp->in_flags.swait || clp->out_flags.swait) {
4413*44704f69SBart Van Assche if (clp->verbose)
4414*44704f69SBart Van Assche pr2serr("the 'swait' flag is now ignored\n");
4415*44704f69SBart Van Assche /* remnants ... */
4416*44704f69SBart Van Assche if (clp->in_flags.swait && (! clp->out_flags.swait))
4417*44704f69SBart Van Assche clp->out_flags.swait = true;
4418*44704f69SBart Van Assche }
4419*44704f69SBart Van Assche clp->unit_nanosec = (do_time > 1) || !!getenv("SG3_UTILS_LINUX_NANO");
4420*44704f69SBart Van Assche #if 0
4421*44704f69SBart Van Assche if (clp->verbose) {
4422*44704f69SBart Van Assche pr2serr("%sif=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%"
4423*44704f69SBart Van Assche PRId64, my_name, inf, clp->skip, outf, clp->seek, dd_count);
4424*44704f69SBart Van Assche if (clp->nmrqs > 0)
4425*44704f69SBart Van Assche pr2serr(" mrq=%d%s\n", clp->nmrqs, (clp->mrq_cmds ? ",C" : ""));
4426*44704f69SBart Van Assche else
4427*44704f69SBart Van Assche pr2serr("\n");
4428*44704f69SBart Van Assche }
4429*44704f69SBart Van Assche #endif
4430*44704f69SBart Van Assche return 0;
4431*44704f69SBart Van Assche }
4432*44704f69SBart Van Assche
4433*44704f69SBart Van Assche
4434*44704f69SBart Van Assche int
main(int argc,char * argv[])4435*44704f69SBart Van Assche main(int argc, char * argv[])
4436*44704f69SBart Van Assche {
4437*44704f69SBart Van Assche char inf[INOUTF_SZ];
4438*44704f69SBart Van Assche char outf[INOUTF_SZ];
4439*44704f69SBart Van Assche char out2f[INOUTF_SZ];
4440*44704f69SBart Van Assche char outregf[INOUTF_SZ];
4441*44704f69SBart Van Assche int res, k, err;
4442*44704f69SBart Van Assche int64_t in_num_sect = 0;
4443*44704f69SBart Van Assche int64_t out_num_sect = 0;
4444*44704f69SBart Van Assche int in_sect_sz, out_sect_sz, status, flags;
4445*44704f69SBart Van Assche void * vp;
4446*44704f69SBart Van Assche const char * ccp = NULL;
4447*44704f69SBart Van Assche const char * cc2p;
4448*44704f69SBart Van Assche struct global_collection * clp = &gcoll;
4449*44704f69SBart Van Assche Thread_info thread_arr[MAX_NUM_THREADS] {};
4450*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
4451*44704f69SBart Van Assche #if SG_LIB_ANDROID
4452*44704f69SBart Van Assche struct sigaction actions;
4453*44704f69SBart Van Assche
4454*44704f69SBart Van Assche memset(&actions, 0, sizeof(actions));
4455*44704f69SBart Van Assche sigemptyset(&actions.sa_mask);
4456*44704f69SBart Van Assche actions.sa_flags = 0;
4457*44704f69SBart Van Assche actions.sa_handler = thread_exit_handler;
4458*44704f69SBart Van Assche sigaction(SIGUSR1, &actions, NULL);
4459*44704f69SBart Van Assche sigaction(SIGUSR2, &actions, NULL);
4460*44704f69SBart Van Assche #endif
4461*44704f69SBart Van Assche /* memset(clp, 0, sizeof(*clp)); */
4462*44704f69SBart Van Assche clp->bpt = DEF_BLOCKS_PER_TRANSFER;
4463*44704f69SBart Van Assche clp->cmd_timeout = DEF_TIMEOUT;
4464*44704f69SBart Van Assche clp->in_type = FT_OTHER;
4465*44704f69SBart Van Assche /* change dd's default: if of=OFILE not given, assume /dev/null */
4466*44704f69SBart Van Assche clp->out_type = FT_DEV_NULL;
4467*44704f69SBart Van Assche clp->out2_type = FT_DEV_NULL;
4468*44704f69SBart Van Assche clp->cdbsz_in = DEF_SCSI_CDBSZ;
4469*44704f69SBart Van Assche clp->cdbsz_out = DEF_SCSI_CDBSZ;
4470*44704f69SBart Van Assche clp->sdt_ict = DEF_SDT_ICT_MS;
4471*44704f69SBart Van Assche clp->sdt_crt = DEF_SDT_CRT_SEC;
4472*44704f69SBart Van Assche clp->nmrqs = DEF_NUM_MRQS;
4473*44704f69SBart Van Assche clp->unshare = true;
4474*44704f69SBart Van Assche inf[0] = '\0';
4475*44704f69SBart Van Assche outf[0] = '\0';
4476*44704f69SBart Van Assche out2f[0] = '\0';
4477*44704f69SBart Van Assche outregf[0] = '\0';
4478*44704f69SBart Van Assche fetch_sg_version();
4479*44704f69SBart Van Assche if (sg_version >= 40045)
4480*44704f69SBart Van Assche sg_version_ge_40045 = true;
4481*44704f69SBart Van Assche
4482*44704f69SBart Van Assche res = parse_cmdline_sanity(argc, argv, clp, inf, outf, out2f, outregf);
4483*44704f69SBart Van Assche if (SG_LIB_OK_FALSE == res)
4484*44704f69SBart Van Assche return 0;
4485*44704f69SBart Van Assche if (res)
4486*44704f69SBart Van Assche return res;
4487*44704f69SBart Van Assche if (sg_version > 40000) {
4488*44704f69SBart Van Assche if (! clp->in_flags.v3)
4489*44704f69SBart Van Assche clp->in_flags.v4 = true;
4490*44704f69SBart Van Assche if (! clp->out_flags.v3)
4491*44704f69SBart Van Assche clp->out_flags.v4 = true;
4492*44704f69SBart Van Assche }
4493*44704f69SBart Van Assche
4494*44704f69SBart Van Assche install_handler(SIGINT, interrupt_handler);
4495*44704f69SBart Van Assche install_handler(SIGQUIT, interrupt_handler);
4496*44704f69SBart Van Assche install_handler(SIGPIPE, interrupt_handler);
4497*44704f69SBart Van Assche install_handler(SIGUSR1, siginfo_handler);
4498*44704f69SBart Van Assche install_handler(SIGUSR2, siginfo2_handler);
4499*44704f69SBart Van Assche
4500*44704f69SBart Van Assche clp->infd = STDIN_FILENO;
4501*44704f69SBart Van Assche clp->outfd = STDOUT_FILENO;
4502*44704f69SBart Van Assche if (clp->in_flags.ff && clp->in_flags.zero) {
4503*44704f69SBart Van Assche ccp = "<addr_as_data>";
4504*44704f69SBart Van Assche cc2p = "addr_as_data";
4505*44704f69SBart Van Assche } else if (clp->in_flags.ff) {
4506*44704f69SBart Van Assche ccp = "<0xff bytes>";
4507*44704f69SBart Van Assche cc2p = "ff";
4508*44704f69SBart Van Assche } else if (clp->in_flags.random) {
4509*44704f69SBart Van Assche ccp = "<random>";
4510*44704f69SBart Van Assche cc2p = "random";
4511*44704f69SBart Van Assche } else if (clp->in_flags.zero) {
4512*44704f69SBart Van Assche ccp = "<zero bytes>";
4513*44704f69SBart Van Assche cc2p = "00";
4514*44704f69SBart Van Assche }
4515*44704f69SBart Van Assche if (ccp) {
4516*44704f69SBart Van Assche if (inf[0]) {
4517*44704f69SBart Van Assche pr2serr("%siflag=%s and if=%s contradict\n", my_name, cc2p, inf);
4518*44704f69SBart Van Assche return SG_LIB_CONTRADICT;
4519*44704f69SBart Van Assche }
4520*44704f69SBart Van Assche clp->in_type = FT_RANDOM_0_FF;
4521*44704f69SBart Van Assche clp->infp = ccp;
4522*44704f69SBart Van Assche clp->infd = -1;
4523*44704f69SBart Van Assche } else if (inf[0] && ('-' != inf[0])) {
4524*44704f69SBart Van Assche clp->in_type = dd_filetype(inf, clp->in_st_size);
4525*44704f69SBart Van Assche
4526*44704f69SBart Van Assche if (FT_ERROR == clp->in_type) {
4527*44704f69SBart Van Assche pr2serr("%sunable to access %s\n", my_name, inf);
4528*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4529*44704f69SBart Van Assche } else if (FT_ST == clp->in_type) {
4530*44704f69SBart Van Assche pr2serr("%sunable to use scsi tape device %s\n", my_name, inf);
4531*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4532*44704f69SBart Van Assche } else if (FT_CHAR == clp->in_type) {
4533*44704f69SBart Van Assche pr2serr("%sunable to use unknown char device %s\n", my_name, inf);
4534*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4535*44704f69SBart Van Assche } else if (FT_SG == clp->in_type) {
4536*44704f69SBart Van Assche clp->infd = sg_in_open(clp, inf, NULL, NULL);
4537*44704f69SBart Van Assche if (clp->verbose > 2)
4538*44704f69SBart Van Assche pr2serr("using sg v%c interface on %s\n",
4539*44704f69SBart Van Assche (clp->in_flags.v4 ? '4' : '3'), inf);
4540*44704f69SBart Van Assche if (clp->infd < 0)
4541*44704f69SBart Van Assche return -clp->infd;
4542*44704f69SBart Van Assche } else {
4543*44704f69SBart Van Assche flags = O_RDONLY;
4544*44704f69SBart Van Assche if (clp->in_flags.direct)
4545*44704f69SBart Van Assche flags |= O_DIRECT;
4546*44704f69SBart Van Assche if (clp->in_flags.excl)
4547*44704f69SBart Van Assche flags |= O_EXCL;
4548*44704f69SBart Van Assche if (clp->in_flags.dsync)
4549*44704f69SBart Van Assche flags |= O_SYNC;
4550*44704f69SBart Van Assche
4551*44704f69SBart Van Assche if ((clp->infd = open(inf, flags)) < 0) {
4552*44704f69SBart Van Assche err = errno;
4553*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%scould not open %s for reading",
4554*44704f69SBart Van Assche my_name, inf);
4555*44704f69SBart Van Assche perror(ebuff);
4556*44704f69SBart Van Assche return sg_convert_errno(err);
4557*44704f69SBart Van Assche } else if (clp->skip > 0) {
4558*44704f69SBart Van Assche off64_t offset = clp->skip;
4559*44704f69SBart Van Assche
4560*44704f69SBart Van Assche offset *= clp->bs; /* could exceed 32 here! */
4561*44704f69SBart Van Assche if (lseek64(clp->infd, offset, SEEK_SET) < 0) {
4562*44704f69SBart Van Assche err = errno;
4563*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%scouldn't skip to required "
4564*44704f69SBart Van Assche "position on %s", my_name, inf);
4565*44704f69SBart Van Assche perror(ebuff);
4566*44704f69SBart Van Assche return sg_convert_errno(err);
4567*44704f69SBart Van Assche }
4568*44704f69SBart Van Assche }
4569*44704f69SBart Van Assche }
4570*44704f69SBart Van Assche clp->infp = inf;
4571*44704f69SBart Van Assche if ((clp->in_flags.v3 || clp->in_flags.v4_given) &&
4572*44704f69SBart Van Assche (FT_SG != clp->in_type)) {
4573*44704f69SBart Van Assche clp->in_flags.v3 = false;
4574*44704f69SBart Van Assche clp->in_flags.v4 = false;
4575*44704f69SBart Van Assche pr2serr("%siflag= v3 and v4 both ignored when IFILE is not sg "
4576*44704f69SBart Van Assche "device\n", my_name);
4577*44704f69SBart Van Assche }
4578*44704f69SBart Van Assche }
4579*44704f69SBart Van Assche if (clp->verbose && (clp->in_flags.no_waitq || clp->out_flags.no_waitq))
4580*44704f69SBart Van Assche pr2serr("no_waitq: flag no longer does anything\n");
4581*44704f69SBart Van Assche if (outf[0])
4582*44704f69SBart Van Assche clp->ofile_given = true;
4583*44704f69SBart Van Assche if (outf[0] && ('-' != outf[0])) {
4584*44704f69SBart Van Assche clp->out_type = dd_filetype(outf, clp->out_st_size);
4585*44704f69SBart Van Assche
4586*44704f69SBart Van Assche if ((FT_SG != clp->out_type) && clp->verify) {
4587*44704f69SBart Van Assche pr2serr("%s --verify only supported by sg OFILEs\n", my_name);
4588*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4589*44704f69SBart Van Assche } else if (FT_ST == clp->out_type) {
4590*44704f69SBart Van Assche pr2serr("%sunable to use scsi tape device %s\n", my_name, outf);
4591*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4592*44704f69SBart Van Assche } else if (FT_CHAR == clp->out_type) {
4593*44704f69SBart Van Assche pr2serr("%sunable to use unknown char device %s\n", my_name, outf);
4594*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4595*44704f69SBart Van Assche } else if (FT_SG == clp->out_type) {
4596*44704f69SBart Van Assche clp->outfd = sg_out_open(clp, outf, NULL, NULL);
4597*44704f69SBart Van Assche if (clp->verbose > 2)
4598*44704f69SBart Van Assche pr2serr("using sg v%c interface on %s\n",
4599*44704f69SBart Van Assche (clp->out_flags.v4 ? '4' : '3'), outf);
4600*44704f69SBart Van Assche if (clp->outfd < 0)
4601*44704f69SBart Van Assche return -clp->outfd;
4602*44704f69SBart Van Assche } else if (FT_DEV_NULL == clp->out_type)
4603*44704f69SBart Van Assche clp->outfd = -1; /* don't bother opening */
4604*44704f69SBart Van Assche else {
4605*44704f69SBart Van Assche flags = O_WRONLY;
4606*44704f69SBart Van Assche if (! clp->out_flags.nocreat)
4607*44704f69SBart Van Assche flags |= O_CREAT;
4608*44704f69SBart Van Assche if (clp->out_flags.direct)
4609*44704f69SBart Van Assche flags |= O_DIRECT;
4610*44704f69SBart Van Assche if (clp->out_flags.excl)
4611*44704f69SBart Van Assche flags |= O_EXCL;
4612*44704f69SBart Van Assche if (clp->out_flags.dsync)
4613*44704f69SBart Van Assche flags |= O_SYNC;
4614*44704f69SBart Van Assche if (clp->out_flags.append)
4615*44704f69SBart Van Assche flags |= O_APPEND;
4616*44704f69SBart Van Assche
4617*44704f69SBart Van Assche if ((clp->outfd = open(outf, flags, 0666)) < 0) {
4618*44704f69SBart Van Assche err = errno;
4619*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%scould not open %s for "
4620*44704f69SBart Van Assche "writing", my_name, outf);
4621*44704f69SBart Van Assche perror(ebuff);
4622*44704f69SBart Van Assche return sg_convert_errno(err);
4623*44704f69SBart Van Assche }
4624*44704f69SBart Van Assche if (clp->seek > 0) {
4625*44704f69SBart Van Assche off64_t offset = clp->seek;
4626*44704f69SBart Van Assche
4627*44704f69SBart Van Assche offset *= clp->bs; /* could exceed 32 bits here! */
4628*44704f69SBart Van Assche if (lseek64(clp->outfd, offset, SEEK_SET) < 0) {
4629*44704f69SBart Van Assche err = errno;
4630*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to required "
4631*44704f69SBart Van Assche "position on %s", my_name, outf);
4632*44704f69SBart Van Assche perror(ebuff);
4633*44704f69SBart Van Assche return sg_convert_errno(err);
4634*44704f69SBart Van Assche }
4635*44704f69SBart Van Assche }
4636*44704f69SBart Van Assche }
4637*44704f69SBart Van Assche clp->outfp = outf;
4638*44704f69SBart Van Assche if ((clp->out_flags.v3 || clp->out_flags.v4_given) &&
4639*44704f69SBart Van Assche (FT_SG != clp->out_type)) {
4640*44704f69SBart Van Assche clp->out_flags.v3 = false;
4641*44704f69SBart Van Assche clp->out_flags.v4 = false;
4642*44704f69SBart Van Assche pr2serr("%soflag= v3 and v4 both ignored when OFILE is not sg "
4643*44704f69SBart Van Assche "device\n", my_name);
4644*44704f69SBart Van Assche }
4645*44704f69SBart Van Assche }
4646*44704f69SBart Van Assche
4647*44704f69SBart Van Assche if (out2f[0])
4648*44704f69SBart Van Assche clp->ofile2_given = true;
4649*44704f69SBart Van Assche if (out2f[0] && ('-' != out2f[0])) {
4650*44704f69SBart Van Assche off_t out2_st_size;
4651*44704f69SBart Van Assche
4652*44704f69SBart Van Assche clp->out2_type = dd_filetype(out2f, out2_st_size);
4653*44704f69SBart Van Assche if (FT_ST == clp->out2_type) {
4654*44704f69SBart Van Assche pr2serr("%sunable to use scsi tape device %s\n", my_name, out2f);
4655*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4656*44704f69SBart Van Assche }
4657*44704f69SBart Van Assche else if (FT_SG == clp->out2_type) {
4658*44704f69SBart Van Assche clp->out2fd = sg_out_open(clp, out2f, NULL, NULL);
4659*44704f69SBart Van Assche if (clp->out2fd < 0)
4660*44704f69SBart Van Assche return -clp->out2fd;
4661*44704f69SBart Van Assche }
4662*44704f69SBart Van Assche else if (FT_DEV_NULL == clp->out2_type)
4663*44704f69SBart Van Assche clp->out2fd = -1; /* don't bother opening */
4664*44704f69SBart Van Assche else {
4665*44704f69SBart Van Assche flags = O_WRONLY;
4666*44704f69SBart Van Assche if (! clp->out_flags.nocreat)
4667*44704f69SBart Van Assche flags |= O_CREAT;
4668*44704f69SBart Van Assche if (clp->out_flags.direct)
4669*44704f69SBart Van Assche flags |= O_DIRECT;
4670*44704f69SBart Van Assche if (clp->out_flags.excl)
4671*44704f69SBart Van Assche flags |= O_EXCL;
4672*44704f69SBart Van Assche if (clp->out_flags.dsync)
4673*44704f69SBart Van Assche flags |= O_SYNC;
4674*44704f69SBart Van Assche if (clp->out_flags.append)
4675*44704f69SBart Van Assche flags |= O_APPEND;
4676*44704f69SBart Van Assche
4677*44704f69SBart Van Assche if ((clp->out2fd = open(out2f, flags, 0666)) < 0) {
4678*44704f69SBart Van Assche err = errno;
4679*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%scould not open %s for "
4680*44704f69SBart Van Assche "writing", my_name, out2f);
4681*44704f69SBart Van Assche perror(ebuff);
4682*44704f69SBart Van Assche return sg_convert_errno(err);
4683*44704f69SBart Van Assche }
4684*44704f69SBart Van Assche if (clp->seek > 0) {
4685*44704f69SBart Van Assche off64_t offset = clp->seek;
4686*44704f69SBart Van Assche
4687*44704f69SBart Van Assche offset *= clp->bs; /* could exceed 32 bits here! */
4688*44704f69SBart Van Assche if (lseek64(clp->out2fd, offset, SEEK_SET) < 0) {
4689*44704f69SBart Van Assche err = errno;
4690*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to required "
4691*44704f69SBart Van Assche "position on %s", my_name, out2f);
4692*44704f69SBart Van Assche perror(ebuff);
4693*44704f69SBart Van Assche return sg_convert_errno(err);
4694*44704f69SBart Van Assche }
4695*44704f69SBart Van Assche }
4696*44704f69SBart Van Assche }
4697*44704f69SBart Van Assche clp->out2fp = out2f;
4698*44704f69SBart Van Assche }
4699*44704f69SBart Van Assche if ((FT_SG == clp->in_type ) && (FT_SG == clp->out_type)) {
4700*44704f69SBart Van Assche if (clp->nmrqs > 0) {
4701*44704f69SBart Van Assche if (clp->is_mrq_i == clp->is_mrq_o) {
4702*44704f69SBart Van Assche if (clp->ofsplit > 0) {
4703*44704f69SBart Van Assche if (0 != (clp->nmrqs % 3)) {
4704*44704f69SBart Van Assche pr2serr("When both IFILE+OFILE sg devices and OSP>0, "
4705*44704f69SBart Van Assche "mrq=NRQS must be divisible by 3\n");
4706*44704f69SBart Van Assche pr2serr(" triple NRQS to avoid error\n");
4707*44704f69SBart Van Assche clp->nmrqs *= 3;
4708*44704f69SBart Van Assche }
4709*44704f69SBart Van Assche } else if (0 != (clp->nmrqs % 2)) {
4710*44704f69SBart Van Assche pr2serr("When both IFILE+OFILE sg devices (and OSP=0), "
4711*44704f69SBart Van Assche "mrq=NRQS must be even\n");
4712*44704f69SBart Van Assche pr2serr(" double NRQS to avoid error\n");
4713*44704f69SBart Van Assche clp->nmrqs *= 2;
4714*44704f69SBart Van Assche }
4715*44704f69SBart Van Assche }
4716*44704f69SBart Van Assche if (clp->is_mrq_i && clp->is_mrq_o)
4717*44704f69SBart Van Assche ;
4718*44704f69SBart Van Assche else if (clp->is_mrq_i || clp->is_mrq_o)
4719*44704f69SBart Van Assche clp->unbalanced_mrq = true;
4720*44704f69SBart Van Assche }
4721*44704f69SBart Van Assche if (clp->in_flags.v4_given && (! clp->out_flags.v3)) {
4722*44704f69SBart Van Assche if (! clp->out_flags.v4_given) {
4723*44704f69SBart Van Assche clp->out_flags.v4 = true;
4724*44704f69SBart Van Assche if (clp->verbose)
4725*44704f69SBart Van Assche pr2serr("Changing OFILE from v3 to v4, use oflag=v3 to "
4726*44704f69SBart Van Assche "force v3\n");
4727*44704f69SBart Van Assche }
4728*44704f69SBart Van Assche }
4729*44704f69SBart Van Assche if (clp->out_flags.v4_given && (! clp->in_flags.v3)) {
4730*44704f69SBart Van Assche if (! clp->in_flags.v4_given) {
4731*44704f69SBart Van Assche clp->in_flags.v4 = true;
4732*44704f69SBart Van Assche if (clp->verbose)
4733*44704f69SBart Van Assche pr2serr("Changing IFILE from v3 to v4, use iflag=v3 to "
4734*44704f69SBart Van Assche "force v3\n");
4735*44704f69SBart Van Assche }
4736*44704f69SBart Van Assche }
4737*44704f69SBart Van Assche #if 0
4738*44704f69SBart Van Assche if (clp->mrq_async && !(clp->noshare)) {
4739*44704f69SBart Van Assche pr2serr("With mrq_immed also need noshare on sg-->sg copy\n");
4740*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4741*44704f69SBart Van Assche }
4742*44704f69SBart Van Assche #endif
4743*44704f69SBart Van Assche } else if ((FT_SG == clp->in_type ) || (FT_SG == clp->out_type)) {
4744*44704f69SBart Van Assche if (clp->nmrqs > 0)
4745*44704f69SBart Van Assche clp->unbalanced_mrq = true;
4746*44704f69SBart Van Assche }
4747*44704f69SBart Van Assche if (outregf[0]) {
4748*44704f69SBart Van Assche off_t outrf_st_size;
4749*44704f69SBart Van Assche int ftyp = dd_filetype(outregf, outrf_st_size);
4750*44704f69SBart Van Assche
4751*44704f69SBart Van Assche clp->outreg_type = ftyp;
4752*44704f69SBart Van Assche if (! ((FT_OTHER == ftyp) || (FT_ERROR == ftyp) ||
4753*44704f69SBart Van Assche (FT_DEV_NULL == ftyp))) {
4754*44704f69SBart Van Assche pr2serr("File: %s can only be regular file or pipe (or "
4755*44704f69SBart Van Assche "/dev/null)\n", outregf);
4756*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4757*44704f69SBart Van Assche }
4758*44704f69SBart Van Assche if ((clp->outregfd = open(outregf, O_WRONLY | O_CREAT, 0666)) < 0) {
4759*44704f69SBart Van Assche err = errno;
4760*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "could not open %s for writing",
4761*44704f69SBart Van Assche outregf);
4762*44704f69SBart Van Assche perror(ebuff);
4763*44704f69SBart Van Assche return sg_convert_errno(err);
4764*44704f69SBart Van Assche }
4765*44704f69SBart Van Assche if (clp->verbose > 1)
4766*44704f69SBart Van Assche pr2serr("ofreg=%s opened okay, fd=%d\n", outregf, clp->outregfd);
4767*44704f69SBart Van Assche if (FT_ERROR == ftyp)
4768*44704f69SBart Van Assche clp->outreg_type = FT_OTHER; /* regular file created */
4769*44704f69SBart Van Assche } else
4770*44704f69SBart Van Assche clp->outregfd = -1;
4771*44704f69SBart Van Assche
4772*44704f69SBart Van Assche if ((STDIN_FILENO == clp->infd) && (STDOUT_FILENO == clp->outfd)) {
4773*44704f69SBart Van Assche pr2serr("Won't default both IFILE to stdin _and_ OFILE to "
4774*44704f69SBart Van Assche "/dev/null\n");
4775*44704f69SBart Van Assche pr2serr("For more information use '--help' or '-h'\n");
4776*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
4777*44704f69SBart Van Assche }
4778*44704f69SBart Van Assche if (dd_count < 0) {
4779*44704f69SBart Van Assche in_num_sect = -1;
4780*44704f69SBart Van Assche if (FT_SG == clp->in_type) {
4781*44704f69SBart Van Assche res = scsi_read_capacity(clp->infd, &in_num_sect, &in_sect_sz);
4782*44704f69SBart Van Assche if (2 == res) {
4783*44704f69SBart Van Assche pr2serr("Unit attention, media changed(in), continuing\n");
4784*44704f69SBart Van Assche res = scsi_read_capacity(clp->infd, &in_num_sect,
4785*44704f69SBart Van Assche &in_sect_sz);
4786*44704f69SBart Van Assche }
4787*44704f69SBart Van Assche if (0 != res) {
4788*44704f69SBart Van Assche if (res == SG_LIB_CAT_INVALID_OP)
4789*44704f69SBart Van Assche pr2serr("read capacity not supported on %s\n", inf);
4790*44704f69SBart Van Assche else if (res == SG_LIB_CAT_NOT_READY)
4791*44704f69SBart Van Assche pr2serr("read capacity failed, %s not ready\n", inf);
4792*44704f69SBart Van Assche else
4793*44704f69SBart Van Assche pr2serr("Unable to read capacity on %s\n", inf);
4794*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4795*44704f69SBart Van Assche } else if (clp->bs != in_sect_sz) {
4796*44704f69SBart Van Assche pr2serr(">> warning: logical block size on %s confusion: "
4797*44704f69SBart Van Assche "bs=%d, device claims=%d\n", clp->infp, clp->bs,
4798*44704f69SBart Van Assche in_sect_sz);
4799*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4800*44704f69SBart Van Assche }
4801*44704f69SBart Van Assche } else if (FT_BLOCK == clp->in_type) {
4802*44704f69SBart Van Assche if (0 != read_blkdev_capacity(clp->infd, &in_num_sect,
4803*44704f69SBart Van Assche &in_sect_sz)) {
4804*44704f69SBart Van Assche pr2serr("Unable to read block capacity on %s\n", inf);
4805*44704f69SBart Van Assche in_num_sect = -1;
4806*44704f69SBart Van Assche }
4807*44704f69SBart Van Assche if (clp->bs != in_sect_sz) {
4808*44704f69SBart Van Assche pr2serr("logical block size on %s confusion; bs=%d, from "
4809*44704f69SBart Van Assche "device=%d\n", inf, clp->bs, in_sect_sz);
4810*44704f69SBart Van Assche in_num_sect = -1;
4811*44704f69SBart Van Assche }
4812*44704f69SBart Van Assche } else if (FT_OTHER == clp->in_type) {
4813*44704f69SBart Van Assche in_num_sect = clp->in_st_size / clp->bs;
4814*44704f69SBart Van Assche if (clp->in_st_size % clp->bs) {
4815*44704f69SBart Van Assche ++in_num_sect;
4816*44704f69SBart Van Assche pr2serr("Warning: the file size of %s is not a multiple of BS "
4817*44704f69SBart Van Assche "[%d]\n", inf, clp->bs);
4818*44704f69SBart Van Assche }
4819*44704f69SBart Van Assche }
4820*44704f69SBart Van Assche if (in_num_sect > clp->skip)
4821*44704f69SBart Van Assche in_num_sect -= clp->skip;
4822*44704f69SBart Van Assche
4823*44704f69SBart Van Assche out_num_sect = -1;
4824*44704f69SBart Van Assche if (FT_SG == clp->out_type) {
4825*44704f69SBart Van Assche res = scsi_read_capacity(clp->outfd, &out_num_sect, &out_sect_sz);
4826*44704f69SBart Van Assche if (2 == res) {
4827*44704f69SBart Van Assche pr2serr("Unit attention, media changed(out), continuing\n");
4828*44704f69SBart Van Assche res = scsi_read_capacity(clp->outfd, &out_num_sect,
4829*44704f69SBart Van Assche &out_sect_sz);
4830*44704f69SBart Van Assche }
4831*44704f69SBart Van Assche if (0 != res) {
4832*44704f69SBart Van Assche if (res == SG_LIB_CAT_INVALID_OP)
4833*44704f69SBart Van Assche pr2serr("read capacity not supported on %s\n", outf);
4834*44704f69SBart Van Assche else if (res == SG_LIB_CAT_NOT_READY)
4835*44704f69SBart Van Assche pr2serr("read capacity failed, %s not ready\n", outf);
4836*44704f69SBart Van Assche else
4837*44704f69SBart Van Assche pr2serr("Unable to read capacity on %s\n", outf);
4838*44704f69SBart Van Assche out_num_sect = -1;
4839*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4840*44704f69SBart Van Assche } else if (clp->bs != out_sect_sz) {
4841*44704f69SBart Van Assche pr2serr(">> warning: logical block size on %s confusion: "
4842*44704f69SBart Van Assche "bs=%d, device claims=%d\n", clp->outfp, clp->bs,
4843*44704f69SBart Van Assche out_sect_sz);
4844*44704f69SBart Van Assche return SG_LIB_FILE_ERROR;
4845*44704f69SBart Van Assche }
4846*44704f69SBart Van Assche } else if (FT_BLOCK == clp->out_type) {
4847*44704f69SBart Van Assche if (0 != read_blkdev_capacity(clp->outfd, &out_num_sect,
4848*44704f69SBart Van Assche &out_sect_sz)) {
4849*44704f69SBart Van Assche pr2serr("Unable to read block capacity on %s\n", outf);
4850*44704f69SBart Van Assche out_num_sect = -1;
4851*44704f69SBart Van Assche }
4852*44704f69SBart Van Assche if (clp->bs != out_sect_sz) {
4853*44704f69SBart Van Assche pr2serr("logical block size on %s confusion: bs=%d, from "
4854*44704f69SBart Van Assche "device=%d\n", outf, clp->bs, out_sect_sz);
4855*44704f69SBart Van Assche out_num_sect = -1;
4856*44704f69SBart Van Assche }
4857*44704f69SBart Van Assche } else if (FT_OTHER == clp->out_type) {
4858*44704f69SBart Van Assche out_num_sect = clp->out_st_size / clp->bs;
4859*44704f69SBart Van Assche if (clp->out_st_size % clp->bs) {
4860*44704f69SBart Van Assche ++out_num_sect;
4861*44704f69SBart Van Assche pr2serr("Warning: the file size of %s is not a multiple of BS "
4862*44704f69SBart Van Assche "[%d]\n", outf, clp->bs);
4863*44704f69SBart Van Assche }
4864*44704f69SBart Van Assche }
4865*44704f69SBart Van Assche if (out_num_sect > clp->seek)
4866*44704f69SBart Van Assche out_num_sect -= clp->seek;
4867*44704f69SBart Van Assche
4868*44704f69SBart Van Assche if (in_num_sect > 0) {
4869*44704f69SBart Van Assche if (out_num_sect > 0)
4870*44704f69SBart Van Assche dd_count = (in_num_sect > out_num_sect) ? out_num_sect :
4871*44704f69SBart Van Assche in_num_sect;
4872*44704f69SBart Van Assche else
4873*44704f69SBart Van Assche dd_count = in_num_sect;
4874*44704f69SBart Van Assche }
4875*44704f69SBart Van Assche else
4876*44704f69SBart Van Assche dd_count = out_num_sect;
4877*44704f69SBart Van Assche }
4878*44704f69SBart Van Assche if (clp->verbose > 2)
4879*44704f69SBart Van Assche pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64
4880*44704f69SBart Van Assche ", out_num_sect=%" PRId64 "\n", dd_count, in_num_sect,
4881*44704f69SBart Van Assche out_num_sect);
4882*44704f69SBart Van Assche if (dd_count < 0) {
4883*44704f69SBart Van Assche pr2serr("Couldn't calculate count, please give one\n");
4884*44704f69SBart Van Assche return SG_LIB_CAT_OTHER;
4885*44704f69SBart Van Assche }
4886*44704f69SBart Van Assche if (! clp->cdbsz_given) {
4887*44704f69SBart Van Assche if ((FT_SG == clp->in_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_in) &&
4888*44704f69SBart Van Assche (((dd_count + clp->skip) > UINT_MAX) || (clp->bpt > USHRT_MAX))) {
4889*44704f69SBart Van Assche pr2serr("Note: SCSI command size increased to 16 bytes (for "
4890*44704f69SBart Van Assche "'if')\n");
4891*44704f69SBart Van Assche clp->cdbsz_in = MAX_SCSI_CDBSZ;
4892*44704f69SBart Van Assche }
4893*44704f69SBart Van Assche if ((FT_SG == clp->out_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_out) &&
4894*44704f69SBart Van Assche (((dd_count + clp->seek) > UINT_MAX) || (clp->bpt > USHRT_MAX))) {
4895*44704f69SBart Van Assche pr2serr("Note: SCSI command size increased to 16 bytes (for "
4896*44704f69SBart Van Assche "'of')\n");
4897*44704f69SBart Van Assche clp->cdbsz_out = MAX_SCSI_CDBSZ;
4898*44704f69SBart Van Assche }
4899*44704f69SBart Van Assche }
4900*44704f69SBart Van Assche
4901*44704f69SBart Van Assche // clp->in_count = dd_count;
4902*44704f69SBart Van Assche clp->in_rem_count = dd_count;
4903*44704f69SBart Van Assche clp->out_count = dd_count;
4904*44704f69SBart Van Assche clp->out_rem_count = dd_count;
4905*44704f69SBart Van Assche clp->out_blk = clp->seek;
4906*44704f69SBart Van Assche status = pthread_mutex_init(&clp->in_mutex, NULL);
4907*44704f69SBart Van Assche if (0 != status) err_exit(status, "init in_mutex");
4908*44704f69SBart Van Assche status = pthread_mutex_init(&clp->out_mutex, NULL);
4909*44704f69SBart Van Assche if (0 != status) err_exit(status, "init out_mutex");
4910*44704f69SBart Van Assche status = pthread_mutex_init(&clp->out2_mutex, NULL);
4911*44704f69SBart Van Assche if (0 != status) err_exit(status, "init out2_mutex");
4912*44704f69SBart Van Assche status = pthread_cond_init(&clp->out_sync_cv, NULL);
4913*44704f69SBart Van Assche if (0 != status) err_exit(status, "init out_sync_cv");
4914*44704f69SBart Van Assche
4915*44704f69SBart Van Assche if (clp->dry_run > 0) {
4916*44704f69SBart Van Assche pr2serr("Due to --dry-run option, bypass copy/read\n");
4917*44704f69SBart Van Assche goto fini;
4918*44704f69SBart Van Assche }
4919*44704f69SBart Van Assche if (! clp->ofile_given)
4920*44704f69SBart Van Assche pr2serr("of=OFILE not given so only read from IFILE, to output to "
4921*44704f69SBart Van Assche "stdout use 'of=-'\n");
4922*44704f69SBart Van Assche
4923*44704f69SBart Van Assche sigemptyset(&signal_set);
4924*44704f69SBart Van Assche sigaddset(&signal_set, SIGINT);
4925*44704f69SBart Van Assche sigaddset(&signal_set, SIGUSR2);
4926*44704f69SBart Van Assche status = pthread_sigmask(SIG_BLOCK, &signal_set, &orig_signal_set);
4927*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_sigmask");
4928*44704f69SBart Van Assche status = pthread_create(&sig_listen_thread_id, NULL,
4929*44704f69SBart Van Assche sig_listen_thread, (void *)clp);
4930*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_create, sig...");
4931*44704f69SBart Van Assche
4932*44704f69SBart Van Assche if (do_time) {
4933*44704f69SBart Van Assche start_tm.tv_sec = 0;
4934*44704f69SBart Van Assche start_tm.tv_usec = 0;
4935*44704f69SBart Van Assche gettimeofday(&start_tm, NULL);
4936*44704f69SBart Van Assche }
4937*44704f69SBart Van Assche
4938*44704f69SBart Van Assche /* vvvvvvvvvvv Start worker threads vvvvvvvvvvvvvvvvvvvvvvvv */
4939*44704f69SBart Van Assche if ((clp->out_rem_count.load() > 0) && (num_threads > 0)) {
4940*44704f69SBart Van Assche Thread_info *tip = thread_arr + 0;
4941*44704f69SBart Van Assche
4942*44704f69SBart Van Assche tip->gcp = clp;
4943*44704f69SBart Van Assche tip->id = 0;
4944*44704f69SBart Van Assche /* Run 1 work thread to shake down infant retryable stuff */
4945*44704f69SBart Van Assche status = pthread_mutex_lock(&clp->out_mutex);
4946*44704f69SBart Van Assche if (0 != status) err_exit(status, "lock out_mutex");
4947*44704f69SBart Van Assche status = pthread_create(&tip->a_pthr, NULL, read_write_thread,
4948*44704f69SBart Van Assche (void *)tip);
4949*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_create");
4950*44704f69SBart Van Assche
4951*44704f69SBart Van Assche /* wait for any broadcast */
4952*44704f69SBart Van Assche pthread_cleanup_push(cleanup_out, (void *)clp);
4953*44704f69SBart Van Assche status = pthread_cond_wait(&clp->out_sync_cv, &clp->out_mutex);
4954*44704f69SBart Van Assche if (0 != status) err_exit(status, "cond out_sync_cv");
4955*44704f69SBart Van Assche pthread_cleanup_pop(0);
4956*44704f69SBart Van Assche status = pthread_mutex_unlock(&clp->out_mutex);
4957*44704f69SBart Van Assche if (0 != status) err_exit(status, "unlock out_mutex");
4958*44704f69SBart Van Assche
4959*44704f69SBart Van Assche /* now start the rest of the threads */
4960*44704f69SBart Van Assche for (k = 1; k < num_threads; ++k) {
4961*44704f69SBart Van Assche tip = thread_arr + k;
4962*44704f69SBart Van Assche tip->gcp = clp;
4963*44704f69SBart Van Assche tip->id = k;
4964*44704f69SBart Van Assche status = pthread_create(&tip->a_pthr, NULL, read_write_thread,
4965*44704f69SBart Van Assche (void *)tip);
4966*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_create");
4967*44704f69SBart Van Assche }
4968*44704f69SBart Van Assche
4969*44704f69SBart Van Assche /* now wait for worker threads to finish */
4970*44704f69SBart Van Assche for (k = 0; k < num_threads; ++k) {
4971*44704f69SBart Van Assche tip = thread_arr + k;
4972*44704f69SBart Van Assche status = pthread_join(tip->a_pthr, &vp);
4973*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_join");
4974*44704f69SBart Van Assche if (clp->verbose > 2)
4975*44704f69SBart Van Assche pr2serr_lk("%d <-- Worker thread terminated, vp=%s\n", k,
4976*44704f69SBart Van Assche ((vp == clp) ? "clp" : "NULL (or !clp)"));
4977*44704f69SBart Van Assche }
4978*44704f69SBart Van Assche } /* started worker threads and here after they have all exited */
4979*44704f69SBart Van Assche
4980*44704f69SBart Van Assche if (do_time && (start_tm.tv_sec || start_tm.tv_usec))
4981*44704f69SBart Van Assche calc_duration_throughput(0);
4982*44704f69SBart Van Assche
4983*44704f69SBart Van Assche shutting_down = true;
4984*44704f69SBart Van Assche status = pthread_join(sig_listen_thread_id, &vp);
4985*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_join");
4986*44704f69SBart Van Assche #if 0
4987*44704f69SBart Van Assche /* pthread_cancel() has issues and is not supported in Android */
4988*44704f69SBart Van Assche status = pthread_kill(sig_listen_thread_id, SIGUSR2);
4989*44704f69SBart Van Assche if (0 != status) err_exit(status, "pthread_kill");
4990*44704f69SBart Van Assche std::this_thread::yield(); // not enough it seems
4991*44704f69SBart Van Assche { /* allow time for SIGUSR2 signal to get through */
4992*44704f69SBart Van Assche struct timespec tspec = {0, 400000}; /* 400 usecs */
4993*44704f69SBart Van Assche
4994*44704f69SBart Van Assche nanosleep(&tspec, NULL);
4995*44704f69SBart Van Assche }
4996*44704f69SBart Van Assche #endif
4997*44704f69SBart Van Assche
4998*44704f69SBart Van Assche if (do_sync) {
4999*44704f69SBart Van Assche if (FT_SG == clp->out_type) {
5000*44704f69SBart Van Assche pr2serr_lk(">> Synchronizing cache on %s\n", outf);
5001*44704f69SBart Van Assche res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false, 0);
5002*44704f69SBart Van Assche if (SG_LIB_CAT_UNIT_ATTENTION == res) {
5003*44704f69SBart Van Assche pr2serr_lk("Unit attention(out), continuing\n");
5004*44704f69SBart Van Assche res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false,
5005*44704f69SBart Van Assche 0);
5006*44704f69SBart Van Assche }
5007*44704f69SBart Van Assche if (0 != res)
5008*44704f69SBart Van Assche pr2serr_lk("Unable to synchronize cache\n");
5009*44704f69SBart Van Assche }
5010*44704f69SBart Van Assche if (FT_SG == clp->out2_type) {
5011*44704f69SBart Van Assche pr2serr_lk(">> Synchronizing cache on %s\n", out2f);
5012*44704f69SBart Van Assche res = sg_ll_sync_cache_10(clp->out2fd, 0, 0, 0, 0, 0, false, 0);
5013*44704f69SBart Van Assche if (SG_LIB_CAT_UNIT_ATTENTION == res) {
5014*44704f69SBart Van Assche pr2serr_lk("Unit attention(out2), continuing\n");
5015*44704f69SBart Van Assche res = sg_ll_sync_cache_10(clp->out2fd, 0, 0, 0, 0, 0, false,
5016*44704f69SBart Van Assche 0);
5017*44704f69SBart Van Assche }
5018*44704f69SBart Van Assche if (0 != res)
5019*44704f69SBart Van Assche pr2serr_lk("Unable to synchronize cache (of2)\n");
5020*44704f69SBart Van Assche }
5021*44704f69SBart Van Assche }
5022*44704f69SBart Van Assche
5023*44704f69SBart Van Assche fini:
5024*44704f69SBart Van Assche if ((STDIN_FILENO != clp->infd) && (clp->infd >= 0))
5025*44704f69SBart Van Assche close(clp->infd);
5026*44704f69SBart Van Assche if ((STDOUT_FILENO != clp->outfd) && (FT_DEV_NULL != clp->out_type) &&
5027*44704f69SBart Van Assche (clp->outfd >= 0))
5028*44704f69SBart Van Assche close(clp->outfd);
5029*44704f69SBart Van Assche if ((clp->out2fd >= 0) && (STDOUT_FILENO != clp->out2fd) &&
5030*44704f69SBart Van Assche (FT_DEV_NULL != clp->out2_type))
5031*44704f69SBart Van Assche close(clp->out2fd);
5032*44704f69SBart Van Assche if ((clp->outregfd >= 0) && (STDOUT_FILENO != clp->outregfd) &&
5033*44704f69SBart Van Assche (FT_DEV_NULL != clp->outreg_type))
5034*44704f69SBart Van Assche close(clp->outregfd);
5035*44704f69SBart Van Assche res = exit_status;
5036*44704f69SBart Van Assche if ((0 != clp->out_count.load()) && (0 == clp->dry_run)) {
5037*44704f69SBart Van Assche pr2serr(">>>> Some error occurred, remaining blocks=%" PRId64 "\n",
5038*44704f69SBart Van Assche clp->out_count.load());
5039*44704f69SBart Van Assche if (0 == res)
5040*44704f69SBart Van Assche res = SG_LIB_CAT_OTHER;
5041*44704f69SBart Van Assche }
5042*44704f69SBart Van Assche print_stats("");
5043*44704f69SBart Van Assche if (clp->dio_incomplete_count.load()) {
5044*44704f69SBart Van Assche int fd;
5045*44704f69SBart Van Assche char c;
5046*44704f69SBart Van Assche
5047*44704f69SBart Van Assche pr2serr(">> Direct IO requested but incomplete %d times\n",
5048*44704f69SBart Van Assche clp->dio_incomplete_count.load());
5049*44704f69SBart Van Assche if ((fd = open(sg_allow_dio, O_RDONLY)) >= 0) {
5050*44704f69SBart Van Assche if (1 == read(fd, &c, 1)) {
5051*44704f69SBart Van Assche if ('0' == c)
5052*44704f69SBart Van Assche pr2serr(">>> %s set to '0' but should be set to '1' for "
5053*44704f69SBart Van Assche "direct IO\n", sg_allow_dio);
5054*44704f69SBart Van Assche }
5055*44704f69SBart Van Assche close(fd);
5056*44704f69SBart Van Assche }
5057*44704f69SBart Van Assche }
5058*44704f69SBart Van Assche if (clp->sum_of_resids.load())
5059*44704f69SBart Van Assche pr2serr(">> Non-zero sum of residual counts=%d\n",
5060*44704f69SBart Van Assche clp->sum_of_resids.load());
5061*44704f69SBart Van Assche if (clp->verbose && (num_start_eagain > 0))
5062*44704f69SBart Van Assche pr2serr("Number of start EAGAINs: %d\n", num_start_eagain.load());
5063*44704f69SBart Van Assche if (clp->verbose && (num_fin_eagain > 0))
5064*44704f69SBart Van Assche pr2serr("Number of finish EAGAINs: %d\n", num_fin_eagain.load());
5065*44704f69SBart Van Assche if (clp->verbose && (num_ebusy > 0))
5066*44704f69SBart Van Assche pr2serr("Number of EBUSYs: %d\n", num_ebusy.load());
5067*44704f69SBart Van Assche if (clp->verbose && clp->aen_given && (num_abort_req > 0)) {
5068*44704f69SBart Van Assche pr2serr("Number of Aborts: %d\n", num_abort_req.load());
5069*44704f69SBart Van Assche pr2serr("Number of successful Aborts: %d\n",
5070*44704f69SBart Van Assche num_abort_req_success.load());
5071*44704f69SBart Van Assche }
5072*44704f69SBart Van Assche if (clp->verbose && clp->m_aen_given && (num_mrq_abort_req > 0)) {
5073*44704f69SBart Van Assche pr2serr("Number of MRQ Aborts: %d\n", num_mrq_abort_req.load());
5074*44704f69SBart Van Assche pr2serr("Number of successful MRQ Aborts: %d\n",
5075*44704f69SBart Van Assche num_mrq_abort_req_success.load());
5076*44704f69SBart Van Assche }
5077*44704f69SBart Van Assche if (clp->verbose && (num_miscompare > 0))
5078*44704f69SBart Van Assche pr2serr("Number of miscompare%s: %d\n",
5079*44704f69SBart Van Assche (num_miscompare > 1) ? "s" : "", num_miscompare.load());
5080*44704f69SBart Van Assche if (clp->verbose > 1) {
5081*44704f69SBart Van Assche if (clp->verbose > 3)
5082*44704f69SBart Van Assche pr2serr("Final pack_id=%d, mrq_id=%d\n", mono_pack_id.load(),
5083*44704f69SBart Van Assche mono_mrq_id.load());
5084*44704f69SBart Van Assche pr2serr("Number of SG_GET_NUM_WAITING calls=%ld\n",
5085*44704f69SBart Van Assche num_waiting_calls.load());
5086*44704f69SBart Van Assche }
5087*44704f69SBart Van Assche if (clp->verify && (SG_LIB_CAT_MISCOMPARE == res))
5088*44704f69SBart Van Assche pr2serr("Verify/compare failed due to miscompare\n");
5089*44704f69SBart Van Assche return (res >= 0) ? res : SG_LIB_CAT_OTHER;
5090*44704f69SBart Van Assche }
5091