xref: /aosp_15_r20/external/sg3_utils/testing/sgs_dd.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
1 /*
2  * Test code for the extensions to the Linux OS SCSI generic ("sg")
3  * device driver.
4  * Copyright (C) 1999-2022 D. Gilbert and P. Allworth
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * SPDX-License-Identifier: GPL-2.0-or-later
12  *
13  * This program is a specialization of the Unix "dd" command in which
14  * one or both of the given files is a scsi generic device. A block size
15  * ('bs') is assumed to be 512 if not given. This program complains if
16  * 'ibs' or 'obs' are given with some other value than 'bs'.
17  * If 'if' is not given or 'if=-' then stdin is assumed. If 'of' is
18  * not given of 'of=-' then stdout assumed. The multipliers "c, b, k, m"
19  * are recognized on numeric arguments.
20  *
21  * A non-standard argument "bpt" (blocks per transfer) is added to control
22  * the maximum number of blocks in each transfer. The default bpt value is
23  * (64 * 1024 * 1024 / bs) or 1 if the first expression is 0. That is an
24  * integer division (rounds toward 0). For example if "bs=512" and "bpt=32"
25  * are given then a maximum of 32 blocks (16KB in this case) are transferred
26  * to or from the sg device in a single SCSI command.
27  *
28  * BEWARE: If the 'of' file is a 'sg' device (eg a disk) then it _will_
29  * be written to, potentially destroying its previous contents.
30  *
31  * This version should compile with Linux sg drivers with version numbers
32  * >= 30000 . Also this version also allows SIGPOLL or a RT signal to be
33  * chosen. SIGIO is a synonym for SIGPOLL; SIGIO seems to be deprecated.
34  */
35 
36 /* We need F_SETSIG, (signal redirect), so following define */
37 #define _GNU_SOURCE 1
38 
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdbool.h>
44 #include <stdarg.h>
45 #include <stdint.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <errno.h>
49 #include <poll.h>
50 #include <signal.h>
51 #include <sys/ioctl.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <sys/mman.h>           /* for mmap() system call */
55 #include <sys/eventfd.h>
56 #include <sys/epoll.h>
57 #define __STDC_FORMAT_MACROS 1
58 #include <inttypes.h>
59 
60 #ifndef HAVE_LINUX_SG_V4_HDR
61 /* Kernel uapi header contain __user decorations on user space pointers
62  * to indicate they are unsafe in the kernel space. However glibc takes
63  * all those __user decorations out from headers in /usr/include/linux .
64  * So to stop compile errors when directly importing include/uapi/scsi/sg.h
65  * undef __user before doing that include. */
66 #define __user
67 
68 /* Want to block the original sg.h header from also being included. That
69  * causes lots of multiple definition errors. This will only work if this
70  * header is included _before_ the original sg.h header.  */
71 #define _SCSI_GENERIC_H         /* original kernel header guard */
72 #define _SCSI_SG_H              /* glibc header guard */
73 
74 #include "uapi_sg.h"    /* local copy of include/uapi/scsi/sg.h */
75 
76 #else
77 #define __user
78 #endif  /* end of: ifndef HAVE_LINUX_SG_V4_HDR */
79 
80 #include "sg_lib.h"
81 #include "sg_linux_inc.h"
82 #include "sg_io_linux.h"
83 #include "sg_pr2serr.h"
84 #include "sg_unaligned.h"
85 
86 
87 static const char * version_str = "4.24 20221020";
88 static const char * my_name = "sgs_dd";
89 
90 #ifndef SGV4_FLAG_POLLED
91 #define SGV4_FLAG_POLLED 0x800
92 #endif
93 
94 #define DEF_BLOCK_SIZE 512
95 #define DEF_BPT_TIMES_BS_SZ (64 * 1024) /* 64 KB */
96 
97 #define SENSE_BUFF_LEN 32       /* Arbitrary, could be larger */
98 #define DEF_TIMEOUT 40000       /* 40,000 millisecs == 40 seconds */
99 #define S_RW_LEN 10             /* Use SCSI READ(10) and WRITE(10) */
100 #define SGQ_MAX_RD_AHEAD 32
101 #define SGQ_MAX_WR_AHEAD 32
102 #define SGQ_NUM_ELEMS (SGQ_MAX_RD_AHEAD + SGQ_MAX_WR_AHEAD + 1)
103 #define MAX_BPT_VALUE (1 << 24)         /* used for maximum bs as well */
104 #define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */
105 
106 #define SGQ_FREE 0
107 #define SGQ_IO_STARTED 1
108 #define SGQ_IO_FINISHED 2
109 #define SGQ_IO_ERR 3
110 #define SGQ_IO_WAIT 4
111 
112 #define SGQ_CAN_DO_NOTHING 0    /* only temporarily in use */
113 #define SGQ_CAN_READ 1
114 #define SGQ_CAN_WRITE 2
115 #define SGQ_TIMEOUT 4
116 
117 #define DEF_SIGTIMEDWAIT_USEC 100
118 
119 
120 #define STR_SZ 1024
121 #define INOUTF_SZ 900
122 #define EBUFF_SZ 1024
123 
124 struct flags_t {
125     bool dio;
126     bool evfd;
127     bool excl;
128     bool immed;
129     bool mmap;
130     bool noxfer;
131     bool pack;
132     bool polled;
133     bool tag;
134     bool v3;
135     bool v4;
136     bool given_v3v4;
137 };
138 
139 typedef struct request_element
140 {
141     struct request_element * nextp;
142     bool stop_after_wr;
143     bool wr;
144     int state;
145     int blk;
146     int num_blks;
147     uint8_t * buffp;
148     uint8_t * free_buffp;
149     sg_io_hdr_t io_hdr;
150     struct sg_io_v4 io_v4;
151     struct flags_t * iflagp;
152     struct flags_t * oflagp;
153     uint8_t cmd[S_RW_LEN];
154     uint8_t sb[SENSE_BUFF_LEN];
155     int result;
156 } Rq_elem;
157 
158 typedef struct request_collection
159 {
160     bool in_is_sg;
161     bool out_is_sg;
162     bool no_sig;
163     bool use_rt_sig;
164     bool both_mmap;
165     int infd;
166     int in_evfd;
167     int in_blk;                 /* most recent read */
168     int in_count;               /* most recent read */
169     int in_done_count;          /* count of completed in blocks */
170     int in_partial;
171     int outfd;
172     int out_evfd;
173     int lowest_seek;
174     int out_blk;                /* most recent write */
175     int out_count;              /* most recent write */
176     int out_done_count;         /* count of completed out blocks */
177     int out_partial;
178     int bs;
179     int bpt;
180     int dio_incomplete;
181     int sum_of_resids;
182     int poll_ms;
183     int pollerr_count;
184     int debug;                  /* also set with -v up to -vvvvv */
185     sigset_t blocked_sigs;
186     int sigs_waiting;
187     int sigs_rt_received;
188     int sigs_io_received;
189     int blk_poll_count;
190     Rq_elem * rd_posp;
191     Rq_elem * wr_posp;
192     uint8_t * in_mmapp;
193     uint8_t * out_mmapp;
194     struct flags_t iflag;
195     struct flags_t oflag;
196     Rq_elem elem[SGQ_NUM_ELEMS];
197 } Rq_coll;
198 
199 static bool sgs_old_sg_driver = false;  /* true if VERSION_NUM < 4.00.00 */
200 static bool sgs_full_v4_sg_driver = false; /* set if VERSION_NUM >= 4.00.30 */
201 static bool sgs_nanosec_unit = false;
202 
203 static int sgq_rd_ahead_lim = SGQ_MAX_RD_AHEAD;
204 static int sgq_wr_ahead_lim = SGQ_MAX_WR_AHEAD;
205 static int sgq_num_elems = (SGQ_MAX_RD_AHEAD + SGQ_MAX_WR_AHEAD + 1);
206 
207 
208 static void
usage(int pg_num)209 usage(int pg_num)
210 {
211     if (pg_num > 1)
212         goto second_page;
213     printf("Usage: "
214            "sgs_dd  [bpt=BPT] [bs=BS] [count=NUM] [deb=DEB] [if=IFILE]\n"
215            "               [iflag=FLAGS] [no_sig=0|1] [of=OFILE] "
216            "[oflag=FLAGS]\n"
217            "               [poll_ms=MS] [rt_sig=0|1] [seek=SEEK] "
218            "[skip=SKIP]\n"
219            "               [--help] [--version]\n"
220            "where:\n"
221            "  bpt      blocks_per_transfer (default: 65536/bs (or 128 for "
222            "bs=512))\n"
223            "  bs       must be the logical block size of device (def: 512)\n"
224            "  deb      debug: 0->no debug (def); > 0 -> more debug\n"
225            "           -v (up to -vvvvv) sets deb value to number of 'v's\n"
226            "  iflag    comma separated list from: dio,evfd,excl,immed,mmap,"
227            "noxfer,\n"
228            "           null,pack,polled,tag,v3,v4 bound to IFILE\n"
229            "  no_sig   0-> use signals; 1-> no signals, hard polling "
230            "instead;\n"
231            "           default 0, unless polled flag(s) given then it's 1\n"
232            "  oflag    same flags as iflag but bound to OFILE\n"
233            "  poll_ms    number of milliseconds to wait on poll (def: 0)\n"
234            "  rt_sig   0->use SIGIO (def); 1->use RT sig (SIGRTMIN + 1)\n"
235            "  <other operands>     as per dd command\n\n");
236     printf("dd clone for testing Linux sg driver SIGPOLL and/or polling. "
237            "Either\nIFILE or OFILE must be a scsi generic device. If OFILE "
238            "not given then\n/dev/null assumed (rather than stdout like "
239            "dd). Use '-hh' for flag\ninformation.\n");
240     return;
241 second_page:
242     printf("flag description:\n"
243            "  dio      this driver's version of O_DIRECT\n"
244            "  evfd     when poll() gives POLLIN, use eventfd to find "
245            "out how many\n"
246            "  excl     open IFILE or OFILE with O_EXCL\n"
247            "  hipri    same as 'polled'; name 'hipri' is deprecated\n"
248            "  immed    use SGV4_FLAG_IMMED flag on each request\n"
249            "  mmap     use mmap()-ed IO on IFILE or OFILE\n"
250            "  noxfer    no transfer between user space and kernel IO "
251            "buffers\n"
252            "  null      does nothing, placeholder\n"
253            "  pack      submit with rising pack_id, complete matching "
254            "each pack_id\n"
255            "  polled    set POLLED flag and use blk_poll() for completion\n"
256            "  tag       use tag (from block layer) rather than "
257            "pack_id\n"
258            "  v3        use sg v3 interface (default)\n"
259            "  v4        use sg vr interface (i.e. struct sg_io_v4)\n");
260 }
261 
262 static int
get_mmap_addr(int fd,int num,uint8_t ** mmpp)263 get_mmap_addr(int fd, int num, uint8_t ** mmpp)
264 {
265     uint8_t * mmp;
266 
267     if (! mmpp)
268         return -EINVAL;
269     mmp = (uint8_t *)mmap(NULL, num, PROT_READ | PROT_WRITE,
270                           MAP_SHARED, fd, 0);
271     if (MAP_FAILED == mmp) {
272         int err = errno;
273 
274         pr2serr("%s%s: sz=%d, fd=%d, mmap() failed: %s\n",
275                 my_name, __func__, num, fd, strerror(err));
276         return -err;
277     }
278     *mmpp = mmp;
279     return 0;
280 }
281 
282 /* Return of 0 -> success, -1 -> failure, 2 -> try again */
283 static int
read_capacity(int sg_fd,int * num_sect,int * sect_sz)284 read_capacity(int sg_fd, int * num_sect, int * sect_sz)
285 {
286     int res;
287     uint8_t rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0};
288     uint8_t rcBuff[64];
289     uint8_t sense_b[64];
290     sg_io_hdr_t io_hdr;
291 
292     memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
293     io_hdr.interface_id = 'S';
294     io_hdr.cmd_len = sizeof(rcCmdBlk);
295     io_hdr.mx_sb_len = sizeof(sense_b);
296     io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
297     io_hdr.dxfer_len = sizeof(rcBuff);
298     io_hdr.dxferp = rcBuff;
299     io_hdr.cmdp = rcCmdBlk;
300     io_hdr.sbp = sense_b;
301     io_hdr.timeout = DEF_TIMEOUT;
302 
303     if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
304         res = -errno;
305         perror("read_capacity (SG_IO) error");
306         return res;
307     }
308     res = sg_err_category3(&io_hdr);
309     if (SG_LIB_CAT_UNIT_ATTENTION == res)
310         return 2; /* probably have another go ... */
311     else if (SG_LIB_CAT_CLEAN != res) {
312         sg_chk_n_print3("read capacity", &io_hdr, true);
313         return -1;
314     }
315     *num_sect = sg_get_unaligned_be32(rcBuff + 0) + 1;
316     *sect_sz = sg_get_unaligned_be32(rcBuff + 4);
317     return 0;
318 }
319 
320 /* -ve -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM) */
321 static int
sg_start_io(Rq_coll * clp,Rq_elem * rep)322 sg_start_io(Rq_coll * clp, Rq_elem * rep)
323 {
324     bool is_wr = rep->wr;
325     int res;
326     int fd = is_wr ? clp->outfd : clp->infd;
327     int num_bytes = clp->bs * rep->num_blks;
328     struct flags_t * flagp = is_wr ? rep->oflagp : rep->iflagp;
329     sg_io_hdr_t * hp = &rep->io_hdr;
330     struct sg_io_v4 * h4p = &rep->io_v4;
331 
332     if (clp->both_mmap && is_wr)
333         memcpy(clp->out_mmapp, clp->in_mmapp, num_bytes);
334     memset(rep->cmd, 0, sizeof(rep->cmd));
335     rep->cmd[0] = is_wr ? 0x2a : 0x28;
336     sg_put_unaligned_be32((uint32_t)rep->blk, rep->cmd + 2);
337     sg_put_unaligned_be16((uint16_t)rep->num_blks, rep->cmd + 7);
338     if (flagp->v4)
339         goto do_v4;
340 
341     memset(hp, 0, sizeof(sg_io_hdr_t));
342     hp->interface_id = 'S';
343     hp->cmd_len = sizeof(rep->cmd);
344     hp->cmdp = rep->cmd;
345     hp->dxfer_direction = is_wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
346     hp->dxfer_len = num_bytes;
347     hp->mx_sb_len = sizeof(rep->sb);
348     hp->sbp = rep->sb;
349     hp->timeout = DEF_TIMEOUT;
350     hp->usr_ptr = rep;
351     hp->pack_id = rep->blk;
352     if (flagp->dio)
353         hp->flags |= SG_FLAG_DIRECT_IO;
354     if (flagp->noxfer)
355         hp->flags |= SG_FLAG_NO_DXFER;
356     if (flagp->immed)
357         hp->flags |= SGV4_FLAG_IMMED;
358     if (flagp->polled)
359         hp->flags |= SGV4_FLAG_POLLED;
360     if (flagp->mmap) {
361         hp->flags |= SG_FLAG_MMAP_IO;
362         hp->dxferp = is_wr ? clp->out_mmapp : clp->in_mmapp;
363     } else
364         hp->dxferp = rep->buffp;
365     if (flagp->evfd)
366         hp->flags |= SGV4_FLAG_EVENTFD;
367     if (clp->debug > 5) {
368         pr2serr("%s: SCSI %s, blk=%d num_blks=%d\n", __func__,
369                 is_wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
370         sg_print_command(hp->cmdp);
371         pr2serr("dir=%d, len=%d, dxfrp=%p, cmd_len=%d\n", hp->dxfer_direction,
372                 hp->dxfer_len, hp->dxferp, hp->cmd_len);
373     }
374 
375     while (((res = write(fd, hp, sizeof(sg_io_hdr_t))) < 0) &&
376            (EINTR == errno))
377         ;
378     if (res < 0) {
379         if (ENOMEM == errno)
380             return 1;
381         if ((EDOM == errno) || (EAGAIN == errno) || (EBUSY == errno)) {
382             rep->state = SGQ_IO_WAIT;   /* busy so wait */
383             return 0;
384         }
385         pr2serr("%s: write(): %s [%d]\n", __func__, strerror(errno), errno);
386         rep->state = SGQ_IO_ERR;
387         return res;
388     }
389     rep->state = SGQ_IO_STARTED;
390     if (! clp->no_sig)
391         clp->sigs_waiting++;
392     return 0;
393 do_v4:
394     memset(h4p, 0, sizeof(struct sg_io_v4));
395     h4p->guard = 'Q';
396     h4p->request_len = sizeof(rep->cmd);
397     h4p->request = (uint64_t)(uintptr_t)rep->cmd;
398     if (is_wr)
399         h4p->dout_xfer_len = num_bytes;
400     else if (rep->num_blks > 0)
401         h4p->din_xfer_len = num_bytes;
402     h4p->max_response_len = sizeof(rep->sb);
403     h4p->response = (uint64_t)(uintptr_t)rep->sb;
404     h4p->timeout = DEF_TIMEOUT;
405     h4p->usr_ptr = (uint64_t)(uintptr_t)rep;
406     h4p->request_extra = rep->blk;/* N.B. blk --> pack_id --> request_extra */
407     if (flagp->dio)
408         h4p->flags |= SG_FLAG_DIRECT_IO;
409     if (flagp->noxfer)
410         h4p->flags |= SG_FLAG_NO_DXFER;
411     if (flagp->immed)
412         h4p->flags |= SGV4_FLAG_IMMED;
413     if (flagp->polled)
414         h4p->flags |= SGV4_FLAG_POLLED;
415     if (flagp->mmap) {
416         h4p->flags |= SG_FLAG_MMAP_IO;
417         hp->dxferp = is_wr ? clp->out_mmapp : clp->in_mmapp;
418     } else {
419         if (is_wr)
420             h4p->dout_xferp = (uint64_t)(uintptr_t)rep->buffp;
421         else if (rep->num_blks > 0)
422             h4p->din_xferp = (uint64_t)(uintptr_t)rep->buffp;
423     }
424     if (flagp->tag)
425         h4p->flags |= SGV4_FLAG_YIELD_TAG;
426     if (flagp->evfd)
427         h4p->flags |= SGV4_FLAG_EVENTFD;
428     if (! clp->no_sig)
429         h4p->flags |= SGV4_FLAG_SIGNAL;
430 
431     while (((res = ioctl(fd, SG_IOSUBMIT, h4p)) < 0) && (EINTR == errno))
432         ;
433     if (res < 0) {
434         if (ENOMEM == errno)
435             return 1;
436         if ((EDOM == errno) || (EAGAIN == errno) || (EBUSY == errno)) {
437             rep->state = SGQ_IO_WAIT;   /* busy so wait */
438             return 0;
439         }
440         pr2serr("%s: ioctl(SG_IOSUBMIT): %s [%d]\n", __func__,
441                 strerror(errno), errno);
442         rep->state = SGQ_IO_ERR;
443         return res;
444     }
445     rep->state = SGQ_IO_STARTED;
446     if (! clp->no_sig)
447         clp->sigs_waiting++;
448     if (clp->debug > 5) {
449         if (is_wr ? clp->oflag.tag : clp->iflag.tag)
450             pr2serr("%s:  generated_tag=0x%" PRIx64 "\n", __func__,
451                     (uint64_t)h4p->generated_tag);
452     }
453     return 0;
454 }
455 
456 /* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */
457 static int
sg_finish_io(Rq_coll * clp,bool wr,Rq_elem ** repp)458 sg_finish_io(Rq_coll * clp, bool wr, Rq_elem ** repp)
459 {
460     struct flags_t *flagsp = wr ? &clp->oflag : &clp->iflag;
461     bool dio = false;
462     bool is_v4 = flagsp->v4;
463     bool use_pack = flagsp->pack;
464     bool use_tag = flagsp->tag;
465     int fd = wr ? clp->outfd : clp->infd;
466     int res, id, n;
467     sg_io_hdr_t io_hdr;
468     sg_io_hdr_t * hp;
469     struct sg_io_v4 io_v4;
470     struct sg_io_v4 * h4p;
471     Rq_elem * rep;
472 
473     if (is_v4)
474         goto do_v4;
475     if (use_pack) {
476         while (true) {
477             if ( ((res = ioctl(fd, SG_GET_NUM_WAITING, &n))) < 0) {
478                 res = -errno;
479                 pr2serr("%s: ioctl(SG_GET_NUM_WAITING): %s [%d]\n",
480                         __func__, strerror(errno), errno);
481                 return res;
482             }
483             if (n > 0) {
484                 if ( (ioctl(fd, SG_GET_PACK_ID, &id)) < 0) {
485                     res = errno;
486                     pr2serr("%s: ioctl(SG_GET_PACK_ID): %s [%d]\n",
487                             __func__, strerror(res), res);
488                     return -res;
489                 }
490                 /* got pack_id or tag of first waiting */
491                 break;
492             }
493         }
494     }
495     memset(&io_hdr, 0 , sizeof(sg_io_hdr_t));
496     if (use_pack)
497         io_hdr.pack_id = id;
498     while (((res = read(fd, &io_hdr, sizeof(sg_io_hdr_t))) < 0) &&
499            ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
500         ;
501     rep = (Rq_elem *)io_hdr.usr_ptr;
502     if (rep) {
503         dio = flagsp->dio;
504         if (rep->io_hdr.flags & SGV4_FLAG_POLLED)
505             ++clp->blk_poll_count;
506     }
507     if (res < 0) {
508         res = -errno;
509         pr2serr("%s: read(): %s [%d]\n", __func__, strerror(errno), errno);
510         if (rep)
511             rep->state = SGQ_IO_ERR;
512         return res;
513     }
514     if (! (rep && (SGQ_IO_STARTED == rep->state))) {
515         pr2serr("%s: bad usr_ptr\n", __func__);
516         if (rep)
517             rep->state = SGQ_IO_ERR;
518         return -1;
519     }
520     memcpy(&rep->io_hdr, &io_hdr, sizeof(sg_io_hdr_t));
521     hp = &rep->io_hdr;
522     if (repp)
523         *repp = rep;
524 
525     switch (sg_err_category3(hp)) {
526         case SG_LIB_CAT_CLEAN:
527             break;
528         case SG_LIB_CAT_RECOVERED:
529             pr2serr("Recovered error on block=%d, num=%d\n", rep->blk,
530                     rep->num_blks);
531             break;
532         case SG_LIB_CAT_UNIT_ATTENTION:
533             return 1;
534         default:
535             sg_chk_n_print3(wr ? "writing": "reading", hp, true);
536             rep->state = SGQ_IO_ERR;
537             return -1;
538     }
539     if (dio && ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
540         ++clp->dio_incomplete; /* count dios done as indirect IO */
541     clp->sum_of_resids += hp->resid;
542     rep->state = SGQ_IO_FINISHED;
543     if (clp->debug > 5) {
544         pr2serr("%s: %s  ", __func__, wr ? "writing" : "reading");
545         pr2serr("    SGQ_IO_FINISHED elem idx=%zd\n", rep - clp->elem);
546     }
547     return 0;
548 do_v4:
549     id = -1;
550     if (use_pack || use_tag) {
551         while (true) {
552             if ( ((res = ioctl(fd, SG_GET_NUM_WAITING, &n))) < 0) {
553                 res = -errno;
554                 pr2serr("%s: ioctl(SG_GET_NUM_WAITING): %s [%d]\n",
555                         __func__, strerror(errno), errno);
556                 return res;
557             }
558             if (n > 0) {
559                 if ( (ioctl(fd, SG_GET_PACK_ID, &id)) < 0) {
560                     res = errno;
561                     pr2serr("%s: ioctl(SG_GET_PACK_ID): %s [%d]\n",
562                             __func__, strerror(res), res);
563                     return -res;
564                 }
565                 /* got pack_id or tag of first waiting */
566                 break;
567             }
568         }
569     }
570     memset(&io_v4, 0 , sizeof(io_v4));
571     io_v4.guard = 'Q';
572     if (use_tag)
573         io_v4.request_tag = id;
574     else if (use_pack)
575         io_v4.request_extra = id;
576     io_v4.flags |= SGV4_FLAG_IMMED;
577     if (flagsp->evfd)
578         io_v4.flags |= SGV4_FLAG_EVENTFD;
579     while (((res = ioctl(fd, SG_IORECEIVE, &io_v4)) < 0) &&
580            ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
581         ;
582     rep = (Rq_elem *)(unsigned long)io_v4.usr_ptr;
583     if (res < 0) {
584         res = -errno;
585         pr2serr("%s: ioctl(SG_IORECEIVE): %s [%d]\n", __func__,
586                 strerror(errno), errno);
587         if (rep)
588             rep->state = SGQ_IO_ERR;
589         return res;
590     }
591     if (rep) {
592         if (rep->io_v4.flags & SGV4_FLAG_POLLED)
593             ++clp->blk_poll_count;
594     }
595     if (! (rep && (SGQ_IO_STARTED == rep->state))) {
596         pr2serr("%s: bad usr_ptr=0x%p\n", __func__, (void *)rep);
597         if (rep)
598             rep->state = SGQ_IO_ERR;
599         return -1;
600     }
601     memcpy(&rep->io_v4, &io_v4, sizeof(struct sg_io_v4));
602     h4p = &rep->io_v4;
603     if (repp)
604         *repp = rep;
605 
606     res = sg_err_category_new(h4p->device_status, h4p->transport_status,
607                               h4p->driver_status,
608                       (const uint8_t *)(unsigned long)h4p->response,
609                               h4p->response_len);
610     switch (res) {
611         case SG_LIB_CAT_CLEAN:
612             break;
613         case SG_LIB_CAT_RECOVERED:
614             pr2serr("Recovered error on block=%d, num=%d\n", rep->blk,
615                     rep->num_blks);
616             break;
617         case SG_LIB_CAT_UNIT_ATTENTION:
618             return 1;
619         default:
620             sg_linux_sense_print(wr ? "writing": "reading",
621                                  h4p->device_status, h4p->transport_status,
622                                  h4p->driver_status,
623                          (const uint8_t *)(unsigned long)h4p->response,
624                                  h4p->response_len, true);
625             rep->state = SGQ_IO_ERR;
626             return -1;
627     }
628     if (dio && ((h4p->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
629         ++clp->dio_incomplete; /* count dios done as indirect IO */
630     clp->sum_of_resids += h4p->din_resid;
631     rep->state = SGQ_IO_FINISHED;
632     if (clp->debug > 5) {
633         pr2serr("%s: %s  ", __func__, wr ? "writing" : "reading");
634         pr2serr("    SGQ_IO_FINISHED elem idx=%zd\n", rep - clp->elem);
635         if (use_pack)
636             pr2serr("%s:  pack_id=%d\n", __func__, h4p->request_extra);
637         else if (use_tag)
638             pr2serr("%s:  request_tag=0x%" PRIx64 "\n", __func__,
639                     (uint64_t)h4p->request_tag);
640     }
641     return 0;
642 }
643 
644 static int
sz_reserve(Rq_coll * clp,bool is_in)645 sz_reserve(Rq_coll * clp, bool is_in)
646 {
647     const struct flags_t *flagsp = is_in ? &clp->iflag : &clp->oflag;
648     bool pack = flagsp->pack;
649     bool vb = clp->debug;
650     int res, t, flags, err;
651     int fd = is_in ? clp->infd : clp->outfd;
652     int tag = flagsp->tag;
653     struct sg_extended_info sei;
654     struct sg_extended_info * seip;
655 
656     seip = &sei;
657     res = ioctl(fd, SG_GET_VERSION_NUM, &t);
658     if ((res < 0) || (t < 30000)) {
659         pr2serr("%s: sg driver prior to 3.0.00\n", my_name);
660         return 1;
661     } else if (t < 40000) {
662         if (vb)
663             pr2serr("%s: warning: sg driver prior to 4.0.00\n", my_name);
664         sgs_old_sg_driver = true;
665     } else if (t < 40045) {
666         sgs_old_sg_driver = false;
667         sgs_full_v4_sg_driver = false;
668     } else
669         sgs_full_v4_sg_driver = true;
670     t = clp->bs * clp->bpt;
671     res = ioctl(fd, SG_SET_RESERVED_SIZE, &t);
672     if (res < 0)
673         perror("sgs_dd: SG_SET_RESERVED_SIZE error");
674 
675     if (sgs_full_v4_sg_driver) {
676         if (sgs_nanosec_unit) {
677             memset(seip, 0, sizeof(*seip));
678             seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
679             seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TIME_IN_NS;
680             seip->ctl_flags |= SG_CTL_FLAGM_TIME_IN_NS;
681             if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
682                 pr2serr("ioctl(EXTENDED(TIME_IN_NS)) failed, errno=%d %s\n",
683                         errno, strerror(errno));
684                 return 1;
685             }
686         }
687         if (tag || pack) {
688             t = 1;
689             if (ioctl(fd, SG_SET_FORCE_PACK_ID, &t) < 0) {
690                 pr2serr("ioctl(SG_SET_FORCE_PACK_ID(on)) failed, errno=%d "
691                         "%s\n", errno, strerror(errno));
692                 return 1;
693             }
694             if (tag) {
695                 memset(seip, 0, sizeof(*seip));
696                 seip->sei_wr_mask |= SG_SEIM_CTL_FLAGS;
697                 seip->ctl_flags_wr_mask |= SG_CTL_FLAGM_TAG_FOR_PACK_ID;
698                 seip->ctl_flags |= SG_CTL_FLAGM_TAG_FOR_PACK_ID;
699                 if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
700                     pr2serr("ioctl(EXTENDED(TAG_FOR_PACK_ID)) failed, "
701                             "errno=%d %s\n", errno, strerror(errno));
702                     return 1;
703                 }
704             }
705         }
706         if (flagsp->evfd) {
707             int evfd = eventfd(0,0);
708 
709             if (evfd < 0) {
710                 err = errno;
711                 pr2serr("eventfd() failed: %s\n", strerror(err));
712                 return 1;
713             }
714             if (is_in)
715                 clp->in_evfd = evfd;
716             else
717                 clp->out_evfd = evfd;
718 
719             memset(seip, 0, sizeof(*seip));
720             seip->sei_wr_mask |= SG_SEIM_EVENTFD;
721             seip->sei_rd_mask |= SG_SEIM_EVENTFD;
722             seip->share_fd = evfd;
723             if (ioctl(fd, SG_SET_GET_EXTENDED, seip) < 0) {
724                 err = errno;
725                 pr2serr("ioctl(EXTENDED(SG_SEIM_EVENTFD)) failed, "
726                         "errno=%d %s\n", err, strerror(err));
727                 return 1;
728             }
729         }
730     }
731     if (!clp->no_sig) {
732         if (-1 == fcntl(fd, F_SETOWN, getpid())) {
733             perror("fcntl(F_SETOWN)");
734             return 1;
735         }
736         flags = fcntl(fd, F_GETFL, 0);
737         if (-1 == fcntl(fd, F_SETFL, flags | O_ASYNC)) {
738             perror("fcntl(F_SETFL)");
739             return 1;
740         }
741         if (clp->use_rt_sig) {/* displaces SIGIO/SIGPOLL with SIGRTMIN + 1 */
742             if (-1 == fcntl(fd, F_SETSIG, SIGRTMIN + 1))
743                 perror("fcntl(F_SETSIG)");
744         }
745     }
746     return 0;
747 }
748 
749 static int
init_elems(Rq_coll * clp)750 init_elems(Rq_coll * clp)
751 {
752     bool either_mmap = false;
753     int res = 0;
754     int num_bytes = clp->bpt * clp->bs;
755     int k;
756     Rq_elem * rep;
757 
758     clp->wr_posp = &clp->elem[0]; /* making ring buffer */
759     clp->rd_posp = clp->wr_posp;
760     if (clp->iflag.mmap || clp->oflag.mmap) {
761         int res;
762 
763         either_mmap = true;
764         sgq_num_elems = 2;
765         sgq_rd_ahead_lim = 1;
766         sgq_wr_ahead_lim = 1;
767         if (clp->iflag.mmap) {
768             res = get_mmap_addr(clp->infd, num_bytes, &clp->in_mmapp);
769             if (res < 0)
770                 return res;
771         }
772         if (clp->oflag.mmap) {
773             res = get_mmap_addr(clp->outfd, num_bytes, &clp->out_mmapp);
774             if (res < 0)
775                 return res;
776         }
777     }
778     for (k = 0; k < sgq_num_elems - 1; ++k)
779         clp->elem[k].nextp = &clp->elem[k + 1];
780     clp->elem[sgq_num_elems - 1].nextp = &clp->elem[0];
781     for (k = 0; k < sgq_num_elems; ++k) {
782         rep = &clp->elem[k];
783         rep->state = SGQ_FREE;
784         rep->iflagp = &clp->iflag;
785         rep->oflagp = &clp->oflag;
786         if (either_mmap) {
787             if (clp->both_mmap)
788                 continue;
789             if (clp->iflag.mmap)
790                 rep->buffp = clp->in_mmapp;
791             else
792                 rep->buffp = clp->out_mmapp;
793             continue;
794         }
795         rep->buffp = sg_memalign(num_bytes, 0, &rep->free_buffp, false);
796         if (NULL == rep->buffp) {
797             pr2serr("out of memory creating user buffers\n");
798             res = -ENOMEM;
799         }
800     }
801     return res;
802 }
803 
804 static void
remove_elems(Rq_coll * clp)805 remove_elems(Rq_coll * clp)
806 {
807     Rq_elem * rep;
808     int k;
809 
810     for (k = 0; k < sgq_num_elems; ++k) {
811         rep = &clp->elem[k];
812         if (rep->free_buffp)
813             free(rep->free_buffp);
814     }
815 }
816 
817 static int
start_read(Rq_coll * clp)818 start_read(Rq_coll * clp)
819 {
820     int blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count;
821     Rq_elem * rep = clp->rd_posp;
822     int buf_sz, res;
823     char ebuff[EBUFF_SZ];
824 
825     if (clp->debug > 5)
826         pr2serr("%s: elem idx=%zd\n", __func__, rep - clp->elem);
827     rep->wr = false;
828     rep->blk = clp->in_blk;
829     rep->num_blks = blocks;
830     clp->in_blk += blocks;
831     clp->in_count -= blocks;
832     if (clp->in_is_sg) {
833         res = sg_start_io(clp, rep);
834         if (1 == res) {     /* ENOMEM, find what's available+try that */
835             if (ioctl(clp->infd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) {
836                 res = -errno;
837                 perror("RESERVED_SIZE ioctls failed");
838                 return res;
839             }
840             clp->bpt = (buf_sz + clp->bs - 1) / clp->bs;
841             pr2serr("Reducing blocks per transfer to %d\n", clp->bpt);
842             if (clp->bpt < 1)
843                 return -ENOMEM;
844             res = sg_start_io(clp, rep);
845             if (1 == res)
846                 res = -ENOMEM;
847         }
848         if (res < 0) {
849             pr2serr("%s: inputting from sg failed, blk=%d\n", my_name,
850                     rep->blk);
851             rep->state = SGQ_IO_ERR;
852             return res;
853         }
854     }
855     else {
856         rep->state = SGQ_IO_STARTED;
857         while (((res = read(clp->infd, rep->buffp, blocks * clp->bs)) < 0) &&
858                (EINTR == errno))
859             ;
860         if (res < 0) {
861             res = -errno;
862             snprintf(ebuff, EBUFF_SZ, "%s: reading, in_blk=%d ", my_name,
863                      rep->blk);
864             perror(ebuff);
865             rep->state = SGQ_IO_ERR;
866             return res;
867         }
868         if (res < blocks * clp->bs) {
869             int o_blocks = blocks;
870             rep->stop_after_wr = true;
871             blocks = res / clp->bs;
872             if ((res % clp->bs) > 0) {
873                 blocks++;
874                 clp->in_partial++;
875             }
876             /* Reverse out + re-apply blocks on clp */
877             clp->in_blk -= o_blocks;
878             clp->in_count += o_blocks;
879             rep->num_blks = blocks;
880             clp->in_blk += blocks;
881             clp->in_count -= blocks;
882         }
883         clp->in_done_count -= blocks;
884         rep->state = SGQ_IO_FINISHED;
885     }
886     clp->rd_posp = rep->nextp;
887     return blocks;
888 }
889 
890 static int
start_write(Rq_coll * clp)891 start_write(Rq_coll * clp)
892 {
893     Rq_elem * rep = clp->wr_posp;
894     int res, blocks;
895     char ebuff[EBUFF_SZ];
896 
897     while ((0 != rep->wr) || (SGQ_IO_FINISHED != rep->state)) {
898         rep = rep->nextp;
899         if (rep == clp->rd_posp)
900             return -1;
901     }
902     if (clp->debug > 5)
903         pr2serr("%s: elem idx=%zd\n", __func__, rep - clp->elem);
904     rep->wr = true;
905     blocks = rep->num_blks;
906     rep->blk = clp->out_blk;
907     clp->out_blk += blocks;
908     clp->out_count -= blocks;
909     if (clp->out_is_sg) {
910         res = sg_start_io(clp, rep);
911         if (1 == res)      /* ENOMEM, give up */
912             return -ENOMEM;
913         else if (res < 0) {
914             pr2serr("%s: output to sg failed, blk=%d\n", my_name, rep->blk);
915             rep->state = SGQ_IO_ERR;
916             return res;
917         }
918     }
919     else {
920         rep->state = SGQ_IO_STARTED;
921         while (((res = write(clp->outfd, rep->buffp,
922                      rep->num_blks * clp->bs)) < 0) && (EINTR == errno))
923             ;
924         if (res < 0) {
925             res = -errno;
926             snprintf(ebuff, EBUFF_SZ, "%s: output, out_blk=%d ", my_name,
927                      rep->blk);
928             perror(ebuff);
929             rep->state = SGQ_IO_ERR;
930             return res;
931         }
932         if (res < blocks * clp->bs) {
933             blocks = res / clp->bs;
934             if ((res % clp->bs) > 0) {
935                 blocks++;
936                 clp->out_partial++;
937             }
938             rep->num_blks = blocks;
939         }
940         rep->state = SGQ_IO_FINISHED;
941     }
942     return blocks;
943 }
944 
945 /* Returns 0 if SIGIO/SIGPOLL or (SIGRTMIN + 1) received, else returns negated
946  * errno value; -EAGAIN for timeout. */
947 static int
do_sigwait(Rq_coll * clp,bool inc1_clear0)948 do_sigwait(Rq_coll * clp, bool inc1_clear0)
949 {
950     siginfo_t info;
951     struct timespec ts;
952 
953     if (clp->debug > 9)
954         pr2serr("%s: inc1_clear0=%d\n", __func__, (int)inc1_clear0);
955     ts.tv_sec = 0;
956     ts.tv_nsec = DEF_SIGTIMEDWAIT_USEC * 1000;
957     while (sigtimedwait(&clp->blocked_sigs, &info, &ts) < 0) {
958         int err = errno;
959 
960         if (EINTR != err) {
961 
962             if (EAGAIN != err)
963                 pr2serr("%s: sigtimedwait(): %s [%d]\n", __func__,
964                         strerror(err), err);
965             return -err;        /* EAGAIN is timeout error */
966         }
967     }
968     if ((SIGRTMIN + 1) == info.si_signo) {
969         if (inc1_clear0) {
970             clp->sigs_waiting--;
971             clp->sigs_rt_received++;
972         } else
973             clp->sigs_waiting = 0;
974     } else if (SIGPOLL == info.si_signo) {
975         if (inc1_clear0) {
976             clp->sigs_waiting--;
977             clp->sigs_io_received++;
978         } else
979             clp->sigs_waiting = 0;
980     } else {
981         pr2serr("%s: sigwaitinfo() returned si_signo=%d\n",
982                 __func__, info.si_signo);
983         return -EINVAL;
984     }
985     return 0;
986 }
987 
988 /* Returns 1 (or more) on success (found), 0 on not found, -1 on error. */
989 static int
do_num_poll_in(Rq_coll * clp,int fd,bool is_evfd)990 do_num_poll_in(Rq_coll * clp, int fd, bool is_evfd)
991 {
992     int err, res;
993     struct pollfd a_pollfd = {0, POLLIN | POLLOUT, 0};
994 
995     if (! clp->no_sig) {
996         if (clp->sigs_waiting) {
997             int res = do_sigwait(clp, true);
998 
999             if ((res < 0) && (-EAGAIN != res))
1000                 return res;
1001         }
1002     }
1003     a_pollfd.fd = fd;
1004     if (poll(&a_pollfd, 1, clp->poll_ms) < 0) {
1005         err = errno;
1006         pr2serr("%s: poll(): %s [%d]\n", __func__, strerror(err), err);
1007         return -err;
1008     }
1009     /* pr2serr("%s: revents=0x%x\n", __func__, a_pollfd.revents); */
1010     if (a_pollfd.revents & POLLIN) {
1011         if (is_evfd) {
1012             uint64_t count;
1013 
1014             if ((res = read(fd, &count, sizeof(count))) < 0) {
1015                 err = errno;
1016                 pr2serr("%s: read(): %s [%d]\n", __func__,
1017                         strerror(err), err);
1018                 return -err;
1019             }
1020             return (res < (int)sizeof(uint64_t)) ? 0 : (int)count;
1021         } else
1022             return 1;   /* could be more but don't know without evfd */
1023     } else if (a_pollfd.revents & POLLERR)
1024         ++clp->pollerr_count;
1025 
1026     return 0;
1027 }
1028 
1029 static int
can_read_write(Rq_coll * clp)1030 can_read_write(Rq_coll * clp)
1031 {
1032     Rq_elem * rep = NULL;
1033     bool writeable = false;
1034     bool in_is_evfd = (clp->in_evfd >= 0);
1035     bool out_is_evfd = (clp->out_evfd >= 0);
1036     int res = 0;
1037     int reading = 0;
1038     int writing = 0;
1039     int rd_waiting = 0;
1040     int wr_waiting = 0;
1041     int sg_finished = 0;
1042     int num;
1043     int ofd = out_is_evfd ? clp->out_evfd : clp->outfd;
1044     int ifd= in_is_evfd ? clp->in_evfd : clp->infd;
1045 
1046     /* if write completion pending, then complete it + start read */
1047     if (clp->out_is_sg) {
1048         while ((res = do_num_poll_in(clp, ofd, out_is_evfd))) {
1049             if (res < 0)
1050                 return res;
1051             num = res;
1052             while (--num >= 0) {
1053                 res = sg_finish_io(clp, true /* write */, &rep);
1054                 if (res < 0)
1055                     return res;
1056                 else if (1 == res) {
1057                     res = sg_start_io(clp, rep);
1058                     if (0 != res)
1059                         return -1;  /* give up if any problems with retry */
1060                 } else
1061                     sg_finished++;
1062             }
1063         }
1064         while ((rep = clp->wr_posp) && (SGQ_IO_FINISHED == rep->state) &&
1065                rep->wr && (rep != clp->rd_posp)) {
1066             rep->state = SGQ_FREE;
1067             clp->out_done_count -= rep->num_blks;
1068             clp->wr_posp = rep->nextp;
1069             if (rep->stop_after_wr)
1070                 return -1;
1071         }
1072     }
1073     else if ((rep = clp->wr_posp) && rep->wr &&
1074              (SGQ_IO_FINISHED == rep->state)) {
1075         rep->state = SGQ_FREE;
1076         clp->out_done_count -= rep->num_blks;
1077         clp->wr_posp = rep->nextp;
1078         if (rep->stop_after_wr)
1079             return -1;
1080     }
1081 
1082     /* if read completion pending, then complete it + start maybe write */
1083     if (clp->in_is_sg) {
1084         while ((res = do_num_poll_in(clp, ifd, in_is_evfd))) {
1085             if (res < 0)
1086                 return res;
1087             num = res;
1088             while (--num >= 0) {
1089                 res = sg_finish_io(clp, false /* read */, &rep);
1090                 if (res < 0)
1091                     return res;
1092                 if (1 == res) {
1093                     res = sg_start_io(clp, rep);
1094                     if (0 != res)
1095                         return -1;  /* give up if any problems with retry */
1096                 } else {
1097                     sg_finished++;
1098                     clp->in_done_count -= rep->num_blks;
1099                 }
1100             }
1101         }
1102     }
1103 
1104     for (rep = clp->wr_posp, res = 1;
1105          rep && (rep != clp->rd_posp); rep = rep->nextp) {
1106         if (SGQ_IO_STARTED == rep->state) {
1107             if (rep->wr)
1108                 ++writing;
1109             else {
1110                 res = 0;
1111                 ++reading;
1112             }
1113         }
1114         else if ((! rep->wr) && (SGQ_IO_FINISHED == rep->state)) {
1115             if (res)
1116                 writeable = true;
1117         }
1118         else if (SGQ_IO_WAIT == rep->state) {
1119             res = 0;
1120             if (rep->wr)
1121                 ++wr_waiting;
1122             else
1123                 ++rd_waiting;
1124         }
1125         else
1126             res = 0;
1127     }
1128     if (clp->debug > 6) {
1129         if ((clp->debug > 7) || wr_waiting || rd_waiting) {
1130             pr2serr("%d/%d (nwb/nrb): read=%d/%d (do/wt) "
1131                     "write=%d/%d (do/wt) writeable=%d sg_fin=%d\n",
1132                     clp->out_blk, clp->in_blk, reading, rd_waiting,
1133                     writing, wr_waiting, (int)writeable, sg_finished);
1134         }
1135         // fflush(stdout);
1136     }
1137     if (writeable && (writing < sgq_wr_ahead_lim) && (clp->out_count > 0))
1138         return SGQ_CAN_WRITE;
1139     if ((reading < sgq_rd_ahead_lim) && (clp->in_count > 0) &&
1140         (0 == rd_waiting) && (clp->rd_posp->nextp != clp->wr_posp))
1141         return SGQ_CAN_READ;
1142 
1143     if (clp->out_done_count <= 0)
1144         return SGQ_CAN_DO_NOTHING;
1145 
1146     /* usleep(10000); */      /* hang about for 10 milliseconds */
1147     if ((! clp->no_sig) && clp->sigs_waiting) {
1148         res = do_sigwait(clp, false);
1149         if ((res < 0) && (-EAGAIN != res))
1150             return res;     /* wasn't timeout */
1151     }
1152     /* Now check the _whole_ buffer for pending requests */
1153     for (rep = clp->rd_posp->nextp; rep && (rep != clp->rd_posp);
1154          rep = rep->nextp) {
1155         if (SGQ_IO_WAIT == rep->state) {
1156             res = sg_start_io(clp, rep);
1157             if (res < 0)
1158                 return res;
1159             if (res > 0)
1160                 return -1;
1161             break;
1162         }
1163     }
1164     return SGQ_CAN_DO_NOTHING;
1165 }
1166 
1167 static bool
process_flags(const char * arg,struct flags_t * fp)1168 process_flags(const char * arg, struct flags_t * fp)
1169 {
1170     char buff[256];
1171     char * cp;
1172     char * np;
1173 
1174     strncpy(buff, arg, sizeof(buff));
1175     buff[sizeof(buff) - 1] = '\0';
1176     if ('\0' == buff[0]) {
1177         pr2serr("no flag found, 'null' can be used as a placeholder\n");
1178         return false;
1179     }
1180     cp = buff;
1181     do {
1182         np = strchr(cp, ',');
1183         if (np)
1184             *np++ = '\0';
1185         if (0 == strcmp(cp, "dio"))
1186             fp->dio = true;
1187         else if (0 == strcmp(cp, "evfd"))
1188             fp->evfd = true;
1189         else if (0 == strcmp(cp, "excl"))
1190             fp->excl = true;
1191         else if (0 == strcmp(cp, "hipri"))
1192             fp->polled = true;
1193         else if (0 == strcmp(cp, "immed"))
1194             fp->immed = true;
1195         else if (0 == strcmp(cp, "mmap"))
1196             fp->mmap = true;
1197         else if (0 == strcmp(cp, "noxfer"))
1198             fp->noxfer = true;
1199         else if (0 == strcmp(cp, "null"))
1200             ;
1201         else if (0 == strcmp(cp, "pack"))
1202             fp->pack = true;
1203         else if (0 == strcmp(cp, "polled"))
1204             fp->polled = true;
1205         else if (0 == strcmp(cp, "tag"))
1206             fp->tag = true;
1207         else if (0 == strcmp(cp, "v3")) {
1208             fp->v3 = true;
1209             fp->v4 = false;
1210             fp->given_v3v4 = true;
1211         } else if (0 == strcmp(cp, "v4")) {
1212             fp->v3 = false;
1213             fp->v4 = true;
1214             fp->given_v3v4 = true;
1215         } else {
1216             pr2serr("unrecognised flag: %s\n", cp);
1217             return false;
1218         }
1219         cp = np;
1220     } while (cp);
1221     if (fp->dio && fp->mmap) {
1222         pr2serr(" Can't set both mmap and dio\n");
1223         return false;
1224     }
1225     if ((fp->dio || fp->mmap) && fp->noxfer) {
1226         pr2serr(" Can't have mmap or dio with noxfer\n");
1227         return false;
1228     }
1229     return true;
1230 }
1231 
1232 
1233 int
main(int argc,char * argv[])1234 main(int argc, char * argv[])
1235 {
1236     bool bs_given = false;
1237     bool no_sig_given = false;
1238     bool polled_present;
1239     int skip = 0;
1240     int seek = 0;
1241     int ibs = 0;
1242     int obs = 0;
1243     int count = -1;
1244     int in_num_sect = 0;
1245     int out_num_sect = 0;
1246     int help_pg = 0;
1247     int res, k, in_sect_sz, out_sect_sz, crw, open_fl;
1248     char str[STR_SZ];
1249     char * key;
1250     char * buf;
1251     char inf[INOUTF_SZ];
1252     char outf[INOUTF_SZ];
1253     char ebuff[EBUFF_SZ];
1254     Rq_coll rcoll;
1255     Rq_coll * clp = &rcoll;
1256 
1257     memset(clp, 0, sizeof(*clp));
1258     clp->bpt = 0;
1259     clp->in_evfd = -1;
1260     clp->out_evfd = -1;
1261     clp->iflag.v3 = true;
1262     clp->oflag.v3 = true;
1263     inf[0] = '\0';
1264     outf[0] = '\0';
1265     if (argc < 2) {
1266         usage(1);
1267         return 1;
1268     }
1269     sgs_nanosec_unit = !!getenv("SG3_UTILS_LINUX_NANO");
1270 
1271     for(k = 1; k < argc; k++) {
1272         if (argv[k]) {
1273             strncpy(str, argv[k], STR_SZ);
1274             str[STR_SZ - 1] = '\0';
1275         }
1276         else
1277             continue;
1278         for(key = str, buf = key; *buf && *buf != '=';)
1279             buf++;
1280         if (*buf)
1281             *buf++ = '\0';
1282         if (0 == strcmp(key,"bpt")) {
1283             clp->bpt = sg_get_num(buf);
1284             if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) {
1285                 pr2serr("%s: bad argument to 'bpt='\n", my_name);
1286                 return SG_LIB_SYNTAX_ERROR;
1287             }
1288         } else if (0 == strcmp(key,"bs")) {
1289             clp->bs = sg_get_num(buf);
1290             if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) {
1291                 pr2serr("%s: bad argument to 'bs='\n", my_name);
1292                 return SG_LIB_SYNTAX_ERROR;
1293             }
1294         } else if (0 == strcmp(key,"count")) {
1295             count = sg_get_num(buf);
1296             if (count < 0) {
1297                 pr2serr("%s: bad argument to 'count='\n", my_name);
1298                 return SG_LIB_SYNTAX_ERROR;
1299             }
1300         } else if (0 == strcmp(key,"deb"))
1301             clp->debug += sg_get_num(buf);
1302         else if (0 == strcmp(key,"ibs")) {
1303             ibs = sg_get_num(buf);
1304             if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) {
1305                 pr2serr("%s: bad argument to 'ibs='\n", my_name);
1306                 return SG_LIB_SYNTAX_ERROR;
1307             }
1308         } else if (strcmp(key,"if") == 0) {
1309             memcpy(inf, buf, INOUTF_SZ);
1310             inf[INOUTF_SZ - 1] = '\0';
1311         } else if (0 == strcmp(key, "iflag")) {
1312             if (! process_flags(buf, &clp->iflag)) {
1313                 pr2serr("%s: bad argument to 'iflag='\n", my_name);
1314                 return SG_LIB_SYNTAX_ERROR;
1315             }
1316         } else if (strcmp(key,"mrq") == 0)
1317             ;           /* do nothing */
1318         else if (0 == strcmp(key,"no_sig")) { /* default changes */
1319             clp->no_sig = !!sg_get_num(buf);
1320             no_sig_given = true;
1321         } else if (0 == strcmp(key,"obs")) {
1322             obs = sg_get_num(buf);
1323             if ((obs < 0) || (obs > MAX_BPT_VALUE)) {
1324                 pr2serr("%s: bad argument to 'obs='\n", my_name);
1325                 return SG_LIB_SYNTAX_ERROR;
1326             }
1327         } else if (strcmp(key,"of") == 0) {
1328             memcpy(outf, buf, INOUTF_SZ);
1329             outf[INOUTF_SZ - 1] = '\0';
1330         } else if (0 == strcmp(key, "oflag")) {
1331             if (! process_flags(buf, &clp->oflag)) {
1332                 pr2serr("%s: bad argument to 'oflag='\n", my_name);
1333                 return SG_LIB_SYNTAX_ERROR;
1334             }
1335         } else if (0 == strcmp(key,"poll_ms"))
1336             clp->poll_ms = sg_get_num(buf);
1337         else if (0 == strcmp(key,"rt_sig"))
1338             clp->use_rt_sig = !!sg_get_num(buf);
1339         else if (0 == strcmp(key,"seek")) {
1340             seek = sg_get_num(buf);
1341             if (seek < 0) {
1342                 pr2serr("%s: bad argument to 'seek='\n", my_name);
1343                 return SG_LIB_SYNTAX_ERROR;
1344             }
1345         } else if (0 == strcmp(key,"skip")) {
1346             skip = sg_get_num(buf);
1347             if (skip < 0) {
1348                 pr2serr("%s: bad argument to 'skip='\n", my_name);
1349                 return SG_LIB_SYNTAX_ERROR;
1350             }
1351         } else if (0 == strcmp(key,"time"))
1352             ;           /* do nothing */
1353         else if ((0 == strcmp(key,"-V")) || (0 == strcmp(key,"--version"))) {
1354             pr2serr("%s: version: %s\n", my_name, version_str);
1355             return 0;
1356         } else if (0 == strncmp(key,"-vvvvvvv", 8))
1357             clp->debug += 7;
1358         else if (0 == strncmp(key,"-vvvvvv", 7))
1359             clp->debug += 6;
1360         else if (0 == strncmp(key,"-vvvvv", 6))
1361             clp->debug += 5;
1362         else if (0 == strncmp(key,"-vvvv", 5))
1363             clp->debug += 4;
1364         else if (0 == strncmp(key,"-vvv", 4))
1365             clp->debug += 3;
1366         else if (0 == strncmp(key,"-vv", 3))
1367             clp->debug += 2;
1368         else if ((0 == strcmp(key,"--verbose")) || (0 == strncmp(key,"-v", 2)))
1369             ++clp->debug;
1370         else if (0 == strcmp(key,"-hhhh"))
1371             help_pg += 4;
1372         else if (0 == strcmp(key,"-hhh"))
1373             help_pg += 3;
1374         else if (0 == strcmp(key,"-hh"))
1375             help_pg += 2;
1376         else if ((0 == strcmp(key,"-h")) || (0 == strcmp(key,"--help")))
1377             ++help_pg;
1378         else {
1379             pr2serr("Unrecognized argument '%s'\n", key);
1380             usage(help_pg);
1381             return 1;
1382         }
1383     }
1384     if (clp->bs <= 0) {
1385         clp->bs = DEF_BLOCK_SIZE;
1386     } else
1387         bs_given = true;
1388 
1389     if (help_pg > 0) {
1390         usage(help_pg);
1391         return 0;
1392     }
1393 
1394     polled_present = (clp->iflag.polled || clp->oflag.polled);
1395     if (no_sig_given) {
1396         if ((0 == clp->no_sig) && polled_present)
1397             pr2serr("Warning: signalling doesn't work with polled flag\n");
1398     } else      /* no_sig default varies: 0 normally and 1 if polled present */
1399         clp->no_sig = polled_present ? 1 : 0;
1400 
1401     if ((ibs && (ibs != clp->bs)) || (obs && (obs != clp->bs))) {
1402         pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
1403         usage(1);
1404         return 1;
1405     }
1406     if (clp->bpt <= 0) {
1407         clp->bpt = (DEF_BPT_TIMES_BS_SZ / clp->bs);
1408         if (0 == clp->bpt)
1409             clp->bpt = 1;
1410         if (! bs_given)
1411             pr2serr("Assume blocks size bs=%d [bytes] and blocks "
1412                     "per transfer bpt=%d\n", clp->bs, clp->bpt);
1413     } else if (! bs_given)
1414         pr2serr("Assume 'bs' (block size) of %d bytes\n", clp->bs);
1415 
1416     if ((skip < 0) || (seek < 0)) {
1417         pr2serr("%s: skip and seek cannot be negative\n", my_name);
1418         return 1;
1419     }
1420     if (clp->iflag.mmap && clp->oflag.mmap)
1421         clp->both_mmap = true;
1422 
1423     if (clp->debug > 3)
1424         pr2serr("%s: if=%s skip=%d of=%s seek=%d count=%d\n", my_name,
1425                 inf, skip, outf, seek, count);
1426     if (! clp->no_sig) {
1427         /* Need to block signals before SIGPOLL is enabled in sz_reserve() */
1428         sigemptyset(&clp->blocked_sigs);
1429         if (clp->use_rt_sig)
1430             sigaddset(&clp->blocked_sigs, SIGRTMIN + 1);
1431         sigaddset(&clp->blocked_sigs, SIGINT);
1432         sigaddset(&clp->blocked_sigs, SIGPOLL);
1433         sigprocmask(SIG_BLOCK, &clp->blocked_sigs, 0);
1434     }
1435 
1436     clp->infd = STDIN_FILENO;
1437     clp->outfd = STDOUT_FILENO;
1438     if (inf[0] && ('-' != inf[0])) {
1439         open_fl = clp->iflag.excl ? O_EXCL : 0;
1440         if ((clp->infd = open(inf, open_fl | O_RDONLY)) < 0) {
1441             snprintf(ebuff, EBUFF_SZ, "%s: could not open %s for reading",
1442                      my_name, inf);
1443             perror(ebuff);
1444             return 1;
1445         }
1446         if (ioctl(clp->infd, SG_GET_TIMEOUT, 0) < 0) {
1447             clp->in_is_sg = false;
1448             if (skip > 0) {
1449                 off_t offset = skip;
1450 
1451                 offset *= clp->bs;       /* could overflow here! */
1452                 if (lseek(clp->infd, offset, SEEK_SET) < 0) {
1453                     snprintf(ebuff, EBUFF_SZ, "%s: couldn't skip to required "
1454                                               "position on %s", my_name, inf);
1455                     perror(ebuff);
1456                     return 1;
1457                 }
1458             }
1459         } else { /* looks like sg device so close then re-open it RW */
1460             close(clp->infd);
1461             open_fl = clp->iflag.excl ? O_EXCL : 0;
1462             open_fl |= (O_RDWR | O_NONBLOCK);
1463             if ((clp->infd = open(inf, open_fl)) < 0) {
1464                 pr2serr("If %s is a sg device, need read+write "
1465                         "permissions, even to read it!\n", inf);
1466                 return 1;
1467             }
1468             clp->in_is_sg = true;
1469             if (sz_reserve(clp, true /* is_in */))
1470                 return 1;
1471             if (sgs_old_sg_driver && (clp->iflag.v4 || clp->oflag.v4)) {
1472                 pr2serr("Unable to implement v4 flag because sg driver too "
1473                         "old\n");
1474                 return 1;
1475             }
1476         }
1477     }
1478     if (outf[0] && ('-' != outf[0])) {
1479         open_fl = clp->oflag.excl ? O_EXCL : 0;
1480         open_fl |= (O_RDWR | O_NONBLOCK);
1481         if ((clp->outfd = open(outf, open_fl)) >= 0) {
1482             if (ioctl(clp->outfd, SG_GET_TIMEOUT, 0) < 0) {
1483                 /* not a scsi generic device so now try and open RDONLY */
1484                 close(clp->outfd);
1485                 clp->outfd = -1;
1486             }
1487             else {
1488                 clp->out_is_sg = true;
1489                 if (sz_reserve(clp, false /* hence ! is_in */))
1490                     return 1;
1491                 if (sgs_old_sg_driver && (clp->iflag.v4 || clp->oflag.v4)) {
1492                     pr2serr("Unable to implement v4 flag because sg driver "
1493                             "too old\n");
1494                     return 1;
1495                 }
1496             }
1497         }
1498         if (! clp->out_is_sg) {
1499             if (clp->outfd >= 0) {
1500                 close(clp->outfd);
1501                 clp->outfd = -1;
1502             }
1503             open_fl = clp->oflag.excl ? O_EXCL : 0;
1504             open_fl |= (O_WRONLY | O_CREAT);
1505             if ((clp->outfd = open(outf, open_fl, 0666)) < 0) {
1506                 snprintf(ebuff, EBUFF_SZ,
1507                          "%s: could not open %s for writing", my_name, outf);
1508                 perror(ebuff);
1509                 return 1;
1510             }
1511             else if (seek > 0) {
1512                 off_t offset = seek;
1513 
1514                 offset *= clp->bs;       /* could overflow here! */
1515                 if (lseek(clp->outfd, offset, SEEK_SET) < 0) {
1516                     snprintf(ebuff, EBUFF_SZ, "%s: couldn't seek to required "
1517                              "position on %s", my_name, outf);
1518                     perror(ebuff);
1519                     return 1;
1520                 }
1521             }
1522         }
1523     } else if ('\0' == outf[0]) {
1524         if (STDIN_FILENO == clp->infd) {
1525             pr2serr("Can't have both 'if' as stdin _and_ 'of' as "
1526                     "/dev/null\n");
1527             return 1;
1528         }
1529         clp->outfd = open("/dev/null", O_RDWR);
1530         if (clp->outfd < 0) {
1531             perror("sgs_dd: could not open /dev/null");
1532             return 1;
1533         }
1534         clp->out_is_sg = false;
1535         /* ignore any seek */
1536     } else {    /* must be '-' for stdout */
1537         if (STDIN_FILENO == clp->infd) {
1538             pr2serr("Can't have both 'if' as stdin _and_ 'of' as stdout\n");
1539             return 1;
1540         }
1541     }
1542     if ((clp->in_is_sg || clp->out_is_sg) && !clp->iflag.given_v3v4 &&
1543         !clp->oflag.given_v3v4 && (clp->debug > 0)) {
1544         clp->iflag.v3 = true;
1545         pr2serr("using sg driver version 3 interface on %s\n",
1546                 clp->in_is_sg ? inf : outf);
1547     }
1548 
1549     if (0 == count)
1550         return 0;
1551     else if (count < 0) {
1552         if (clp->in_is_sg) {
1553             res = read_capacity(clp->infd, &in_num_sect, &in_sect_sz);
1554             if (2 == res) {
1555                 pr2serr("Unit attention, media changed(in), try again\n");
1556                 res = read_capacity(clp->infd, &in_num_sect, &in_sect_sz);
1557             }
1558             if (0 != res) {
1559                 pr2serr("Unable to read capacity on %s\n", inf);
1560                 in_num_sect = -1;
1561             } else {
1562                 if (clp->debug > 4)
1563                     pr2serr("ifile: number of sectors=%d, sector size=%d\n",
1564                             in_num_sect, in_sect_sz);
1565                 if (in_num_sect > skip)
1566                     in_num_sect -= skip;
1567             }
1568         }
1569         if (clp->out_is_sg) {
1570             res = read_capacity(clp->outfd, &out_num_sect, &out_sect_sz);
1571             if (2 == res) {
1572                 pr2serr("Unit attention, media changed(out), try again\n");
1573                 res = read_capacity(clp->outfd, &out_num_sect, &out_sect_sz);
1574             }
1575             if (0 != res) {
1576                 pr2serr("Unable to read capacity on %s\n", outf);
1577                 out_num_sect = -1;
1578             } else {
1579                 if (clp->debug > 4)
1580                     pr2serr("ofile: number of sectors=%d, sector size=%d\n",
1581                             out_num_sect, out_sect_sz);
1582                 if (out_num_sect > seek)
1583                     out_num_sect -= seek;
1584             }
1585         }
1586         if (clp->debug > 3)
1587             pr2serr("Start of loop, count=%d, in_num_sect=%d, "
1588                     "out_num_sect=%d\n", count, in_num_sect, out_num_sect);
1589         if (in_num_sect > 0) {
1590             if (out_num_sect > 0)
1591                 count = (in_num_sect > out_num_sect) ? out_num_sect :
1592                                                        in_num_sect;
1593             else
1594                 count = in_num_sect;
1595         }
1596         else
1597             count = out_num_sect;
1598     }
1599     if (clp->debug > 4)
1600         pr2serr("Start of loop, count=%d, bpt=%d\n", count, clp->bpt);
1601 
1602     clp->in_count = count;
1603     clp->in_done_count = count;
1604     clp->in_blk = skip;
1605     clp->out_count = count;
1606     clp->out_done_count = count;
1607     clp->out_blk = seek;
1608     res = init_elems(clp);
1609     if (res < 0)
1610         pr2serr("init_elems() failed, res=%d\n", res);
1611     res = 0;
1612 
1613 /* vvvvvvvvvvvvvvvvv  Main Loop  vvvvvvvvvvvvvvvvvvvvvvvv */
1614     while (clp->out_done_count > 0) {
1615         crw = can_read_write(clp);
1616         if (crw < 0)
1617             break;
1618         if (SGQ_CAN_READ & crw) {
1619             res = start_read(clp);
1620             if (res <= 0) {
1621                 pr2serr("start_read: res=%d\n", res);
1622                 break;
1623             }
1624             res = 0;
1625         }
1626         if (SGQ_CAN_WRITE & crw) {
1627             res = start_write(clp);
1628             if (res <= 0) {
1629                 pr2serr("start_write: res=%d\n", res);
1630                 break;
1631             }
1632             res = 0;
1633         }
1634     }
1635 
1636     if ((STDIN_FILENO != clp->infd) && (clp->infd >= 0))
1637         close(clp->infd);
1638     if ((STDOUT_FILENO != clp->outfd) && (clp->outfd >= 0))
1639         close(clp->outfd);
1640     if (0 != clp->out_count) {
1641         pr2serr("Some error occurred, remaining blocks=%d\n", clp->out_count);
1642         res = 1;
1643     }
1644     pr2serr("%d+%d records in\n", count - clp->in_done_count,
1645             clp->in_partial);
1646     pr2serr("%d+%d records out\n", count - clp->out_done_count,
1647             clp->out_partial);
1648     if (clp->dio_incomplete)
1649         pr2serr(">> Direct IO requested but incomplete %d times\n",
1650                 clp->dio_incomplete);
1651     if (clp->sum_of_resids)
1652         pr2serr(">> Non-zero sum of residual counts=%d\n",
1653                 clp->sum_of_resids);
1654     if (clp->debug > 0) {
1655         if (! clp->no_sig)
1656             pr2serr("SIGIO/SIGPOLL signals received: %d, RT sigs: %d\n",
1657                     clp->sigs_io_received, clp->sigs_rt_received);
1658         if (polled_present)
1659             pr2serr("POLLED (blk_poll) used to complete %d commands\n",
1660                     clp->blk_poll_count);
1661     }
1662     if (clp->pollerr_count > 0)
1663         pr2serr(">> poll() system call gave POLLERR %d times\n",
1664                 clp->pollerr_count);
1665     remove_elems(clp);
1666     return res < 0 ? 99 : res;
1667 }
1668