diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2014-07-25 08:03:57 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2014-07-25 08:03:57 +0000 |
commit | 3425de81164083a71e3773fd3a580ae28d394411 (patch) | |
tree | dca259bee1980266dd94079865ea92258eca66d8 /src/sg_write_verify.c | |
parent | 15b98ae2e51c57f419f7f1fdcda25824206a6f54 (diff) | |
download | sg3_utils-3425de81164083a71e3773fd3a580ae28d394411.tar.gz |
sg_write_verify: add --repeat option logic
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@595 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src/sg_write_verify.c')
-rw-r--r-- | src/sg_write_verify.c | 272 |
1 files changed, 181 insertions, 91 deletions
diff --git a/src/sg_write_verify.c b/src/sg_write_verify.c index 8ebb2751..cb5d1e9d 100644 --- a/src/sg_write_verify.c +++ b/src/sg_write_verify.c @@ -33,7 +33,7 @@ #include "sg_pt.h" #include "sg_cmds_basic.h" -static const char * version_str = "1.02 20140721"; +static const char * version_str = "1.02 20140723"; #define ME "sg_write_verify: " @@ -50,16 +50,27 @@ static const char * version_str = "1.02 20140721"; #define DEF_TIMEOUT_SECS 60 +/* Only uncomment the following for testing */ +#define WRITE_FOR_WVERIFY 1 + +#ifdef WRITE_FOR_WVERIFY +#define WRITE10_CMD 0x2a +#define WRITE16_CMD 0x8a + +#warning "<<<TEST>>> version using WRITE cdbs instead of WRITE AND VERIFY" +#endif + static struct option long_options[] = { {"16", no_argument, 0, 'S'}, {"bytchk", required_argument, 0, 'b'}, {"dpo", no_argument, 0, 'd'}, {"group", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, - {"in", required_argument, 0, 'i'}, {"ilen", required_argument, 0, 'I'}, + {"in", required_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"num", required_argument, 0, 'n'}, + {"repeat", no_argument, 0, 'R'}, {"timeout", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, @@ -74,9 +85,10 @@ usage() fprintf(stderr, "Usage: " "sg_write_verify [--16] [--bytchk=BC] [--dpo] [--group=GN] " "[--help]\n" - " [--in=IF] [--ilen=IL] --lba=LBA " + " [--ilen=IL] [--in=IF] --lba=LBA " "[--num=NUM]\n" - " [--timeout=TO] [--verbose] [--version]\n" + " [--repeat] [--timeout=TO] [--verbose] " + "[--version]\n" " [--wrprotect=WPR] DEVICE\n" " where:\n" " --16|-S do WRITE AND VERIFY(16) (default: 10)\n" @@ -84,28 +96,30 @@ usage() " --dpo|-d set DPO bit (default: 0)\n" " --group=GN|-g GN GN is group number (default: 0)\n" " --help|-h print out usage message\n" - " --in=IF|-i IF IF is a file containing the data to " - "be written\n" " --ilen=IL| -I IL input (file) length in bytes, becomes " "data-out\n" " buffer length (def: deduced from IF " "size)\n" + " --in=IF|-i IF IF is a file containing the data to " + "be written\n" " --lba=LBA|-l LBA LBA of the first block to write " "and verify;\n" " no default, must be given\n" " --num=NUM|-n NUM number of logical blocks to write and " "verify\n" + " --repeat|-R while IF still has data to read, send " + "another\n" + " command, bumping LBA with up to NUM " + "blocks again\n" " --timeout=TO|-t TO command timeout in seconds (def: 60)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n" " --wrprotect|-w WPR WPR is the WRPROTECT field value " "(def: 0)\n\n" - "Performs a SCSI WRITE AND VERIFY (10 or 16) command. NUM logical " - "blocks\nstarting at LBA written to DEVICE. Written data is fetched " - "from the IF file\n(of no more than IL bytes). If BC is 0 then a " - "verify takes place (e.g. ECC\nrechecked) after the write. If BC " - "is 1 then additionally data is read back\nand compared with the " - "original data-out buffer (that the DEVICE received).\n" + "Performs a SCSI WRITE AND VERIFY (10 or 16) command on DEVICE, " + "startings\nat LBA for NUM logical blocks. More commands performed " + "only if '--repeat'\noption given. Data to be written is fetched " + "from the IF file.\n" ); } @@ -121,7 +135,11 @@ run_scsi_transaction(int sg_fd, const unsigned char *cdbp, int cdb_len, struct sg_pt_base * ptvp; char b[32]; +#ifdef WRITE_FOR_WVERIFY + snprintf(b, sizeof(b), "Write(%d)", cdb_len); +#else snprintf(b, sizeof(b), "Write and verify(%d)", cdb_len); +#endif if (verbose) { fprintf(stderr, " %s cmd: ", b); for (k = 0; k < cdb_len; ++k) @@ -188,7 +206,11 @@ sg_ll_write_verify10(int sg_fd, int wrprotect, int dpo, int bytchk, unsigned char wv_cdb[WRITE_VERIFY10_CMDLEN]; memset(wv_cdb, 0, WRITE_VERIFY10_CMDLEN); +#ifdef WRITE_FOR_WVERIFY + wv_cdb[0] = WRITE10_CMD; +#else wv_cdb[0] = WRITE_VERIFY10_CMD; +#endif wv_cdb[1] = ((wrprotect & WRPROTECT_MASK) << WRPROTECT_SHIFT); if (dpo) wv_cdb[1] |= 0x10; @@ -219,7 +241,11 @@ sg_ll_write_verify16(int sg_fd, int wrprotect, int dpo, int bytchk, memset(wv_cdb, 0, sizeof(wv_cdb)); +#ifdef WRITE_FOR_WVERIFY + wv_cdb[0] = WRITE16_CMD; +#else wv_cdb[0] = WRITE_VERIFY16_CMD; +#endif wv_cdb[1] = ((wrprotect & WRPROTECT_MASK) << WRPROTECT_SHIFT); if (dpo) wv_cdb[1] |= 0x10; @@ -269,7 +295,7 @@ open_if(const char * fn, int got_stdin) int main(int argc, char * argv[]) { - int sg_fd, res, c, n; + int sg_fd, res, c, n, first_time; unsigned char * wvb = NULL; void * wrkBuff = NULL; int dpo = 0; @@ -280,6 +306,8 @@ main(int argc, char * argv[]) uint64_t llba = 0; int lba_given = 0; uint32_t num_lb = 1; + uint32_t snum_lb = 1; + int repeat = 0; int timeout = DEF_TIMEOUT_SECS; int verbose = 0; int64_t ll; @@ -288,14 +316,15 @@ main(int argc, char * argv[]) const char * ifnp; int has_filename = 0; int ilen = -1; - int wfd = -1; + int ifd = -1; int ret = 1; + int b_p_lb = 512; char cmd_name[32]; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "b:dg:hi:I:l:n:St:w:vV", long_options, + c = getopt_long(argc, argv, "b:dg:hi:I:l:n:RSt:w:vV", long_options, &option_index); if (c == -1) break; @@ -358,6 +387,9 @@ main(int argc, char * argv[]) } num_lb = (uint32_t)n; break; + case 'R': + ++repeat; + break; case 'S': do_16 = 1; given_do_16 = 1; @@ -414,6 +446,26 @@ main(int argc, char * argv[]) usage(); return SG_LIB_SYNTAX_ERROR; } + if (repeat) { + if (! has_filename) { + fprintf(stderr, "with '--repeat' need '--in=IF' option\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + if (ilen < 1) { + fprintf(stderr, "with '--repeat' need '--ilen=ILEN' option\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } else { + b_p_lb = ilen / num_lb; + if (b_p_lb < 64) { + fprintf(stderr, "calculated %d bytes per logical block, " + "too small\n", b_p_lb); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + } + } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { @@ -432,90 +484,128 @@ main(int argc, char * argv[]) fprintf(stderr, "Switching to %s because LBA or NUM too large\n", cmd_name); - //If a file with data to write has been provided - if (has_filename) { - struct stat a_stat; - - if ((1 == strlen(ifnp)) && ('-' == ifnp[0])) { - fprintf(stderr, ME "don't allow stdin for write " - "file\n"); - ret = SG_LIB_FILE_ERROR; - goto err_out; - } - wfd = open_if(ifnp, 0); - if (wfd < 0) { - ret = -wfd; - goto err_out; - } - if (ilen < 1) { - if (fstat(wfd, &a_stat) < 0) { - fprintf(stderr, "Could not fstat(%s)\n", ifnp); - goto err_out; - } - ilen = (int)a_stat.st_size; - if (ilen < 1) { - fprintf(stderr, "%s file size too small\n", ifnp); - goto err_out; - } else if (verbose) - fprintf(stderr, "Using file size of %d bytes\n", ilen); - } - if (NULL == (wrkBuff = malloc(ilen))) { - fprintf(stderr, ME "out of memory\n"); - ret = SG_LIB_CAT_OTHER; - goto err_out; - } - wvb = (unsigned char *)wrkBuff; - - res = read(wfd, wvb, ilen); - if (res < 0) { - fprintf(stderr, "Could not read from %s", ifnp); - goto err_out; - } - - //Check if the amount to write is not bigger than file itself - if (res < ilen) { - fprintf(stderr, "Read only %d bytes (expected %d) from %s\n", - res, ilen, ifnp); - goto err_out; - } - } else { - if (ilen < 1) { - if (verbose) - fprintf(stderr, "Default write length to %d*%d=%d bytes\n", - num_lb, 512, 512 * num_lb); - ilen = 512 * num_lb; - } - if (NULL == (wrkBuff = malloc(ilen))) { - fprintf(stderr, ME "out of memory\n"); - ret = SG_LIB_CAT_OTHER; - goto err_out; - } - wvb = (unsigned char *)wrkBuff; - /* Not sure this is a good idea to default contents to 0xff bytes */ - memset(wrkBuff, 0xff, ilen); - } - if (verbose) { fprintf(stderr, "Issue %s to device %s\n\tilen= %d " "(0x%x), lba=%" PRIu64 " (0x%" PRIx64 ")\n\twrprotect=%d, " - "dpo=%d, bytchk=%d, group=%d\n", cmd_name, device_name, - ilen, ilen, llba, llba, wrprotect, dpo, bytchk, group); + "dpo=%d, bytchk=%d, group=%d, repeat=%d\n", cmd_name, + device_name, ilen, ilen, llba, llba, wrprotect, dpo, bytchk, + group, repeat); } - if (do_16) - res = sg_ll_write_verify16(sg_fd, wrprotect, dpo, bytchk, llba, - num_lb, group, wvb, ilen, timeout, - verbose); - else - res = sg_ll_write_verify10(sg_fd, wrprotect, dpo, bytchk, - (unsigned int)llba, num_lb, group, wvb, - ilen, timeout, verbose); - ret = res; + first_time = 1; + do { + if (first_time) { + //If a file with data to write has been provided + if (has_filename) { + struct stat a_stat; + + if ((1 == strlen(ifnp)) && ('-' == ifnp[0])) { + ifd = STDIN_FILENO; + ifnp = "<stdin>"; + if (verbose > 1) + fprintf(stderr, "Reading input data from stdin\n"); + } else { + ifd = open_if(ifnp, 0); + if (ifd < 0) { + ret = -ifd; + goto err_out; + } + } + if (ilen < 1) { + if (fstat(ifd, &a_stat) < 0) { + fprintf(stderr, "Could not fstat(%s)\n", ifnp); + goto err_out; + } + if (! S_ISREG(a_stat.st_mode)) { + fprintf(stderr, "Cannot determine IF size, please " + "give '--ilen='\n"); + goto err_out; + } + ilen = (int)a_stat.st_size; + if (ilen < 1) { + fprintf(stderr, "%s file size too small\n", ifnp); + goto err_out; + } else if (verbose) + fprintf(stderr, "Using file size of %d bytes\n", ilen); + } + if (NULL == (wrkBuff = malloc(ilen))) { + fprintf(stderr, ME "out of memory\n"); + ret = SG_LIB_CAT_OTHER; + goto err_out; + } + wvb = (unsigned char *)wrkBuff; + res = read(ifd, wvb, ilen); + if (res < 0) { + fprintf(stderr, "Could not read from %s", ifnp); + goto err_out; + } + if (res < ilen) { + fprintf(stderr, "Read only %d bytes (expected %d) from " + "%s\n", res, ilen, ifnp); + if (repeat) + fprintf(stderr, "Will scale subsequent pieces when " + "repeat=1, but this is first\n"); + goto err_out; + } + } else { + if (ilen < 1) { + if (verbose) + fprintf(stderr, "Default write length to %d*%d=%d " + "bytes\n", num_lb, 512, 512 * num_lb); + ilen = 512 * num_lb; + } + if (NULL == (wrkBuff = malloc(ilen))) { + fprintf(stderr, ME "out of memory\n"); + ret = SG_LIB_CAT_OTHER; + goto err_out; + } + wvb = (unsigned char *)wrkBuff; + /* Not sure about this: default contents to 0xff bytes */ + memset(wrkBuff, 0xff, ilen); + } + first_time = 0; + snum_lb = num_lb; + } else { /* repeat=1, first_time=0, must be reading file */ + llba += snum_lb; + res = read(ifd, wvb, ilen); + if (res < 0) { + fprintf(stderr, "Could not read from %s", ifnp); + goto err_out; + } else { + if (verbose > 1) + fprintf(stderr, "Subsequent read from %s got %d bytes\n", + ifnp, res); + if (0 == res) + break; + if (res < ilen) { + snum_lb = (uint32_t)(res / b_p_lb); + n = res % b_p_lb; + if (0 != n) + fprintf(stderr, ">>> warning: ignoring last %d " + "bytes of %s\n", n, ifnp); + if (snum_lb < 1) + break; + } + } + } + if (do_16) + res = sg_ll_write_verify16(sg_fd, wrprotect, dpo, bytchk, llba, + snum_lb, group, wvb, ilen, timeout, + verbose); + else + res = sg_ll_write_verify10(sg_fd, wrprotect, dpo, bytchk, + (unsigned int)llba, snum_lb, group, + wvb, ilen, timeout, verbose); + ret = res; + if (ret || (snum_lb != num_lb)) + break; + } while (repeat); + err_out: if (wrkBuff) free(wrkBuff); - if (wfd >= 0) - close(wfd); + if ((ifd >= 0) && (STDIN_FILENO != ifd)) + close(ifd); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); |