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