diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2018-11-27 18:38:56 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2018-11-27 18:38:56 +0000 |
commit | 8101850bc7cd2a05d35b4df3ecfd3f934cff584e (patch) | |
tree | 09532aaaf968dbffe9599c90cb2af79996552a00 /testing | |
parent | d6e191ba93e7188a95b6b4fd73dbfa9157dda3ac (diff) | |
download | sg3_utils-8101850bc7cd2a05d35b4df3ecfd3f934cff584e.tar.gz |
sg_write_buffer: allow comma and period separated lists when input from stdin; sg driver share testing
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@796 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing')
-rw-r--r-- | testing/sg_tst_ioctl.c | 85 | ||||
-rw-r--r-- | testing/sgs_dd.c | 256 | ||||
-rw-r--r-- | testing/uapi_sg.h | 22 |
3 files changed, 226 insertions, 137 deletions
diff --git a/testing/sg_tst_ioctl.c b/testing/sg_tst_ioctl.c index bb747754..b37be2e6 100644 --- a/testing/sg_tst_ioctl.c +++ b/testing/sg_tst_ioctl.c @@ -38,12 +38,11 @@ * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * Invocation: sg_tst_ioctl [-l=Q_LEN] [-t] <sg_device> - * -t queue at tail + * Invocation: See usage() function below. * */ -static const char * version_str = "Version: 0.96 20181106"; +static const char * version_str = "Version: 0.97 20181121"; #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 @@ -66,9 +65,33 @@ static const char * version_str = "Version: 0.96 20181106"; #define DEF_RESERVE_BUFF_SZ (256 * 1024) -int main(int argc, char * argv[]) +static void +usage(void) +{ + printf("Usage: 'sg_tst_ioctl [-h] [-l=Q_LEN] [-o] [-r=SZ] [-s=SEC] " + "[-t]\n" + " [-v] [-V] [-w] <sg_device>'\n" + " where:\n" + " -h help: print usage message then exit\n" + " -l=Q_LEN queue length, between 1 and 511 (def: 16)\n" + " -o ioctls only, then exit\n" + " -r=SZ reserve buffer size in KB (def: 256 --> 256 " + "KB)\n" + " -s=SEC sleep between writes and reads (def: 0)\n" + " -t queue_at_tail (def: q_at_head)\n" + " -v increase verbosity of output\n" + " -V print version string then exit\n" + " -w write (submit) only then exit\n"); +} + + +int +main(int argc, char * argv[]) { bool done; + bool q_at_tail = false; + bool ioctl_only = false; + bool write_only = false; int sg_fd, k, ok, ver_num, pack_id, num_waiting, access_count; int sg_fd2 = -1; uint8_t inq_cdb[INQ_CMD_LEN] = @@ -81,7 +104,6 @@ int main(int argc, char * argv[]) char * file_name = 0; char ebuff[EBUFF_SZ]; uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN]; - int q_at_tail = 0; int q_len = DEF_Q_LEN; int sleep_secs = 0; int reserve_buff_sz = DEF_RESERVE_BUFF_SZ; @@ -94,7 +116,7 @@ int main(int argc, char * argv[]) for (k = 1; k < argc; ++k) { if (0 == memcmp("-t", argv[k], 2)) - ++q_at_tail; + q_at_tail = true; else if (0 == memcmp("-h", argv[k], 2)) { file_name = 0; break; @@ -106,7 +128,9 @@ int main(int argc, char * argv[]) file_name = 0; break; } - } else if (0 == memcmp("-r=", argv[k], 3)) { + } else if (0 == memcmp("-o", argv[k], 2)) + ioctl_only = true; + else if (0 == memcmp("-r=", argv[k], 3)) { reserve_buff_sz = atoi(argv[k] + 3); if (reserve_buff_sz < 0) { printf("Expect -r= to take a number 0 or higher\n"); @@ -132,7 +156,9 @@ int main(int argc, char * argv[]) printf("%s\n", version_str); file_name = 0; break; - } else if (*argv[k] == '-') { + } else if (0 == memcmp("-w", argv[k], 2)) + write_only = true; + else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; @@ -146,18 +172,7 @@ int main(int argc, char * argv[]) } } if (0 == file_name) { - printf("Usage: 'sg_tst_ioctl [-h] [-l=Q_LEN] [-t] [-v] [-V] " - "<sg_device>'\n" - " where:\n" - " -h help: print usage message then exit\n" - " -l=Q_LEN queue length, between 1 and 511 " - "(def: 16)\n" - " -r=SZ reserve buffer size in KB (def: 256 --> 256 " - "KB)\n" - " -s=SEC sleep between writes and reads (def: 0)\n" - " -t queue_at_tail (def: q_at_head)\n" - " -v increase verbosity of output\n" - " -V print version string then exit\n"); + usage(); return 1; } @@ -294,7 +309,6 @@ int main(int argc, char * argv[]) } printf(" read_value[SG_SEIRV_FL_RQS]= %u\n", seip->read_value); -#if 1 memset(seip, 0, sizeof(*seip)); seip->valid_wr_mask |= SG_SEIM_READ_VAL; seip->valid_rd_mask |= SG_SEIM_READ_VAL; @@ -305,7 +319,28 @@ int main(int argc, char * argv[]) goto out; } printf(" read_value[SG_SEIRV_DEV_FL_RQS]= %u\n", seip->read_value); -#endif + + memset(seip, 0, sizeof(*seip)); + seip->valid_wr_mask |= SG_SEIM_READ_VAL; + seip->valid_rd_mask |= SG_SEIM_READ_VAL; + seip->read_value = SG_SEIRV_TRC_SZ; + if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { + pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, + strerror(errno)); + goto out; + } + printf(" read_value[SG_SEIRV_TRC_SZ]= %u\n", seip->read_value); + + memset(seip, 0, sizeof(*seip)); + seip->valid_wr_mask |= SG_SEIM_READ_VAL; + seip->valid_rd_mask |= SG_SEIM_READ_VAL; + seip->read_value = SG_SEIRV_TRC_MAX_SZ; + if (ioctl(sg_fd, SG_SET_GET_EXTENDED, seip) < 0) { + pr2serr("ioctl(SG_SET_GET_EXTENDED) failed, errno=%d %s\n", errno, + strerror(errno)); + goto out; + } + printf(" read_value[SG_SEIRV_TRC_MAX_SZ]= %u\n", seip->read_value); memset(seip, 0, sizeof(*seip)); seip->valid_wr_mask |= SG_SEIM_SHARE_FD; @@ -334,6 +369,9 @@ int main(int argc, char * argv[]) printf("SG_SET_TRANSFORM okay (does nothing)\n"); printf("\n"); + if (ioctl_only) + goto out; + printf("start write() calls\n"); for (k = 0; k < q_len; ++k) { /* Prepare INQUIRY command */ @@ -396,6 +434,9 @@ int main(int argc, char * argv[]) sleep(sleep_secs); + if (write_only) + goto out; + if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0) pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n", errno, strerror(errno)); diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c index dd2b41d2..a82ca80a 100644 --- a/testing/sgs_dd.c +++ b/testing/sgs_dd.c @@ -1,7 +1,7 @@ /* A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * - * Copyright (C) 1999 - 2018 D. Gilbert and P. Allworth + * Copyright (C) 2018 D. Gilbert * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -85,7 +85,7 @@ #include "sg_pr2serr.h" -static const char * version_str = "1.02 20180912"; +static const char * version_str = "1.03 20181126"; #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 @@ -139,6 +139,7 @@ typedef struct global_collection int64_t skip; int in_type; int cdbsz_in; + int help; struct flags_t in_flags; int64_t in_blk; /* -\ next block address to read */ int64_t in_count; /* | blocks remaining for next read */ @@ -149,6 +150,8 @@ typedef struct global_collection int outfd; int64_t seek; int out_type; + int out2fd; + int out2_type; int cdbsz_out; struct flags_t out_flags; int64_t out_blk; /* -\ next block address to write */ @@ -174,6 +177,7 @@ typedef struct request_element int id; int infd; int outfd; + int out2fd; int64_t blk; int num_blks; uint8_t * buffp; @@ -413,8 +417,10 @@ dd_filetype(const char * filename) } static void -usage() +usage(int pg_num) { + if (pg_num > 0) + goto page2; pr2serr("Usage: sgs_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]" " [iflag=FLAGS]\n" " [obs=BS] [of=OFILE] [oflag=FLAGS] " @@ -422,22 +428,12 @@ usage() " [--help] [--version]\n\n"); pr2serr(" [bpt=BPT] [cdbsz=6|10|12|16] [coe=0|1] " "[deb=VERB] [dio=0|1]\n" - " [fua=0|1|2|3] [sync=0|1] [thr=THR] " - "[time=0|1] [verbose=VERB]\n" - " [--dry-run] [--verbose]\n" - " where:\n" - " bpt is blocks_per_transfer (default is 128)\n" + " [fua=0|1|2|3] [of2=OFILE2] [sync=0|1] [thr=THR] " + "[time=0|1]\n" + " [verbose=VERB] [--dry-run] [--verbose]\n" + " where the main options (shown in first group above) are:\n" " bs must be device block size (default 512)\n" - " cdbsz size of SCSI READ or WRITE cdb (default is 10)\n" - " coe continue on error, 0->exit (def), " - "1->zero + continue\n" " count number of blocks to copy (def: device size)\n" - " deb for debug, 0->none (def), > 0->varying degrees " - "of debug\n"); - pr2serr(" dio is direct IO, 1->attempt, 0->indirect IO (def)\n" - " fua force unit access: 0->don't(def), 1->OFILE, " - "2->IFILE,\n" - " 3->OFILE+IFILE\n" " if file or device to read from (def: stdin)\n" " iflag comma separated list from: [coe,dio,direct,dpo," "dsync,excl,\n" @@ -450,6 +446,38 @@ usage() " excl,fua,noshare,null]\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" + " --version|-V output version string then exit\n\n" + "Copy from IFILE to OFILE, similar to dd command. This utility " + "is specialized\nfor SCSI devices and uses multiple POSIX " + "threads. It expects one or both\nIFILE and OFILE to be SCSI " + "generic devices. If both are sg devices 'shared'\nmode is " + "selected unless 'noshare' is given to 'iflag=' or 'oflag='. " + "If\n'of2=OFLAG2' is given, the read-side is output to OFLAG2. " + "Without 'of2=' and\nwith IFILE and OFILE sg devices the copy " + "is via a single in-kernel buffer.\n" + ); + return; +page2: + pr2serr("Syntax: sgs_dd [operands] [options]\n\n" + " where: operands have the form name=value and are pecular to " + "'dd'\n style commands, and options start with one or two " + "hyphens\n\n" + " where the less used options (not shown on first help page) " + "are:\n" + " bpt is blocks_per_transfer (default is 128)\n" + " cdbsz size of SCSI READ or WRITE cdb (default is 10)\n" + " coe continue on error, 0->exit (def), " + "1->zero + continue\n" + " deb for debug, 0->none (def), > 0->varying degrees " + "of debug\n" + " dio is direct IO, 1->attempt, 0->indirect IO (def)\n" + " fua force unit access: 0->don't(def), 1->OFILE, " + "2->IFILE,\n" + " 3->OFILE+IFILE\n" + " of2 OFILE2 is regular file or pipe to output what is " + "read from the\n" + " disk in the first half of each shared element\n" " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE " "after copy\n" " thr is number of threads, must be > 0, default 4, " @@ -458,12 +486,8 @@ usage() "throughput\n" " verbose same as 'deb=VERB': increase verbosity\n" " --dry-run|-d prepare but bypass copy/read\n" - " --help|-h output this usage message then exit\n" " --verbose|-v increase verbosity of utility\n" - " --version|-V output version string then exit\n\n" - "Copy from IFILE to OFILE, similar to dd command. This utility " - "is\nspecialized for SCSI devices, uses multiple POSIX threads. " - "It expects\n"); + ); } static void @@ -565,7 +589,7 @@ sig_listen_thread(void * v_clp) if (shutting_down) break; if (SIGINT == sig_number) { - pr2serr("%sinterrupted by SIGINT\n", my_name); + pr2serr_lk("%sinterrupted by SIGINT\n", my_name); guarded_stop_both(clp); pthread_cond_broadcast(&clp->out_sync_cv); } @@ -573,7 +597,7 @@ sig_listen_thread(void * v_clp) return NULL; } -static int +static bool sg_share_prepare(int slave_writer_fd, int master_reader_fd, int id, bool vb_b) { struct sg_extended_info sei; @@ -587,11 +611,11 @@ sg_share_prepare(int slave_writer_fd, int master_reader_fd, int id, bool vb_b) if (ioctl(slave_writer_fd, SG_SET_GET_EXTENDED, seip) < 0) { if (vb_b) pr2serr_lk("tid=%d: ioctl(EXTENDED(shared_fd=%d), failed " - "errno=%d %s\n", id, master_reader_fd, errno, - strerror(errno)); - return 1; + "errno=%d %s\n", id, master_reader_fd, errno, + strerror(errno)); + return false; } - return 0; + return true; } static void @@ -645,6 +669,7 @@ read_write_thread(void * v_tip) rep->bs = clp->bs; rep->infd = clp->infd; rep->outfd = clp->outfd; + rep->out2fd = clp->out2fd; rep->debug = clp->debug; rep->cdbsz_in = clp->cdbsz_in; rep->cdbsz_out = clp->cdbsz_out; @@ -654,8 +679,8 @@ read_write_thread(void * v_tip) if (vb) pr2serr_lk("Skipping share on both IFILE and OFILE\n"); } else - rep->has_share = !(sg_share_prepare(clp->outfd, clp->infd, rep->id, - clp->debug)); + rep->has_share = sg_share_prepare(clp->outfd, clp->infd, rep->id, + clp->debug); if (vb > 0) pr2serr_lk("starting thread %d, has_share=%s\n", rep->id, (rep->has_share ? "true" : "false")); @@ -915,7 +940,6 @@ sg_in_operation(Gbl_coll * clp, Rq_elem * rep) /* enters holding in_mutex */ while (1) { -// sleep(20); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx res = sg_start_io(rep); if (1 == res) err_exit(ENOMEM, "sg starting in command"); @@ -929,11 +953,9 @@ sg_in_operation(Gbl_coll * clp, Rq_elem * rep) } /* Now release in mutex to let other reads run in parallel */ status = pthread_mutex_unlock(&clp->in_mutex); -// sleep(20); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx if (0 != status) err_exit(status, "unlock in_mutex"); res = sg_finish_io(rep->wr, rep, &clp->aux_mutex); -// sleep(6); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx switch (res) { case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: @@ -994,9 +1016,9 @@ sg_out_operation(Gbl_coll * clp, Rq_elem * rep) int res; int status; + /* enters holding out_mutex */ while (1) { -// sleep(10); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx res = sg_start_io(rep); if (1 == res) err_exit(ENOMEM, "sg starting out command"); @@ -1012,9 +1034,7 @@ sg_out_operation(Gbl_coll * clp, Rq_elem * rep) status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); -// sleep(10); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx res = sg_finish_io(rep->wr, rep, &clp->aux_mutex); -// sleep(6); // ************************ <<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxx switch (res) { case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: @@ -1076,6 +1096,7 @@ sg_start_io(Rq_elem * rep) int res; struct sg_io_hdr * hp = &rep->io_hdr; const char * cp = ""; + const char * c2p = ""; if (sg_build_scsi_cdb(rep->cmd, cdbsz, rep->num_blks, rep->blk, rep->wr, fua, dpo)) { @@ -1097,21 +1118,22 @@ sg_start_io(Rq_elem * rep) hp->pack_id = (int)rep->blk; if (dio) hp->flags |= SG_FLAG_DIRECT_IO; -#if 1 if (rep->has_share) { -#else - if (rep->has_share && !wr) { /* && !wr is temporary xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ -#endif hp->flags |= SGV4_FLAG_SHARE; if (wr) - hp->flags |= SGV4_FLAG_NO_DXFER; + hp->flags |= SGV4_FLAG_NO_DXFER; + else if (rep->out2fd < 0) + hp->flags |= SGV4_FLAG_NO_DXFER; + if (hp->flags & SGV4_FLAG_NO_DXFER) + c2p = " and FLAG_NO_DXFER"; + cp = (wr ? " slave active" : " master active"); - } + } else cp = (wr ? " slave not sharing" : " master not sharing"); - if (rep->debug > 8) { - pr2serr_lk("%s tid=%d: SCSI %s%s, blk=%" PRId64 " num_blks=%d\n", + if (rep->debug > 3) { + pr2serr_lk("%s tid=%d: SCSI %s%s%s, blk=%" PRId64 " num_blks=%d\n", __func__, rep->id, (rep->wr ? "WRITE" : "READ"), cp, - rep->blk, rep->num_blks); + c2p, rep->blk, rep->num_blks); sg_print_command(hp->cmdp); } @@ -1134,7 +1156,7 @@ sg_start_io(Rq_elem * rep) static int sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp) { - int res, status; + int res, err, status; struct sg_io_hdr io_hdr; struct sg_io_hdr * hp; #if 0 @@ -1162,31 +1184,31 @@ sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp) res = sg_err_category3(hp); switch (res) { - case SG_LIB_CAT_CLEAN: - break; - case SG_LIB_CAT_RECOVERED: - sg_chk_n_print3((wr ? "writing continuing": - "reading continuing"), hp, false); - break; - case SG_LIB_CAT_ABORTED_COMMAND: - case SG_LIB_CAT_UNIT_ATTENTION: - if (rep->debug > 8) - sg_chk_n_print3((wr ? "writing": "reading"), hp, false); + case SG_LIB_CAT_CLEAN: + break; + case SG_LIB_CAT_RECOVERED: + sg_chk_n_print3((wr ? "writing continuing": + "reading continuing"), hp, false); + break; + case SG_LIB_CAT_ABORTED_COMMAND: + case SG_LIB_CAT_UNIT_ATTENTION: + if (rep->debug > 3) + sg_chk_n_print3((wr ? "writing": "reading"), hp, 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); + status = pthread_mutex_lock(a_mutp); + if (0 != status) err_exit(status, "lock aux_mutex"); + sg_chk_n_print3(ebuff, hp, false); + status = pthread_mutex_unlock(a_mutp); + if (0 != status) err_exit(status, "unlock aux_mutex"); 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); - status = pthread_mutex_lock(a_mutp); - if (0 != status) err_exit(status, "lock aux_mutex"); - sg_chk_n_print3(ebuff, hp, false); - status = pthread_mutex_unlock(a_mutp); - if (0 != status) err_exit(status, "unlock aux_mutex"); - return res; - } + } } #if 0 if (0 == (++testing % 100)) return -1; @@ -1197,7 +1219,18 @@ sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp) else rep->dio_incomplete_count = 0; rep->resid = hp->resid; - if (rep->debug > 8) + if ((! wr) && (rep->out2fd >= 0)) { + status = pthread_mutex_lock(a_mutp); + if (0 != status) err_exit(status, "lock aux_mutex"); + res = write(rep->out2fd, rep->buffp, rep->bs * rep->num_blks); + err = errno; + status = pthread_mutex_unlock(a_mutp); + if (0 != status) err_exit(status, "unlock aux_mutex"); + if (res < 0) + pr2serr_lk("%s: tid=%d: write(out2fd) failed: %s\n", __func__, + rep->id, strerror(err)); + } + if (rep->debug > 3) pr2serr_lk("%s: tid=%d: completed %s\n", __func__, rep->id, wr ? "WRITE" : "READ"); return 0; @@ -1334,7 +1367,7 @@ sg_out_open(Gbl_coll *clp, const char *outf) } if (sg_prepare(fd, clp->bs, clp->bpt)) return -SG_LIB_FILE_ERROR; - else if (gcoll.debug > 0) + else if (gcoll.debug > 1) pr2serr("Sharing writer's fd (%d) with reader (fd=%d) " "successful\n", clp->infd, fd); return fd; @@ -1359,6 +1392,7 @@ main(int argc, char * argv[]) char * buf; char inf[INOUTF_SZ]; char outf[INOUTF_SZ]; + char out2f[INOUTF_SZ]; int res, k, err, keylen; int64_t in_num_sect = 0; int64_t out_num_sect = 0; @@ -1383,6 +1417,7 @@ main(int argc, char * argv[]) gcoll.cdbsz_out = DEF_SCSI_CDBSZ; inf[0] = '\0'; outf[0] = '\0'; + out2f[0] = '\0'; for (k = 1; k < argc; k++) { if (argv[k]) { @@ -1459,6 +1494,12 @@ main(int argc, char * argv[]) pr2serr("%sbad argument to 'obs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } + } else if (strcmp(key,"of2") == 0) { + if ('\0' != out2f[0]) { + pr2serr("Second OFILE2 argument??\n"); + return SG_LIB_CONTRADICT; + } else + strncpy(out2f, buf, INOUTF_SZ - 1); } else if (strcmp(key,"of") == 0) { if ('\0' != outf[0]) { pr2serr("Second 'of=' argument??\n"); @@ -1494,10 +1535,8 @@ main(int argc, char * argv[]) gcoll.dry_run += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'h'); - if (n > 0) { - usage(); - return 0; - } + gcoll.help += n; + res += n; n = num_chs_in_str(key + 1, keylen - 1, 'v'); if (n > 0) verbose_given = true; @@ -1517,10 +1556,9 @@ main(int argc, char * argv[]) (0 == strncmp(key, "--dry_run", 9))) ++gcoll.dry_run; else if ((0 == strncmp(key, "--help", 6)) || - (0 == strcmp(key, "-?"))) { - usage(); - return 0; - } else if (0 == strncmp(key, "--verb", 6)) { + (0 == strcmp(key, "-?"))) + ++gcoll.help; + else if (0 == strncmp(key, "--verb", 6)) { verbose_given = true; ++gcoll.debug; /* --verbose */ } else if (0 == strncmp(key, "--vers", 6)) @@ -1552,14 +1590,20 @@ main(int argc, char * argv[]) pr2serr("%s%s\n", my_name, version_str); return 0; } - + if (gcoll.help > 0) { + if (1 == gcoll.help) + usage(0); + else + usage(1); + return 0; + } if (gcoll.bs <= 0) { gcoll.bs = DEF_BLOCK_SIZE; pr2serr("Assume default 'bs' (block size) of %d bytes\n", gcoll.bs); } if ((ibs && (ibs != gcoll.bs)) || (obs && (obs != gcoll.bs))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); - usage(); + usage(0); return SG_LIB_SYNTAX_ERROR; } if ((skip < 0) || (seek < 0)) { @@ -1581,7 +1625,7 @@ main(int argc, char * argv[]) gcoll.bpt = DEF_BLOCKS_PER_2048TRANSFER; if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) { pr2serr("too few or too many threads requested\n"); - usage(); + usage(1); return SG_LIB_SYNTAX_ERROR; } if (gcoll.debug) @@ -1695,6 +1739,17 @@ main(int argc, char * argv[]) } } } + if (out2f[0]) { + gcoll.out2_type = dd_filetype(out2f); + if ((gcoll.out2fd = open(out2f, O_WRONLY | O_CREAT, 0666)) < 0) { + err = errno; + snprintf(ebuff, EBUFF_SZ, "could not open %s for writing", out2f); + perror(ebuff); + return sg_convert_errno(err); + } + } else + gcoll.out2fd = -1; + if ((STDIN_FILENO == gcoll.infd) && (STDOUT_FILENO == gcoll.outfd)) { pr2serr("Won't default both IFILE to stdin _and_ OFILE to stdout\n"); pr2serr("For more information use '--help'\n"); @@ -1775,7 +1830,7 @@ main(int argc, char * argv[]) else dd_count = out_num_sect; } - if (gcoll.debug > 1) + if (gcoll.debug > 2) pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", out_num_sect=%" PRId64 "\n", dd_count, in_num_sect, out_num_sect); @@ -1845,8 +1900,8 @@ main(int argc, char * argv[]) status = pthread_create(&threads[0], NULL, read_write_thread, (void *)&ti); if (0 != status) err_exit(status, "pthread_create"); - if (gcoll.debug) - pr2serr("Starting worker thread k=0\n"); + if (gcoll.debug > 1) + pr2serr_lk("Starting worker thread k=0\n"); /* wait for any broadcast */ pthread_cleanup_push(cleanup_out, (void *)&gcoll); @@ -1865,16 +1920,16 @@ main(int argc, char * argv[]) status = pthread_create(&threads[k], NULL, read_write_thread, (void *)&tinfo); if (0 != status) err_exit(status, "pthread_create"); - if (gcoll.debug) - pr2serr("Starting worker thread k=%d\n", k); + if (gcoll.debug > 1) + pr2serr_lk("Starting worker thread k=%d\n", k); } /* now wait for worker threads to finish */ for (k = 0; k < num_threads; ++k) { status = pthread_join(threads[k], &vp); if (0 != status) err_exit(status, "pthread_join"); - if (gcoll.debug) - pr2serr("Worker thread k=%d terminated\n", k); + if (gcoll.debug > 0) + pr2serr_lk("Worker thread k=%d terminated\n", k); } } /* started worker threads and here after they have all exited */ @@ -1883,30 +1938,18 @@ main(int argc, char * argv[]) if (do_sync) { if (FT_SG == gcoll.out_type) { - pr2serr(">> Synchronizing cache on %s\n", outf); + pr2serr_lk(">> Synchronizing cache on %s\n", outf); res = sg_ll_sync_cache_10(gcoll.outfd, 0, 0, 0, 0, 0, false, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { - pr2serr("Unit attention(out), continuing\n"); + pr2serr_lk("Unit attention(out), continuing\n"); res = sg_ll_sync_cache_10(gcoll.outfd, 0, 0, 0, 0, 0, false, 0); } if (0 != res) - pr2serr("Unable to synchronize cache\n"); + pr2serr_lk("Unable to synchronize cache\n"); } } -#if 0 -#if SG_LIB_ANDROID - /* Android doesn't have pthread_cancel() so use pthread_kill() instead. - * Also there is no need to link with -lpthread in Android */ - status = pthread_kill(sig_listen_thread_id, SIGUSR1); - if (0 != status) err_exit(status, "pthread_kill"); -#else - status = pthread_cancel(sig_listen_thread_id); - if (0 != status) err_exit(status, "pthread_cancel"); -#endif -#endif /* #if 0, because always do pthread_kill(), see next */ - shutting_down = true; status = pthread_kill(sig_listen_thread_id, SIGINT); if (0 != status) err_exit(status, "pthread_kill"); @@ -1915,11 +1958,12 @@ main(int argc, char * argv[]) fini: -// sleep(20); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< xxxxxxxxxxxxxx if (STDIN_FILENO != gcoll.infd) close(gcoll.infd); if ((STDOUT_FILENO != gcoll.outfd) && (FT_DEV_NULL != gcoll.out_type)) close(gcoll.outfd); + if ((STDOUT_FILENO != gcoll.out2fd) && (FT_DEV_NULL != gcoll.out2_type)) + close(gcoll.out2fd); res = exit_status; if ((0 != gcoll.out_count) && (0 == gcoll.dry_run)) { pr2serr(">>>> Some error occurred, remaining blocks=%" PRId64 "\n", diff --git a/testing/uapi_sg.h b/testing/uapi_sg.h index f9d8298e..1485c2e8 100644 --- a/testing/uapi_sg.h +++ b/testing/uapi_sg.h @@ -13,7 +13,7 @@ * Version 2 and 3 extensions to driver: * Copyright (C) 1998 - 2018 Douglas Gilbert * - * Version: 3.9.02 (20181104) + * Version: 3.9.02 (20181118) * This version is for Linux 2.6, 3 and 4 series kernels. * * Documentation @@ -30,12 +30,12 @@ #include <linux/types.h> #include <linux/major.h> -/* bsg.h contains the sg v4 use space interface structure. */ +/* bsg.h contains the sg v4 user space interface structure. */ #include <linux/bsg.h> /* * Same structure as used by readv() call. It defines one scatter-gather - * element. "Scatter-gather" is abbreviated to "sgat" in thsi driver to + * element. "Scatter-gather" is abbreviated to "sgat" in this driver to * avoid confusion with this driver's name. */ typedef struct sg_iovec { @@ -143,7 +143,7 @@ typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ char req_state; /* 0 -> not used, 1 -> written, 2 -> ready to read */ - char orphan; /* 0 -> normal request, 1 -> from interruped SG_IO */ + char orphan; /* 0 -> normal request, 1 -> from interrupted SG_IO */ char sg_io_owned;/* 0 -> complete with read(), 1 -> owned by SG_IO */ char problem; /* 0 -> no problem detected, 1 -> error to report */ int pack_id; /* pack_id associated with request */ @@ -182,11 +182,13 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ #define SG_CTL_FLAGM_OTHER_OPENS 0x4 /* rd: other sg fd_s on this dev */ #define SG_CTL_FLAGM_ORPHANS 0x8 /* rd: orphaned requests on this fd */ #define SG_CTL_FLAGM_Q_TAIL 0x10 /* used for future cmds on this fd */ -#define SG_CTL_FLAGM_UNSHARE 0x20 /* undo share after inflight cmd */ -#define SG_CTL_FLAGM_MASTER_FINI 0x40 /* share: master finished; 1: finish */ -#define SG_CTL_FLAGM_MASTER_ERR 0x80 /* rd: sharing, master got error */ -#define SG_CTL_FLAGM_CHECK_FOR_MORE 0x100 /* additional ready to read? */ -#define SG_CTL_FLAGM_ALL_BITS 0x1ff /* should be OR of previous items */ +#define SG_CTL_FLAGM_IS_SHARE 0x20 /* rd: fd is master or slave share */ +#define SG_CTL_FLAGM_IS_MASTER 0x40 /* rd: this fd is share master */ +#define SG_CTL_FLAGM_UNSHARE 0x80 /* undo share after inflight cmd */ +#define SG_CTL_FLAGM_MASTER_FINI 0x100 /* share: master finished; 1: finish */ +#define SG_CTL_FLAGM_MASTER_ERR 0x200 /* rd: sharing, master got error */ +#define SG_CTL_FLAGM_CHECK_FOR_MORE 0x400 /* additional ready to read? */ +#define SG_CTL_FLAGM_ALL_BITS 0x7ff /* should be OR of previous items */ /* Write one of the following values to sg_extended_info::read_value, get... */ #define SG_SEIRV_INT_MASK 0x0 /* get SG_SEIM_ALL_BITS */ @@ -194,6 +196,8 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ #define SG_SEIRV_VERS_NUM 0x2 /* get driver version number as int */ #define SG_SEIRV_FL_RQS 0x3 /* number of requests in free list */ #define SG_SEIRV_DEV_FL_RQS 0x4 /* sum of rqs on all fds on this dev */ +#define SG_SEIRV_TRC_SZ 0x5 /* current size of trace buffer */ +#define SG_SEIRV_TRC_MAX_SZ 0x6 /* maximum size of trace buffer */ /* * A pointer to the following structure is passed as the third argument to |