diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2019-01-23 16:25:58 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2019-01-23 16:25:58 +0000 |
commit | a918d1a30569c4d3f09cc87836ff19215db6d8b7 (patch) | |
tree | 9d75cdc5dc54583fd103800abbd732e4d1fe5023 /testing/sg_tst_bidi.c | |
parent | e168d3764b642fd96aac1c65f83a64af994ee111 (diff) | |
download | sg3_utils-a918d1a30569c4d3f09cc87836ff19215db6d8b7.tar.gz |
sg_xcopy: add --fco (fast copy only) (spc5r20), implement --app=1 (append) on regular OFILE type; sg_tst_bidi work
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@808 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'testing/sg_tst_bidi.c')
-rw-r--r-- | testing/sg_tst_bidi.c | 176 |
1 files changed, 140 insertions, 36 deletions
diff --git a/testing/sg_tst_bidi.c b/testing/sg_tst_bidi.c index a0b14588..fd5d00c0 100644 --- a/testing/sg_tst_bidi.c +++ b/testing/sg_tst_bidi.c @@ -53,7 +53,7 @@ is implemented by the scsi_debug driver is used. */ -static const char * version_str = "Version: 1.02 20190115"; +static const char * version_str = "Version: 1.03 20190122"; #define INQ_REPLY_LEN 96 #define INQ_CMD_OP 0x12 @@ -90,8 +90,9 @@ usage(void) { printf("Usage: sg_tst_bidi [-b=LB_SZ] [-d=DIO_BLKS] [-D] [-h] -l=LBA [-N] " "[-q=Q_LEN]\n" - " [-Q] [-r=SZ] [-s=SEC] [-t] [-v] [-V] [-w] " - "<sg_device>\n" + " [-Q] [-r=SZ] [-R=RC] [-s=SEC] [-t] [-v] [-V] " + "[-w]\n" + " <sg_or_bsg_device>\n" " where:\n" " -b=LB_SZ logical block size (def: 512 bytes)\n" " -d=DIO_BLKS data in and out length (unit: logical " @@ -102,17 +103,23 @@ usage(void) " -l=LBA logical block address (LDA) of first modded " "block\n" " -N durations in nanoseconds (def: milliseconds)\n" - " -q=Q_LEN queue length, between 1 and 511 (def: 16)\n" + " -q=Q_LEN queue length, between 1 and 511 (def: 16). " + " Calls\n" + " ioctl(SG_IO) when -q=1 else SG_IOSUBMIT " + "(async)\n" " -Q quiet, suppress usual output\n" " -r=SZ reserve buffer size in KB (def: 256 --> 256 " "KB)\n" + " -R=RC repetition count (def: 0)\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 sets DISABLE WRITE bit on cdb to 0 (def: 1)\n\n" "Warning: this test utility writes to location LBA and Q_LEN " - "following\nblocks using the XDWRITEREAD(10) SBC-3 command\n"); + "following\nblocks using the XDWRITEREAD(10) SBC-3 command. " + "When -q=1 does\nioctl(SG_IO) and that is only case when a " + "bsg device can be given.\n"); } static int @@ -153,9 +160,10 @@ main(int argc, char * argv[]) bool nanosecs = false; bool quiet = false; bool disable_write = true; - int k, j, ok, ver_num, pack_id, num_waiting, access_count, din_len; + int k, j, ok, ver_num, pack_id, num_waiting, din_len; int dout_len, cat; int ret = 0; + int rep_count = 0; int sg_fd = -1; int lb_sz = 512; int dio_blks = 1; @@ -175,7 +183,6 @@ main(int argc, char * argv[]) uint8_t * free_doutp = NULL; char ebuff[EBUFF_SZ]; uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN]; - struct sg_scsi_id ssi; for (k = 1; k < argc; ++k) { if (0 == memcmp("-b=", argv[k], 3)) { @@ -230,6 +237,13 @@ main(int argc, char * argv[]) file_name = 0; break; } + } else if (0 == memcmp("-R=", argv[k], 3)) { + rep_count = atoi(argv[k] + 3); + if (rep_count < 0) { + printf("Expect -R= to take a number 0 or higher\n"); + file_name = 0; + break; + } } else if (0 == memcmp("-s=", argv[k], 3)) { sleep_secs = atoi(argv[k] + 3); if (sleep_secs < 0) { @@ -312,14 +326,99 @@ main(int argc, char * argv[]) strerror(errno)); goto out; } - printf("Linux sg driver version: %d\n", ver_num); - if (ext_ioctl(sg_fd, nanosecs)) + if (! quiet) + printf("Linux sg driver version: %d\n", ver_num); + if ((q_len > 1) && ext_ioctl(sg_fd, nanosecs)) goto out; - printf("start write() calls\n"); + + if (1 == q_len) { /* do sync ioct(SG_IO) */ + io_v4p = &io_v4[k]; +rep_sg_io: + memset(io_v4p, 0, sizeof(*io_v4p)); + io_v4p->guard = 'Q'; + if (direct_io) + io_v4p->flags |= SG_FLAG_DIRECT_IO; + if (disable_write) + xdwrrd10_cdb[2] |= 0x4; + sg_put_unaligned_be16(dio_blks, xdwrrd10_cdb + 7); + sg_put_unaligned_be32(lba, xdwrrd10_cdb + 2); + if (verbose > 2) { + pr2serr(" %s cdb: ", "XDWRITE(10)"); + for (j = 0; j < XDWRITEREAD_10_LEN; ++j) + pr2serr("%02x ", xdwrrd10_cdb[j]); + pr2serr("\n"); + } + io_v4p->request_len = XDWRITEREAD_10_LEN; + io_v4p->request = (uint64_t)xdwrrd10_cdb; + io_v4p->din_xfer_len = din_len; + io_v4p->din_xferp = (uint64_t)(dinp + (k * din_len)); + io_v4p->dout_xfer_len = dout_len; + io_v4p->dout_xferp = (uint64_t)(doutp + (k * dout_len)); + io_v4p->response = (uint64_t)sense_buffer[k]; + io_v4p->max_response_len = SENSE_BUFFER_LEN; + io_v4p->timeout = 20000; /* 20000 millisecs == 20 seconds */ + io_v4p->request_extra = 99; /* so pack_id doesn't start at 0 */ + /* default is to queue at head (in SCSI mid level) */ + if (q_at_tail) + io_v4p->flags |= SG_FLAG_Q_AT_TAIL; + else + io_v4p->flags |= SG_FLAG_Q_AT_HEAD; + /* io_v4p->usr_ptr = NULL; */ + + if (ioctl(sg_fd, SG_IO, io_v4p) < 0) { + pr2serr("sg ioctl(SG_IO) errno=%d [%s]\n", errno, + strerror(errno)); + close(sg_fd); + return 1; + } + /* now for the error processing */ + ok = 0; + rio_v4 = *io_v4p; + cat = sg_err_category_new(rio_v4.device_status, + rio_v4.transport_status, + rio_v4.driver_status, + (const uint8_t *)rio_v4.response, + rio_v4.response_len); + switch (cat) { + case SG_LIB_CAT_CLEAN: + ok = 1; + break; + case SG_LIB_CAT_RECOVERED: + printf("Recovered error, continuing\n"); + ok = 1; + break; + default: /* won't bother decoding other categories */ + sg_linux_sense_print(NULL, rio_v4.device_status, + rio_v4.transport_status, + rio_v4.driver_status, + (const uint8_t *)rio_v4.response, + rio_v4.response_len, true); + break; + } + if ((rio_v4.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO) + ++dirio_count; + if (verbose > 3) { + pr2serr(">> din_resid=%d, dout_resid=%d, info=0x%x\n", + rio_v4.din_resid, rio_v4.dout_resid, rio_v4.info); + if (rio_v4.response_len > 0) { + pr2serr("sense buffer: "); + hex2stderr(sense_buffer[k], rio_v4.response_len, -1); + } + } + if ((! quiet) && ok) /* output result if it is available */ + printf("XDWRITEREAD(10) using ioctl(SG_IO) duration=%u\n", + rio_v4.duration); + if (rep_count-- > 0) + goto rep_sg_io; + goto out; + } + +rep_async: + if (! quiet) + printf("start write() calls\n"); for (k = 0; k < q_len; ++k) { io_v4p = &io_v4[k]; - /* Prepare INQUIRY command */ memset(io_v4p, 0, sizeof(*io_v4p)); io_v4p->guard = 'Q'; if (direct_io) @@ -373,28 +472,34 @@ main(int argc, char * argv[]) } } - memset(&ssi, 0, sizeof(ssi)); - if (ioctl(sg_fd, SG_GET_SCSI_ID, &ssi) < 0) - pr2serr("ioctl(SG_GET_SCSI_ID) failed, errno=%d %s\n", - errno, strerror(errno)); - else { - printf("host_no: %d\n", ssi.host_no); - printf(" channel: %d\n", ssi.channel); - printf(" scsi_id: %d\n", ssi.scsi_id); - printf(" lun: %d\n", ssi.lun); - printf(" pdt: %d\n", ssi.scsi_type); - printf(" h_cmd_per_lun: %d\n", ssi.h_cmd_per_lun); - printf(" d_queue_depth: %d\n", ssi.d_queue_depth); +#if 0 + { + struct sg_scsi_id ssi; + + memset(&ssi, 0, sizeof(ssi)); + if (ioctl(sg_fd, SG_GET_SCSI_ID, &ssi) < 0) + pr2serr("ioctl(SG_GET_SCSI_ID) failed, errno=%d %s\n", + errno, strerror(errno)); + else { + printf("host_no: %d\n", ssi.host_no); + printf(" channel: %d\n", ssi.channel); + printf(" scsi_id: %d\n", ssi.scsi_id); + printf(" lun: %d\n", ssi.lun); + printf(" pdt: %d\n", ssi.scsi_type); + printf(" h_cmd_per_lun: %d\n", ssi.h_cmd_per_lun); + printf(" d_queue_depth: %d\n", ssi.d_queue_depth); + } } +#endif 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)); - else + else if (! quiet) printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); - else + else if (! quiet) printf("num_waiting: %d\n", num_waiting); if (sleep_secs > 0) @@ -403,34 +508,31 @@ main(int argc, char * argv[]) 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)); - else + else if (! quiet) printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); - else + else if (! quiet) printf("num_waiting: %d\n", num_waiting); - printf("\nstart read() calls\n"); + if (! quiet) + printf("\nstart read() calls\n"); for (k = 0, done = false; k < q_len; ++k) { if ((! done) && (k == q_len / 2)) { done = true; - printf("\n>>> half way through read\n"); + if (! quiet) + printf("\n>>> half way through read\n"); 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)); - else + else if (! quiet) printf("first available pack_id: %d\n", pack_id); if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0) pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n", errno, strerror(errno)); - else + else if (! quiet) printf("num_waiting: %d\n", num_waiting); - if (ioctl(sg_fd, SG_GET_ACCESS_COUNT, &access_count) < 0) - pr2serr("ioctl(SG_GET_ACCESS_COUNT) failed, errno=%d %s\n", - errno, strerror(errno)); - else - printf("access_count: %d\n", access_count); } memset(&rio_v4, 0, sizeof(struct sg_io_v4)); rio_v4.guard = 'Q'; @@ -486,6 +588,8 @@ main(int argc, char * argv[]) pr2serr("Direct IO requested %d times, done %d times\nMaybe need " "'echo 1 > /proc/scsi/sg/allow_dio'\n", q_len, dirio_count); } + if (rep_count-- > 0) + goto rep_async; ret = 0; out: |