diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2014-08-19 22:35:51 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2014-08-19 22:35:51 +0000 |
commit | a158633e318fd0ccb5358594152739714273f9ee (patch) | |
tree | 4fde4d6ff5bc61d1fd1cdbc31580462a35ce6d84 /examples | |
parent | edb9b7023b9590d882ae7c9c09077b8a53c3814c (diff) | |
download | sg3_utils-a158633e318fd0ccb5358594152739714273f9ee.tar.gz |
examples/sg_tst_async.cpp: allow multiple devices; -M <maxq_p_thr>
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@600 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'examples')
-rw-r--r-- | examples/sg_tst_async.cpp | 328 | ||||
-rw-r--r-- | examples/sgq_dd.c | 64 |
2 files changed, 265 insertions, 127 deletions
diff --git a/examples/sg_tst_async.cpp b/examples/sg_tst_async.cpp index 4ff60ab1..978eba28 100644 --- a/examples/sg_tst_async.cpp +++ b/examples/sg_tst_async.cpp @@ -56,12 +56,13 @@ #include "sg_lib.h" #include "sg_io_linux.h" -static const char * version_str = "1.04 20140712"; +static const char * version_str = "1.05 20140819"; static const char * util_name = "sg_tst_async"; /* This is a test program for checking the async usage of the Linux sg - * driver. Each thread opens 1 file descriptor to the given sg device and - * then starts up to 16 commands while checking with the poll command (or + * driver. Each thread opens 1 file descriptor to the next sg device (1 + * or more can be given on the command line) and then starts up to 16 + * commands while checking with the poll command (or * ioctl(SG_GET_NUM_WAITING) ) for the completion of those commands. Each * command has a unique "pack_id" which is a sequence starting at 1. * Either TEST UNIT UNIT, READ(16) or WRITE(16) commands are issued. @@ -105,8 +106,9 @@ using namespace std::chrono; #define DEF_BLOCKING 0 #define DEF_DIRECT 0 #define DEF_NO_XFER 0 +#define DEF_LBA 1000 -#define Q_PER_FD 16 /* sg driver per file descriptor limit */ +#define MAX_Q_PER_FD 16 /* sg driver per file descriptor limit */ #define MAX_CONSEC_NOMEMS 16 #define URANDOM_DEV "/dev/urandom" @@ -118,7 +120,6 @@ using namespace std::chrono; #endif -#define DEF_LBA 1000 #define EBUFF_SZ 256 @@ -137,12 +138,14 @@ enum blkQDiscipline {BQ_DEFAULT, BQ_AT_HEAD, BQ_AT_TAIL}; enum myQDiscipline {MQD_LOW, MQD_MEDIUM, MQD_HIGH}; struct opts_t { - const char * dev_name; + vector<const char *> dev_names; bool direct; + int maxq_per_thread; int num_per_thread; bool block; uint64_t lba; unsigned int hi_lba; /* last one, inclusive range */ + vector<unsigned int> hi_lbas; /* only used when hi_lba=-1 */ int lb_sz; bool no_xfer; int verbose; @@ -191,11 +194,13 @@ private: static void usage(void) { - printf("Usage: %s [-d] [-f] [-h] [-l <lba+>] [-n <n_per_thr>] [-N]\n" - " [-q 0|1] [-Q 0|1|2] [-R] [-s <lb_sz>]\n" - " [-t <num_thrs>] [-T] [-v] [-V] " - "[-w <wait_ms>]\n" - " [-W] <sg_disk_device>\n", util_name); + printf("Usage: %s [-d] [-f] [-h] [-l <lba+>] [-M <maxq_per_thr>]\n" + " [-n <n_per_thr>] [-N] [-q 0|1] [-Q 0|1|2] " + "[-R]\n" + " [-s <lb_sz>] [-t <num_thrs>] [-T] [-v] " + "[-V]\n" + " [-w <wait_ms>] [-W] <sg_disk_device>*\n", + util_name); printf(" where\n"); printf(" -d do direct_io (def: indirect)\n"); printf(" -f force: any sg device (def: only scsi_debug " @@ -204,7 +209,11 @@ usage(void) printf(" -h print this usage message then exit\n"); printf(" -l <lba> logical block to access (def: %u)\n", DEF_LBA); - printf(" -l <lba,hi_lba> logical block range (inclusive)\n"); + printf(" -l <lba,hi_lba> logical block range (inclusive), if " + "hi_lba=-1\n" + " assume last block on device\n"); + printf(" -M <maxq_per_thr> maximum commands queued per thread " + "(def:%d)\n", MAX_Q_PER_FD); printf(" -n <n_per_thr> number of commands per thread " "(def: %d)\n", DEF_NUM_PER_THREAD); printf(" -N no data xfer (def: xfer on READ and " @@ -224,27 +233,28 @@ usage(void) printf(" -w <wait_ms> >0: poll(<wait_ms>); =0: poll(0); (def: " "%d)\n", DEF_WAIT_MS); printf(" -W do WRITEs (def: TUR)\n\n"); - printf("Multiple threads do READ(16), WRITE(16) or TEST UNIT READY " - "(TUR) SCSI\ncommands. Each thread has its own file descriptor " - "and queues up to\n16 commands. One block is transferred by " - "each READ and WRITE; zeros\nare written. If a logical block " - "range is given, a uniform distribution\ngenerates a pseudo " + printf("Multiple threads send READ(16), WRITE(16) or TEST UNIT READY " + "(TUR) SCSI\ncommands. There can be 1 or more <sg_disk_device>s " + "and each thread takes\nthe next in a round robin fashion. " + "Each thread queues up to 16 commands.\nOne block is transferred " + "by each READ and WRITE; zeros are written. If a\nlogical block " + "range is given, a uniform distribution generates a pseudo\n" "random sequence of LBAs.\n"); } #ifdef __GNUC__ -static int pr2serr(const char * fmt, ...) +static int pr2serr_lk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); -static void pr_errno(int e_no, const char * fmt, ...) +static void pr_errno_lk(int e_no, const char * fmt, ...) __attribute__ ((format (printf, 2, 3))); #else -static int pr2serr(const char * fmt, ...); -static void pr_errno(int e_no, const char * fmt, ...); +static int pr2serr_lk(const char * fmt, ...); +static void pr_errno_lk(int e_no, const char * fmt, ...); #endif static int -pr2serr(const char * fmt, ...) +pr2serr_lk(const char * fmt, ...) { int n; @@ -261,9 +271,9 @@ pr2serr(const char * fmt, ...) } static void -pr_errno(int e_no, const char * fmt, ...) +pr_errno_lk(int e_no, const char * fmt, ...) { - char b[128]; + char b[160]; console_mutex.lock(); { @@ -372,7 +382,7 @@ start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba, this_thread::yield(); continue; } - pr_errno(errno, "%s: %s, pack_id=%d", __func__, np, pack_id); + pr_errno_lk(errno, "%s: %s, pack_id=%d", __func__, np, pack_id); return -1; } return 0; @@ -416,7 +426,7 @@ finish_sg3_cmd(int sg_fd, command2execute cmd2exe, int & pack_id, int wait_ms, sleep(0); // process yield ?? } if (res < 0) { - pr_errno(errno, "%s: %s", __func__, np); + pr_errno_lk(errno, "%s: %s", __func__, np); return -1; } /* now for the error processing */ @@ -427,7 +437,7 @@ finish_sg3_cmd(int sg_fd, command2execute cmd2exe, int & pack_id, int wait_ms, ok = 1; break; case SG_LIB_CAT_RECOVERED: - pr2serr("%s: Recovered error on %s, continuing\n", __func__, np); + pr2serr_lk("%s: Recovered error on %s, continuing\n", __func__, np); ok = 1; break; default: /* won't bother decoding other categories */ @@ -453,7 +463,7 @@ get_aligned_heap(int bytes_at_least) #if 1 int err = posix_memalign(&wp, page_size, n); if (err) { - pr2serr("posix_memalign: error [%d] out of memory?\n", err); + pr2serr_lk("posix_memalign: error [%d] out of memory?\n", err); return NULL; } memset(wp, 0, n); @@ -464,7 +474,7 @@ get_aligned_heap(int bytes_at_least) memset(wp, 0, n); return (unsigned char *)wp; } else { - pr2serr("get_aligned_heap: too fiddly to align, choose smaller " + pr2serr_lk("get_aligned_heap: too fiddly to align, choose smaller " "lb_sz\n"); return NULL; } @@ -485,6 +495,7 @@ work_thread(int id, struct opts_t * op) char ebuff[EBUFF_SZ]; uint64_t lba; unsigned char * lbp; + const char * dev_name; const char * err = NULL; Rand_uint * ruip = NULL; struct pollfd pfd[1]; @@ -492,15 +503,25 @@ work_thread(int id, struct opts_t * op) map<int, unsigned char *> pi_2_buff; map<int, uint64_t> pi_2_lba; - if (op->verbose) - pr2serr("Enter work_thread id=%d\n", id); + n = op->dev_names.size(); + dev_name = op->dev_names[id % n]; + if (op->verbose) { + if ((op->verbose > 1) && op->hi_lba) + pr2serr_lk("Enter work_thread id=%d using %s\n" + " LBA range: 0x%x to 0x%x (inclusive)\n", + id, dev_name, (unsigned int)op->lba, + (UINT_MAX == op->hi_lba) ? op->hi_lbas[id % n] + : op->hi_lba); + else + pr2serr_lk("Enter work_thread id=%d using %s\n", id, dev_name); + } if (! op->block) open_flags |= O_NONBLOCK; - sg_fd = open(op->dev_name, open_flags); + sg_fd = open(dev_name, open_flags); if (sg_fd < 0) { - pr_errno(errno, "%s: id=%d, error opening file: %s", __func__, id, - op->dev_name); + pr_errno_lk(errno, "%s: id=%d, error opening file: %s", __func__, id, + dev_name); return; } pfd[0].fd = sg_fd; @@ -508,8 +529,12 @@ work_thread(int id, struct opts_t * op) if (is_rw && op->hi_lba) { seed = get_urandom_uint(); if (op->verbose > 1) - pr2serr(" id=%d, /dev/urandom seed=0x%x\n", id, seed); - ruip = new Rand_uint((unsigned int)op->lba, op->hi_lba, seed); + pr2serr_lk(" id=%d, /dev/urandom seed=0x%x\n", id, seed); + if (UINT_MAX == op->hi_lba) + ruip = new Rand_uint((unsigned int)op->lba, op->hi_lbas[id % n], + seed); + else + ruip = new Rand_uint((unsigned int)op->lba, op->hi_lba, seed); } sg_flags = 0; @@ -522,14 +547,15 @@ work_thread(int id, struct opts_t * op) if (op->no_xfer) sg_flags |= SG_FLAG_NO_DXFER; if (op->verbose > 1) - pr2serr("sg_flags=0x%x, %s cmds\n", sg_flags, ((SCSI_TUR == op->c2e) ? - "TUR": ((SCSI_READ16 == op->c2e) ? "READ" : "WRITE"))); + pr2serr_lk(" id=%d, sg_flags=0x%x, %s cmds\n", id, sg_flags, + ((SCSI_TUR == op->c2e) ? "TUR": + ((SCSI_READ16 == op->c2e) ? "READ" : "WRITE"))); num = op->num_per_thread; for (k = 0, num_outstanding = 0; (k < num) || num_outstanding; k = do_inc ? k + 1 : k) { do_inc = 0; - if ((num_outstanding < Q_PER_FD) && (k < num)) { + if ((num_outstanding < op->maxq_per_thread) && (k < num)) { do_inc = 1; pack_id = uniq_pack_id.fetch_add(1); if (is_rw) { @@ -549,7 +575,8 @@ work_thread(int id, struct opts_t * op) if (ruip) { lba = ruip->get(); if (op->verbose > 3) - pr2serr(" start IO at lba=0x%" PRIx64 "\n", lba); + pr2serr_lk(" id=%d: start IO at lba=0x%" PRIx64 "\n", + id, lba); } else lba = op->lba; } else @@ -566,7 +593,7 @@ work_thread(int id, struct opts_t * op) pi_2_lba[pack_id] = lba; } num_to_read = 0; - if ((num_outstanding >= Q_PER_FD) || (k >= num)) { + if ((num_outstanding >= op->maxq_per_thread) || (k >= num)) { /* full queue or finished injecting */ num_waiting_read = 0; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting_read) < 0) { @@ -653,8 +680,12 @@ work_thread(int id, struct opts_t * op) if (ruip && (pack_id > 0)) { auto q = pi_2_lba.find(pack_id); - if (q != pi_2_lba.end()) + if (q != pi_2_lba.end()) { + if (op->verbose > 3) + pr2serr_lk(" id=%d: finish IO at lba=0x%" PRIx64 + "\n", id, q->second); pi_2_lba.erase(q); + } } if (err) break; @@ -668,15 +699,15 @@ work_thread(int id, struct opts_t * op) if (err || (k < num)) { if (k < num) - pr2serr("thread id=%d FAILed at iteration %d%s%s\n", id, k, + pr2serr_lk("thread id=%d FAILed at iteration %d%s%s\n", id, k, (err ? ", Reason: " : ""), (err ? err : "")); else - pr2serr("thread id=%d FAILed on last%s%s\n", id, + pr2serr_lk("thread id=%d FAILed on last%s%s\n", id, (err ? ", Reason: " : ""), (err ? err : "")); } n = pi_2_buff.size(); if (n > 0) - pr2serr("thread id=%d Still %d elements in pi_2_buff map on exit\n", + pr2serr_lk("thread id=%d Still %d elements in pi_2_buff map on exit\n", id, n); for (k = 0; ! free_lst.empty(); ++k) { lbp = free_lst.back(); @@ -685,7 +716,7 @@ work_thread(int id, struct opts_t * op) free(lbp); } if ((op->verbose > 2) && (k > 0)) - pr2serr("thread id=%d Maximum number of READ/WRITEs queued: %d\n", + pr2serr_lk("thread id=%d Maximum number of READ/WRITEs queued: %d\n", id, k); async_starts += thr_async_starts; async_finishes += thr_async_finishes; @@ -707,16 +738,13 @@ do_inquiry_prod_id(const char * dev_name, int block, char * b, int b_mlen) {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; unsigned char sense_buffer[64]; - char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; /* O_EXCL | O_RDONLY fails with EPERM */ if (! block) open_flags |= O_NONBLOCK; sg_fd = open(dev_name, open_flags); if (sg_fd < 0) { - snprintf(ebuff, EBUFF_SZ, - "do_inquiry_prod_id: error opening file: %s", dev_name); - perror(ebuff); + pr_errno_lk(errno, "%s: error opening file: %s", __func__, dev_name); return -1; } /* Prepare INQUIRY command */ @@ -736,7 +764,7 @@ do_inquiry_prod_id(const char * dev_name, int block, char * b, int b_mlen) /* pt.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &pt) < 0) { - perror("do_inquiry_prod_id: Inquiry SG_IO ioctl error"); + pr_errno_lk(errno, "%s: Inquiry SG_IO ioctl error", __func__); close(sg_fd); return -1; } @@ -748,11 +776,13 @@ do_inquiry_prod_id(const char * dev_name, int block, char * b, int b_mlen) ok = 1; break; case SG_LIB_CAT_RECOVERED: - fprintf(stderr, "Recovered error on INQUIRY, continuing\n"); + pr2serr_lk("Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ + console_mutex.lock(); sg_chk_n_print3("INQUIRY command error", &pt, 1); + console_mutex.unlock(); break; } if (ok) { @@ -773,6 +803,65 @@ do_inquiry_prod_id(const char * dev_name, int block, char * b, int b_mlen) return ret; } +/* Only allow ranges up to 2**32-1 upper limit, so READ CAPACITY(10) + * sufficient. Return of 0 -> success, -1 -> failure, 2 -> try again */ +static int +do_read_capacity(const char * dev_name, int block, unsigned int * last_lba, + unsigned int * blk_sz) +{ + int res, sg_fd; + unsigned char rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned char rcBuff[64]; + unsigned char sense_b[64]; + sg_io_hdr_t io_hdr; + int open_flags = O_RDWR; /* O_EXCL | O_RDONLY fails with EPERM */ + + if (! block) + open_flags |= O_NONBLOCK; + sg_fd = open(dev_name, open_flags); + if (sg_fd < 0) { + pr_errno_lk(errno, "%s: error opening file: %s", __func__, dev_name); + return -1; + } + /* Prepare READ CAPACITY(10) command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(rcCmdBlk); + io_hdr.mx_sb_len = sizeof(sense_b); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = sizeof(rcBuff); + io_hdr.dxferp = rcBuff; + io_hdr.cmdp = rcCmdBlk; + io_hdr.sbp = sense_b; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */; + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + pr_errno_lk(errno, "%s (SG_IO) error", __func__); + close(sg_fd); + return -1; + } + res = sg_err_category3(&io_hdr); + if (SG_LIB_CAT_UNIT_ATTENTION == res) { + console_mutex.lock(); + sg_chk_n_print3("read capacity", &io_hdr, 1); + console_mutex.unlock(); + close(sg_fd); + return 2; /* probably have another go ... */ + } else if (SG_LIB_CAT_CLEAN != res) { + console_mutex.lock(); + sg_chk_n_print3("read capacity", &io_hdr, 1); + console_mutex.unlock(); + close(sg_fd); + return -1; + } + *last_lba = ((rcBuff[0] << 24) | (rcBuff[1] << 16) | + (rcBuff[2] << 8) | rcBuff[3]); + *blk_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) | + (rcBuff[6] << 8) | rcBuff[7]; + close(sg_fd); + return 0; +} + int main(int argc, char * argv[]) @@ -780,20 +869,19 @@ main(int argc, char * argv[]) int k, n, res; int force = 0; int64_t ll; - unsigned int inq_ebusy_count = 0; int num_threads = DEF_NUM_THREADS; - char b[64]; + char b[128]; struct timespec start_tm, end_tm; struct opts_t opts; struct opts_t * op; const char * cp; op = &opts; - op->dev_name = NULL; op->direct = !! DEF_DIRECT; op->lba = DEF_LBA; op->hi_lba = 0; - op->lb_sz = DEF_LB_SZ;; + op->lb_sz = DEF_LB_SZ; + op->maxq_per_thread = MAX_Q_PER_FD; op->num_per_thread = DEF_NUM_PER_THREAD; op->no_xfer = !! DEF_NO_XFER; op->verbose = 0; @@ -817,20 +905,36 @@ main(int argc, char * argv[]) if ((k < argc) && isdigit(*argv[k])) { ll = sg_get_llnum(argv[k]); if (-1 == ll) { - fprintf(stderr, "could not decode lba\n"); + pr2serr_lk("could not decode lba\n"); return 1; } else op->lba = (uint64_t)ll; cp = strchr(argv[k], ','); if (cp) { - ll = sg_get_llnum(cp + 1); - if ((-1 == ll) || (ll > UINT_MAX)) { - fprintf(stderr, "could not decode hi_lba, or > " - "UINT_MAX\n"); - return 1; - } else - op->hi_lba = (unsigned int)ll; + if (0 == strcmp("-1", cp + 1)) + op->hi_lba = UINT_MAX; + else { + ll = sg_get_llnum(cp + 1); + if ((-1 == ll) || (ll > UINT_MAX)) { + pr2serr_lk("could not decode hi_lba, or > " + "UINT_MAX\n"); + return 1; + } else + op->hi_lba = (unsigned int)ll; + } + } + } else + break; + } else if (0 == memcmp("-M", argv[k], 2)) { + ++k; + if ((k < argc) && isdigit(*argv[k])) { + n = atoi(argv[k]); + if ((n < 1) || (n > MAX_Q_PER_FD)) { + pr2serr_lk("-M expects a value from 1 to %d\n", + MAX_Q_PER_FD); + return 1; } + op->maxq_per_thread = n; } else break; } else if (0 == memcmp("-n", argv[k], 2)) { @@ -849,7 +953,8 @@ main(int argc, char * argv[]) op->bqd = BQ_AT_HEAD; else if (1 == n) op->bqd = BQ_AT_TAIL; - } + } else + break; } else if (0 == memcmp("-Q", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) { @@ -860,7 +965,8 @@ main(int argc, char * argv[]) op->mqd = MQD_MEDIUM; else if (2 == n) op->mqd = MQD_HIGH; - } + } else + break; } else if (0 == memcmp("-R", argv[k], 2)) op->c2e = SCSI_READ16; else if (0 == memcmp("-s", argv[k], 2)) { @@ -904,19 +1010,12 @@ main(int argc, char * argv[]) } else if (0 == memcmp("-W", argv[k], 2)) op->c2e = SCSI_WRITE16; else if (*argv[k] == '-') { - fprintf(stderr, "Unrecognized switch: %s\n", argv[k]); - op->dev_name = NULL; - break; - } - else if (! op->dev_name) - op->dev_name = argv[k]; - else { - cerr << "too many arguments" << endl; - op->dev_name = NULL; - break; - } + pr2serr_lk("Unrecognized switch: %s\n", argv[k]); + return 1; + } else + op->dev_names.push_back(argv[k]); } - if (0 == op->dev_name) { + if (0 == op->dev_names.size()) { usage(); return 1; } @@ -928,34 +1027,59 @@ main(int argc, char * argv[]) try { struct stat a_stat; - if (stat(op->dev_name, &a_stat) < 0) { - perror("stat() on dev_name failed"); - return 1; - } - if (! S_ISCHR(a_stat.st_mode)) { - fprintf(stderr, "%s should be a sg device which is a char " - "device. %s\n", op->dev_name, op->dev_name); - fprintf(stderr, "is not a char device and damage could be done " - "if it is a BLOCK\ndevice, exiting ...\n"); - return 1; - } - if (! force) { - res = do_inquiry_prod_id(op->dev_name, op->block, b, sizeof(b)); - if (res) { - fprintf(stderr, "INQUIRY failed on %s\n", op->dev_name); + for (k = 0; k < (int)op->dev_names.size(); ++k) { + if (stat(op->dev_names[k], &a_stat) < 0) { + snprintf(b, sizeof(b), "could not stat() %s", + op->dev_names[k]); + perror(b); return 1; } - // For safety, since <lba> written to, only permit scsi_debug - // devices. Bypass this with '-f' option. - if (0 != memcmp("scsi_debug", b, 10)) { - fprintf(stderr, "Since this utility may write to LBA 0x%" - PRIx64 ", only devices with the\n" - "product ID 'scsi_debug' accepted. Use '-f' to " - "override.\n", op->lba); - return 2; + if (! S_ISCHR(a_stat.st_mode)) { + pr2serr_lk("%s should be a sg device which is a char " + "device. %s\n", op->dev_names[k], op->dev_names[k]); + pr2serr_lk("is not a char device and damage could be " + "done if it is a BLOCK\ndevice, exiting ...\n"); + return 1; + } + if (! force) { + res = do_inquiry_prod_id(op->dev_names[k], op->block, b, + sizeof(b)); + if (res) { + pr2serr_lk("INQUIRY failed on %s\n", op->dev_names[k]); + return 1; + } + // For safety, since <lba> written to, only permit scsi_debug + // devices. Bypass this with '-f' option. + if (0 != memcmp("scsi_debug", b, 10)) { + pr2serr_lk("Since this utility may write to LBAs, " + "only devices with the\n" + "product ID 'scsi_debug' accepted. Use '-f' " + "to override.\n"); + return 2; + } + } + if (UINT_MAX == op->hi_lba) { + unsigned int last_lba; + unsigned int blk_sz; + + res = do_read_capacity(op->dev_names[k], op->block, + &last_lba, &blk_sz); + if (2 == res) + res = do_read_capacity(op->dev_names[k], op->block, + &last_lba, &blk_sz); + if (res) { + pr2serr_lk("READ CAPACITY(10) failed on %s\n", + op->dev_names[k]); + return 1; + } + op->hi_lbas.push_back(last_lba); + if (blk_sz != (unsigned int)op->lb_sz) + pr2serr_lk(">>> warning: Logical block size (%d) of %s\n" + " differs from command line option (or " + "default)\n", blk_sz, op->dev_names[k]); } - ebusy_count += inq_ebusy_count; } + start_tm.tv_sec = 0; start_tm.tv_nsec = 0; if (clock_gettime(CLOCK_MONOTONIC, &start_tm) < 0) diff --git a/examples/sgq_dd.c b/examples/sgq_dd.c index 55b03c34..380493f7 100644 --- a/examples/sgq_dd.c +++ b/examples/sgq_dd.c @@ -47,7 +47,8 @@ typedef unsigned char u_char; /* horrible, for scsi.h */ */ -static char * version_str = "0.56 20140409"; /* was "0.55 20020509" */ +static char * version_str = "0.57 20140819"; +/* resurrected from "0.55 20020509" */ #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 @@ -144,15 +145,11 @@ static int dd_count = -1; static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio"; -int sg_fin_in_operation(Rq_coll * clp, Rq_elem * rep); -int sg_fin_out_operation(Rq_coll * clp, Rq_elem * rep); -int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks); -int normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks); -int sg_start_io(Rq_elem * rep); -int sg_finish_io(int wr, Rq_elem * rep); +static int sg_finish_io(int wr, Rq_elem * rep); -static void install_handler (int sig_num, void (*sig_handler) (int sig)) +static void +install_handler (int sig_num, void (*sig_handler) (int sig)) { struct sigaction sigact; sigaction (sig_num, NULL, &sigact); @@ -165,7 +162,8 @@ static void install_handler (int sig_num, void (*sig_handler) (int sig)) } } -void print_stats() +static void +print_stats() { int infull, outfull; @@ -177,7 +175,8 @@ void print_stats() fprintf(stderr, "%d+%d records out\n", outfull, rcoll.out_partial); } -static void interrupt_handler(int sig) +static void +interrupt_handler(int sig) { struct sigaction sigact; @@ -190,14 +189,16 @@ static void interrupt_handler(int sig) kill (getpid (), sig); } -static void siginfo_handler(int sig) +static void +siginfo_handler(int sig) { fprintf(stderr, "Progress report, continuing ...\n"); print_stats (); if (sig) { } /* suppress unused warning */ } -int dd_filetype(const char * filename) +static int +dd_filetype(const char * filename) { struct stat st; @@ -212,7 +213,8 @@ int dd_filetype(const char * filename) return FT_OTHER; } -void usage() +static void +usage() { fprintf(stderr, "Usage: " "sgq_dd [if=<infile>] [skip=<n>] [of=<ofile>] [seek=<n>] " @@ -232,7 +234,8 @@ void usage() } /* Returns -1 for error, 0 for nothing found, QS_IN_POLL or QS_OUT_POLL */ -int do_poll(Rq_coll * clp, int timeout, int * req_indexp) +static int +do_poll(Rq_coll * clp, int timeout, int * req_indexp) { int k, res; @@ -277,7 +280,8 @@ int do_poll(Rq_coll * clp, int timeout, int * req_indexp) /* Return of 0 -> success, -1 -> failure, 2 -> try again */ -int read_capacity(int sg_fd, int * num_sect, int * sect_sz) +static int +read_capacity(int sg_fd, int * num_sect, int * sect_sz) { int res; unsigned char rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -319,7 +323,8 @@ int read_capacity(int sg_fd, int * num_sect, int * sect_sz) } /* 0 -> ok, 1 -> short read, -1 -> error */ -int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks) +static int +normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks) { int res; int stop_after_write = 0; @@ -357,7 +362,8 @@ int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks) } /* 0 -> ok, -1 -> error */ -int normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks) +static int +normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks) { int res; @@ -387,7 +393,8 @@ int normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks) } /* Returns 1 for retryable, 0 for ok, -ve for error */ -int sg_fin_in_operation(Rq_coll * clp, Rq_elem * rep) +static int +sg_fin_in_operation(Rq_coll * clp, Rq_elem * rep) { int res; @@ -416,7 +423,8 @@ int sg_fin_in_operation(Rq_coll * clp, Rq_elem * rep) } /* Returns 1 for retryable, 0 for ok, -ve for error */ -int sg_fin_out_operation(Rq_coll * clp, Rq_elem * rep) +static int +sg_fin_out_operation(Rq_coll * clp, Rq_elem * rep) { int res; @@ -443,7 +451,8 @@ int sg_fin_out_operation(Rq_coll * clp, Rq_elem * rep) return res; } -int sg_start_io(Rq_elem * rep) +static int +sg_start_io(Rq_elem * rep) { sg_io_hdr_t * hp = &rep->io_hdr; int res; @@ -491,7 +500,8 @@ int sg_start_io(Rq_elem * rep) } /* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */ -int sg_finish_io(int wr, Rq_elem * rep) +static int +sg_finish_io(int wr, Rq_elem * rep) { int res; sg_io_hdr_t io_hdr; @@ -555,7 +565,8 @@ int sg_finish_io(int wr, Rq_elem * rep) } /* Returns scsi_type or -1 for error */ -int sg_prepare(int fd, int sz) +static int +sg_prepare(int fd, int sz) { int res, t; struct sg_scsi_id info; @@ -584,7 +595,8 @@ int sg_prepare(int fd, int sz) } /* Return 0 for ok, anything else for errors */ -int prepare_rq_elems(Rq_coll * clp, const char * inf, const char * outf) +static int +prepare_rq_elems(Rq_coll * clp, const char * inf, const char * outf) { int k; Rq_elem * rep; @@ -658,7 +670,8 @@ int prepare_rq_elems(Rq_coll * clp, const char * inf, const char * outf) /* Returns a "QS" code and req index, or QS_IDLE and position of first idle (-1 if no idle position). Returns -1 on poll error. */ -int decider(Rq_coll * clp, int first_xfer, int * req_indexp) +static int +decider(Rq_coll * clp, int first_xfer, int * req_indexp) { int k, res; Rq_elem * rep; @@ -705,7 +718,8 @@ int decider(Rq_coll * clp, int first_xfer, int * req_indexp) } -int main(int argc, char * argv[]) +int +main(int argc, char * argv[]) { int skip = 0; int seek = 0; |