diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2018-12-13 18:50:10 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2018-12-13 18:50:10 +0000 |
commit | d906e8cb000e95d9260d1833d3692c1c763e489a (patch) | |
tree | 8c1c3a3fc6aebf2751670d64f8389ca0ca8aa4b3 /testing/sgs_dd.c | |
parent | 4445eeca7f024eb55a9d5eb5ee6a7183816f0c2e (diff) | |
download | sg3_utils-d906e8cb000e95d9260d1833d3692c1c763e489a.tar.gz |
sg_format: add --dcrt used twice (FOV=1 DCRT=0); sg_pt_linux: uses sg v4 interface if sg driver >= 4.0.0
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@798 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing/sgs_dd.c')
-rw-r--r-- | testing/sgs_dd.c | 208 |
1 files changed, 185 insertions, 23 deletions
diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c index 95d36fc2..16aab4fa 100644 --- a/testing/sgs_dd.c +++ b/testing/sgs_dd.c @@ -88,7 +88,7 @@ #include "sg_pr2serr.h" -static const char * version_str = "1.04 20181207"; +static const char * version_str = "1.05 20181213"; #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wclobbered" @@ -141,6 +141,8 @@ struct flags_t { bool fua; bool mmap; bool noshare; + bool v3; + bool v4; }; typedef struct global_collection @@ -195,6 +197,7 @@ typedef struct request_element uint8_t * buffp; uint8_t * alloc_bp; struct sg_io_hdr io_hdr; + struct sg_io_v4 io_hdr4; uint8_t cmd[MAX_SCSI_CDBSZ]; uint8_t sb[SENSE_BUFF_LEN]; int bs; @@ -308,6 +311,17 @@ lk_chk_n_print3(const char * leadin, struct sg_io_hdr * hp, bool raw_sinfo) pthread_mutex_unlock(&strerr_mut); } + +static void +lk_chk_n_print4(const char * leadin, struct sg_io_v4 * h4p, bool raw_sinfo) +{ + pthread_mutex_lock(&strerr_mut); + sg_linux_sense_print(leadin, h4p->device_status, h4p->transport_status, + h4p->driver_status, (const uint8_t *)h4p->response, + h4p->response_len, raw_sinfo); + pthread_mutex_unlock(&strerr_mut); +} + static void calc_duration_throughput(int contin) { @@ -474,13 +488,13 @@ usage(int pg_num) " if file or device to read from (def: stdin)\n" " iflag comma separated list from: [2fds,coe,defres,dio," "direct,dpo,\n" - " dsync,excl,fua,mmap,noshare,null]\n" + " dsync,excl,fua,mmap,noshare,null,v3,v4]\n" " of file or device to write to (def: stdout), " "OFILE of '.'\n" " treated as /dev/null\n" " oflag comma separated list from: [2fds,append,coe,dio," "direct,dpo,\n" - " dsync,excl,fua,mmap,noshare,null]\n" + " dsync,excl,fua,mmap,noshare,null,v3,v4]\n" " seek block position to start writing to OFILE\n" " skip block position to start reading from IFILE\n" " --help|-h output this usage message then exit\n" @@ -545,8 +559,12 @@ page3: " mmap setup mmap IO on IFILE or OFILE; OFILE only " "with noshare\n" " noshare if IFILE and OFILE are sg devices, don't set " - "up share\n" + "up sharing\n" " (def: do)\n" + " v3 use v3 sg interface which is the default (aslo " + "see v4)\n" + " v4 use v4 sg interface (def: v3 unless other side " + "us v4)\n" "\n" "If both are sg devices 'shared' mode is selected unless " "'noshare' is given\nto 'iflag=' or 'oflag='. If 'of2=OFLAG2' " @@ -916,6 +934,10 @@ fini: if (own_outfd) close(rep->outfd); pthread_cond_broadcast(&clp->out_sync_cv); + if ((0 == rep->id) && is_first) { + is_first = false; /* allow rest of threads to start */ + pthread_cond_broadcast(&clp->hold_1st_cv); + } return stop_after_write ? NULL : clp; } @@ -1217,6 +1239,7 @@ sg_out_wr_cmd(Gbl_coll * clp, Rq_elem * rep) } /* end of while (1) loop */ } +/* Returns 0 on success, 1 if ENOMEM error else -1 for other errors. */ static int sg_start_io(Rq_elem * rep) { @@ -1225,9 +1248,12 @@ sg_start_io(Rq_elem * rep) 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 v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4; int cdbsz = wr ? rep->cdbsz_out : rep->cdbsz_in; + int flags = 0; int res, err; 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 = ""; @@ -1238,31 +1264,19 @@ sg_start_io(Rq_elem * rep) my_name, rep->blk, rep->num_blks); return -1; } - memset(hp, 0, sizeof(struct sg_io_hdr)); - hp->interface_id = 'S'; - 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->mx_sb_len = sizeof(rep->sb); - hp->sbp = rep->sb; - hp->timeout = DEF_TIMEOUT; - hp->usr_ptr = rep; - hp->pack_id = (int)rep->blk; if (mmap && (rep->out2fd >= 0)) { - hp->flags |= SG_FLAG_MMAP_IO; + flags |= SG_FLAG_MMAP_IO; c3p = " mmap"; } if (dio) - hp->flags |= SG_FLAG_DIRECT_IO; + flags |= SG_FLAG_DIRECT_IO; if (rep->has_share) { - hp->flags |= SGV4_FLAG_SHARE; + flags |= SGV4_FLAG_SHARE; if (wr) - hp->flags |= SGV4_FLAG_NO_DXFER; + flags |= SGV4_FLAG_NO_DXFER; else if (rep->out2fd < 0) - hp->flags |= SGV4_FLAG_NO_DXFER; - if (hp->flags & SGV4_FLAG_NO_DXFER) + flags |= SGV4_FLAG_NO_DXFER; + if (flags & SGV4_FLAG_NO_DXFER) c2p = " and FLAG_NO_DXFER"; cp = (wr ? " slave active" : " master active"); @@ -1272,8 +1286,24 @@ sg_start_io(Rq_elem * rep) pr2serr_lk("%s tid=%d: SCSI %s%s%s%s, blk=%" PRId64 " num_blks=%d\n", __func__, rep->id, (rep->wr ? "WRITE" : "READ"), cp, c2p, c3p, rep->blk, rep->num_blks); - lk_print_command(hp->cmdp); + lk_print_command(rep->cmd); } + if (v4) + goto do_v4; + + memset(hp, 0, sizeof(struct sg_io_hdr)); + hp->interface_id = 'S'; + 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->mx_sb_len = sizeof(rep->sb); + hp->sbp = rep->sb; + hp->timeout = DEF_TIMEOUT; + hp->usr_ptr = rep; + hp->pack_id = (int)rep->blk; + hp->flags = flags; while (((res = write(rep->wr ? rep->outfd : rep->infd, hp, sizeof(struct sg_io_hdr))) < 0) && @@ -1288,6 +1318,37 @@ sg_start_io(Rq_elem * rep) return -1; } return 0; +do_v4: + memset(h4p, 0, sizeof(struct sg_io_v4)); + h4p->guard = 'Q'; + 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; + } else if (rep->num_blks > 0) { + h4p->din_xfer_len = rep->bs * rep->num_blks; + h4p->din_xferp = (uint64_t)rep->buffp; + } + 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 = rep->blk;/* N.B. blk --> pack_id --> request_extra */ + h4p->flags = flags; + while (((res = ioctl(rep->wr ? rep->outfd : rep->infd, SG_IOSUBMIT, + h4p)) < 0) && ((EINTR == errno) || + (EAGAIN == errno))) + ; + err = errno; + 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)); + return -1; + } + return 0; } /* 0 -> successful, SG_LIB_CAT_UNIT_ATTENTION or SG_LIB_CAT_ABORTED_COMMAND @@ -1296,13 +1357,17 @@ sg_start_io(Rq_elem * rep) static int sg_finish_io(bool wr, Rq_elem * rep) { + bool v4 = wr ? rep->out_flags.v4 : rep->in_flags.v4; int res; struct sg_io_hdr io_hdr; struct sg_io_hdr * hp; + struct sg_io_v4 * h4p; #if 0 static int testing = 0; /* thread dubious! */ #endif + if (v4) + goto do_v4; memset(&io_hdr, 0 , sizeof(struct sg_io_hdr)); /* FORCE_PACK_ID active set only read packet with matching pack_id */ io_hdr.interface_id = 'S'; @@ -1359,6 +1424,67 @@ sg_finish_io(bool wr, Rq_elem * rep) pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id, wr ? "WRITE" : "READ"); return 0; + +do_v4: + h4p = &rep->io_hdr4; + while (((res = ioctl(wr ? rep->outfd : rep->infd, SG_IORECEIVE, + h4p)) < 0) && ((EINTR == errno) || + (EAGAIN == errno))) + ; + if (res < 0) { + perror("finishing io on sg device, error"); + return -1; + } + if (rep != (Rq_elem *)h4p->usr_ptr) + err_exit(0, "sg_finish_io: bad usr_ptr, request-response mismatch\n"); + res = sg_err_category_new(h4p->device_status, h4p->transport_status, + h4p->driver_status, + (const uint8_t *)h4p->response, + h4p->response_len); + switch (res) { + case SG_LIB_CAT_CLEAN: + break; + case SG_LIB_CAT_RECOVERED: + lk_chk_n_print4((wr ? "writing continuing": + "reading continuing"), h4p, false); + break; + case SG_LIB_CAT_ABORTED_COMMAND: + case SG_LIB_CAT_UNIT_ATTENTION: + if (rep->debug > 3) + lk_chk_n_print4((wr ? "writing": "reading"), h4p, false); + return res; + case SG_LIB_CAT_NOT_READY: + default: + { + char ebuff[EBUFF_SZ]; + + snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64, + wr ? "writing": "reading", rep->blk); + lk_chk_n_print4(ebuff, h4p, false); + return res; + } + } +#if 0 + if (0 == (++testing % 100)) return -1; +#endif + if ((wr ? rep->out_flags.dio : rep->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) { + pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id, + wr ? "WRITE" : "READ"); + if (rep->debug > 4) + pr2serr_lk(" info=0x%x sg_info_check=%d another_waiting=%d " + "direct=%d detaching=%d\n", h4p->info, + !!(h4p->info & SG_INFO_CHECK), + !!(h4p->info & SG_INFO_ANOTHER_WAITING), + !!(h4p->info & SG_INFO_DIRECT_IO), + !!(h4p->info & SG_INFO_DEVICE_DETACHING)); + } + return 0; } /* Returns reserved_buffer_size/mmap_size if success, else 0 for failure */ @@ -1439,6 +1565,10 @@ process_flags(const char * arg, struct flags_t * fp) fp->noshare = true; else if (0 == strcmp(cp, "null")) ; + else if (0 == strcmp(cp, "v3")) + fp->v3 = true; + else if (0 == strcmp(cp, "v4")) + fp->v4 = true; else { pr2serr("unrecognised flag: %s\n", cp); return false; @@ -1841,6 +1971,13 @@ main(int argc, char * argv[]) } } clp->infp = inf; + if ((clp->in_flags.v3 || clp->in_flags.v4) && + (FT_SG != clp->in_type)) { + clp->in_flags.v3 = false; + clp->in_flags.v4 = false; + pr2serr("%siflag= v3 and v4 both ignored when IFILE is not sg " + "device\n", my_name); + } } if (outf[0] && ('-' != outf[0])) { clp->out_type = dd_filetype(outf); @@ -1899,6 +2036,31 @@ main(int argc, char * argv[]) } } clp->outfp = outf; + if ((clp->out_flags.v3 || clp->out_flags.v4) && + (FT_SG != clp->out_type)) { + clp->out_flags.v3 = false; + clp->out_flags.v4 = false; + pr2serr("%soflag= v3 and v4 both ignored when OFILE is not sg " + "device\n", my_name); + } + } + if ((FT_SG == clp->in_type ) && (FT_SG == clp->out_type)) { + if (clp->in_flags.v4 && (! clp->out_flags.v3)) { + if (! clp->out_flags.v4) { + clp->out_flags.v4 = true; + if (clp->debug) + pr2serr("Changing OFILE from v3 to v4, use oflag=v3 to " + "force v3\n"); + } + } + if (clp->out_flags.v4 && (! clp->in_flags.v3)) { + if (! clp->in_flags.v4) { + clp->in_flags.v4 = true; + if (clp->debug) + pr2serr("Changing IFILE from v3 to v4, use iflag=v3 to " + "force v3\n"); + } + } } if (out2f[0]) { clp->out2_type = dd_filetype(out2f); |