diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2019-09-30 03:59:25 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2019-09-30 03:59:25 +0000 |
commit | ee26c8116cfc960af016b8ad81bb3f2fc9ab7d09 (patch) | |
tree | 9dfeda5b47ed87762f9e56962253b4cd1600bf47 /testing | |
parent | bcdf18e4dd92f592617c35edbc9ffbb2817bd36c (diff) | |
download | sg3_utils-ee26c8116cfc960af016b8ad81bb3f2fc9ab7d09.tar.gz |
testing/sgh_dd.cpp: major work for special variable blocking mrq
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@833 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing')
-rw-r--r-- | testing/sgh_dd.cpp | 784 |
1 files changed, 503 insertions, 281 deletions
diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp index 5a44f426..f13efa09 100644 --- a/testing/sgh_dd.cpp +++ b/testing/sgh_dd.cpp @@ -108,7 +108,7 @@ using namespace std; -static const char * version_str = "1.44 20190906"; +static const char * version_str = "1.49 20190929"; #ifdef __GNUC__ #ifndef __clang__ @@ -203,6 +203,8 @@ typedef struct global_collection atomic<bool> in_stop; /* | */ pthread_mutex_t in_mutex; /* -/ */ int nmrqs; /* Number of multi-reqs for sg v4 */ + int inmrqs; /* if both imrq= and omrq= must be == */ + int onmrqs; /* ... unless one is zero */ int outfd; int64_t seek; int out_type; @@ -229,12 +231,16 @@ typedef struct global_collection int debug; /* both -v and deb=VERB bump this field */ int dry_run; bool aen_given; + bool cdbsz_given; + bool is_mrq_i; + bool is_mrq_o; bool m_aen_given; bool ofile_given; bool ofile2_given; bool unit_nanosec; /* default duration unit is millisecond */ bool mrq_cmds; /* mrq=<NRQS>,C given */ - bool mrq_async; /* any mrq_immed or no_waitq flags given */ + bool mrq_async; /* either mrq_immed or no_waitq flags given */ + bool unbalanced_mrq; /* so _not_ sg->sg request sharing sync mrq */ const char * infp; const char * outfp; const char * out2fp; @@ -250,6 +256,7 @@ typedef struct mrq_abort_info typedef struct request_element { /* one instance per worker thread */ + Gbl_coll *clp; bool wr; bool has_share; bool both_sg; @@ -258,12 +265,9 @@ typedef struct request_element bool only_out_sg; bool swait; /* interleave READ WRITE async copy segment: READ submit, * WRITE submit, READ receive, WRITE receive */ - bool mrq_cmds; /* mrq=<NRQS>,C given */ - bool mrq_async; /* any mrq_immed or no_waitq flags given */ // bool mrq_abort_thread_active; int id; int infd; - int nmrqs; int outfd; int out2fd; int outregfd; @@ -276,25 +280,18 @@ typedef struct request_element struct sg_io_v4 io_hdr4; uint8_t cmd[MAX_SCSI_CDBSZ]; uint8_t sb[SENSE_BUFF_LEN]; - int bs; int dio_incomplete_count; int resid; - int cdbsz_in; - int cdbsz_out; - int aen; - int m_aen; int rd_p_id; int rep_count; int rq_id; int mmap_len; int mrq_id; + int mrq_index; uint32_t in_mrq_q_blks; uint32_t out_mrq_q_blks; pthread_t mrq_abort_thread_id; Mrq_abort_info mai; - struct flags_t in_flags; - struct flags_t out_flags; - int debug; } Rq_elem; typedef struct thread_info @@ -344,10 +341,9 @@ static pthread_t sig_listen_thread_id; static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio"; static void sg_in_rd_cmd(Gbl_coll * clp, Rq_elem * rep, mrq_arr_t & def_arr); -static void sg_out_wr_cmd(Gbl_coll * clp, Rq_elem * rep, mrq_arr_t & def_arr, - bool is_wr2); -static bool normal_in_rd(Gbl_coll * clp, Rq_elem * rep, int blocks); -static void normal_out_wr(Gbl_coll * clp, Rq_elem * rep, int blocks); +static void sg_out_wr_cmd(Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2); +static bool normal_in_rd(Rq_elem * rep, int blocks); +static void normal_out_wr(Rq_elem * rep, int blocks); static int sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, bool is_wr2); static int sg_finish_io(bool wr, Rq_elem * rep, int pack_id, bool is_wr2); @@ -369,7 +365,7 @@ static bool sg_version_lt_4 = false; static bool sg_version_ge_40030 = false; static bool shutting_down = false; static bool do_sync = false; -static bool do_time = true; +static int do_time = 1; static Gbl_coll gcoll; static struct timeval start_tm; static int64_t dd_count = -1; @@ -462,24 +458,120 @@ hex2stderr_lk(const uint8_t * b_str, int len, int no_ascii) pthread_mutex_unlock(&strerr_mut); } +/* Flags decoded into abbreviations for those that are set, separated by + * '|' . */ +static char * +sg_flags_str(int flags, int b_len, char * b) +{ + int n = 0; + + if ((b_len < 1) || (! b)) + return b; + b[0] = '\0'; + if (SG_FLAG_DIRECT_IO & flags) { /* 0x1 */ + n += sg_scnpr(b + n, b_len - n, "DIO|"); + if (n >= b_len) + goto fini; + } + if (SG_FLAG_MMAP_IO & flags) { /* 0x4 */ + n += sg_scnpr(b + n, b_len - n, "MMAP|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_YIELD_TAG & flags) { /* 0x8 */ + n += sg_scnpr(b + n, b_len - n, "YTAG|"); + if (n >= b_len) + goto fini; + } + if (SG_FLAG_Q_AT_TAIL & flags) { /* 0x10 */ + n += sg_scnpr(b + n, b_len - n, "QTAI|"); + if (n >= b_len) + goto fini; + } + if (SG_FLAG_Q_AT_HEAD & flags) { /* 0x20 */ + n += sg_scnpr(b + n, b_len - n, "QHEA|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_NO_WAITQ & flags) { /* 0x40 */ + n += sg_scnpr(b + n, b_len - n, "NWTQ|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_COMPLETE_B4 & flags) { /* 0x100 */ + n += sg_scnpr(b + n, b_len - n, "NWTQ|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_SIG_ON_OTHER & flags) { /* 0x200 */ + n += sg_scnpr(b + n, b_len - n, "SIGOTH|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_IMMED & flags) { /* 0x400 */ + n += sg_scnpr(b + n, b_len - n, "IMM|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_STOP_IF & flags) { /* 0x800 */ + n += sg_scnpr(b + n, b_len - n, "STOPIF|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_DEV_SCOPE & flags) { /* 0x1000 */ + n += sg_scnpr(b + n, b_len - n, "DEV_SC|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_SHARE & flags) { /* 0x2000 */ + n += sg_scnpr(b + n, b_len - n, "SHARE|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_DO_ON_OTHER & flags) { /* 0x4000 */ + n += sg_scnpr(b + n, b_len - n, "DO_OTH|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_NO_DXFER & flags) { /* 0x10000 */ + n += sg_scnpr(b + n, b_len - n, "NDXFER|"); + if (n >= b_len) + goto fini; + } + if (SGV4_FLAG_MULTIPLE_REQS & flags) { /* 0x20000 */ + n += sg_scnpr(b + n, b_len - n, "MRQS|"); + if (n >= b_len) + goto fini; + } +fini: + if (n < b_len) { /* trim trailing '\' */ + if ('|' == b[n - 1]) + b[n - 1] = '\0'; + } else if ('|' == b[b_len - 1]) + b[b_len - 1] = '\0'; + return b; +} + static void v4hdr_out_lk(const char * leadin, const sg_io_v4 * h4p, int id) { + char b[80]; + pthread_mutex_lock(&strerr_mut); if (leadin) pr2serr("%s [id=%d]:\n", leadin, id); if (('Q' != h4p->guard) || (0 != h4p->protocol) || (0 != h4p->subprotocol)) pr2serr(" <<<sg_io_v4 _NOT_ properly set>>>\n"); - pr2serr(" pointers: cdb=%s sense=%s din=%s dout=%s\n", + pr2serr(" pointers: cdb=%s sense=%s din=%p dout=%p\n", (h4p->request ? "y" : "NULL"), (h4p->response ? "y" : "NULL"), - (h4p->din_xferp ? "y" : "NULL"), - (h4p->dout_xferp ? "y" : "NULL")); + (void *)h4p->din_xferp, (void *)h4p->dout_xferp); pr2serr(" lengths: cdb=%u sense=%u din=%u dout=%u\n", h4p->request_len, h4p->max_response_len, h4p->din_xfer_len, h4p->dout_xfer_len); pr2serr(" flags=0x%x request_extra{pack_id}=%d\n", h4p->flags, h4p->request_extra); + pr2serr(" flags set: %s\n", sg_flags_str(h4p->flags, sizeof(b), b)); pr2serr(" OUT:\n"); pr2serr(" response_len=%d driver/transport/device_status=" "0x%x/0x%x/0x%x\n", h4p->response_len, h4p->driver_status, @@ -576,7 +668,7 @@ interrupt_handler(int sig) sigact.sa_flags = 0; sigaction(sig, &sigact, NULL); pr2serr("Interrupted by signal,"); - if (do_time) + if (do_time > 0) calc_duration_throughput(0); print_stats(""); kill(getpid (), sig); @@ -587,7 +679,7 @@ siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ pr2serr("Progress report, continuing ...\n"); - if (do_time) + if (do_time > 0) calc_duration_throughput(1); print_stats(" "); } @@ -599,7 +691,7 @@ siginfo2_handler(int sig) if (sig) { ; } /* unused, dummy to suppress warning */ pr2serr("Progress report, continuing ...\n"); - if (do_time) + if (do_time > 0) calc_duration_throughput(1); print_stats(" "); pr2serr("Send broadcast on out_sync_cv condition variable\n"); @@ -699,7 +791,7 @@ usage(int pg_num) "[coe=0|1]\n" " [deb=VERB] [dio=0|1] [elemsz_kb=ESK] " "[fua=0|1|2|3]\n" - " [mrq=NRQS[,C]] [of2=OFILE2] [ofreg=OFREG] " + " [mrq=[IO,]NRQS[,C]] [of2=OFILE2] [ofreg=OFREG] " "[sync=0|1]\n" " [thr=THR] [time=0|1] [verbose=VERB] [--dry-run] " "[--verbose]\n\n" @@ -772,8 +864,8 @@ page2: "after copy\n" " thr is number of threads, must be > 0, default 4, " "max 1024\n" - " time 0->no timing, 1->time plus calculate " - "throughput (def)\n" + " time 0->no timing, 1->calc throughput(def), " + "2->nanosec precision\n" " verbose same as 'deb=VERB': increase verbosity\n" " --dry-run|-d prepare but bypass copy/read\n" " --verbose|-v increase verbosity of utility\n\n" @@ -813,7 +905,7 @@ page3: " same_fds each thread use the same IFILE and OFILE(2) " "file\n" " descriptors (def: each threads has own file " - "desciptors)\n" + "descriptors)\n" " swait slave wait: issue WRITE on OFILE before READ " "is finished;\n" " [oflag only] and IFILE and OFILE must be sg " @@ -1080,6 +1172,28 @@ cleanup_out(void * v_clp) pthread_cond_broadcast(&clp->out_sync_cv); } +static void inline buffp_onto_next(Rq_elem * rep) +{ + Gbl_coll * clp = rep->clp; + + if ((clp->nmrqs > 0) && clp->unbalanced_mrq) { + ++rep->mrq_index; + if (rep->mrq_index >= clp->nmrqs) + rep->mrq_index = 0; /* wrap */ + } +} + +static inline uint8_t * +get_buffp(Rq_elem * rep) +{ + Gbl_coll * clp = rep->clp; + + if ((clp->nmrqs > 0) && clp->unbalanced_mrq && (rep->mrq_index > 0)) + return rep->buffp + (rep->mrq_index * clp->bs * clp->bpt); + else + return rep->buffp; +} + static void * read_write_thread(void * v_tip) { @@ -1087,7 +1201,7 @@ read_write_thread(void * v_tip) Gbl_coll * clp; Rq_elem rel; Rq_elem * rep = &rel; - int sz, blocks, status, vb, err, res, wr_blks; + int n, sz, blocks, status, vb, err, res, wr_blks; int num_sg = 0; int64_t my_index; volatile bool stop_after_write = false; @@ -1103,32 +1217,27 @@ read_write_thread(void * v_tip) sz = clp->bpt * clp->bs; memset(rep, 0, sizeof(Rq_elem)); /* Following clp members are constant during lifetime of thread */ + rep->clp = clp; rep->id = tip->id; if (vb > 2) pr2serr_lk("%d <-- Starting worker thread\n", rep->id); if (! clp->in_flags.mmap) { - rep->buffp = sg_memalign(sz, 0 /* page align */, &rep->alloc_bp, + int n = sz; + + if (clp->unbalanced_mrq) + n *= clp->nmrqs; + rep->buffp = sg_memalign(n, 0 /* page align */, &rep->alloc_bp, false); if (NULL == rep->buffp) err_exit(ENOMEM, "out of memory creating user buffers\n"); } - - rep->bs = clp->bs; rep->infd = clp->infd; rep->outfd = clp->outfd; rep->out2fd = clp->out2fd; rep->outregfd = clp->outregfd; - rep->debug = clp->debug; - rep->cdbsz_in = clp->cdbsz_in; - rep->cdbsz_out = clp->cdbsz_out; - rep->in_flags = clp->in_flags; - rep->out_flags = clp->out_flags; - rep->nmrqs = clp->nmrqs; - rep->mrq_cmds = clp->mrq_cmds; - rep->mrq_async = clp->mrq_async; - rep->aen = clp->aen; - rep->m_aen = clp->m_aen; rep->rep_count = 0; + if (clp->unbalanced_mrq && (clp->nmrqs > 0)) + rep->mrq_index = clp->nmrqs - 1; if (rep->infd == rep->outfd) { if (FT_SG == clp->in_type) @@ -1140,9 +1249,9 @@ read_write_thread(void * v_tip) else if (FT_SG == clp->out_type) rep->only_out_sg = true; - if (rep->in_flags.same_fds || rep->out_flags.same_fds) { + if (clp->in_flags.same_fds || clp->out_flags.same_fds) { /* we are sharing a single pair of fd_s across all threads */ - if (rep->out_flags.swait && (! swait_reported)) { + if (clp->out_flags.swait && (! swait_reported)) { swait_reported = true; pr2serr_lk("oflag=swait ignored because same_fds flag given\n"); } @@ -1151,8 +1260,8 @@ read_write_thread(void * v_tip) if ((FT_SG == clp->in_type) && clp->infp) { fd = sg_in_open(clp, clp->infp, - (rep->in_flags.mmap ? &rep->buffp : NULL), - (rep->in_flags.mmap ? &rep->mmap_len : NULL)); + (clp->in_flags.mmap ? &rep->buffp : NULL), + (clp->in_flags.mmap ? &rep->mmap_len : NULL)); if (fd < 0) goto fini; rep->infd = fd; @@ -1163,8 +1272,8 @@ read_write_thread(void * v_tip) } if ((FT_SG == clp->out_type) && clp->outfp) { fd = sg_out_open(clp, clp->outfp, - (rep->out_flags.mmap ? &rep->buffp : NULL), - (rep->out_flags.mmap ? &rep->mmap_len : NULL)); + (clp->out_flags.mmap ? &rep->buffp : NULL), + (clp->out_flags.mmap ? &rep->mmap_len : NULL)); if (fd < 0) goto fini; rep->outfd = fd; @@ -1175,8 +1284,8 @@ read_write_thread(void * v_tip) } if ((FT_SG == clp->out2_type) && clp->out2fp) { fd = sg_out_open(clp, clp->out2fp, - (rep->out_flags.mmap ? &rep->buffp : NULL), - (rep->out_flags.mmap ? &rep->mmap_len : NULL)); + (clp->out_flags.mmap ? &rep->buffp : NULL), + (clp->out_flags.mmap ? &rep->mmap_len : NULL)); if (fd < 0) goto fini; rep->out2fd = fd; @@ -1184,7 +1293,7 @@ read_write_thread(void * v_tip) if (vb > 2) pr2serr_lk("thread=%d: opened local sg OFILE2\n", rep->id); } - if (rep->out_flags.swait) { + if (clp->out_flags.swait) { if (num_sg < 2) pr2serr_lk("oflag=swait ignored since need both IFILE and " "OFILE to be sg devices\n"); @@ -1207,16 +1316,16 @@ read_write_thread(void * v_tip) if (vb > 4) pr2serr_lk("thread=%d: Skipping share because driver too old\n", rep->id); - } else if (rep->in_flags.noshare || rep->out_flags.noshare) { - if (rep->nmrqs > 0) - sg_share_prepare(rep->outfd, rep->infd, rep->id, rep->debug > 9); + } else if (clp->in_flags.noshare || clp->out_flags.noshare) { + if (clp->nmrqs > 0) + sg_share_prepare(rep->outfd, rep->infd, rep->id, vb > 9); else if (vb > 4) pr2serr_lk("thread=%d: Skipping IFILE share with OFILE due to " "mrq>0\n", rep->id); } else if (sg_version_ge_40030 && (FT_SG == clp->in_type) && (FT_SG == clp->out_type)) rep->has_share = sg_share_prepare(rep->outfd, rep->infd, rep->id, - rep->debug > 9); + vb > 9); if (vb > 9) pr2serr_lk("tid=%d, has_share=%s\n", rep->id, (rep->has_share ? "true" : "false")); @@ -1227,6 +1336,7 @@ read_write_thread(void * v_tip) rep->wr = false; my_index = atomic_fetch_add(&pos_index, (long int)clp->bpt); /* Start of READ half of a segment */ + buffp_onto_next(rep); status = pthread_mutex_lock(&clp->in_mutex); if (0 != status) err_exit(status, "lock in_mutex"); @@ -1234,8 +1344,8 @@ read_write_thread(void * v_tip) if (my_index >= dd_count) { status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); - if ((rep->nmrqs > 0) && (deferred_arr.first.size() > 0)) { - if (rep->debug > 2) + if ((clp->nmrqs > 0) && (deferred_arr.first.size() > 0)) { + if (vb > 2) pr2serr_lk("thread=%d: tail-end my_index>=dd_count, " "to_do=%u\n", rep->id, (uint32_t)deferred_arr.first.size()); @@ -1263,7 +1373,7 @@ read_write_thread(void * v_tip) else /* unlocks in_mutex mid op */ sg_in_rd_cmd(clp, rep, deferred_arr); } else { - stop_after_write = normal_in_rd(clp, rep, blocks); + stop_after_write = normal_in_rd(rep, blocks); status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); } @@ -1306,12 +1416,13 @@ skip_force_out_sequence: pthread_cleanup_push(cleanup_out, (void *)clp); if (rep->outregfd >= 0) { - res = write(rep->outregfd, rep->buffp, rep->bs * rep->num_blks); + res = write(rep->outregfd, get_buffp(rep), + rep->clp->bs * rep->num_blks); err = errno; if (res < 0) pr2serr_lk("%s: tid=%d: write(outregfd) failed: %s\n", __func__, rep->id, strerror(err)); - else if (rep->debug > 9) + else if (vb > 9) pr2serr_lk("%s: tid=%d: write(outregfd), fd=%d, num_blks=%d" "\n", __func__, rep->id, rep->outregfd, rep->num_blks); @@ -1323,7 +1434,7 @@ skip_force_out_sequence: status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); } else /* release out_mtx */ - sg_out_wr_cmd(clp, rep, deferred_arr, false); + sg_out_wr_cmd(rep, deferred_arr, false); } else if (FT_DEV_NULL == clp->out_type) { /* skip actual write operation */ wr_blks = 0; @@ -1332,7 +1443,7 @@ skip_force_out_sequence: if (0 != status) err_exit(status, "unlock out_mutex"); --rep->rep_count; } else { - normal_out_wr(clp, rep, blocks); + normal_out_wr(rep, blocks); status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); } @@ -1345,15 +1456,15 @@ skip_force_out_sequence: status = pthread_mutex_lock(&clp->out2_mutex); if (0 != status) err_exit(status, "lock out2_mutex"); /* releases out2_mutex mid operation */ - sg_out_wr_cmd(clp, rep, deferred_arr, true); + sg_out_wr_cmd(rep, deferred_arr, true); pthread_cleanup_pop(0); } if (0 == rep->num_blks) { - if ((rep->nmrqs > 0) && (deferred_arr.first.size() > 0)) { + if ((clp->nmrqs > 0) && (deferred_arr.first.size() > 0)) { if (wr_blks > 0) rep->out_mrq_q_blks += wr_blks; - if (rep->debug > 2) + if (vb > 2) pr2serr_lk("thread=%d: tail-end, to_do=%u\n", rep->id, (uint32_t)deferred_arr.first.size()); res = sgh_do_deferred_mrq(rep, deferred_arr); @@ -1387,10 +1498,34 @@ fini: } else if (rep->alloc_bp) free(rep->alloc_bp); - if (own_infd && (rep->infd >= 0)) + if (own_infd && (rep->infd >= 0)) { + if (vb && (FT_SG == clp->in_type)) { + if (ioctl(rep->infd, SG_GET_NUM_WAITING, &n) >= 0) { + if (n > 0) + pr2serr_lk("%s: tid=%d: num_waiting=%d prior close(in)\n", + __func__, rep->id, n); + } else { + err = errno; + pr2serr_lk("%s: [%d] ioctl(SG_GET_NUM_WAITING) errno=%d: " + "%s\n", __func__, rep->id, err, strerror(err)); + } + } close(rep->infd); - if (own_outfd && (rep->outfd >= 0)) + } + if (own_outfd && (rep->outfd >= 0)) { + if (vb && (FT_SG == clp->out_type)) { + if (ioctl(rep->outfd, SG_GET_NUM_WAITING, &n) >= 0) { + if (n > 0) + pr2serr_lk("%s: tid=%d: num_waiting=%d prior " + "close(out)\n", __func__, rep->id, n); + } else { + err = errno; + pr2serr_lk("%s: [%d] ioctl(SG_GET_NUM_WAITING) errno=%d: " + "%s\n", __func__, rep->id, err, strerror(err)); + } + } close(rep->outfd); + } if (own_out2fd && (rep->out2fd >= 0)) close(rep->out2fd); pthread_cond_broadcast(&clp->out_sync_cv); @@ -1398,13 +1533,17 @@ fini: } static bool -normal_in_rd(Gbl_coll * clp, Rq_elem * rep, int blocks) +normal_in_rd(Rq_elem * rep, int blocks) { + Gbl_coll * clp = rep->clp; bool stop_after_write = false; - bool same_fds = rep->in_flags.same_fds || rep->out_flags.same_fds; + bool same_fds = clp->in_flags.same_fds || clp->out_flags.same_fds; int res; char strerr_buff[STRERR_BUFF_LEN]; + if (clp->debug > 4) + pr2serr_lk("%s: tid=%d: iblk=%" PRIu64 ", blocks=%d\n", __func__, + rep->id, rep->iblk, blocks); if (! same_fds) { /* each has own file pointer, so we need to move it */ int64_t pos = rep->iblk * clp->bs; @@ -1416,15 +1555,15 @@ normal_in_rd(Gbl_coll * clp, Rq_elem * rep, int blocks) } } /* enters holding in_mutex */ - while (((res = read(clp->infd, rep->buffp, blocks * clp->bs)) < 0) && + while (((res = read(clp->infd, get_buffp(rep), blocks * clp->bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) std::this_thread::yield();/* another thread may be able to progress */ if (res < 0) { if (clp->in_flags.coe) { - memset(rep->buffp, 0, rep->num_blks * rep->bs); + memset(get_buffp(rep), 0, rep->num_blks * clp->bs); pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64 " for %d bytes, %s\n", rep->id, rep->iblk, - rep->num_blks * rep->bs, + rep->num_blks * clp->bs, tsafe_strerror(errno, strerr_buff)); res = rep->num_blks * clp->bs; } @@ -1456,20 +1595,24 @@ normal_in_rd(Gbl_coll * clp, Rq_elem * rep, int blocks) } static void -normal_out_wr(Gbl_coll * clp, Rq_elem * rep, int blocks) +normal_out_wr(Rq_elem * rep, int blocks) { int res; + Gbl_coll * clp = rep->clp; char strerr_buff[STRERR_BUFF_LEN]; /* enters holding out_mutex */ - while (((res = write(clp->outfd, rep->buffp, rep->num_blks * clp->bs)) + if (clp->debug > 4) + pr2serr_lk("%s: tid=%d: oblk=%" PRIu64 ", blocks=%d\n", __func__, + rep->id, rep->oblk, blocks); + while (((res = write(clp->outfd, get_buffp(rep), rep->num_blks * clp->bs)) < 0) && ((EINTR == errno) || (EAGAIN == errno))) std::this_thread::yield();/* another thread may be able to progress */ if (res < 0) { if (clp->out_flags.coe) { pr2serr_lk("tid=%d: >> ignored error for out blk=%" PRId64 " for %d bytes, %s\n", rep->id, rep->oblk, - rep->num_blks * rep->bs, + rep->num_blks * clp->bs, tsafe_strerror(errno, strerr_buff)); res = rep->num_blks * clp->bs; } @@ -1601,10 +1744,10 @@ sg_in_rd_cmd(Gbl_coll * clp, Rq_elem * rep, mrq_arr_t & def_arr) stop_both(clp); return; } else { - memset(rep->buffp, 0, rep->num_blks * rep->bs); + memset(get_buffp(rep), 0, rep->num_blks * clp->bs); pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64 " for %d bytes\n", rep->id, rep->iblk, - rep->num_blks * rep->bs); + rep->num_blks * clp->bs); } #if defined(__GNUC__) #if (__GNUC__ >= 7) @@ -1640,10 +1783,10 @@ sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before) bool not_first = false; int err = 0; int master_fd = rep->infd; /* in (READ) side is master */ + Gbl_coll * clp = rep->clp; struct sg_extended_info sei; - struct sg_extended_info * seip; + struct sg_extended_info * seip = &sei; - seip = &sei; memset(seip, 0, sizeof(*seip)); seip->sei_wr_mask |= SG_SEIM_CHG_SHARE_FD; seip->sei_rd_mask |= SG_SEIM_CHG_SHARE_FD; @@ -1659,7 +1802,7 @@ sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before) (EBUSY == errno)) { err = errno; if (! not_first) { - if (rep->debug > 9) + if (clp->debug > 9) pr2serr_lk("tid=%d: ioctl(EXTENDED(change_shared_fd=%d), " "failed errno=%d %s\n", rep->id, master_fd, err, strerror(err)); @@ -1673,7 +1816,7 @@ sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before) "errno=%d %s\n", rep->id, master_fd, err, strerror(err)); return false; } - if (rep->debug > 15) + if (clp->debug > 15) pr2serr_lk("%s: tid=%d: ioctl(EXTENDED(change_shared_fd)) ok, " "master_fd=%d, to_slave_fd=%d\n", __func__, rep->id, master_fd, to_fd); @@ -1682,9 +1825,10 @@ sg_wr_swap_share(Rq_elem * rep, int to_fd, bool before) /* Enters this function holding out_mutex */ static void -sg_out_wr_cmd(Gbl_coll * clp, Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2) +sg_out_wr_cmd(Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2) { int res, status, pack_id; + Gbl_coll * clp = rep->clp; pthread_mutex_t * mutexp = is_wr2 ? &clp->out2_mutex : &clp->out_mutex; if (rep->has_share && is_wr2) @@ -1725,7 +1869,7 @@ sg_out_wr_cmd(Gbl_coll * clp, Rq_elem * rep, mrq_arr_t & def_arr, bool is_wr2) goto fini; } else pr2serr_lk(">> ignored error for out blk=%" PRId64 " for %d " - "bytes\n", rep->oblk, rep->num_blks * rep->bs); + "bytes\n", rep->oblk, rep->num_blks * clp->bs); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); @@ -1763,6 +1907,7 @@ chk_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p, const struct sg_io_v4 * a_v4p, int nrq, uint32_t * good_inblksp, uint32_t * good_outblksp) { + Gbl_coll * clp = rep->clp; bool ok; int id = rep->id; int resid = ctl_v4p->din_resid; @@ -1770,7 +1915,7 @@ chk_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p, int n_subm = nrq - ctl_v4p->dout_resid; int n_cmpl = ctl_v4p->info; int n_good = 0; - int vb = rep->debug; + int vb = clp->debug; int k, slen; uint32_t good_inblks = 0; uint32_t good_outblks = 0; @@ -1795,9 +1940,12 @@ chk_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p, /* Check if those submitted have finished or not */ for (k = 0; k < n_subm; ++k, ++a_np) { slen = a_np->response_len; - if (! (SG_INFO_MRQ_FINI & a_np->info)) + if (! (SG_INFO_MRQ_FINI & a_np->info)) { pr2serr_lk("[%d] %s, a_n[%d]: missing SG_INFO_MRQ_FINI ? ?\n", id, __func__, k); + v4hdr_out_lk("a_np", a_np, id); + v4hdr_out_lk("cop", ctl_v4p, id); + } ok = true; if (a_np->device_status || a_np->transport_status || a_np->driver_status) { @@ -1826,12 +1974,12 @@ chk_mrq_response(Rq_elem * rep, const struct sg_io_v4 * ctl_v4p, } if (ok) { ++n_good; - if (a_np->dout_xfer_len >= (uint32_t)rep->bs) + if (a_np->dout_xfer_len >= (uint32_t)clp->bs) good_outblks += (a_np->dout_xfer_len - a_np->dout_resid) / - rep->bs; - if (a_np->din_xfer_len >= (uint32_t)rep->bs) + clp->bs; + if (a_np->din_xfer_len >= (uint32_t)clp->bs) good_inblks += (a_np->din_xfer_len - a_np->din_resid) / - rep->bs; + clp->bs; } } if ((n_subm == nrq) || (vb < 3)) @@ -1856,40 +2004,41 @@ fini: return n_good; } +/* do mrq 'submit (waitless) non-blocking' call. These are restricted to + * a single file descriptor (i.e. the 'fd' argument). */ static int sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd, struct sg_io_v4 * ctlop, int nrq) { - bool wless = false; int half = nrq / 2; - int k, res, nwait, half_num, rest, err, num_good; + int k, res, nwait, half_num, rest, err, num_good, b_len; const int64_t wait_us = 10; uint32_t in_fin_blks, out_fin_blks; - const char * sub_str = "SG_IOSUBMIT, MULTIPLE_REQS | "; - const char * rec_str = "SG_IORECEIVE, MULTIPLE_REQS | IMMED"; struct sg_io_v4 * a_v4p; struct sg_io_v4 hold_ctlo; + Gbl_coll * clp = rep->clp; + char b[80]; hold_ctlo = *ctlop; + b_len = sizeof(b); a_v4p = def_arr.first.data(); ctlop->flags = SGV4_FLAG_MULTIPLE_REQS; - if (rep->in_flags.no_waitq || rep->out_flags.no_waitq) { - wless = true; + if (clp->in_flags.no_waitq || clp->out_flags.no_waitq) ctlop->flags |= SGV4_FLAG_NO_WAITQ; /* waitless non-blocking */ - } else + else ctlop->flags |= SGV4_FLAG_IMMED; /* submit non-blocking */ - if (rep->debug > 4) { + if (clp->debug > 4) { pr2serr_lk("%s: Controlling object _before_ ioctl(SG_IOSUBMIT):\n", __func__); - if (rep->debug > 5) + if (clp->debug > 5) hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1); v4hdr_out_lk("Controlling object before", ctlop, rep->id); } res = ioctl(fd, SG_IOSUBMIT, ctlop); if (res < 0) { err = errno; - pr2serr_lk("%s: ioctl(%s%s)-->%d, errno=%d: %s\n", __func__, - sub_str, (wless ? "NO_WAITQ" : "IMMED"), res, err, + pr2serr_lk("%s: ioctl(SG_IOSUBMIT, %s)-->%d, errno=%d: %s\n", __func__, + sg_flags_str(ctlop->flags, b_len, b), res, err, strerror(err)); return -1; } @@ -1911,20 +2060,21 @@ sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd, if (res < 0) { err = errno; if (ENODATA != err) { - pr2serr_lk("%s: ioctl(%s),1-->%d, errno=%d: %s\n", __func__, - rec_str, res, err, strerror(err)); + pr2serr_lk("%s: ioctl(SG_IORECEIVE, %s),1-->%d, errno=%d: %s\n", + __func__, sg_flags_str(ctlop->flags, b_len, b), res, + err, strerror(err)); return -1; } half_num = 0; } else half_num = ctlop->info; - if (rep->debug > 4) { + if (clp->debug > 4) { pr2serr_lk("%s: Controlling object output by ioctl(SG_IORECEIVE),1: " "num_received=%d\n", __func__, half_num); - if (rep->debug > 5) + if (clp->debug > 5) hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1); v4hdr_out_lk("Controlling object after", ctlop, rep->id); - if (rep->debug > 5) { + if (clp->debug > 5) { for (k = 0; k < half_num; ++k) { pr2serr_lk("AFTER: def_arr[%d]:\n", k); v4hdr_out_lk("normal v4 object", (a_v4p + k), rep->id); @@ -1937,7 +2087,7 @@ sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd, out_fin_blks = 0; num_good = chk_mrq_response(rep, ctlop, a_v4p, half_num, &in_fin_blks, &out_fin_blks); - if (rep->debug > 2) + if (clp->debug > 2) pr2serr_lk("%s: >>>1 num_good=%d, in_q/fin blks=%u/%u; out_q/fin " "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks, in_fin_blks, rep->out_mrq_q_blks, out_fin_blks); @@ -1981,20 +2131,21 @@ sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd, if (res < 0) { err = errno; if (ENODATA != err) { - pr2serr_lk("%s: ioctl(%s),2-->%d, errno=%d: %s\n", __func__, - rec_str, res, err, strerror(err)); + pr2serr_lk("%s: ioctl(SG_IORECEIVE, %s),2-->%d, errno=%d: %s\n", + __func__, sg_flags_str(ctlop->flags, b_len, b), res, + err, strerror(err)); return -1; } half_num = 0; } else half_num = ctlop->info; - if (rep->debug > 4) { + if (clp->debug > 4) { pr2serr_lk("%s: Controlling object output by ioctl(SG_IORECEIVE),2: " "num_received=%d\n", __func__, half_num); - if (rep->debug > 5) + if (clp->debug > 5) hex2stderr_lk((const uint8_t *)ctlop, sizeof(*ctlop), 1); v4hdr_out_lk("Controlling object after", ctlop, rep->id); - if (rep->debug > 5) { + if (clp->debug > 5) { for (k = 0; k < half_num; ++k) { pr2serr_lk("AFTER: def_arr[%d]:\n", k); v4hdr_out_lk("normal v4 object", (a_v4p + k), rep->id); @@ -2007,7 +2158,7 @@ sgh_do_async_mrq(Rq_elem * rep, mrq_arr_t & def_arr, int fd, out_fin_blks = 0; num_good = chk_mrq_response(rep, ctlop, a_v4p, half_num, &in_fin_blks, &out_fin_blks); - if (rep->debug > 2) + if (clp->debug > 2) pr2serr_lk("%s: >>>2 num_good=%d, in_q/fin blks=%u/%u; out_q/fin " "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks, in_fin_blks, rep->out_mrq_q_blks, out_fin_blks); @@ -2070,14 +2221,18 @@ static int sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) { bool launch_mrq_abort = false; - int nrq, k, res, fd, mrq_pack_id, status, id, num_good; + int nrq, k, res, fd, mrq_pack_id, status, id, num_good, b_len; uint32_t in_fin_blks, out_fin_blks; const int max_cdb_sz = 16; struct sg_io_v4 * a_v4p; struct sg_io_v4 ctl_v4; uint8_t * cmd_ap = NULL; + Gbl_coll * clp = rep->clp; + const char * iosub_str = clp->unbalanced_mrq ? "SUBMIT" : ""; + char b[80]; id = rep->id; + b_len = sizeof(b); memset(&ctl_v4, 0, sizeof(ctl_v4)); ctl_v4.guard = 'Q'; a_v4p = def_arr.first.data(); @@ -2086,7 +2241,7 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) pr2serr_lk("[%d] %s: strange nrq=0, nothing to do\n", id, __func__); return 0; } - if (rep->mrq_cmds) { + if (clp->mrq_cmds) { cmd_ap = (uint8_t *)calloc(nrq, max_cdb_sz); if (NULL == cmd_ap) { pr2serr_lk("[%d] %s: no memory for calloc(%d * 16)\n", id, @@ -2098,14 +2253,21 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) struct sg_io_v4 * h4p = a_v4p + k; uint8_t *cmdp = &def_arr.second[k].front(); - if (rep->mrq_cmds) { + if (clp->mrq_cmds) { memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len); h4p->request = 0; } else h4p->request = (uint64_t)cmdp; - if (rep->debug > 5) { - pr2serr_lk("[%d] def_arr[%d]:\n", id, k); - hex2stderr_lk((const uint8_t *)(a_v4p + k), sizeof(*a_v4p), 1); + if (clp->debug > 5) { + pr2serr_lk("%s%s[%d] def_arr[%d]", ((0 == k) ? __func__ : ""), + ((0 == k) ? ": " : ""), id, k); + if (h4p->din_xferp) + pr2serr_lk(" [din=0x%p]:\n", (void *)h4p->din_xferp); + else if (h4p->dout_xferp) + pr2serr_lk(" [dout=0x%p]:\n", (void *)h4p->dout_xferp); + else + pr2serr_lk(":\n"); + hex2stderr_lk((const uint8_t *)h4p, sizeof(*h4p), 1); } } if (rep->both_sg || rep->same_sg) @@ -2120,29 +2282,29 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) goto fini; } res = 0; - if (rep->mrq_cmds) { + if (clp->mrq_cmds) { ctl_v4.request_len = nrq * max_cdb_sz; ctl_v4.request = (uint64_t)cmd_ap; } - if (! rep->mrq_async) + ctl_v4.flags = SGV4_FLAG_MULTIPLE_REQS; + if (! clp->mrq_async) ctl_v4.flags |= SGV4_FLAG_STOP_IF; - ctl_v4.flags = SGV4_FLAG_MULTIPLE_REQS | SGV4_FLAG_STOP_IF; ctl_v4.dout_xferp = (uint64_t)a_v4p; /* request array */ ctl_v4.dout_xfer_len = nrq * sizeof(*a_v4p); ctl_v4.din_xferp = (uint64_t)a_v4p; /* response array */ ctl_v4.din_xfer_len = nrq * sizeof(*a_v4p); mrq_pack_id = atomic_fetch_add(&mono_mrq_id, 1); - if ((rep->m_aen > 0) && (MONO_MRQ_ID_INIT != mrq_pack_id) && - (0 == ((mrq_pack_id - MONO_MRQ_ID_INIT) % rep->m_aen))) { + if ((clp->m_aen > 0) && (MONO_MRQ_ID_INIT != mrq_pack_id) && + (0 == ((mrq_pack_id - MONO_MRQ_ID_INIT) % clp->m_aen))) { launch_mrq_abort = true; - if (rep->debug > 2) + if (clp->debug > 2) pr2serr_lk("[%d] %s: Decide to launch MRQ abort thread, " "mrq_id=%d\n", id, __func__, mrq_pack_id); memset(&rep->mai, 0, sizeof(rep->mai)); rep->mai.from_tid = id; rep->mai.mrq_id = mrq_pack_id; rep->mai.fd = fd; - rep->mai.debug = rep->debug; + rep->mai.debug = clp->debug; status = pthread_create(&rep->mrq_abort_thread_id, NULL, mrq_abort_thread, (void *)&rep->mai); @@ -2150,17 +2312,23 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) } ctl_v4.request_extra = launch_mrq_abort ? mrq_pack_id : 0; rep->mrq_id = mrq_pack_id; - if (rep->debug > 4) { - pr2serr_lk("%s: Controlling object _before_ ioctl(SG_IO):\n", - __func__); - if (rep->debug > 5) + if (clp->debug > 4) { + if (rep->both_sg && clp->mrq_async) + iosub_str = "SUBMIT(variable)"; + pr2serr_lk("%s: Controlling object _before_ ioctl(SG_IO%s):\n", + __func__, iosub_str); + if (clp->debug > 5) hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1); v4hdr_out_lk("Controlling object before", &ctl_v4, id); } - if (rep->mrq_async) { + if (clp->mrq_async && (! rep->both_sg)) { + /* do 'submit non-blocking' or 'submit waitless non_blocking' + * multiple request */ mrq_arr_t fd_def_arr; mrq_arr_t o_fd_def_arr; + /* need to deconstruct def_arr[] into two separate lists, one for + * the source, the other for the destination. */ int o_num_fd = split_def_arr(def_arr, fd_def_arr, o_fd_def_arr); int num_fd = fd_def_arr.first.size(); if (num_fd > 0) { @@ -2171,12 +2339,12 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) struct sg_io_v4 * h4p = aa_v4p + k; uint8_t *cmdp = &fd_def_arr.second[k].front(); - if (rep->mrq_cmds) { + if (clp->mrq_cmds) { memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len); h4p->request = 0; } else h4p->request = (uint64_t)cmdp; - if (rep->debug > 5) { + if (clp->debug > 5) { pr2serr_lk("[%d] df_def_arr[%d]:\n", id, k); hex2stderr_lk((const uint8_t *)(aa_v4p + k), sizeof(*aa_v4p), 1); @@ -2188,6 +2356,7 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) fd_ctl.din_xferp = (uint64_t)aa_v4p; /* response array */ fd_ctl.din_xfer_len = num_fd * sizeof(*aa_v4p); fd_ctl.request_extra = launch_mrq_abort ? mrq_pack_id : 0; + /* this is the source side mrq command */ res = sgh_do_async_mrq(rep, fd_def_arr, fd, &fd_ctl, num_fd); rep->in_mrq_q_blks = 0; if (res) @@ -2201,12 +2370,12 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) struct sg_io_v4 * h4p = aa_v4p + k; uint8_t *cmdp = &o_fd_def_arr.second[k].front(); - if (rep->mrq_cmds) { + if (clp->mrq_cmds) { memcpy(cmd_ap + (k * max_cdb_sz), cmdp, h4p->request_len); h4p->request = 0; } else h4p->request = (uint64_t)cmdp; - if (rep->debug > 5) { + if (clp->debug > 5) { pr2serr_lk("[%d] o_fd_def_arr[%d]:\n", id, k); hex2stderr_lk((const uint8_t *)(aa_v4p + k), sizeof(*aa_v4p), 1); @@ -2218,6 +2387,7 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) o_fd_ctl.din_xferp = (uint64_t)aa_v4p; /* response array */ o_fd_ctl.din_xfer_len = o_num_fd * sizeof(*aa_v4p); o_fd_ctl.request_extra = launch_mrq_abort ? mrq_pack_id : 0; + /* this is the destination side mrq command */ res = sgh_do_async_mrq(rep, o_fd_def_arr, rep->outfd, &o_fd_ctl, o_num_fd); rep->out_mrq_q_blks = 0; @@ -2225,20 +2395,29 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) goto fini; } - res = ioctl(fd, SG_IO, &ctl_v4); // MULTIPLE_REQS | STOP_IF + if (clp->unbalanced_mrq) + res = ioctl(fd, SG_IOSUBMIT, &ctl_v4); + else { + if (clp->mrq_async) { + iosub_str = "SUBMIT(variable)"; + res = ioctl(fd, SG_IOSUBMIT, &ctl_v4); + } else + res = ioctl(fd, SG_IO, &ctl_v4); + } if (res < 0) { - pr2serr_lk("%s: ioctl(SG_IO, MULTIPLE_REQS)-->%d, errno=%d: %s\n", - __func__, res, errno, strerror(errno)); + pr2serr_lk("%s: ioctl(SG_IO%s, %s)-->%d, errno=%d: %s\n", + __func__, iosub_str, sg_flags_str(ctl_v4.flags, b_len, b), + res, errno, strerror(errno)); res = -1; goto fini; } - if (rep->debug > 4) { - pr2serr_lk("%s: Controlling object output by ioctl(SG_IO):\n", - __func__); - if (rep->debug > 5) + if (clp->debug > 4) { + pr2serr_lk("%s: Controlling object output by ioctl(SG_IO%s):\n", + __func__, iosub_str); + if (clp->debug > 5) hex2stderr_lk((const uint8_t *)&ctl_v4, sizeof(ctl_v4), 1); v4hdr_out_lk("Controlling object after", &ctl_v4, id); - if (rep->debug > 5) { + if (clp->debug > 5) { for (k = 0; k < nrq; ++k) { pr2serr_lk("AFTER: def_arr[%d]:\n", k); v4hdr_out_lk("normal v4 object", (a_v4p + k), id); @@ -2251,7 +2430,7 @@ sgh_do_deferred_mrq(Rq_elem * rep, mrq_arr_t & def_arr) out_fin_blks = 0; num_good = chk_mrq_response(rep, &ctl_v4, a_v4p, nrq, &in_fin_blks, &out_fin_blks); - if (rep->debug > 2) + if (clp->debug > 2) pr2serr_lk("%s: >>> num_good=%d, in_q/fin blks=%u/%u; out_q/fin " "blks=%u/%u\n", __func__, num_good, rep->in_mrq_q_blks, in_fin_blks, rep->out_mrq_q_blks, out_fin_blks); @@ -2277,7 +2456,7 @@ fini: if (cmd_ap) free(cmd_ap); if (launch_mrq_abort) { - if (rep->debug > 1) + if (clp->debug > 1) pr2serr_lk("[%d] %s: About to join MRQ abort thread, " "mrq_id=%d\n", id, __func__, mrq_pack_id); @@ -2293,26 +2472,27 @@ static int sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, bool is_wr2) { + Gbl_coll * clp = rep->clp; bool wr = rep->wr; - bool fua = wr ? rep->out_flags.fua : rep->in_flags.fua; - bool dpo = wr ? rep->out_flags.dpo : rep->in_flags.dpo; - bool dio = wr ? rep->out_flags.dio : rep->in_flags.dio; - bool mmap = wr ? rep->out_flags.mmap : rep->in_flags.mmap; - bool no_waitq = wr ? rep->out_flags.no_waitq : rep->in_flags.no_waitq; - bool noxfer = wr ? rep->out_flags.noxfer : rep->in_flags.noxfer; - bool v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4; - bool qtail = wr ? rep->out_flags.qtail : rep->in_flags.qtail; - int cdbsz = wr ? rep->cdbsz_out : rep->cdbsz_in; + bool fua = wr ? clp->out_flags.fua : clp->in_flags.fua; + bool dpo = wr ? clp->out_flags.dpo : clp->in_flags.dpo; + bool dio = wr ? clp->out_flags.dio : clp->in_flags.dio; + bool mmap = wr ? clp->out_flags.mmap : clp->in_flags.mmap; + bool no_waitq = wr ? clp->out_flags.no_waitq : clp->in_flags.no_waitq; + bool noxfer = wr ? clp->out_flags.noxfer : clp->in_flags.noxfer; + bool v4 = wr ? clp->out_flags.v4 : clp->in_flags.v4; + bool qtail = wr ? clp->out_flags.qtail : clp->in_flags.qtail; + int cdbsz = wr ? clp->cdbsz_out : clp->cdbsz_in; int flags = 0; - int res, err, fd; + int res, err, fd, b_len; int64_t blk = wr ? rep->oblk : rep->iblk; struct sg_io_hdr * hp = &rep->io_hdr; struct sg_io_v4 * h4p = &rep->io_hdr4; const char * cp = ""; - const char * c2p = ""; - const char * c3p = ""; const char * crwp; + char b[80]; + b_len = sizeof(b); if (wr) { fd = is_wr2 ? rep->out2fd : rep->outfd; crwp = is_wr2 ? "writing2" : "writing"; @@ -2326,10 +2506,8 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, my_name, blk, rep->num_blks); return -1; } - if (mmap && (rep->outregfd >= 0)) { + if (mmap && (rep->outregfd >= 0)) flags |= SG_FLAG_MMAP_IO; - c3p = " mmap"; - } if (noxfer) flags |= SG_FLAG_NO_DXFER; if (dio) @@ -2342,8 +2520,6 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, flags |= SGV4_FLAG_NO_DXFER; else if (rep->outregfd < 0) flags |= SGV4_FLAG_NO_DXFER; - if (flags & SGV4_FLAG_NO_DXFER) - c2p = " and FLAG_NO_DXFER"; cp = (wr ? " slave active" : " master active"); } else @@ -2358,10 +2534,10 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, } else pack_id = atomic_fetch_add(&mono_pack_id, 1); /* fetch before */ rep->rq_id = pack_id; - if (rep->debug > 3) { - pr2serr_lk("%s tid,rq_id=%d,%d: SCSI %s%s%s%s, blk=%" PRId64 + if (clp->debug > 3) { + pr2serr_lk("%s tid,rq_id=%d,%d: SCSI %s%s %s, blk=%" PRId64 " num_blks=%d\n", __func__, rep->id, pack_id, crwp, cp, - c2p, c3p, blk, rep->num_blks); + sg_flags_str(flags, b_len, b), blk, rep->num_blks); lk_print_command(rep->cmd); } if (v4) @@ -2372,8 +2548,8 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, hp->cmd_len = cdbsz; hp->cmdp = rep->cmd; hp->dxfer_direction = wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; - hp->dxfer_len = rep->bs * rep->num_blks; - hp->dxferp = rep->buffp; + hp->dxfer_len = clp->bs * rep->num_blks; + hp->dxferp = get_buffp(rep); hp->mx_sb_len = sizeof(rep->sb); hp->sbp = rep->sb; hp->timeout = DEF_TIMEOUT; @@ -2387,13 +2563,13 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, ++num_start_eagain; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) - sg_take_snap(fd, rep->id, (rep->debug > 2)); + sg_take_snap(fd, rep->id, (clp->debug > 2)); #endif } else if (EBUSY == errno) { ++num_ebusy; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) - sg_take_snap(fd, rep->id, (rep->debug > 2)); + sg_take_snap(fd, rep->id, (clp->debug > 2)); #endif } std::this_thread::yield();/* another thread may be able to progress */ @@ -2402,8 +2578,9 @@ sg_start_io(Rq_elem * rep, mrq_arr_t & def_arr, int & pack_id, if (res < 0) { if (ENOMEM == err) return 1; - pr2serr_lk("%s tid=%d: %s%s%s write(2) failed: %s\n", __func__, - rep->id, cp, c2p, c3p, strerror(err)); + pr2serr_lk("%s tid=%d: %s %s write(2) failed: %s\n", __func__, + rep->id, cp, sg_flags_str(hp->flags, b_len, b), + strerror(err)); return -1; } return 0; @@ -2413,19 +2590,21 @@ do_v4: h4p->request_len = cdbsz; h4p->request = (uint64_t)rep->cmd; if (wr) { - h4p->dout_xfer_len = rep->bs * rep->num_blks; - h4p->dout_xferp = (uint64_t)rep->buffp; + h4p->dout_xfer_len = clp->bs * rep->num_blks; + h4p->dout_xferp = (uint64_t)get_buffp(rep); } else if (rep->num_blks > 0) { - h4p->din_xfer_len = rep->bs * rep->num_blks; - h4p->din_xferp = (uint64_t)rep->buffp; + h4p->din_xfer_len = clp->bs * rep->num_blks; + h4p->din_xferp = (uint64_t)get_buffp(rep); } h4p->max_response_len = sizeof(rep->sb); h4p->response = (uint64_t)rep->sb; h4p->timeout = DEF_TIMEOUT; h4p->usr_ptr = (uint64_t)rep; h4p->request_extra = pack_id; /* this is the pack_id */ - h4p->flags = flags | (no_waitq ? SGV4_FLAG_NO_WAITQ : SGV4_FLAG_IMMED); - if (rep->nmrqs > 0) { + h4p->flags = flags; + if (no_waitq) + h4p->flags |= SGV4_FLAG_NO_WAITQ; + if (clp->nmrqs > 0) { big_cdb cdb_arr; uint8_t * cmdp = &(cdb_arr[0]); @@ -2439,7 +2618,7 @@ do_v4: def_arr.first.push_back(*h4p); def_arr.second.push_back(cdb_arr); res = 0; - if ((int)def_arr.first.size() >= rep->nmrqs) + if ((int)def_arr.first.size() >= clp->nmrqs) res = sgh_do_deferred_mrq(rep, def_arr); return res; } @@ -2449,13 +2628,13 @@ do_v4: ++num_start_eagain; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) - sg_take_snap(fd, rep->id, (rep->debug > 2)); + sg_take_snap(fd, rep->id, (clp->debug > 2)); #endif } else if (EBUSY == errno) { ++num_ebusy; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) - sg_take_snap(fd, rep->id, (rep->debug > 2)); + sg_take_snap(fd, rep->id, (clp->debug > 2)); #endif } std::this_thread::yield();/* another thread may be able to progress */ @@ -2464,12 +2643,14 @@ do_v4: if (res < 0) { if (ENOMEM == err) return 1; - pr2serr_lk("%s tid=%d: %s%s%s ioctl(2) failed: %s\n", __func__, - rep->id, cp, c2p, c3p, strerror(err)); + pr2serr_lk("%s tid=%d: %s %s ioctl(2) failed: %s\n", __func__, + rep->id, cp, sg_flags_str(h4p->flags, b_len, b), + strerror(err)); + // v4hdr_out_lk("leadin", h4p, rep->id); return -1; } - if ((rep->aen > 0) && (rep->rep_count > 0)) { - if (0 == (rep->rq_id % rep->aen)) { + if ((clp->aen > 0) && (rep->rep_count > 0)) { + if (0 == (rep->rq_id % clp->aen)) { struct timespec tspec = {0, 4000 /* 4 usecs */}; nanosleep(&tspec, NULL); @@ -2498,7 +2679,7 @@ do_v4: __func__, safe_strerror(err), err); } else { ++num_abort_req_success; - if (rep->debug > 1) + if (clp->debug > 1) pr2serr_lk("%s: sent ioctl(SG_IOABORT) on rq_id=%d, " "success\n", __func__, pack_id); } @@ -2513,7 +2694,8 @@ do_v4: static int sg_finish_io(bool wr, Rq_elem * rep, int pack_id, bool is_wr2) { - bool v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4; + Gbl_coll * clp = rep->clp; + bool v4 = wr ? clp->out_flags.v4 : clp->in_flags.v4; int res, fd; int64_t blk = wr ? rep->oblk : rep->iblk; struct sg_io_hdr io_hdr; @@ -2545,13 +2727,13 @@ sg_finish_io(bool wr, Rq_elem * rep, int pack_id, bool is_wr2) ++num_fin_eagain; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) - sg_take_snap(fd, rep->id, (rep->debug > 2)); + sg_take_snap(fd, rep->id, (clp->debug > 2)); #endif } else if (EBUSY == errno) { ++num_ebusy; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) - sg_take_snap(fd, rep->id, (rep->debug > 2)); + sg_take_snap(fd, rep->id, (clp->debug > 2)); #endif } std::this_thread::yield();/* another thread may be able to progress */ @@ -2574,7 +2756,7 @@ sg_finish_io(bool wr, Rq_elem * rep, int pack_id, bool is_wr2) break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: - if (rep->debug > 3) + if (clp->debug > 3) lk_chk_n_print3(cp, hp, false); return res; case SG_LIB_CAT_NOT_READY: @@ -2590,18 +2772,18 @@ sg_finish_io(bool wr, Rq_elem * rep, int pack_id, bool is_wr2) #if 0 if (0 == (++testing % 100)) return -1; #endif - if ((wr ? rep->out_flags.dio : rep->in_flags.dio) && + if ((wr ? clp->out_flags.dio : clp->in_flags.dio) && ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) rep->dio_incomplete_count = 1; /* count dios done as indirect IO */ else rep->dio_incomplete_count = 0; rep->resid = hp->resid; - if (rep->debug > 3) + if (clp->debug > 3) pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id, cp); return 0; do_v4: - if (rep->nmrqs > 0) { + if (clp->nmrqs > 0) { rep->resid = 0; return 0; } @@ -2613,13 +2795,13 @@ do_v4: ++num_fin_eagain; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) - sg_take_snap(fd, rep->id, (rep->debug > 2)); + sg_take_snap(fd, rep->id, (clp->debug > 2)); #endif } else if (EBUSY == errno) { ++num_ebusy; #ifdef SGH_DD_SNAP_DEV if (0 == (num_ebusy % 1000)) - sg_take_snap(fd, rep->id, (rep->debug > 2)); + sg_take_snap(fd, rep->id, (clp->debug > 2)); #endif } std::this_thread::yield();/* another thread may be able to progress */ @@ -2642,7 +2824,7 @@ do_v4: break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: - if (rep->debug > 3) + if (clp->debug > 3) lk_chk_n_print4(cp, h4p, false); return res; case SG_LIB_CAT_NOT_READY: @@ -2653,7 +2835,7 @@ do_v4: snprintf(ebuff, EBUFF_SZ, "%s rq_id=%d, blk=%" PRId64, cp, pack_id, blk); lk_chk_n_print4(ebuff, h4p, false); - if ((rep->debug > 4) && h4p->info) + if ((clp->debug > 4) && h4p->info) pr2serr_lk(" info=0x%x sg_info_check=%d direct=%d " "detaching=%d aborted=%d\n", h4p->info, !!(h4p->info & SG_INFO_CHECK), @@ -2666,16 +2848,16 @@ do_v4: #if 0 if (0 == (++testing % 100)) return -1; #endif - if ((wr ? rep->out_flags.dio : rep->in_flags.dio) && + if ((wr ? clp->out_flags.dio : clp->in_flags.dio) && (h4p->info & SG_INFO_DIRECT_IO)) rep->dio_incomplete_count = 1; /* count dios done as indirect IO */ else rep->dio_incomplete_count = 0; rep->resid = h4p->din_resid; - if (rep->debug > 3) { + if (clp->debug > 3) { pr2serr_lk("%s: tid,rq_id=%d,%d: completed %s\n", __func__, rep->id, pack_id, cp); - if ((rep->debug > 4) && h4p->info) + if ((clp->debug > 4) && h4p->info) pr2serr_lk(" info=0x%x sg_info_check=%d direct=%d " "detaching=%d aborted=%d\n", h4p->info, !!(h4p->info & SG_INFO_CHECK), @@ -2751,10 +2933,10 @@ read_complet: // return; break; } else { - memset(rep->buffp, 0, rep->num_blks * rep->bs); + memset(get_buffp(rep), 0, rep->num_blks * clp->bs); pr2serr_lk("tid=%d: >> substituted zeros for in blk=%" PRId64 " for %d bytes\n", rep->id, rep->iblk, - rep->num_blks * rep->bs); + rep->num_blks * clp->bs); } #if defined(__GNUC__) #if (__GNUC__ >= 7) @@ -2811,7 +2993,7 @@ write_complet: return; } else pr2serr_lk(">> ignored error for out blk=%" PRId64 " for %d " - "bytes\n", rep->oblk, rep->num_blks * rep->bs); + "bytes\n", rep->oblk, rep->num_blks * clp->bs); #if defined(__GNUC__) #if (__GNUC__ >= 7) __attribute__((fallthrough)); @@ -3113,64 +3295,20 @@ sg_out_open(Gbl_coll *clp, const char *outf, uint8_t **mmpp, int * mmap_lenp) #define STR_SZ 1024 #define INOUTF_SZ 512 -int -main(int argc, char * argv[]) +static int +parse_cmdline_sanity(int argc, char * argv[], Gbl_coll * clp, char * inf, + char * outf, char * out2f, char * outregf) { bool verbose_given = false; bool version_given = false; bool bpt_given = false; - bool cdbsz_given = false; - int64_t skip = 0; - int64_t seek = 0; int ibs = 0; int obs = 0; + int k, keylen, n, res; char str[STR_SZ]; char * key; char * buf; - char inf[INOUTF_SZ]; - char outf[INOUTF_SZ]; - char out2f[INOUTF_SZ]; - char outregf[INOUTF_SZ]; - int res, k, err, keylen; - int64_t in_num_sect = 0; - int64_t out_num_sect = 0; - int in_sect_sz, out_sect_sz, status, n, flags; - void * vp; const char * cp; - Gbl_coll * clp = &gcoll; - Thread_info thread_arr[MAX_NUM_THREADS]; - char ebuff[EBUFF_SZ]; -#if SG_LIB_ANDROID - struct sigaction actions; - - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = thread_exit_handler; - sigaction(SIGUSR1, &actions, NULL); - sigaction(SIGUSR2, &actions, NULL); -#endif - memset(clp, 0, sizeof(*clp)); - memset(thread_arr, 0, sizeof(thread_arr)); - clp->bpt = DEF_BLOCKS_PER_TRANSFER; - clp->in_type = FT_OTHER; - /* change dd's default: if of=OFILE not given, assume /dev/null */ - clp->out_type = FT_DEV_NULL; - clp->out2_type = FT_DEV_NULL; - clp->cdbsz_in = DEF_SCSI_CDBSZ; - clp->cdbsz_out = DEF_SCSI_CDBSZ; - clp->nmrqs = DEF_NUM_MRQS; - inf[0] = '\0'; - outf[0] = '\0'; - out2f[0] = '\0'; - outregf[0] = '\0'; - fetch_sg_version(); - if (sg_version > 40000) { - clp->in_flags.v4 = true; - clp->out_flags.v4 = true; - if (sg_version >= 40030) - sg_version_ge_40030 = true; - } for (k = 1; k < argc; k++) { if (argv[k]) { @@ -3218,7 +3356,7 @@ main(int argc, char * argv[]) } else if (0 == strcmp(key, "cdbsz")) { clp->cdbsz_in = sg_get_num(buf); clp->cdbsz_out = clp->cdbsz_in; - cdbsz_given = true; + clp->cdbsz_given = true; } else if (0 == strcmp(key, "coe")) { clp->in_flags.coe = !! sg_get_num(buf); clp->out_flags.coe = clp->in_flags.coe; @@ -3269,13 +3407,27 @@ main(int argc, char * argv[]) return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "mrq")) { - clp->nmrqs = sg_get_num(buf); - if ((-1 == clp->nmrqs) || (1 == (clp->nmrqs % 2))) { - pr2serr("%sbad argument to 'mrq=', want even number or " - "zero\n", my_name); + if (isdigit(buf[0])) + cp = buf; + else { + if ('I' == isupper(buf[0])) + clp->is_mrq_i = true; + else if ('O' == isupper(buf[0])) + clp->is_mrq_o = true; + else { + pr2serr("%sonly mrq=i,NRQS or mrq=o,NRQS allowed here\n", + my_name); + return SG_LIB_SYNTAX_ERROR; + } + cp = strchr(buf, ','); + ++cp; + } + clp->nmrqs = sg_get_num(cp); + if (clp->nmrqs < 0) { + pr2serr("%sbad argument to 'mrq='\n", my_name); return SG_LIB_SYNTAX_ERROR; } - cp = strchr(buf, ','); + cp = strchr(cp, ','); if (cp && ('C' == toupper(cp[1]))) clp->mrq_cmds = true; } else if (0 == strcmp(key, "obs")) { @@ -3314,14 +3466,14 @@ main(int argc, char * argv[]) return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "seek")) { - seek = sg_get_llnum(buf); - if (-1LL == seek) { + clp->seek = sg_get_llnum(buf); + if (-1LL == clp->seek) { pr2serr("%sbad argument to 'seek='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "skip")) { - skip = sg_get_llnum(buf); - if (-1LL == skip) { + clp->skip = sg_get_llnum(buf); + if (-1LL == clp->skip) { pr2serr("%sbad argument to 'skip='\n", my_name); return SG_LIB_SYNTAX_ERROR; } @@ -3330,7 +3482,7 @@ main(int argc, char * argv[]) else if (0 == strcmp(key, "thr")) num_threads = sg_get_num(buf); else if (0 == strcmp(key, "time")) - do_time = !! sg_get_num(buf); + do_time = sg_get_num(buf); else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'd'); @@ -3406,11 +3558,11 @@ main(int argc, char * argv[]) usage(0); return SG_LIB_SYNTAX_ERROR; } - if ((skip < 0) || (seek < 0)) { + if ((clp->skip < 0) || (clp->seek < 0)) { pr2serr("skip and seek cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } - if (clp->out_flags.append && (seek > 0)) { + if (clp->out_flags.append && (clp->seek > 0)) { pr2serr("Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } @@ -3457,15 +3609,69 @@ main(int argc, char * argv[]) pr2serr("iflag=swait is treated as oflag=swait\n"); clp->out_flags.swait = true; } - clp->unit_nanosec = !!getenv("SG3_UTILS_LINUX_NANO"); + clp->unit_nanosec = (do_time > 1) || !!getenv("SG3_UTILS_LINUX_NANO"); if (clp->debug) { pr2serr("%sif=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" - PRId64, my_name, inf, skip, outf, seek, dd_count); + PRId64, my_name, inf, clp->skip, outf, clp->seek, dd_count); if (clp->nmrqs > 0) pr2serr(" mrq=%d%s\n", clp->nmrqs, (clp->mrq_cmds ? ",C" : "")); else pr2serr("\n"); } + return 0; +} + + +int +main(int argc, char * argv[]) +{ + char inf[INOUTF_SZ]; + char outf[INOUTF_SZ]; + char out2f[INOUTF_SZ]; + char outregf[INOUTF_SZ]; + int res, k, err; + int64_t in_num_sect = 0; + int64_t out_num_sect = 0; + int in_sect_sz, out_sect_sz, status, flags; + void * vp; + Gbl_coll * clp = &gcoll; + Thread_info thread_arr[MAX_NUM_THREADS]; + char ebuff[EBUFF_SZ]; +#if SG_LIB_ANDROID + struct sigaction actions; + + memset(&actions, 0, sizeof(actions)); + sigemptyset(&actions.sa_mask); + actions.sa_flags = 0; + actions.sa_handler = thread_exit_handler; + sigaction(SIGUSR1, &actions, NULL); + sigaction(SIGUSR2, &actions, NULL); +#endif + memset(clp, 0, sizeof(*clp)); + memset(thread_arr, 0, sizeof(thread_arr)); + clp->bpt = DEF_BLOCKS_PER_TRANSFER; + clp->in_type = FT_OTHER; + /* change dd's default: if of=OFILE not given, assume /dev/null */ + clp->out_type = FT_DEV_NULL; + clp->out2_type = FT_DEV_NULL; + clp->cdbsz_in = DEF_SCSI_CDBSZ; + clp->cdbsz_out = DEF_SCSI_CDBSZ; + clp->nmrqs = DEF_NUM_MRQS; + inf[0] = '\0'; + outf[0] = '\0'; + out2f[0] = '\0'; + outregf[0] = '\0'; + fetch_sg_version(); + if (sg_version > 40000) { + clp->in_flags.v4 = true; + clp->out_flags.v4 = true; + if (sg_version >= 40030) + sg_version_ge_40030 = true; + } + + res = parse_cmdline_sanity(argc, argv, clp, inf, outf, out2f, outregf); + if (res) + return res; install_handler(SIGINT, interrupt_handler); install_handler(SIGQUIT, interrupt_handler); @@ -3503,8 +3709,8 @@ main(int argc, char * argv[]) my_name, inf); perror(ebuff); return sg_convert_errno(err); - } else if (skip > 0) { - off64_t offset = skip; + } else if (clp->skip > 0) { + off64_t offset = clp->skip; offset *= clp->bs; /* could exceed 32 here! */ if (lseek64(clp->infd, offset, SEEK_SET) < 0) { @@ -3570,8 +3776,8 @@ main(int argc, char * argv[]) return sg_convert_errno(err); } } - if (seek > 0) { - off64_t offset = seek; + if (clp->seek > 0) { + off64_t offset = clp->seek; offset *= clp->bs; /* could exceed 32 bits here! */ if (lseek64(clp->outfd, offset, SEEK_SET) < 0) { @@ -3638,8 +3844,8 @@ main(int argc, char * argv[]) return sg_convert_errno(err); } } - if (seek > 0) { - off64_t offset = seek; + if (clp->seek > 0) { + off64_t offset = clp->seek; offset *= clp->bs; /* could exceed 32 bits here! */ if (lseek64(clp->out2fd, offset, SEEK_SET) < 0) { @@ -3654,6 +3860,17 @@ main(int argc, char * argv[]) clp->out2fp = out2f; } if ((FT_SG == clp->in_type ) && (FT_SG == clp->out_type)) { + if (clp->nmrqs > 0) { + if ((clp->is_mrq_i == clp->is_mrq_o) && (0 != (clp->nmrqs % 2))) { + pr2serr("When both IFILE and OFILE sg devices, mrq=NRQS must " + "be even\n"); + return SG_LIB_SYNTAX_ERROR; + } + if (clp->is_mrq_i && clp->is_mrq_o) + ; + else if (clp->is_mrq_i || clp->is_mrq_o) + clp->unbalanced_mrq = true; + } if (clp->in_flags.v4_given && (! clp->out_flags.v3)) { if (! clp->out_flags.v4_given) { clp->out_flags.v4 = true; @@ -3670,11 +3887,16 @@ main(int argc, char * argv[]) "force v3\n"); } } +#if 0 if (clp->mrq_async && !(clp->in_flags.noshare || clp->out_flags.noshare)) { pr2serr("With mrq_immed also need noshare on sg-->sg copy\n"); return SG_LIB_SYNTAX_ERROR; } +#endif + } else if ((FT_SG == clp->in_type ) || (FT_SG == clp->out_type)) { + if (clp->nmrqs > 0) + clp->unbalanced_mrq = true; } if (outregf[0]) { int ftyp = dd_filetype(outregf); @@ -3736,8 +3958,8 @@ main(int argc, char * argv[]) in_num_sect = -1; } } - if (in_num_sect > skip) - in_num_sect -= skip; + if (in_num_sect > clp->skip) + in_num_sect -= clp->skip; out_num_sect = -1; if (FT_SG == clp->out_type) { @@ -3768,8 +3990,8 @@ main(int argc, char * argv[]) out_num_sect = -1; } } - if (out_num_sect > seek) - out_num_sect -= seek; + if (out_num_sect > clp->seek) + out_num_sect -= clp->seek; if (in_num_sect > 0) { if (out_num_sect > 0) @@ -3789,15 +4011,15 @@ main(int argc, char * argv[]) pr2serr("Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } - if (! cdbsz_given) { + if (! clp->cdbsz_given) { if ((FT_SG == clp->in_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_in) && - (((dd_count + skip) > UINT_MAX) || (clp->bpt > USHRT_MAX))) { + (((dd_count + clp->skip) > UINT_MAX) || (clp->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'if')\n"); clp->cdbsz_in = MAX_SCSI_CDBSZ; } if ((FT_SG == clp->out_type) && (MAX_SCSI_CDBSZ != clp->cdbsz_out) && - (((dd_count + seek) > UINT_MAX) || (clp->bpt > USHRT_MAX))) { + (((dd_count + clp->seek) > UINT_MAX) || (clp->bpt > USHRT_MAX))) { pr2serr("Note: SCSI command size increased to 16 bytes (for " "'of')\n"); clp->cdbsz_out = MAX_SCSI_CDBSZ; @@ -3806,12 +4028,9 @@ main(int argc, char * argv[]) // clp->in_count = dd_count; clp->in_rem_count = dd_count; - clp->skip = skip; - // clp->in_blk = skip; clp->out_count = dd_count; clp->out_rem_count = dd_count; - clp->seek = seek; - clp->out_blk = seek; + clp->out_blk = clp->seek; status = pthread_mutex_init(&clp->in_mutex, NULL); if (0 != status) err_exit(status, "init in_mutex"); status = pthread_mutex_init(&clp->out_mutex, NULL); @@ -3974,5 +4193,8 @@ fini: pr2serr("Number of successful MRQ Aborts: %d\n", num_mrq_abort_req_success.load()); } + if (clp->debug > 3) + pr2serr("Final pack_id=%d, mrq_id=%d\n", mono_pack_id.load(), + mono_mrq_id.load()); return (res >= 0) ? res : SG_LIB_CAT_OTHER; } |