1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * A utility program for the Linux OS SCSI generic ("sg") device driver.
3*44704f69SBart Van Assche * Copyright (C) 1999-2010 D. Gilbert and P. Allworth
4*44704f69SBart Van Assche * This program is free software; you can redistribute it and/or modify
5*44704f69SBart Van Assche * it under the terms of the GNU General Public License as published by
6*44704f69SBart Van Assche * the Free Software Foundation; either version 2, or (at your option)
7*44704f69SBart Van Assche * any later version.
8*44704f69SBart Van Assche *
9*44704f69SBart Van Assche * SPDX-License-Identifier: GPL-2.0-or-later
10*44704f69SBart Van Assche *
11*44704f69SBart Van Assche * This program is a specialization of the Unix "dd" command in which
12*44704f69SBart Van Assche * one or both of the given files is a scsi generic device or a raw
13*44704f69SBart Van Assche * device. A block size ('bs') is assumed to be 512 if not given. This
14*44704f69SBart Van Assche * program complains if 'ibs' or 'obs' are given with some other value
15*44704f69SBart Van Assche * than 'bs'. If 'if' is not given or 'if=-' then stdin is assumed. If
16*44704f69SBart Van Assche * 'of' is not given or 'of=-' then stdout assumed. Multipliers:
17*44704f69SBart Van Assche * 'c','C' *1 'b','B' *512 'k' *1024 'K' *1000
18*44704f69SBart Van Assche * 'm' *(1024^2) 'M' *(1000^2) 'g' *(1024^3) 'G' *(1000^3)
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 (16KB
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 should compile with Linux sg drivers with version numbers
27*44704f69SBart Van Assche * >= 30000 . This version uses queuing within the Linux sg driver.
28*44704f69SBart Van Assche */
29*44704f69SBart Van Assche
30*44704f69SBart Van Assche #define _XOPEN_SOURCE 500
31*44704f69SBart Van Assche
32*44704f69SBart Van Assche #include <unistd.h>
33*44704f69SBart Van Assche #include <fcntl.h>
34*44704f69SBart Van Assche #include <stdio.h>
35*44704f69SBart Van Assche #include <stdlib.h>
36*44704f69SBart Van Assche #include <stdint.h>
37*44704f69SBart Van Assche #include <stdbool.h>
38*44704f69SBart Van Assche #include <string.h>
39*44704f69SBart Van Assche #include <ctype.h>
40*44704f69SBart Van Assche #include <errno.h>
41*44704f69SBart Van Assche #include <limits.h>
42*44704f69SBart Van Assche #include <signal.h>
43*44704f69SBart Van Assche #include <poll.h>
44*44704f69SBart Van Assche #include <sys/ioctl.h>
45*44704f69SBart Van Assche #include <sys/types.h>
46*44704f69SBart Van Assche #include <sys/stat.h>
47*44704f69SBart Van Assche #include <sys/sysmacros.h>
48*44704f69SBart Van Assche #include <linux/major.h>
49*44704f69SBart Van Assche #include <sys/time.h>
50*44704f69SBart Van Assche typedef uint8_t u_char; /* horrible, for scsi.h */
51*44704f69SBart Van Assche #include "sg_lib.h"
52*44704f69SBart Van Assche #include "sg_io_linux.h"
53*44704f69SBart Van Assche #include "sg_unaligned.h"
54*44704f69SBart Van Assche
55*44704f69SBart Van Assche
56*44704f69SBart Van Assche static char * version_str = "0.63 20190324";
57*44704f69SBart Van Assche /* resurrected from "0.55 20020509" */
58*44704f69SBart Van Assche
59*44704f69SBart Van Assche #define DEF_BLOCK_SIZE 512
60*44704f69SBart Van Assche #define DEF_BLOCKS_PER_TRANSFER 128
61*44704f69SBart Van Assche
62*44704f69SBart Van Assche
63*44704f69SBart Van Assche #define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
64*44704f69SBart Van Assche #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
65*44704f69SBart Van Assche #define S_RW_LEN 10 /* Use SCSI READ(10) and WRITE(10) */
66*44704f69SBart Van Assche
67*44704f69SBart Van Assche #define SGP_READ10 0x28
68*44704f69SBart Van Assche #define SGP_WRITE10 0x2a
69*44704f69SBart Van Assche #define DEF_NUM_THREADS 4 /* actually degree of concurrency */
70*44704f69SBart Van Assche #define MAX_NUM_THREADS 1024
71*44704f69SBart Van Assche
72*44704f69SBart Van Assche #ifndef RAW_MAJOR
73*44704f69SBart Van Assche #define RAW_MAJOR 255 /*unlikely value */
74*44704f69SBart Van Assche #endif
75*44704f69SBart Van Assche
76*44704f69SBart Van Assche #define FT_OTHER 0 /* filetype other than sg or raw device */
77*44704f69SBart Van Assche #define FT_SG 1 /* filetype is sg char device */
78*44704f69SBart Van Assche #define FT_RAW 2 /* filetype is raw char device */
79*44704f69SBart Van Assche
80*44704f69SBart Van Assche #define QS_IDLE 0 /* ready to start a copy cycle */
81*44704f69SBart Van Assche #define QS_IN_STARTED 1 /* commenced read */
82*44704f69SBart Van Assche #define QS_IN_FINISHED 2 /* finished read, ready for write */
83*44704f69SBart Van Assche #define QS_OUT_STARTED 3 /* commenced write */
84*44704f69SBart Van Assche
85*44704f69SBart Van Assche #define QS_IN_POLL 11
86*44704f69SBart Van Assche #define QS_OUT_POLL 12
87*44704f69SBart Van Assche
88*44704f69SBart Van Assche #define STR_SZ 1024
89*44704f69SBart Van Assche #define INOUTF_SZ 512
90*44704f69SBart Van Assche #define EBUFF_SZ 512
91*44704f69SBart Van Assche
92*44704f69SBart Van Assche
93*44704f69SBart Van Assche struct request_element;
94*44704f69SBart Van Assche
95*44704f69SBart Van Assche typedef struct request_collection
96*44704f69SBart Van Assche { /* one instance visible to all threads */
97*44704f69SBart Van Assche int infd;
98*44704f69SBart Van Assche int skip;
99*44704f69SBart Van Assche int in_type;
100*44704f69SBart Van Assche int in_scsi_type;
101*44704f69SBart Van Assche int in_blk; /* next block address to read */
102*44704f69SBart Van Assche int in_count; /* blocks remaining for next read */
103*44704f69SBart Van Assche int in_done_count; /* count of completed in blocks */
104*44704f69SBart Van Assche int in_partial;
105*44704f69SBart Van Assche int outfd;
106*44704f69SBart Van Assche int seek;
107*44704f69SBart Van Assche int out_type;
108*44704f69SBart Van Assche int out_scsi_type;
109*44704f69SBart Van Assche int out_blk; /* next block address to write */
110*44704f69SBart Van Assche int out_count; /* blocks remaining for next write */
111*44704f69SBart Van Assche int out_done_count; /* count of completed out blocks */
112*44704f69SBart Van Assche int out_partial;
113*44704f69SBart Van Assche int bs;
114*44704f69SBart Van Assche int bpt;
115*44704f69SBart Van Assche int dio;
116*44704f69SBart Van Assche int dio_incomplete;
117*44704f69SBart Van Assche int sum_of_resids;
118*44704f69SBart Van Assche int coe;
119*44704f69SBart Van Assche int debug;
120*44704f69SBart Van Assche int num_rq_elems;
121*44704f69SBart Van Assche struct request_element * req_arr;
122*44704f69SBart Van Assche } Rq_coll;
123*44704f69SBart Van Assche
124*44704f69SBart Van Assche typedef struct request_element
125*44704f69SBart Van Assche { /* one instance per worker thread */
126*44704f69SBart Van Assche int qstate; /* "QS" state */
127*44704f69SBart Van Assche int infd;
128*44704f69SBart Van Assche int outfd;
129*44704f69SBart Van Assche int wr;
130*44704f69SBart Van Assche int blk;
131*44704f69SBart Van Assche int num_blks;
132*44704f69SBart Van Assche uint8_t * buffp;
133*44704f69SBart Van Assche uint8_t * alloc_bp;
134*44704f69SBart Van Assche sg_io_hdr_t io_hdr;
135*44704f69SBart Van Assche uint8_t cmd[S_RW_LEN];
136*44704f69SBart Van Assche uint8_t sb[SENSE_BUFF_LEN];
137*44704f69SBart Van Assche int bs;
138*44704f69SBart Van Assche int dio;
139*44704f69SBart Van Assche int dio_incomplete;
140*44704f69SBart Van Assche int resid;
141*44704f69SBart Van Assche int in_scsi_type;
142*44704f69SBart Van Assche int out_scsi_type;
143*44704f69SBart Van Assche int debug;
144*44704f69SBart Van Assche } Rq_elem;
145*44704f69SBart Van Assche
146*44704f69SBart Van Assche static Rq_coll rcoll;
147*44704f69SBart Van Assche static struct pollfd in_pollfd_arr[MAX_NUM_THREADS];
148*44704f69SBart Van Assche static struct pollfd out_pollfd_arr[MAX_NUM_THREADS];
149*44704f69SBart Van Assche static int dd_count = -1;
150*44704f69SBart Van Assche
151*44704f69SBart Van Assche static const char * sg_allow_dio = "/sys/module/sg/parameters/allow_dio";
152*44704f69SBart Van Assche
153*44704f69SBart Van Assche static int sg_finish_io(int wr, Rq_elem * rep);
154*44704f69SBart Van Assche
155*44704f69SBart Van Assche
156*44704f69SBart Van Assche /* Returns the number of times 'ch' is found in string 's' given the
157*44704f69SBart Van Assche * string's length. */
158*44704f69SBart Van Assche static int
num_chs_in_str(const char * s,int slen,int ch)159*44704f69SBart Van Assche num_chs_in_str(const char * s, int slen, int ch)
160*44704f69SBart Van Assche {
161*44704f69SBart Van Assche int res = 0;
162*44704f69SBart Van Assche
163*44704f69SBart Van Assche while (--slen >= 0) {
164*44704f69SBart Van Assche if (ch == s[slen])
165*44704f69SBart Van Assche ++res;
166*44704f69SBart Van Assche }
167*44704f69SBart Van Assche return res;
168*44704f69SBart Van Assche }
169*44704f69SBart Van Assche
170*44704f69SBart Van Assche static void
install_handler(int sig_num,void (* sig_handler)(int sig))171*44704f69SBart Van Assche install_handler (int sig_num, void (*sig_handler) (int sig))
172*44704f69SBart Van Assche {
173*44704f69SBart Van Assche struct sigaction sigact;
174*44704f69SBart Van Assche sigaction (sig_num, NULL, &sigact);
175*44704f69SBart Van Assche if (sigact.sa_handler != SIG_IGN)
176*44704f69SBart Van Assche {
177*44704f69SBart Van Assche sigact.sa_handler = sig_handler;
178*44704f69SBart Van Assche sigemptyset (&sigact.sa_mask);
179*44704f69SBart Van Assche sigact.sa_flags = 0;
180*44704f69SBart Van Assche sigaction (sig_num, &sigact, NULL);
181*44704f69SBart Van Assche }
182*44704f69SBart Van Assche }
183*44704f69SBart Van Assche
184*44704f69SBart Van Assche static void
print_stats()185*44704f69SBart Van Assche print_stats()
186*44704f69SBart Van Assche {
187*44704f69SBart Van Assche int infull, outfull;
188*44704f69SBart Van Assche
189*44704f69SBart Van Assche if (0 != rcoll.out_count)
190*44704f69SBart Van Assche fprintf(stderr, " remaining block count=%d\n", rcoll.out_count);
191*44704f69SBart Van Assche infull = dd_count - rcoll.in_done_count - rcoll.in_partial;
192*44704f69SBart Van Assche fprintf(stderr, "%d+%d records in\n", infull, rcoll.in_partial);
193*44704f69SBart Van Assche outfull = dd_count - rcoll.out_done_count - rcoll.out_partial;
194*44704f69SBart Van Assche fprintf(stderr, "%d+%d records out\n", outfull, rcoll.out_partial);
195*44704f69SBart Van Assche }
196*44704f69SBart Van Assche
197*44704f69SBart Van Assche static void
interrupt_handler(int sig)198*44704f69SBart Van Assche interrupt_handler(int sig)
199*44704f69SBart Van Assche {
200*44704f69SBart Van Assche struct sigaction sigact;
201*44704f69SBart Van Assche
202*44704f69SBart Van Assche sigact.sa_handler = SIG_DFL;
203*44704f69SBart Van Assche sigemptyset (&sigact.sa_mask);
204*44704f69SBart Van Assche sigact.sa_flags = 0;
205*44704f69SBart Van Assche sigaction (sig, &sigact, NULL);
206*44704f69SBart Van Assche fprintf(stderr, "Interrupted by signal,");
207*44704f69SBart Van Assche print_stats ();
208*44704f69SBart Van Assche kill (getpid (), sig);
209*44704f69SBart Van Assche }
210*44704f69SBart Van Assche
211*44704f69SBart Van Assche static void
siginfo_handler(int sig)212*44704f69SBart Van Assche siginfo_handler(int sig)
213*44704f69SBart Van Assche {
214*44704f69SBart Van Assche fprintf(stderr, "Progress report, continuing ...\n");
215*44704f69SBart Van Assche print_stats ();
216*44704f69SBart Van Assche if (sig) { } /* suppress unused warning */
217*44704f69SBart Van Assche }
218*44704f69SBart Van Assche
219*44704f69SBart Van Assche static int
dd_filetype(const char * filename)220*44704f69SBart Van Assche dd_filetype(const char * filename)
221*44704f69SBart Van Assche {
222*44704f69SBart Van Assche struct stat st;
223*44704f69SBart Van Assche
224*44704f69SBart Van Assche if (stat(filename, &st) < 0)
225*44704f69SBart Van Assche return FT_OTHER;
226*44704f69SBart Van Assche if (S_ISCHR(st.st_mode)) {
227*44704f69SBart Van Assche if (RAW_MAJOR == major(st.st_rdev))
228*44704f69SBart Van Assche return FT_RAW;
229*44704f69SBart Van Assche else if (SCSI_GENERIC_MAJOR == major(st.st_rdev))
230*44704f69SBart Van Assche return FT_SG;
231*44704f69SBart Van Assche }
232*44704f69SBart Van Assche return FT_OTHER;
233*44704f69SBart Van Assche }
234*44704f69SBart Van Assche
235*44704f69SBart Van Assche static void
usage()236*44704f69SBart Van Assche usage()
237*44704f69SBart Van Assche {
238*44704f69SBart Van Assche fprintf(stderr, "Usage: "
239*44704f69SBart Van Assche "sgq_dd [if=<infile>] [skip=<n>] [of=<ofile>] [seek=<n>] "
240*44704f69SBart Van Assche "[bs=<num>]\n"
241*44704f69SBart Van Assche " [bpt=<num>] [count=<n>] [dio=0|1] [thr=<n>] "
242*44704f69SBart Van Assche "[coe=0|1] [gen=<n>]\n"
243*44704f69SBart Van Assche " [time=0|1] [deb=<n>] [--version]\n"
244*44704f69SBart Van Assche " usually either 'if' or 'of' is a sg or raw device\n"
245*44704f69SBart Van Assche " 'bpt' is blocks_per_transfer (default is 128)\n"
246*44704f69SBart Van Assche " 'dio' is direct IO, 1->attempt, 0->indirect IO (def)\n"
247*44704f69SBart Van Assche " 'thr' is number of queues, must be > 0, default 4, max 1024\n");
248*44704f69SBart Van Assche fprintf(stderr, " 'coe' continue on sg error, 0->exit (def), "
249*44704f69SBart Van Assche "1->zero + continue\n"
250*44704f69SBart Van Assche " 'time' 0->no timing(def), 1->time plus calculate throughput\n"
251*44704f69SBart Van Assche " 'gen' 0-> 1 file is special(def), 1-> any files allowed\n"
252*44704f69SBart Van Assche " 'deb' is debug, 0->none (def), > 0->varying degrees of debug\n");
253*44704f69SBart Van Assche }
254*44704f69SBart Van Assche
255*44704f69SBart Van Assche /* Returns -1 for error, 0 for nothing found, QS_IN_POLL or QS_OUT_POLL */
256*44704f69SBart Van Assche static int
do_poll(Rq_coll * clp,int timeout,int * req_indexp)257*44704f69SBart Van Assche do_poll(Rq_coll * clp, int timeout, int * req_indexp)
258*44704f69SBart Van Assche {
259*44704f69SBart Van Assche int k, res;
260*44704f69SBart Van Assche
261*44704f69SBart Van Assche if (FT_SG == clp->out_type) {
262*44704f69SBart Van Assche while (((res = poll(out_pollfd_arr, clp->num_rq_elems, timeout)) < 0)
263*44704f69SBart Van Assche && (EINTR == errno))
264*44704f69SBart Van Assche ;
265*44704f69SBart Van Assche if (res < 0) {
266*44704f69SBart Van Assche perror("poll error on output fds");
267*44704f69SBart Van Assche return -1;
268*44704f69SBart Van Assche }
269*44704f69SBart Van Assche else if (res > 0) {
270*44704f69SBart Van Assche for (k = 0; k < clp->num_rq_elems; ++k) {
271*44704f69SBart Van Assche if (out_pollfd_arr[k].revents & POLLIN) {
272*44704f69SBart Van Assche if (req_indexp)
273*44704f69SBart Van Assche *req_indexp = k;
274*44704f69SBart Van Assche return QS_OUT_POLL;
275*44704f69SBart Van Assche }
276*44704f69SBart Van Assche }
277*44704f69SBart Van Assche }
278*44704f69SBart Van Assche }
279*44704f69SBart Van Assche if (FT_SG == clp->in_type) {
280*44704f69SBart Van Assche while (((res = poll(in_pollfd_arr, clp->num_rq_elems, timeout)) < 0)
281*44704f69SBart Van Assche && (EINTR == errno))
282*44704f69SBart Van Assche ;
283*44704f69SBart Van Assche if (res < 0) {
284*44704f69SBart Van Assche perror("poll error on input fds");
285*44704f69SBart Van Assche return -1;
286*44704f69SBart Van Assche }
287*44704f69SBart Van Assche else if (res > 0) {
288*44704f69SBart Van Assche for (k = 0; k < clp->num_rq_elems; ++k) {
289*44704f69SBart Van Assche if (in_pollfd_arr[k].revents & POLLIN) {
290*44704f69SBart Van Assche if (req_indexp)
291*44704f69SBart Van Assche *req_indexp = k;
292*44704f69SBart Van Assche return QS_IN_POLL;
293*44704f69SBart Van Assche }
294*44704f69SBart Van Assche }
295*44704f69SBart Van Assche }
296*44704f69SBart Van Assche }
297*44704f69SBart Van Assche return 0;
298*44704f69SBart Van Assche }
299*44704f69SBart Van Assche
300*44704f69SBart Van Assche
301*44704f69SBart Van Assche /* Return of 0 -> success, -1 -> failure, 2 -> try again */
302*44704f69SBart Van Assche static int
read_capacity(int sg_fd,int * num_sect,int * sect_sz)303*44704f69SBart Van Assche read_capacity(int sg_fd, int * num_sect, int * sect_sz)
304*44704f69SBart Van Assche {
305*44704f69SBart Van Assche int res;
306*44704f69SBart Van Assche uint8_t rc_cdb [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0};
307*44704f69SBart Van Assche uint8_t rcBuff[64];
308*44704f69SBart Van Assche uint8_t sense_b[64];
309*44704f69SBart Van Assche sg_io_hdr_t io_hdr;
310*44704f69SBart Van Assche
311*44704f69SBart Van Assche memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
312*44704f69SBart Van Assche io_hdr.interface_id = 'S';
313*44704f69SBart Van Assche io_hdr.cmd_len = sizeof(rc_cdb);
314*44704f69SBart Van Assche io_hdr.mx_sb_len = sizeof(sense_b);
315*44704f69SBart Van Assche io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
316*44704f69SBart Van Assche io_hdr.dxfer_len = sizeof(rcBuff);
317*44704f69SBart Van Assche io_hdr.dxferp = rcBuff;
318*44704f69SBart Van Assche io_hdr.cmdp = rc_cdb;
319*44704f69SBart Van Assche io_hdr.sbp = sense_b;
320*44704f69SBart Van Assche io_hdr.timeout = DEF_TIMEOUT;
321*44704f69SBart Van Assche
322*44704f69SBart Van Assche if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
323*44704f69SBart Van Assche perror("read_capacity (SG_IO) error");
324*44704f69SBart Van Assche return -1;
325*44704f69SBart Van Assche }
326*44704f69SBart Van Assche res = sg_err_category3(&io_hdr);
327*44704f69SBart Van Assche if (SG_LIB_CAT_UNIT_ATTENTION == res)
328*44704f69SBart Van Assche return 2; /* probably have another go ... */
329*44704f69SBart Van Assche else if (SG_LIB_CAT_CLEAN != res) {
330*44704f69SBart Van Assche sg_chk_n_print3("read capacity", &io_hdr, 1);
331*44704f69SBart Van Assche return -1;
332*44704f69SBart Van Assche }
333*44704f69SBart Van Assche *num_sect = 1 + sg_get_unaligned_be32(rcBuff + 0);
334*44704f69SBart Van Assche *sect_sz = sg_get_unaligned_be32(rcBuff + 4);
335*44704f69SBart Van Assche #ifdef DEBUG
336*44704f69SBart Van Assche fprintf(stderr, "number of sectors=%d, sector size=%d\n",
337*44704f69SBart Van Assche *num_sect, *sect_sz);
338*44704f69SBart Van Assche #endif
339*44704f69SBart Van Assche return 0;
340*44704f69SBart Van Assche }
341*44704f69SBart Van Assche
342*44704f69SBart Van Assche /* 0 -> ok, 1 -> short read, -1 -> error */
343*44704f69SBart Van Assche static int
normal_in_operation(Rq_coll * clp,Rq_elem * rep,int blocks)344*44704f69SBart Van Assche normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks)
345*44704f69SBart Van Assche {
346*44704f69SBart Van Assche int res;
347*44704f69SBart Van Assche int stop_after_write = 0;
348*44704f69SBart Van Assche
349*44704f69SBart Van Assche rep->qstate = QS_IN_STARTED;
350*44704f69SBart Van Assche if (rep->debug > 8)
351*44704f69SBart Van Assche fprintf(stderr, "normal_in_operation: start blk=%d num_blks=%d\n",
352*44704f69SBart Van Assche rep->blk, rep->num_blks);
353*44704f69SBart Van Assche while (((res = read(rep->infd, rep->buffp,
354*44704f69SBart Van Assche blocks * rep->bs)) < 0) && (EINTR == errno))
355*44704f69SBart Van Assche ;
356*44704f69SBart Van Assche if (res < 0) {
357*44704f69SBart Van Assche fprintf(stderr, "sgq_dd: reading, in_blk=%d, errno=%d\n", rep->blk,
358*44704f69SBart Van Assche errno);
359*44704f69SBart Van Assche return -1;
360*44704f69SBart Van Assche }
361*44704f69SBart Van Assche if (res < blocks * rep->bs) {
362*44704f69SBart Van Assche int o_blocks = blocks;
363*44704f69SBart Van Assche stop_after_write = 1;
364*44704f69SBart Van Assche blocks = res / rep->bs;
365*44704f69SBart Van Assche if ((res % rep->bs) > 0) {
366*44704f69SBart Van Assche blocks++;
367*44704f69SBart Van Assche clp->in_partial++;
368*44704f69SBart Van Assche }
369*44704f69SBart Van Assche /* Reverse out + re-apply blocks on clp */
370*44704f69SBart Van Assche clp->in_blk -= o_blocks;
371*44704f69SBart Van Assche clp->in_count += o_blocks;
372*44704f69SBart Van Assche rep->num_blks = blocks;
373*44704f69SBart Van Assche clp->in_blk += blocks;
374*44704f69SBart Van Assche clp->in_count -= blocks;
375*44704f69SBart Van Assche }
376*44704f69SBart Van Assche clp->in_done_count -= blocks;
377*44704f69SBart Van Assche rep->qstate = QS_IN_FINISHED;
378*44704f69SBart Van Assche return stop_after_write;
379*44704f69SBart Van Assche }
380*44704f69SBart Van Assche
381*44704f69SBart Van Assche /* 0 -> ok, -1 -> error */
382*44704f69SBart Van Assche static int
normal_out_operation(Rq_coll * clp,Rq_elem * rep,int blocks)383*44704f69SBart Van Assche normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks)
384*44704f69SBart Van Assche {
385*44704f69SBart Van Assche int res;
386*44704f69SBart Van Assche
387*44704f69SBart Van Assche rep->qstate = QS_OUT_STARTED;
388*44704f69SBart Van Assche if (rep->debug > 8)
389*44704f69SBart Van Assche fprintf(stderr, "normal_out_operation: start blk=%d num_blks=%d\n",
390*44704f69SBart Van Assche rep->blk, rep->num_blks);
391*44704f69SBart Van Assche while (((res = write(rep->outfd, rep->buffp,
392*44704f69SBart Van Assche rep->num_blks * rep->bs)) < 0) && (EINTR == errno))
393*44704f69SBart Van Assche ;
394*44704f69SBart Van Assche if (res < 0) {
395*44704f69SBart Van Assche fprintf(stderr, "sgq_dd: output, out_blk=%d, errno=%d\n", rep->blk,
396*44704f69SBart Van Assche errno);
397*44704f69SBart Van Assche return -1;
398*44704f69SBart Van Assche }
399*44704f69SBart Van Assche if (res < blocks * rep->bs) {
400*44704f69SBart Van Assche blocks = res / rep->bs;
401*44704f69SBart Van Assche if ((res % rep->bs) > 0) {
402*44704f69SBart Van Assche blocks++;
403*44704f69SBart Van Assche clp->out_partial++;
404*44704f69SBart Van Assche }
405*44704f69SBart Van Assche rep->num_blks = blocks;
406*44704f69SBart Van Assche }
407*44704f69SBart Van Assche clp->out_done_count -= blocks;
408*44704f69SBart Van Assche rep->qstate = QS_IDLE;
409*44704f69SBart Van Assche return 0;
410*44704f69SBart Van Assche }
411*44704f69SBart Van Assche
412*44704f69SBart Van Assche /* Returns 1 for retryable, 0 for ok, -ve for error */
413*44704f69SBart Van Assche static int
sg_fin_in_operation(Rq_coll * clp,Rq_elem * rep)414*44704f69SBart Van Assche sg_fin_in_operation(Rq_coll * clp, Rq_elem * rep)
415*44704f69SBart Van Assche {
416*44704f69SBart Van Assche int res;
417*44704f69SBart Van Assche
418*44704f69SBart Van Assche rep->qstate = QS_IN_FINISHED;
419*44704f69SBart Van Assche res = sg_finish_io(rep->wr, rep);
420*44704f69SBart Van Assche if (res < 0) {
421*44704f69SBart Van Assche if (clp->coe) {
422*44704f69SBart Van Assche memset(rep->buffp, 0, rep->num_blks * rep->bs);
423*44704f69SBart Van Assche fprintf(stderr, ">> substituted zeros for in blk=%d for "
424*44704f69SBart Van Assche "%d bytes\n", rep->blk, rep->num_blks * rep->bs);
425*44704f69SBart Van Assche res = 0;
426*44704f69SBart Van Assche }
427*44704f69SBart Van Assche else {
428*44704f69SBart Van Assche fprintf(stderr, "error finishing sg in command\n");
429*44704f69SBart Van Assche return res;
430*44704f69SBart Van Assche }
431*44704f69SBart Van Assche }
432*44704f69SBart Van Assche if (0 == res) { /* looks good, going to return */
433*44704f69SBart Van Assche if (rep->dio_incomplete || rep->resid) {
434*44704f69SBart Van Assche clp->dio_incomplete += rep->dio_incomplete;
435*44704f69SBart Van Assche clp->sum_of_resids += rep->resid;
436*44704f69SBart Van Assche }
437*44704f69SBart Van Assche clp->in_done_count -= rep->num_blks;
438*44704f69SBart Van Assche }
439*44704f69SBart Van Assche return res;
440*44704f69SBart Van Assche }
441*44704f69SBart Van Assche
442*44704f69SBart Van Assche /* Returns 1 for retryable, 0 for ok, -ve for error */
443*44704f69SBart Van Assche static int
sg_fin_out_operation(Rq_coll * clp,Rq_elem * rep)444*44704f69SBart Van Assche sg_fin_out_operation(Rq_coll * clp, Rq_elem * rep)
445*44704f69SBart Van Assche {
446*44704f69SBart Van Assche int res;
447*44704f69SBart Van Assche
448*44704f69SBart Van Assche rep->qstate = QS_IDLE;
449*44704f69SBart Van Assche res = sg_finish_io(rep->wr, rep);
450*44704f69SBart Van Assche if (res < 0) {
451*44704f69SBart Van Assche if (clp->coe) {
452*44704f69SBart Van Assche fprintf(stderr, ">> ignored error for out blk=%d for "
453*44704f69SBart Van Assche "%d bytes\n", rep->blk, rep->num_blks * rep->bs);
454*44704f69SBart Van Assche res = 0;
455*44704f69SBart Van Assche }
456*44704f69SBart Van Assche else {
457*44704f69SBart Van Assche fprintf(stderr, "error finishing sg out command\n");
458*44704f69SBart Van Assche return res;
459*44704f69SBart Van Assche }
460*44704f69SBart Van Assche }
461*44704f69SBart Van Assche if (0 == res) {
462*44704f69SBart Van Assche if (rep->dio_incomplete || rep->resid) {
463*44704f69SBart Van Assche clp->dio_incomplete += rep->dio_incomplete;
464*44704f69SBart Van Assche clp->sum_of_resids += rep->resid;
465*44704f69SBart Van Assche }
466*44704f69SBart Van Assche clp->out_done_count -= rep->num_blks;
467*44704f69SBart Van Assche }
468*44704f69SBart Van Assche return res;
469*44704f69SBart Van Assche }
470*44704f69SBart Van Assche
471*44704f69SBart Van Assche static int
sg_start_io(Rq_elem * rep)472*44704f69SBart Van Assche sg_start_io(Rq_elem * rep)
473*44704f69SBart Van Assche {
474*44704f69SBart Van Assche sg_io_hdr_t * hp = &rep->io_hdr;
475*44704f69SBart Van Assche int res;
476*44704f69SBart Van Assche
477*44704f69SBart Van Assche rep->qstate = rep->wr ? QS_OUT_STARTED : QS_IN_STARTED;
478*44704f69SBart Van Assche memset(rep->cmd, 0, sizeof(rep->cmd));
479*44704f69SBart Van Assche rep->cmd[0] = rep->wr ? SGP_WRITE10 : SGP_READ10;
480*44704f69SBart Van Assche sg_put_unaligned_be32((uint32_t)rep->blk, rep->cmd + 2);
481*44704f69SBart Van Assche sg_put_unaligned_be16((uint16_t)rep->num_blks, rep->cmd + 7);
482*44704f69SBart Van Assche memset(hp, 0, sizeof(sg_io_hdr_t));
483*44704f69SBart Van Assche hp->interface_id = 'S';
484*44704f69SBart Van Assche hp->cmd_len = sizeof(rep->cmd);
485*44704f69SBart Van Assche hp->cmdp = rep->cmd;
486*44704f69SBart Van Assche hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
487*44704f69SBart Van Assche hp->dxfer_len = rep->bs * rep->num_blks;
488*44704f69SBart Van Assche hp->dxferp = rep->buffp;
489*44704f69SBart Van Assche hp->mx_sb_len = sizeof(rep->sb);
490*44704f69SBart Van Assche hp->sbp = rep->sb;
491*44704f69SBart Van Assche hp->timeout = DEF_TIMEOUT;
492*44704f69SBart Van Assche hp->usr_ptr = rep;
493*44704f69SBart Van Assche hp->pack_id = rep->blk;
494*44704f69SBart Van Assche if (rep->dio)
495*44704f69SBart Van Assche hp->flags |= SG_FLAG_DIRECT_IO;
496*44704f69SBart Van Assche if (rep->debug > 8) {
497*44704f69SBart Van Assche fprintf(stderr, "sg_start_io: SCSI %s, blk=%d num_blks=%d\n",
498*44704f69SBart Van Assche rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
499*44704f69SBart Van Assche sg_print_command(hp->cmdp);
500*44704f69SBart Van Assche fprintf(stderr, " len=%d, dxfrp=%p, cmd_len=%d\n",
501*44704f69SBart Van Assche hp->dxfer_len, hp->dxferp, hp->cmd_len);
502*44704f69SBart Van Assche }
503*44704f69SBart Van Assche
504*44704f69SBart Van Assche while (((res = write(rep->wr ? rep->outfd : rep->infd, hp,
505*44704f69SBart Van Assche sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno))
506*44704f69SBart Van Assche ;
507*44704f69SBart Van Assche if (res < 0) {
508*44704f69SBart Van Assche if (ENOMEM == errno)
509*44704f69SBart Van Assche return 1;
510*44704f69SBart Van Assche return res;
511*44704f69SBart Van Assche }
512*44704f69SBart Van Assche return 0;
513*44704f69SBart Van Assche }
514*44704f69SBart Van Assche
515*44704f69SBart Van Assche /* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */
516*44704f69SBart Van Assche static int
sg_finish_io(int wr,Rq_elem * rep)517*44704f69SBart Van Assche sg_finish_io(int wr, Rq_elem * rep)
518*44704f69SBart Van Assche {
519*44704f69SBart Van Assche int res;
520*44704f69SBart Van Assche sg_io_hdr_t io_hdr;
521*44704f69SBart Van Assche sg_io_hdr_t * hp;
522*44704f69SBart Van Assche #if 0
523*44704f69SBart Van Assche static int testing = 0; /* thread dubious! */
524*44704f69SBart Van Assche #endif
525*44704f69SBart Van Assche
526*44704f69SBart Van Assche memset(&io_hdr, 0 , sizeof(sg_io_hdr_t));
527*44704f69SBart Van Assche /* FORCE_PACK_ID active set only read packet with matching pack_id */
528*44704f69SBart Van Assche io_hdr.interface_id = 'S';
529*44704f69SBart Van Assche io_hdr.dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
530*44704f69SBart Van Assche io_hdr.pack_id = rep->blk;
531*44704f69SBart Van Assche
532*44704f69SBart Van Assche while (((res = read(wr ? rep->outfd : rep->infd, &io_hdr,
533*44704f69SBart Van Assche sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno))
534*44704f69SBart Van Assche ;
535*44704f69SBart Van Assche if (res < 0) {
536*44704f69SBart Van Assche perror("finishing io on sg device, error");
537*44704f69SBart Van Assche return -1;
538*44704f69SBart Van Assche }
539*44704f69SBart Van Assche if (rep != (Rq_elem *)io_hdr.usr_ptr) {
540*44704f69SBart Van Assche fprintf(stderr,
541*44704f69SBart Van Assche "sg_finish_io: bad usr_ptr, request-response mismatch\n");
542*44704f69SBart Van Assche exit(1);
543*44704f69SBart Van Assche }
544*44704f69SBart Van Assche memcpy(&rep->io_hdr, &io_hdr, sizeof(sg_io_hdr_t));
545*44704f69SBart Van Assche hp = &rep->io_hdr;
546*44704f69SBart Van Assche
547*44704f69SBart Van Assche switch (sg_err_category3(hp)) {
548*44704f69SBart Van Assche case SG_LIB_CAT_CLEAN:
549*44704f69SBart Van Assche break;
550*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
551*44704f69SBart Van Assche fprintf(stderr, "Recovered error on block=%d, num=%d\n",
552*44704f69SBart Van Assche rep->blk, rep->num_blks);
553*44704f69SBart Van Assche break;
554*44704f69SBart Van Assche case SG_LIB_CAT_UNIT_ATTENTION:
555*44704f69SBart Van Assche return 1;
556*44704f69SBart Van Assche default:
557*44704f69SBart Van Assche {
558*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
559*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ, "%s blk=%d",
560*44704f69SBart Van Assche rep->wr ? "writing": "reading", rep->blk);
561*44704f69SBart Van Assche sg_chk_n_print3(ebuff, hp, 1);
562*44704f69SBart Van Assche return -1;
563*44704f69SBart Van Assche }
564*44704f69SBart Van Assche }
565*44704f69SBart Van Assche #if 0
566*44704f69SBart Van Assche if (0 == (++testing % 100)) return -1;
567*44704f69SBart Van Assche #endif
568*44704f69SBart Van Assche if (rep->dio &&
569*44704f69SBart Van Assche ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
570*44704f69SBart Van Assche rep->dio_incomplete = 1; /* count dios done as indirect IO */
571*44704f69SBart Van Assche else
572*44704f69SBart Van Assche rep->dio_incomplete = 0;
573*44704f69SBart Van Assche rep->resid = hp->resid;
574*44704f69SBart Van Assche if (rep->debug > 8)
575*44704f69SBart Van Assche fprintf(stderr, "sg_finish_io: completed %s, blk=%d\n",
576*44704f69SBart Van Assche wr ? "WRITE" : "READ", rep->blk);
577*44704f69SBart Van Assche return 0;
578*44704f69SBart Van Assche }
579*44704f69SBart Van Assche
580*44704f69SBart Van Assche /* Returns scsi_type or -1 for error */
581*44704f69SBart Van Assche static int
sg_prepare(int fd,int sz)582*44704f69SBart Van Assche sg_prepare(int fd, int sz)
583*44704f69SBart Van Assche {
584*44704f69SBart Van Assche int res, t;
585*44704f69SBart Van Assche struct sg_scsi_id info;
586*44704f69SBart Van Assche
587*44704f69SBart Van Assche res = ioctl(fd, SG_GET_VERSION_NUM, &t);
588*44704f69SBart Van Assche if ((res < 0) || (t < 30000)) {
589*44704f69SBart Van Assche fprintf(stderr, "sgq_dd: sg driver prior to 3.x.y\n");
590*44704f69SBart Van Assche return -1;
591*44704f69SBart Van Assche }
592*44704f69SBart Van Assche res = ioctl(fd, SG_SET_RESERVED_SIZE, &sz);
593*44704f69SBart Van Assche if (res < 0)
594*44704f69SBart Van Assche perror("sgq_dd: SG_SET_RESERVED_SIZE error");
595*44704f69SBart Van Assche #if 0
596*44704f69SBart Van Assche t = 1;
597*44704f69SBart Van Assche res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t);
598*44704f69SBart Van Assche if (res < 0)
599*44704f69SBart Van Assche perror("sgq_dd: SG_SET_FORCE_PACK_ID error");
600*44704f69SBart Van Assche #endif
601*44704f69SBart Van Assche res = ioctl(fd, SG_GET_SCSI_ID, &info);
602*44704f69SBart Van Assche if (res < 0) {
603*44704f69SBart Van Assche perror("sgq_dd: SG_SET_SCSI_ID error");
604*44704f69SBart Van Assche return -1;
605*44704f69SBart Van Assche }
606*44704f69SBart Van Assche else
607*44704f69SBart Van Assche return info.scsi_type;
608*44704f69SBart Van Assche }
609*44704f69SBart Van Assche
610*44704f69SBart Van Assche /* Return 0 for ok, anything else for errors */
611*44704f69SBart Van Assche static int
prepare_rq_elems(Rq_coll * clp,const char * inf,const char * outf)612*44704f69SBart Van Assche prepare_rq_elems(Rq_coll * clp, const char * inf, const char * outf)
613*44704f69SBart Van Assche {
614*44704f69SBart Van Assche int k;
615*44704f69SBart Van Assche Rq_elem * rep;
616*44704f69SBart Van Assche size_t psz;
617*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
618*44704f69SBart Van Assche int sz = clp->bpt * clp->bs;
619*44704f69SBart Van Assche int scsi_type;
620*44704f69SBart Van Assche
621*44704f69SBart Van Assche clp->req_arr = malloc(sizeof(Rq_elem) * clp->num_rq_elems);
622*44704f69SBart Van Assche if (NULL == clp->req_arr)
623*44704f69SBart Van Assche return 1;
624*44704f69SBart Van Assche for (k = 0; k < clp->num_rq_elems; ++k) {
625*44704f69SBart Van Assche rep = &clp->req_arr[k];
626*44704f69SBart Van Assche memset(rep, 0, sizeof(Rq_elem));
627*44704f69SBart Van Assche psz = getpagesize();
628*44704f69SBart Van Assche if (NULL == (rep->alloc_bp = malloc(sz + psz)))
629*44704f69SBart Van Assche return 1;
630*44704f69SBart Van Assche rep->buffp = (uint8_t *)
631*44704f69SBart Van Assche (((unsigned long)rep->alloc_bp + psz - 1) & (~(psz - 1)));
632*44704f69SBart Van Assche rep->qstate = QS_IDLE;
633*44704f69SBart Van Assche rep->bs = clp->bs;
634*44704f69SBart Van Assche rep->dio = clp->dio;
635*44704f69SBart Van Assche rep->debug = clp->debug;
636*44704f69SBart Van Assche rep->out_scsi_type = clp->out_scsi_type;
637*44704f69SBart Van Assche if (FT_SG == clp->in_type) {
638*44704f69SBart Van Assche if (0 == k)
639*44704f69SBart Van Assche rep->infd = clp->infd;
640*44704f69SBart Van Assche else {
641*44704f69SBart Van Assche if ((rep->infd = open(inf, O_RDWR)) < 0) {
642*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
643*44704f69SBart Van Assche "sgq_dd: could not open %s for sg reading", inf);
644*44704f69SBart Van Assche perror(ebuff);
645*44704f69SBart Van Assche return 1;
646*44704f69SBart Van Assche }
647*44704f69SBart Van Assche }
648*44704f69SBart Van Assche in_pollfd_arr[k].fd = rep->infd;
649*44704f69SBart Van Assche in_pollfd_arr[k].events = POLLIN;
650*44704f69SBart Van Assche if ((scsi_type = sg_prepare(rep->infd, sz)) < 0)
651*44704f69SBart Van Assche return 1;
652*44704f69SBart Van Assche if (0 == k)
653*44704f69SBart Van Assche clp->in_scsi_type = scsi_type;
654*44704f69SBart Van Assche rep->in_scsi_type = clp->in_scsi_type;
655*44704f69SBart Van Assche }
656*44704f69SBart Van Assche else
657*44704f69SBart Van Assche rep->infd = clp->infd;
658*44704f69SBart Van Assche
659*44704f69SBart Van Assche if (FT_SG == clp->out_type) {
660*44704f69SBart Van Assche if (0 == k)
661*44704f69SBart Van Assche rep->outfd = clp->outfd;
662*44704f69SBart Van Assche else {
663*44704f69SBart Van Assche if ((rep->outfd = open(outf, O_RDWR)) < 0) {
664*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
665*44704f69SBart Van Assche "sgq_dd: could not open %s for sg writing", outf);
666*44704f69SBart Van Assche perror(ebuff);
667*44704f69SBart Van Assche return 1;
668*44704f69SBart Van Assche }
669*44704f69SBart Van Assche }
670*44704f69SBart Van Assche out_pollfd_arr[k].fd = rep->outfd;
671*44704f69SBart Van Assche out_pollfd_arr[k].events = POLLIN;
672*44704f69SBart Van Assche if ((scsi_type = sg_prepare(rep->outfd, sz)) < 0)
673*44704f69SBart Van Assche return 1;
674*44704f69SBart Van Assche if (0 == k)
675*44704f69SBart Van Assche clp->out_scsi_type = scsi_type;
676*44704f69SBart Van Assche rep->out_scsi_type = clp->out_scsi_type;
677*44704f69SBart Van Assche }
678*44704f69SBart Van Assche else
679*44704f69SBart Van Assche rep->outfd = clp->outfd;
680*44704f69SBart Van Assche }
681*44704f69SBart Van Assche return 0;
682*44704f69SBart Van Assche }
683*44704f69SBart Van Assche
684*44704f69SBart Van Assche /* Returns a "QS" code and req index, or QS_IDLE and position of first idle
685*44704f69SBart Van Assche (-1 if no idle position). Returns -1 on poll error. */
686*44704f69SBart Van Assche static int
decider(Rq_coll * clp,int first_xfer,int * req_indexp)687*44704f69SBart Van Assche decider(Rq_coll * clp, int first_xfer, int * req_indexp)
688*44704f69SBart Van Assche {
689*44704f69SBart Van Assche int k, res;
690*44704f69SBart Van Assche Rq_elem * rep;
691*44704f69SBart Van Assche int first_idle_index = -1;
692*44704f69SBart Van Assche int lowest_blk_index = -1;
693*44704f69SBart Van Assche int times;
694*44704f69SBart Van Assche int try_poll = 0;
695*44704f69SBart Van Assche int lowest_blk = INT_MAX;
696*44704f69SBart Van Assche
697*44704f69SBart Van Assche times = first_xfer ? 1 : clp->num_rq_elems;
698*44704f69SBart Van Assche for (k = 0; k < times; ++k) {
699*44704f69SBart Van Assche rep = &clp->req_arr[k];
700*44704f69SBart Van Assche if ((QS_IN_STARTED == rep->qstate) ||
701*44704f69SBart Van Assche (QS_OUT_STARTED == rep->qstate))
702*44704f69SBart Van Assche try_poll = 1;
703*44704f69SBart Van Assche else if ((QS_IN_FINISHED == rep->qstate) && (rep->blk < lowest_blk)) {
704*44704f69SBart Van Assche lowest_blk = rep->blk;
705*44704f69SBart Van Assche lowest_blk_index = k;
706*44704f69SBart Van Assche }
707*44704f69SBart Van Assche else if ((QS_IDLE == rep->qstate) && (first_idle_index < 0))
708*44704f69SBart Van Assche first_idle_index = k;
709*44704f69SBart Van Assche }
710*44704f69SBart Van Assche if (try_poll) {
711*44704f69SBart Van Assche res = do_poll(clp, 0, req_indexp);
712*44704f69SBart Van Assche if (0 != res)
713*44704f69SBart Van Assche return res;
714*44704f69SBart Van Assche }
715*44704f69SBart Van Assche
716*44704f69SBart Van Assche if (lowest_blk_index >= 0) {
717*44704f69SBart Van Assche if (req_indexp)
718*44704f69SBart Van Assche *req_indexp = lowest_blk_index;
719*44704f69SBart Van Assche return QS_IN_FINISHED;
720*44704f69SBart Van Assche }
721*44704f69SBart Van Assche #if 0
722*44704f69SBart Van Assche if (try_poll) {
723*44704f69SBart Van Assche res = do_poll(clp, 2, req_indexp);
724*44704f69SBart Van Assche if (0 != res)
725*44704f69SBart Van Assche return res;
726*44704f69SBart Van Assche }
727*44704f69SBart Van Assche #endif
728*44704f69SBart Van Assche if (req_indexp)
729*44704f69SBart Van Assche *req_indexp = first_idle_index;
730*44704f69SBart Van Assche return QS_IDLE;
731*44704f69SBart Van Assche }
732*44704f69SBart Van Assche
733*44704f69SBart Van Assche
734*44704f69SBart Van Assche int
main(int argc,char * argv[])735*44704f69SBart Van Assche main(int argc, char * argv[])
736*44704f69SBart Van Assche {
737*44704f69SBart Van Assche bool verbose_given = false;
738*44704f69SBart Van Assche bool version_given = false;
739*44704f69SBart Van Assche int skip = 0;
740*44704f69SBart Van Assche int seek = 0;
741*44704f69SBart Van Assche int ibs = 0;
742*44704f69SBart Van Assche int obs = 0;
743*44704f69SBart Van Assche char str[STR_SZ];
744*44704f69SBart Van Assche char * key;
745*44704f69SBart Van Assche char * buf;
746*44704f69SBart Van Assche char inf[INOUTF_SZ];
747*44704f69SBart Van Assche char outf[INOUTF_SZ];
748*44704f69SBart Van Assche int res, k, n, keylen;
749*44704f69SBart Van Assche int in_num_sect = 0;
750*44704f69SBart Van Assche int out_num_sect = 0;
751*44704f69SBart Van Assche int num_threads = DEF_NUM_THREADS;
752*44704f69SBart Van Assche int gen = 0;
753*44704f69SBart Van Assche int do_time = 0;
754*44704f69SBart Van Assche int in_sect_sz, out_sect_sz, first_xfer, qstate, req_index, seek_skip;
755*44704f69SBart Van Assche int blocks, stop_after_write, terminate;
756*44704f69SBart Van Assche char ebuff[EBUFF_SZ];
757*44704f69SBart Van Assche Rq_elem * rep;
758*44704f69SBart Van Assche struct timeval start_tm, end_tm;
759*44704f69SBart Van Assche
760*44704f69SBart Van Assche memset(&rcoll, 0, sizeof(Rq_coll));
761*44704f69SBart Van Assche rcoll.bpt = DEF_BLOCKS_PER_TRANSFER;
762*44704f69SBart Van Assche rcoll.in_type = FT_OTHER;
763*44704f69SBart Van Assche rcoll.out_type = FT_OTHER;
764*44704f69SBart Van Assche inf[0] = '\0';
765*44704f69SBart Van Assche outf[0] = '\0';
766*44704f69SBart Van Assche
767*44704f69SBart Van Assche for(k = 1; k < argc; k++) {
768*44704f69SBart Van Assche if (argv[k])
769*44704f69SBart Van Assche strncpy(str, argv[k], STR_SZ);
770*44704f69SBart Van Assche else
771*44704f69SBart Van Assche continue;
772*44704f69SBart Van Assche for(key = str, buf = key; *buf && *buf != '=';)
773*44704f69SBart Van Assche buf++;
774*44704f69SBart Van Assche if (*buf)
775*44704f69SBart Van Assche *buf++ = '\0';
776*44704f69SBart Van Assche keylen = strlen(key);
777*44704f69SBart Van Assche if (strcmp(key,"if") == 0)
778*44704f69SBart Van Assche strncpy(inf, buf, INOUTF_SZ);
779*44704f69SBart Van Assche else if (strcmp(key,"of") == 0)
780*44704f69SBart Van Assche strncpy(outf, buf, INOUTF_SZ);
781*44704f69SBart Van Assche else if (0 == strcmp(key,"ibs"))
782*44704f69SBart Van Assche ibs = sg_get_num(buf);
783*44704f69SBart Van Assche else if (0 == strcmp(key,"obs"))
784*44704f69SBart Van Assche obs = sg_get_num(buf);
785*44704f69SBart Van Assche else if (0 == strcmp(key,"bs"))
786*44704f69SBart Van Assche rcoll.bs = sg_get_num(buf);
787*44704f69SBart Van Assche else if (0 == strcmp(key,"bpt"))
788*44704f69SBart Van Assche rcoll.bpt = sg_get_num(buf);
789*44704f69SBart Van Assche else if (0 == strcmp(key,"skip"))
790*44704f69SBart Van Assche skip = sg_get_num(buf);
791*44704f69SBart Van Assche else if (0 == strcmp(key,"seek"))
792*44704f69SBart Van Assche seek = sg_get_num(buf);
793*44704f69SBart Van Assche else if (0 == strcmp(key,"count"))
794*44704f69SBart Van Assche dd_count = sg_get_num(buf);
795*44704f69SBart Van Assche else if (0 == strcmp(key,"dio"))
796*44704f69SBart Van Assche rcoll.dio = sg_get_num(buf);
797*44704f69SBart Van Assche else if (0 == strcmp(key,"thr"))
798*44704f69SBart Van Assche num_threads = sg_get_num(buf);
799*44704f69SBart Van Assche else if (0 == strcmp(key,"coe"))
800*44704f69SBart Van Assche rcoll.coe = sg_get_num(buf);
801*44704f69SBart Van Assche else if (0 == strcmp(key,"gen"))
802*44704f69SBart Van Assche gen = sg_get_num(buf);
803*44704f69SBart Van Assche else if ((0 == strncmp(key,"deb", 3)) || (0 == strncmp(key,"verb", 4)))
804*44704f69SBart Van Assche rcoll.debug = sg_get_num(buf);
805*44704f69SBart Van Assche else if (0 == strcmp(key,"time"))
806*44704f69SBart Van Assche do_time = sg_get_num(buf);
807*44704f69SBart Van Assche else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
808*44704f69SBart Van Assche res = 0;
809*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'h');
810*44704f69SBart Van Assche if (n > 0) {
811*44704f69SBart Van Assche usage();
812*44704f69SBart Van Assche return 0;
813*44704f69SBart Van Assche }
814*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'v');
815*44704f69SBart Van Assche if (n > 0)
816*44704f69SBart Van Assche verbose_given = true;
817*44704f69SBart Van Assche rcoll.debug += n;
818*44704f69SBart Van Assche res += n;
819*44704f69SBart Van Assche n = num_chs_in_str(key + 1, keylen - 1, 'V');
820*44704f69SBart Van Assche if (n > 0)
821*44704f69SBart Van Assche version_given = true;
822*44704f69SBart Van Assche res += n;
823*44704f69SBart Van Assche if (res < (keylen - 1)) {
824*44704f69SBart Van Assche fprintf(stderr, "Unrecognised short option in '%s', try "
825*44704f69SBart Van Assche "'--help'\n", key);
826*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
827*44704f69SBart Van Assche }
828*44704f69SBart Van Assche } else if (0 == strncmp(key, "--help", 6)) {
829*44704f69SBart Van Assche usage();
830*44704f69SBart Van Assche return 0;
831*44704f69SBart Van Assche } else if (0 == strncmp(key, "--verb", 6)) {
832*44704f69SBart Van Assche verbose_given = true;
833*44704f69SBart Van Assche ++rcoll.debug;
834*44704f69SBart Van Assche } else if (0 == strncmp(key, "--vers", 6))
835*44704f69SBart Van Assche version_given = true;
836*44704f69SBart Van Assche else {
837*44704f69SBart Van Assche fprintf(stderr, "Unrecognized argument '%s'\n", key);
838*44704f69SBart Van Assche usage();
839*44704f69SBart Van Assche return 1;
840*44704f69SBart Van Assche }
841*44704f69SBart Van Assche }
842*44704f69SBart Van Assche #ifdef DEBUG
843*44704f69SBart Van Assche fprintf(stderr, "In DEBUG mode, ");
844*44704f69SBart Van Assche if (verbose_given && version_given) {
845*44704f69SBart Van Assche fprintf(stderr, "but override: '-vV' given, zero verbose and "
846*44704f69SBart Van Assche "continue\n");
847*44704f69SBart Van Assche verbose_given = false;
848*44704f69SBart Van Assche version_given = false;
849*44704f69SBart Van Assche rcoll.debug = 0;
850*44704f69SBart Van Assche } else if (! verbose_given) {
851*44704f69SBart Van Assche fprintf(stderr, "set '-vv'\n");
852*44704f69SBart Van Assche rcoll.debug = 2;
853*44704f69SBart Van Assche } else
854*44704f69SBart Van Assche fprintf(stderr, "keep verbose=%d\n", rcoll.debug);
855*44704f69SBart Van Assche #else
856*44704f69SBart Van Assche if (verbose_given && version_given)
857*44704f69SBart Van Assche fprintf(stderr, "Not in DEBUG mode, so '-vV' has no special action\n");
858*44704f69SBart Van Assche #endif
859*44704f69SBart Van Assche if (version_given) {
860*44704f69SBart Van Assche fprintf(stderr, "sgq_dd for sg version 3 driver: %s\n",
861*44704f69SBart Van Assche version_str);
862*44704f69SBart Van Assche return 0;
863*44704f69SBart Van Assche return 0;
864*44704f69SBart Van Assche }
865*44704f69SBart Van Assche
866*44704f69SBart Van Assche if (argc < 2) {
867*44704f69SBart Van Assche usage();
868*44704f69SBart Van Assche return 1;
869*44704f69SBart Van Assche }
870*44704f69SBart Van Assche if (rcoll.bs <= 0) {
871*44704f69SBart Van Assche rcoll.bs = DEF_BLOCK_SIZE;
872*44704f69SBart Van Assche fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n",
873*44704f69SBart Van Assche rcoll.bs);
874*44704f69SBart Van Assche }
875*44704f69SBart Van Assche if ((ibs && (ibs != rcoll.bs)) || (obs && (obs != rcoll.bs))) {
876*44704f69SBart Van Assche fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n");
877*44704f69SBart Van Assche usage();
878*44704f69SBart Van Assche return 1;
879*44704f69SBart Van Assche }
880*44704f69SBart Van Assche if ((skip < 0) || (seek < 0)) {
881*44704f69SBart Van Assche fprintf(stderr, "skip and seek cannot be negative\n");
882*44704f69SBart Van Assche return 1;
883*44704f69SBart Van Assche }
884*44704f69SBart Van Assche if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) {
885*44704f69SBart Van Assche fprintf(stderr, "too few or too many threads requested\n");
886*44704f69SBart Van Assche usage();
887*44704f69SBart Van Assche return 1;
888*44704f69SBart Van Assche }
889*44704f69SBart Van Assche if (rcoll.debug)
890*44704f69SBart Van Assche fprintf(stderr, "sgq_dd: if=%s skip=%d of=%s seek=%d count=%d\n",
891*44704f69SBart Van Assche inf, skip, outf, seek, dd_count);
892*44704f69SBart Van Assche install_handler (SIGINT, interrupt_handler);
893*44704f69SBart Van Assche install_handler (SIGQUIT, interrupt_handler);
894*44704f69SBart Van Assche install_handler (SIGPIPE, interrupt_handler);
895*44704f69SBart Van Assche install_handler (SIGUSR1, siginfo_handler);
896*44704f69SBart Van Assche
897*44704f69SBart Van Assche rcoll.infd = STDIN_FILENO;
898*44704f69SBart Van Assche rcoll.outfd = STDOUT_FILENO;
899*44704f69SBart Van Assche if (inf[0] && ('-' != inf[0])) {
900*44704f69SBart Van Assche rcoll.in_type = dd_filetype(inf);
901*44704f69SBart Van Assche
902*44704f69SBart Van Assche if (FT_SG == rcoll.in_type) {
903*44704f69SBart Van Assche if ((rcoll.infd = open(inf, O_RDWR)) < 0) {
904*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
905*44704f69SBart Van Assche "sgq_dd: could not open %s for sg reading", inf);
906*44704f69SBart Van Assche perror(ebuff);
907*44704f69SBart Van Assche return 1;
908*44704f69SBart Van Assche }
909*44704f69SBart Van Assche }
910*44704f69SBart Van Assche if (FT_SG != rcoll.in_type) {
911*44704f69SBart Van Assche if ((rcoll.infd = open(inf, O_RDONLY)) < 0) {
912*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
913*44704f69SBart Van Assche "sgq_dd: could not open %s for reading", inf);
914*44704f69SBart Van Assche perror(ebuff);
915*44704f69SBart Van Assche return 1;
916*44704f69SBart Van Assche }
917*44704f69SBart Van Assche else if (skip > 0) {
918*44704f69SBart Van Assche loff_t offset = skip;
919*44704f69SBart Van Assche
920*44704f69SBart Van Assche offset *= rcoll.bs; /* could exceed 32 here! */
921*44704f69SBart Van Assche if (lseek(rcoll.infd, offset, SEEK_SET) < 0) {
922*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
923*44704f69SBart Van Assche "sgq_dd: couldn't skip to required position on %s", inf);
924*44704f69SBart Van Assche perror(ebuff);
925*44704f69SBart Van Assche return 1;
926*44704f69SBart Van Assche }
927*44704f69SBart Van Assche }
928*44704f69SBart Van Assche }
929*44704f69SBart Van Assche }
930*44704f69SBart Van Assche if (outf[0] && ('-' != outf[0])) {
931*44704f69SBart Van Assche rcoll.out_type = dd_filetype(outf);
932*44704f69SBart Van Assche
933*44704f69SBart Van Assche if (FT_SG == rcoll.out_type) {
934*44704f69SBart Van Assche if ((rcoll.outfd = open(outf, O_RDWR)) < 0) {
935*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
936*44704f69SBart Van Assche "sgq_dd: could not open %s for sg writing", outf);
937*44704f69SBart Van Assche perror(ebuff);
938*44704f69SBart Van Assche return 1;
939*44704f69SBart Van Assche }
940*44704f69SBart Van Assche }
941*44704f69SBart Van Assche else {
942*44704f69SBart Van Assche if (FT_OTHER == rcoll.out_type) {
943*44704f69SBart Van Assche if ((rcoll.outfd = open(outf, O_WRONLY | O_CREAT, 0666)) < 0) {
944*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
945*44704f69SBart Van Assche "sgq_dd: could not open %s for writing", outf);
946*44704f69SBart Van Assche perror(ebuff);
947*44704f69SBart Van Assche return 1;
948*44704f69SBart Van Assche }
949*44704f69SBart Van Assche }
950*44704f69SBart Van Assche else {
951*44704f69SBart Van Assche if ((rcoll.outfd = open(outf, O_WRONLY)) < 0) {
952*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
953*44704f69SBart Van Assche "sgq_dd: could not open %s for raw writing", outf);
954*44704f69SBart Van Assche perror(ebuff);
955*44704f69SBart Van Assche return 1;
956*44704f69SBart Van Assche }
957*44704f69SBart Van Assche }
958*44704f69SBart Van Assche if (seek > 0) {
959*44704f69SBart Van Assche loff_t offset = seek;
960*44704f69SBart Van Assche
961*44704f69SBart Van Assche offset *= rcoll.bs; /* could exceed 32 bits here! */
962*44704f69SBart Van Assche if (lseek(rcoll.outfd, offset, SEEK_SET) < 0) {
963*44704f69SBart Van Assche snprintf(ebuff, EBUFF_SZ,
964*44704f69SBart Van Assche "sgq_dd: couldn't seek to required position on %s", outf);
965*44704f69SBart Van Assche perror(ebuff);
966*44704f69SBart Van Assche return 1;
967*44704f69SBart Van Assche }
968*44704f69SBart Van Assche }
969*44704f69SBart Van Assche }
970*44704f69SBart Van Assche }
971*44704f69SBart Van Assche if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) {
972*44704f69SBart Van Assche fprintf(stderr, "Disallow both if and of to be stdin and stdout\n");
973*44704f69SBart Van Assche return 1;
974*44704f69SBart Van Assche }
975*44704f69SBart Van Assche if ((FT_OTHER == rcoll.in_type) && (FT_OTHER == rcoll.out_type) && !gen) {
976*44704f69SBart Van Assche fprintf(stderr, "Either 'if' or 'of' must be a sg or raw device\n");
977*44704f69SBart Van Assche return 1;
978*44704f69SBart Van Assche }
979*44704f69SBart Van Assche if (0 == dd_count)
980*44704f69SBart Van Assche return 0;
981*44704f69SBart Van Assche else if (dd_count < 0) {
982*44704f69SBart Van Assche if (FT_SG == rcoll.in_type) {
983*44704f69SBart Van Assche res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz);
984*44704f69SBart Van Assche if (2 == res) {
985*44704f69SBart Van Assche fprintf(stderr, "Unit attention, media changed(in), repeat\n");
986*44704f69SBart Van Assche res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz);
987*44704f69SBart Van Assche }
988*44704f69SBart Van Assche if (0 != res) {
989*44704f69SBart Van Assche fprintf(stderr, "Unable to read capacity on %s\n", inf);
990*44704f69SBart Van Assche in_num_sect = -1;
991*44704f69SBart Van Assche }
992*44704f69SBart Van Assche else {
993*44704f69SBart Van Assche if (in_num_sect > skip)
994*44704f69SBart Van Assche in_num_sect -= skip;
995*44704f69SBart Van Assche }
996*44704f69SBart Van Assche }
997*44704f69SBart Van Assche if (FT_SG == rcoll.out_type) {
998*44704f69SBart Van Assche res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz);
999*44704f69SBart Van Assche if (2 == res) {
1000*44704f69SBart Van Assche fprintf(stderr, "Unit attention, media changed(out), "
1001*44704f69SBart Van Assche "repeat\n");
1002*44704f69SBart Van Assche res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz);
1003*44704f69SBart Van Assche }
1004*44704f69SBart Van Assche if (0 != res) {
1005*44704f69SBart Van Assche fprintf(stderr, "Unable to read capacity on %s\n", outf);
1006*44704f69SBart Van Assche out_num_sect = -1;
1007*44704f69SBart Van Assche }
1008*44704f69SBart Van Assche else {
1009*44704f69SBart Van Assche if (out_num_sect > seek)
1010*44704f69SBart Van Assche out_num_sect -= seek;
1011*44704f69SBart Van Assche }
1012*44704f69SBart Van Assche }
1013*44704f69SBart Van Assche if (in_num_sect > 0) {
1014*44704f69SBart Van Assche if (out_num_sect > 0)
1015*44704f69SBart Van Assche dd_count = (in_num_sect > out_num_sect) ? out_num_sect :
1016*44704f69SBart Van Assche in_num_sect;
1017*44704f69SBart Van Assche else
1018*44704f69SBart Van Assche dd_count = in_num_sect;
1019*44704f69SBart Van Assche }
1020*44704f69SBart Van Assche else
1021*44704f69SBart Van Assche dd_count = out_num_sect;
1022*44704f69SBart Van Assche }
1023*44704f69SBart Van Assche if (rcoll.debug > 1)
1024*44704f69SBart Van Assche fprintf(stderr, "Start of loop, count=%d, in_num_sect=%d, "
1025*44704f69SBart Van Assche "out_num_sect=%d\n", dd_count, in_num_sect, out_num_sect);
1026*44704f69SBart Van Assche if (dd_count <= 0) {
1027*44704f69SBart Van Assche fprintf(stderr, "Couldn't calculate count, please give one\n");
1028*44704f69SBart Van Assche return 1;
1029*44704f69SBart Van Assche }
1030*44704f69SBart Van Assche
1031*44704f69SBart Van Assche rcoll.in_count = dd_count;
1032*44704f69SBart Van Assche rcoll.in_done_count = dd_count;
1033*44704f69SBart Van Assche rcoll.skip = skip;
1034*44704f69SBart Van Assche rcoll.in_blk = skip;
1035*44704f69SBart Van Assche rcoll.out_count = dd_count;
1036*44704f69SBart Van Assche rcoll.out_done_count = dd_count;
1037*44704f69SBart Van Assche rcoll.seek = seek;
1038*44704f69SBart Van Assche rcoll.out_blk = seek;
1039*44704f69SBart Van Assche
1040*44704f69SBart Van Assche if ((FT_SG == rcoll.in_type) || (FT_SG == rcoll.out_type))
1041*44704f69SBart Van Assche rcoll.num_rq_elems = num_threads;
1042*44704f69SBart Van Assche else
1043*44704f69SBart Van Assche rcoll.num_rq_elems = 1;
1044*44704f69SBart Van Assche if (prepare_rq_elems(&rcoll, inf, outf)) {
1045*44704f69SBart Van Assche fprintf(stderr, "Setup failure, perhaps no memory\n");
1046*44704f69SBart Van Assche return 1;
1047*44704f69SBart Van Assche }
1048*44704f69SBart Van Assche
1049*44704f69SBart Van Assche first_xfer = 1;
1050*44704f69SBart Van Assche stop_after_write = 0;
1051*44704f69SBart Van Assche terminate = 0;
1052*44704f69SBart Van Assche seek_skip = rcoll.seek - rcoll.skip;
1053*44704f69SBart Van Assche if (do_time) {
1054*44704f69SBart Van Assche start_tm.tv_sec = 0;
1055*44704f69SBart Van Assche start_tm.tv_usec = 0;
1056*44704f69SBart Van Assche gettimeofday(&start_tm, NULL);
1057*44704f69SBart Van Assche }
1058*44704f69SBart Van Assche while (rcoll.out_done_count > 0) { /* >>>>>>>>> main loop */
1059*44704f69SBart Van Assche req_index = -1;
1060*44704f69SBart Van Assche qstate = decider(&rcoll, first_xfer, &req_index);
1061*44704f69SBart Van Assche rep = (req_index < 0) ? NULL : (rcoll.req_arr + req_index);
1062*44704f69SBart Van Assche switch (qstate) {
1063*44704f69SBart Van Assche case QS_IDLE:
1064*44704f69SBart Van Assche if ((NULL == rep) || (rcoll.in_count <= 0)) {
1065*44704f69SBart Van Assche /* usleep(1000); */
1066*44704f69SBart Van Assche /* do_poll(&rcoll, 10, NULL); */
1067*44704f69SBart Van Assche /* do_poll(&rcoll, 0, NULL); */
1068*44704f69SBart Van Assche break;
1069*44704f69SBart Van Assche }
1070*44704f69SBart Van Assche if (rcoll.debug > 8)
1071*44704f69SBart Van Assche fprintf(stderr, " sgq_dd: non-sleeping QS_IDLE state, "
1072*44704f69SBart Van Assche "req_index=%d\n", req_index);
1073*44704f69SBart Van Assche if (first_xfer >= 2)
1074*44704f69SBart Van Assche first_xfer = 0;
1075*44704f69SBart Van Assche else if (1 == first_xfer)
1076*44704f69SBart Van Assche ++first_xfer;
1077*44704f69SBart Van Assche if (stop_after_write) {
1078*44704f69SBart Van Assche terminate = 1;
1079*44704f69SBart Van Assche break;
1080*44704f69SBart Van Assche }
1081*44704f69SBart Van Assche blocks = (rcoll.in_count > rcoll.bpt) ? rcoll.bpt : rcoll.in_count;
1082*44704f69SBart Van Assche rep->wr = 0;
1083*44704f69SBart Van Assche rep->blk = rcoll.in_blk;
1084*44704f69SBart Van Assche rep->num_blks = blocks;
1085*44704f69SBart Van Assche rcoll.in_blk += blocks;
1086*44704f69SBart Van Assche rcoll.in_count -= blocks;
1087*44704f69SBart Van Assche
1088*44704f69SBart Van Assche if (FT_SG == rcoll.in_type) {
1089*44704f69SBart Van Assche res = sg_start_io(rep);
1090*44704f69SBart Van Assche if (0 != res) {
1091*44704f69SBart Van Assche if (1 == res)
1092*44704f69SBart Van Assche fprintf(stderr, "Out of memory starting sg io\n");
1093*44704f69SBart Van Assche terminate = 1;
1094*44704f69SBart Van Assche }
1095*44704f69SBart Van Assche }
1096*44704f69SBart Van Assche else {
1097*44704f69SBart Van Assche res = normal_in_operation(&rcoll, rep, blocks);
1098*44704f69SBart Van Assche if (res < 0)
1099*44704f69SBart Van Assche terminate = 1;
1100*44704f69SBart Van Assche else if (res > 0)
1101*44704f69SBart Van Assche stop_after_write = 1;
1102*44704f69SBart Van Assche }
1103*44704f69SBart Van Assche break;
1104*44704f69SBart Van Assche case QS_IN_FINISHED:
1105*44704f69SBart Van Assche if (rcoll.debug > 8)
1106*44704f69SBart Van Assche fprintf(stderr, " sgq_dd: state is QS_IN_FINISHED, "
1107*44704f69SBart Van Assche "req_index=%d\n", req_index);
1108*44704f69SBart Van Assche if ((rep->blk + seek_skip) != rcoll.out_blk) {
1109*44704f69SBart Van Assche /* if write would be out of sequence then wait */
1110*44704f69SBart Van Assche if (rcoll.debug > 4)
1111*44704f69SBart Van Assche fprintf(stderr, " sgq_dd: QS_IN_FINISHED, "
1112*44704f69SBart Van Assche "out of sequence\n");
1113*44704f69SBart Van Assche usleep(200);
1114*44704f69SBart Van Assche break;
1115*44704f69SBart Van Assche }
1116*44704f69SBart Van Assche rep->wr = 1;
1117*44704f69SBart Van Assche rep->blk = rcoll.out_blk;
1118*44704f69SBart Van Assche blocks = rep->num_blks;
1119*44704f69SBart Van Assche rcoll.out_blk += blocks;
1120*44704f69SBart Van Assche rcoll.out_count -= blocks;
1121*44704f69SBart Van Assche
1122*44704f69SBart Van Assche if (FT_SG == rcoll.out_type) {
1123*44704f69SBart Van Assche res = sg_start_io(rep);
1124*44704f69SBart Van Assche if (0 != res) {
1125*44704f69SBart Van Assche if (1 == res)
1126*44704f69SBart Van Assche fprintf(stderr, "Out of memory starting sg io\n");
1127*44704f69SBart Van Assche terminate = 1;
1128*44704f69SBart Van Assche }
1129*44704f69SBart Van Assche }
1130*44704f69SBart Van Assche else {
1131*44704f69SBart Van Assche if (normal_out_operation(&rcoll, rep, blocks) < 0)
1132*44704f69SBart Van Assche terminate = 1;
1133*44704f69SBart Van Assche }
1134*44704f69SBart Van Assche break;
1135*44704f69SBart Van Assche case QS_IN_POLL:
1136*44704f69SBart Van Assche if (rcoll.debug > 8)
1137*44704f69SBart Van Assche fprintf(stderr, " sgq_dd: state is QS_IN_POLL, "
1138*44704f69SBart Van Assche "req_index=%d\n", req_index);
1139*44704f69SBart Van Assche res = sg_fin_in_operation(&rcoll, rep);
1140*44704f69SBart Van Assche if (res < 0)
1141*44704f69SBart Van Assche terminate = 1;
1142*44704f69SBart Van Assche else if (res > 1) {
1143*44704f69SBart Van Assche if (first_xfer) {
1144*44704f69SBart Van Assche /* only retry on first xfer */
1145*44704f69SBart Van Assche if (0 != sg_start_io(rep))
1146*44704f69SBart Van Assche terminate = 1;
1147*44704f69SBart Van Assche }
1148*44704f69SBart Van Assche else
1149*44704f69SBart Van Assche terminate = 1;
1150*44704f69SBart Van Assche }
1151*44704f69SBart Van Assche break;
1152*44704f69SBart Van Assche case QS_OUT_POLL:
1153*44704f69SBart Van Assche if (rcoll.debug > 8)
1154*44704f69SBart Van Assche fprintf(stderr, " sgq_dd: state is QS_OUT_POLL, "
1155*44704f69SBart Van Assche "req_index=%d\n", req_index);
1156*44704f69SBart Van Assche res = sg_fin_out_operation(&rcoll, rep);
1157*44704f69SBart Van Assche if (res < 0)
1158*44704f69SBart Van Assche terminate = 1;
1159*44704f69SBart Van Assche else if (res > 1) {
1160*44704f69SBart Van Assche if (first_xfer) {
1161*44704f69SBart Van Assche /* only retry on first xfer */
1162*44704f69SBart Van Assche if (0 != sg_start_io(rep))
1163*44704f69SBart Van Assche terminate = 1;
1164*44704f69SBart Van Assche }
1165*44704f69SBart Van Assche else
1166*44704f69SBart Van Assche terminate = 1;
1167*44704f69SBart Van Assche }
1168*44704f69SBart Van Assche break;
1169*44704f69SBart Van Assche default:
1170*44704f69SBart Van Assche if (rcoll.debug > 8)
1171*44704f69SBart Van Assche fprintf(stderr, " sgq_dd: state is ?????\n");
1172*44704f69SBart Van Assche terminate = 1;
1173*44704f69SBart Van Assche break;
1174*44704f69SBart Van Assche }
1175*44704f69SBart Van Assche if (terminate)
1176*44704f69SBart Van Assche break;
1177*44704f69SBart Van Assche } /* >>>>>>>>>>>>> end of main loop */
1178*44704f69SBart Van Assche
1179*44704f69SBart Van Assche if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
1180*44704f69SBart Van Assche struct timeval res_tm;
1181*44704f69SBart Van Assche double a, b;
1182*44704f69SBart Van Assche
1183*44704f69SBart Van Assche gettimeofday(&end_tm, NULL);
1184*44704f69SBart Van Assche res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
1185*44704f69SBart Van Assche res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
1186*44704f69SBart Van Assche if (res_tm.tv_usec < 0) {
1187*44704f69SBart Van Assche --res_tm.tv_sec;
1188*44704f69SBart Van Assche res_tm.tv_usec += 1000000;
1189*44704f69SBart Van Assche }
1190*44704f69SBart Van Assche a = res_tm.tv_sec;
1191*44704f69SBart Van Assche a += (0.000001 * res_tm.tv_usec);
1192*44704f69SBart Van Assche b = (double)rcoll.bs * (dd_count - rcoll.out_done_count);
1193*44704f69SBart Van Assche printf("time to transfer data was %d.%06d secs",
1194*44704f69SBart Van Assche (int)res_tm.tv_sec, (int)res_tm.tv_usec);
1195*44704f69SBart Van Assche if ((a > 0.00001) && (b > 511))
1196*44704f69SBart Van Assche printf(", %.2f MB/sec\n", b / (a * 1000000.0));
1197*44704f69SBart Van Assche else
1198*44704f69SBart Van Assche printf("\n");
1199*44704f69SBart Van Assche }
1200*44704f69SBart Van Assche
1201*44704f69SBart Van Assche if (STDIN_FILENO != rcoll.infd)
1202*44704f69SBart Van Assche close(rcoll.infd);
1203*44704f69SBart Van Assche if (STDOUT_FILENO != rcoll.outfd)
1204*44704f69SBart Van Assche close(rcoll.outfd);
1205*44704f69SBart Van Assche res = 0;
1206*44704f69SBart Van Assche if (0 != rcoll.out_count) {
1207*44704f69SBart Van Assche fprintf(stderr, ">>>> Some error occurred,\n");
1208*44704f69SBart Van Assche res = 2;
1209*44704f69SBart Van Assche }
1210*44704f69SBart Van Assche print_stats();
1211*44704f69SBart Van Assche if (rcoll.dio_incomplete) {
1212*44704f69SBart Van Assche int fd;
1213*44704f69SBart Van Assche char c;
1214*44704f69SBart Van Assche
1215*44704f69SBart Van Assche fprintf(stderr, ">> Direct IO requested but incomplete %d times\n",
1216*44704f69SBart Van Assche rcoll.dio_incomplete);
1217*44704f69SBart Van Assche if ((fd = open(sg_allow_dio, O_RDONLY)) >= 0) {
1218*44704f69SBart Van Assche if (1 == read(fd, &c, 1)) {
1219*44704f69SBart Van Assche if ('0' == c)
1220*44704f69SBart Van Assche fprintf(stderr, ">>> %s set to '0' but should be set "
1221*44704f69SBart Van Assche "to '1' for direct IO\n", sg_allow_dio);
1222*44704f69SBart Van Assche }
1223*44704f69SBart Van Assche close(fd);
1224*44704f69SBart Van Assche }
1225*44704f69SBart Van Assche }
1226*44704f69SBart Van Assche if (rcoll.sum_of_resids)
1227*44704f69SBart Van Assche fprintf(stderr, ">> Non-zero sum of residual counts=%d\n",
1228*44704f69SBart Van Assche rcoll.sum_of_resids);
1229*44704f69SBart Van Assche return res;
1230*44704f69SBart Van Assche }
1231