diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2017-09-25 21:57:43 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2017-09-25 21:57:43 +0000 |
commit | 35242f73d10cb0720c59eeb7343d437ff53fb29a (patch) | |
tree | d3a60b32d29909f09b0862be55122826f7df04d6 /src | |
parent | ea54f8e189eb93c93a236b80c8b91c9f93603aa3 (diff) | |
download | sg3_utils-35242f73d10cb0720c59eeb7343d437ff53fb29a.tar.gz |
sg_write_atomic: new utility; sg_opcode: support CDLP (command duration limit page)
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@717 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 10 | ||||
-rw-r--r-- | src/Makefile.in | 33 | ||||
-rw-r--r-- | src/sg_compare_and_write.c | 6 | ||||
-rw-r--r-- | src/sg_get_lba_status.c | 5 | ||||
-rw-r--r-- | src/sg_logs.c | 2 | ||||
-rw-r--r-- | src/sg_opcodes.c | 111 | ||||
-rw-r--r-- | src/sg_sync.c | 4 | ||||
-rw-r--r-- | src/sg_unmap.c | 6 | ||||
-rw-r--r-- | src/sg_verify.c | 6 | ||||
-rw-r--r-- | src/sg_write_atomic.c | 744 | ||||
-rw-r--r-- | src/sg_write_same.c | 8 | ||||
-rw-r--r-- | src/sg_write_verify.c | 6 |
12 files changed, 859 insertions, 82 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index aa62b5b3..1012a78d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,8 +8,8 @@ bin_PROGRAMS = \ sg_reset_wp sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_identify \ sg_sat_phy_event sg_sat_read_gplog sg_sat_set_features sg_senddiag \ sg_ses sg_ses_microcode sg_start sg_stpg sg_sync sg_timestamp \ - sg_turs sg_unmap sg_verify sg_vpd sg_wr_mode sg_write_buffer \ - sg_write_long sg_write_same sg_write_verify sg_zone + sg_turs sg_unmap sg_verify sg_vpd sg_wr_mode sg_write_atomic \ + sg_write_buffer sg_write_long sg_write_same sg_write_verify sg_zone sg_scan_SOURCES = @@ -166,6 +166,10 @@ sg_verify_LDADD = ../lib/libsgutils2.la @os_libs@ sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c sg_vpd_LDADD = ../lib/libsgutils2.la @os_libs@ +sg_wr_mode_LDADD = ../lib/libsgutils2.la @os_libs@ + +sg_write_atomic_LDADD = ../lib/libsgutils2.la @os_libs@ + sg_write_buffer_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_long_LDADD = ../lib/libsgutils2.la @os_libs@ @@ -174,8 +178,6 @@ sg_write_same_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_verify_LDADD = ../lib/libsgutils2.la @os_libs@ -sg_wr_mode_LDADD = ../lib/libsgutils2.la @os_libs@ - sg_xcopy_LDADD = ../lib/libsgutils2.la @os_libs@ sg_zone_LDADD = ../lib/libsgutils2.la @os_libs@ diff --git a/src/Makefile.in b/src/Makefile.in index 915f3568..fcfe1332 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -106,10 +106,10 @@ bin_PROGRAMS = sg_bg_ctl$(EXEEXT) sg_compare_and_write$(EXEEXT) \ sg_start$(EXEEXT) sg_stpg$(EXEEXT) sg_sync$(EXEEXT) \ sg_timestamp$(EXEEXT) sg_turs$(EXEEXT) sg_unmap$(EXEEXT) \ sg_verify$(EXEEXT) sg_vpd$(EXEEXT) sg_wr_mode$(EXEEXT) \ - sg_write_buffer$(EXEEXT) sg_write_long$(EXEEXT) \ - sg_write_same$(EXEEXT) sg_write_verify$(EXEEXT) \ - sg_zone$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) \ - $(am__EXEEXT_3) + sg_write_atomic$(EXEEXT) sg_write_buffer$(EXEEXT) \ + sg_write_long$(EXEEXT) sg_write_same$(EXEEXT) \ + sg_write_verify$(EXEEXT) sg_zone$(EXEEXT) $(am__EXEEXT_1) \ + $(am__EXEEXT_2) $(am__EXEEXT_3) @OS_LINUX_TRUE@am__append_1 = \ @OS_LINUX_TRUE@ sg_copy_results sg_dd sg_emc_trespass sg_map sg_map26 sg_rbuf \ @OS_LINUX_TRUE@ sg_read sg_reset sg_scan sg_test_rwbuf sg_xcopy sginfo sgm_dd sgp_dd @@ -317,6 +317,9 @@ sg_vpd_DEPENDENCIES = ../lib/libsgutils2.la sg_wr_mode_SOURCES = sg_wr_mode.c sg_wr_mode_OBJECTS = sg_wr_mode.$(OBJEXT) sg_wr_mode_DEPENDENCIES = ../lib/libsgutils2.la +sg_write_atomic_SOURCES = sg_write_atomic.c +sg_write_atomic_OBJECTS = sg_write_atomic.$(OBJEXT) +sg_write_atomic_DEPENDENCIES = ../lib/libsgutils2.la sg_write_buffer_SOURCES = sg_write_buffer.c sg_write_buffer_OBJECTS = sg_write_buffer.$(OBJEXT) sg_write_buffer_DEPENDENCIES = ../lib/libsgutils2.la @@ -391,9 +394,10 @@ SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c sg_dd.c \ sg_sat_read_gplog.c sg_sat_set_features.c $(sg_scan_SOURCES) \ sg_senddiag.c sg_ses.c sg_ses_microcode.c sg_start.c sg_stpg.c \ sg_sync.c sg_test_rwbuf.c sg_timestamp.c sg_turs.c sg_unmap.c \ - sg_verify.c $(sg_vpd_SOURCES) sg_wr_mode.c sg_write_buffer.c \ - sg_write_long.c sg_write_same.c sg_write_verify.c sg_xcopy.c \ - sg_zone.c sginfo.c sgm_dd.c sgp_dd.c + sg_verify.c $(sg_vpd_SOURCES) sg_wr_mode.c sg_write_atomic.c \ + sg_write_buffer.c sg_write_long.c sg_write_same.c \ + sg_write_verify.c sg_xcopy.c sg_zone.c sginfo.c sgm_dd.c \ + sgp_dd.c DIST_SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c \ sg_dd.c sg_decode_sense.c sg_emc_trespass.c sg_format.c \ sg_get_config.c sg_get_lba_status.c sg_ident.c \ @@ -408,9 +412,10 @@ DIST_SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c \ $(am__sg_scan_SOURCES_DIST) sg_senddiag.c sg_ses.c \ sg_ses_microcode.c sg_start.c sg_stpg.c sg_sync.c \ sg_test_rwbuf.c sg_timestamp.c sg_turs.c sg_unmap.c \ - sg_verify.c $(sg_vpd_SOURCES) sg_wr_mode.c sg_write_buffer.c \ - sg_write_long.c sg_write_same.c sg_write_verify.c sg_xcopy.c \ - sg_zone.c sginfo.c sgm_dd.c sgp_dd.c + sg_verify.c $(sg_vpd_SOURCES) sg_wr_mode.c sg_write_atomic.c \ + sg_write_buffer.c sg_write_long.c sg_write_same.c \ + sg_write_verify.c sg_xcopy.c sg_zone.c sginfo.c sgm_dd.c \ + sgp_dd.c am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -630,11 +635,12 @@ sg_unmap_LDADD = ../lib/libsgutils2.la @os_libs@ sg_verify_LDADD = ../lib/libsgutils2.la @os_libs@ sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c sg_vpd_LDADD = ../lib/libsgutils2.la @os_libs@ +sg_wr_mode_LDADD = ../lib/libsgutils2.la @os_libs@ +sg_write_atomic_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_buffer_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_long_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_same_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_verify_LDADD = ../lib/libsgutils2.la @os_libs@ -sg_wr_mode_LDADD = ../lib/libsgutils2.la @os_libs@ sg_xcopy_LDADD = ../lib/libsgutils2.la @os_libs@ sg_zone_LDADD = ../lib/libsgutils2.la @os_libs@ all: all-am @@ -944,6 +950,10 @@ sg_wr_mode$(EXEEXT): $(sg_wr_mode_OBJECTS) $(sg_wr_mode_DEPENDENCIES) $(EXTRA_sg @rm -f sg_wr_mode$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_wr_mode_OBJECTS) $(sg_wr_mode_LDADD) $(LIBS) +sg_write_atomic$(EXEEXT): $(sg_write_atomic_OBJECTS) $(sg_write_atomic_DEPENDENCIES) $(EXTRA_sg_write_atomic_DEPENDENCIES) + @rm -f sg_write_atomic$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(sg_write_atomic_OBJECTS) $(sg_write_atomic_LDADD) $(LIBS) + sg_write_buffer$(EXEEXT): $(sg_write_buffer_OBJECTS) $(sg_write_buffer_DEPENDENCIES) $(EXTRA_sg_write_buffer_DEPENDENCIES) @rm -f sg_write_buffer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_write_buffer_OBJECTS) $(sg_write_buffer_LDADD) $(LIBS) @@ -1045,6 +1055,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd_vendor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_wr_mode.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_atomic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_long.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_same.Po@am__quote@ diff --git a/src/sg_compare_and_write.c b/src/sg_compare_and_write.c index 7abb90fe..4520e374 100644 --- a/src/sg_compare_and_write.c +++ b/src/sg_compare_and_write.c @@ -53,7 +53,7 @@ #include "sg_unaligned.h" #include "sg_pr2serr.h" -static const char * version_str = "1.15 20160217"; +static const char * version_str = "1.16 20170924"; #define DEF_BLOCK_SIZE 512 #define DEF_NUM_BLOCKS (1) @@ -203,9 +203,9 @@ parse_args(int argc, char* argv[], struct opts_t * op) case 'g': op->flags.group = sg_get_num(optarg); if ((op->flags.group < 0) || - (op->flags.group > 31)) { + (op->flags.group > 63)) { pr2serr("argument to '--group' expected to " - "be 0 to 31\n"); + "be 0 to 63\n"); goto out_err_no_usage; } break; diff --git a/src/sg_get_lba_status.c b/src/sg_get_lba_status.c index de253ba0..88da0214 100644 --- a/src/sg_get_lba_status.c +++ b/src/sg_get_lba_status.c @@ -30,7 +30,7 @@ * device. */ -static const char * version_str = "1.10 20170917"; +static const char * version_str = "1.11 20170921"; #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) @@ -303,10 +303,11 @@ main(int argc, char * argv[]) goto free_buff; } + res = 0; if (do_16) res = sg_ll_get_lba_status16(sg_fd, lba, rt, glbasBuffp, maxlen, true, verbose); - else + else if (do_32) /* keep analyser happy since do_32 must be true */ res = sg_ll_get_lba_status32(sg_fd, lba, element_id, scan_len, rt, glbasBuffp, maxlen, true, verbose); diff --git a/src/sg_logs.c b/src/sg_logs.c index 272551be..3666d4c8 100644 --- a/src/sg_logs.c +++ b/src/sg_logs.c @@ -3038,7 +3038,7 @@ show_ie_page(const uint8_t * resp, int len, const struct opts_t * op) sg_get_unaligned_be32(bp + 12), sg_get_unaligned_be32(bp + 16), cp); - decoded = true; + /* decoded = true; */ } else if ((! decoded) && full) { printf(" parameter code = 0x%x, contents in hex:\n", pc); dStrHex((const char *)bp, extra, 1); diff --git a/src/sg_opcodes.c b/src/sg_opcodes.c index 01a92ec8..5739f394 100644 --- a/src/sg_opcodes.c +++ b/src/sg_opcodes.c @@ -30,7 +30,7 @@ #include "sg_pt.h" -static const char * version_str = "0.49 20170917"; /* spc5r10 */ +static const char * version_str = "0.50 20170922"; /* spc5r10 */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ @@ -49,24 +49,25 @@ static const char * version_str = "0.49 20170917"; /* spc5r10 */ static int peri_dtype = -1; /* ugly but not easy to pass to alpha compare */ static struct option long_options[] = { - {"alpha", 0, 0, 'a'}, - {"compact", 0, 0, 'c'}, - {"enumerate", 0, 0, 'e'}, - {"help", 0, 0, 'h'}, - {"hex", 0, 0, 'H'}, - {"mask", 0, 0, 'm'}, - {"no-inquiry", 0, 0, 'n'}, - {"new", 0, 0, 'N'}, - {"opcode", 1, 0, 'o'}, - {"old", 0, 0, 'O'}, - {"raw", 0, 0, 'r'}, - {"rctd", 0, 0, 'R'}, + {"alpha", no_argument, 0, 'a'}, + {"compact", no_argument, 0, 'c'}, + {"enumerate", no_argument, 0, 'e'}, + {"help", no_argument, 0, 'h'}, + {"hex", no_argument, 0, 'H'}, + {"mask", no_argument, 0, 'm'}, + {"no-inquiry", no_argument, 0, 'n'}, + {"new", no_argument, 0, 'N'}, + {"opcode", required_argument, 0, 'o'}, + {"old", no_argument, 0, 'O'}, + {"pdt", required_argument, 0, 'p'}, + {"raw", no_argument, 0, 'r'}, + {"rctd", no_argument, 0, 'R'}, {"repd", 0, 0, 'q'}, - {"sa", 1, 0, 's'}, - {"tmf", 0, 0, 't'}, - {"unsorted", 0, 0, 'u'}, - {"verbose", 0, 0, 'v'}, - {"version", 0, 0, 'V'}, + {"sa", required_argument, 0, 's'}, + {"tmf", no_argument, 0, 't'}, + {"unsorted", no_argument, 0, 'u'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; @@ -644,7 +645,7 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, { int k, j, m, cd_len, serv_act, len, opcode, res; bool sa_v; - unsigned int to; + unsigned int timeout; unsigned char * bp; char name_buff[NAME_BUFF_SZ]; char sa_buff[8]; @@ -660,7 +661,7 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, printf("sg_opcodes: no commands to display\n"); return; } - if (op->do_rctd) { + if (op->do_rctd) { /* Return command timeout descriptor */ if (op->do_compact) { printf("\nOpcode,sa Nominal Recommended Name\n"); printf( " (hex) timeout timeout(sec) \n"); @@ -672,14 +673,14 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, printf("-------------------------------------------------------" "---------\n"); } - } else { + } else { /* RCTD clear in cdb */ if (op->do_compact) { printf("\nOpcode,sa Name\n"); printf( " (hex) \n"); printf("---------------------------------------\n"); } else { - printf("\nOpcode Service CDB Name\n"); - printf( "(hex) action(h) size \n"); + printf("\nOpcode Service CDB CDLP Name\n"); + printf( "(hex) action(h) size \n"); printf("-----------------------------------------------\n"); } } @@ -719,25 +720,26 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, memset(sa_buff, ' ', sizeof(sa_buff)); } if (op->do_rctd) { - if (bp[5] & 0x2) { + if (bp[5] & 0x2) { /* CTDP set */ + /* don't show CDLP because it makes line too long */ if (op->do_compact) printf(" %.2x%c%.4s", opcode, (sa_v ? ',' : ' '), sa_buff); else printf(" %.2x %.4s %3d", opcode, sa_buff, sg_get_unaligned_be16(bp + 6)); - to = sg_get_unaligned_be32(bp + 12); - if (0 == to) + timeout = sg_get_unaligned_be32(bp + 12); + if (0 == timeout) printf(" -"); else - printf(" %8u", to); - to = sg_get_unaligned_be32(bp + 16); - if (0 == to) + printf(" %8u", timeout); + timeout = sg_get_unaligned_be32(bp + 16); + if (0 == timeout) printf(" -"); else - printf(" %8u", to); + printf(" %8u", timeout); printf(" %s\n", name_buff); - } else + } else /* CTDP clear */ if (op->do_compact) printf(" %.2x%c%.4s %s\n", opcode, (sa_v ? ',' : ' '), sa_buff, name_buff); @@ -745,13 +747,15 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, printf(" %.2x %.4s %3d " "%s\n", opcode, sa_buff, sg_get_unaligned_be16(bp + 6), name_buff); - } else + } else { /* RCTD clear in cdb */ if (op->do_compact) printf(" %.2x%c%.4s %s\n", bp[0], (sa_v ? ',' : ' '), sa_buff, name_buff); else - printf(" %.2x %.4s %3d %s\n", bp[0], sa_buff, - sg_get_unaligned_be16(bp + 6), name_buff); + printf(" %.2x %.4s %3d %2d %s\n", bp[0], + sa_buff, sg_get_unaligned_be16(bp + 6), + (*(bp + 5) >> 2) & 0x3, name_buff); + } if (op->do_mask) { int cdb_sz; unsigned char b[64]; @@ -778,10 +782,10 @@ list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, } static void -decode_cmd_to_descriptor(unsigned char * dp, int max_b_len, char * b) +decode_cmd_timeout_desc(unsigned char * dp, int max_b_len, char * b) { int len; - unsigned int to; + unsigned int timeout; if ((max_b_len < 2) || (NULL == dp)) return; @@ -793,22 +797,23 @@ decode_cmd_to_descriptor(unsigned char * dp, int max_b_len, char * b) "(expect 10)", len); return; } - to = sg_get_unaligned_be32(dp + 4); - if (0 == to) + timeout = sg_get_unaligned_be32(dp + 4); + if (0 == timeout) snprintf(b, max_b_len, "no nominal timeout, "); else - snprintf(b, max_b_len, "nominal timeout: %u secs, ", to); + snprintf(b, max_b_len, "nominal timeout: %u secs, ", timeout); len = strlen(b); max_b_len -= len; b += len; - to = sg_get_unaligned_be32(dp + 8); - if (0 == to) + timeout = sg_get_unaligned_be32(dp + 8); + if (0 == timeout) snprintf(b, max_b_len, "no recommended timeout"); else - snprintf(b, max_b_len, "recommended timeout: %u secs", to); + snprintf(b, max_b_len, "recommended timeout: %u secs", timeout); return; } +/* One command descriptor (includes cdb usage data) */ static void list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, struct opts_t * op) @@ -817,6 +822,7 @@ list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, char name_buff[NAME_BUFF_SZ]; unsigned char * bp; const char * cp; + const char * dlp; int v = 0; @@ -828,7 +834,7 @@ list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, ((op->servact > 0) ? op->servact : 0), peri_dtype, NAME_BUFF_SZ, name_buff); printf(" Command_name: %s\n", name_buff); - switch((int)(rsoc_buff[1] & 7)) { + switch((int)(rsoc_buff[1] & 7)) { /* SUPPORT field */ case 0: cp = "not currently available"; break; @@ -849,7 +855,22 @@ list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, cp = name_buff; break; } - printf(" Command %s\n", cp); + k = 0x3 & (rsoc_buff[1] >> 3); + switch (k) { /* CDLP field */ + case 0: + dlp = "no command duration limit mode page"; + break; + case 1: + dlp = "command duration limit A mode page"; + break; + case 2: + dlp = "command duration limit B mode page"; + break; + default: + dlp = "reserved [CDLP=3]"; + break; + } + printf(" Command %s, [%s]\n", cp, dlp); if (v) { printf(" Usage data: "); bp = rsoc_buff + 4; @@ -859,7 +880,7 @@ list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, } if (0x80 & rsoc_buff[1]) { /* CTDP */ bp = rsoc_buff + 4 + cd_len; - decode_cmd_to_descriptor(bp, NAME_BUFF_SZ, name_buff); + decode_cmd_timeout_desc(bp, NAME_BUFF_SZ, name_buff); printf(" %s\n", name_buff); } } diff --git a/src/sg_sync.c b/src/sg_sync.c index ae655868..57d44f45 100644 --- a/src/sg_sync.c +++ b/src/sg_sync.c @@ -27,7 +27,7 @@ * (e.g. disks). */ -static const char * version_str = "1.16 20170917"; +static const char * version_str = "1.16 20170924"; #define SYNCHRONIZE_CACHE16_CMD 0x91 #define SYNCHRONIZE_CACHE16_CMDLEN 16 @@ -172,7 +172,7 @@ int main(int argc, char * argv[]) break; case 'g': group = sg_get_num(optarg); - if ((group < 0) || (group > 31)) { + if ((group < 0) || (group > 63)) { pr2serr("bad argument to '--group'\n"); return SG_LIB_SYNTAX_ERROR; } diff --git a/src/sg_unmap.c b/src/sg_unmap.c index 9e7a28f9..399a3c1f 100644 --- a/src/sg_unmap.c +++ b/src/sg_unmap.c @@ -32,7 +32,7 @@ * logical blocks. */ -static const char * version_str = "1.11 20170917"; +static const char * version_str = "1.11 20170924"; #define DEF_TIMEOUT_SECS 60 @@ -355,10 +355,10 @@ main(int argc, char * argv[]) break; case 'g': num = sscanf(optarg, "%d", &res); - if ((1 == num) && (res >= 0) && (res <= 31)) + if ((1 == num) && (res >= 0) && (res <= 63)) grpnum = res; else { - pr2serr("value for '--grpnum=' must be 0 to 31\n"); + pr2serr("value for '--grpnum=' must be 0 to 63\n"); return SG_LIB_SYNTAX_ERROR; } break; diff --git a/src/sg_verify.c b/src/sg_verify.c index 47c3d8c3..80eb566b 100644 --- a/src/sg_verify.c +++ b/src/sg_verify.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2015 Douglas Gilbert. + * Copyright (c) 2004-2017 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. @@ -34,7 +34,7 @@ * the possibility of protection data (DIF). */ -static const char * version_str = "1.21 20140516"; /* sbc4r01 */ +static const char * version_str = "1.22 20170924"; /* sbc4r01 */ #define ME "sg_verify: " @@ -185,7 +185,7 @@ main(int argc, char * argv[]) break; case 'g': group = sg_get_num(optarg); - if ((group < 0) || (group > 31)) { + if ((group < 0) || (group > 63)) { pr2serr("bad argument to '--group'\n"); return SG_LIB_SYNTAX_ERROR; } diff --git a/src/sg_write_atomic.c b/src/sg_write_atomic.c new file mode 100644 index 00000000..740c98e1 --- /dev/null +++ b/src/sg_write_atomic.c @@ -0,0 +1,744 @@ +/* + * Copyright (c) 2017 Douglas Gilbert. + * All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the BSD_LICENSE file. + */ + +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <getopt.h> +#define __STDC_FORMAT_MACROS 1 +#include <inttypes.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "sg_lib.h" +#include "sg_pt.h" +#include "sg_cmds_basic.h" +#include "sg_cmds_extra.h" +#include "sg_unaligned.h" +#include "sg_pr2serr.h" + +static const char * version_str = "1.00 20170924"; + + +#define ME "sg_write_atomic: " + +#define WRITE_ATOMIC16_OP 0x9c +#define WRITE_16_OP 0x8a +#define VARIABLE_LEN_OP 0x7f +#define WRITE_ATOMIC32_SA 0xf +#define WRITE_32_SA 0xb +#define WRITE_ATOMIC32_ADD 0x18 +#define WRITE_32_ADD 0x18 +#define WRITE_ATOMIC16_LEN 16 +#define WRITE_ATOMIC32_LEN 32 +#define WRITE_16_LEN 16 +#define WRITE_32_LEN 32 +#define RCAP10_RESP_LEN 8 +#define RCAP16_RESP_LEN 32 +#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ +#define DEF_TIMEOUT_SECS 120 /* might need more for large NUM */ +#define DEF_WA_CDB_SIZE WRITE_ATOMIC16_LEN +#define DEF_WA_NUMBLOCKS 0 /* do nothing; for safety */ +#define MAX_XFER_LEN (64 * 1024) +#define EBUFF_SZ 256 + +#ifndef UINT32_MAX +#define UINT32_MAX ((uint32_t)-1) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX ((uint16_t)-1) +#endif + +static struct option long_options[] = { + {"16", no_argument, 0, 'S'}, + {"32", no_argument, 0, 'T'}, + {"app-tag", required_argument, 0, 'a'}, + {"app_tag", required_argument, 0, 'a'}, + {"boundary", required_argument, 0, 'B'}, + {"bs", required_argument, 0, 'b'}, + {"dld", required_argument, 0, 'D'}, + {"dpo", no_argument, 0, 'd'}, + {"fua", no_argument, 0, 'f'}, + {"grpnum", required_argument, 0, 'g'}, + {"help", no_argument, 0, 'h'}, + {"in", required_argument, 0, 'i'}, + {"lba", required_argument, 0, 'l'}, + {"non-atomic", no_argument, 0, 'N'}, + {"non_atomic", no_argument, 0, 'N'}, + {"num", required_argument, 0, 'n'}, + {"offset", required_argument, 0, 'o'}, + {"ref-tag", required_argument, 0, 'r'}, + {"ref_tag", required_argument, 0, 'r'}, + {"strict", no_argument, 0, 's'}, + {"tag-mask", required_argument, 0, 'M'}, + {"tag_mask", required_argument, 0, 'M'}, + {"timeout", required_argument, 0, 't'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"wrprotect", required_argument, 0, 'w'}, + {0, 0, 0, 0}, +}; + +struct opts_t { + bool do_16; + bool do_32; + bool non_atomic; + bool strict; + uint16_t app_tag; + uint16_t atomic_boundary; + uint32_t bs; /* 0 implies use READ CAPACITY(10 or 16) */ + int dld; /* only used by WRITE(16) [why not WRITE(32) ?] */ + bool dpo; + bool fua; + int grpnum; + const char * ifilename; + uint64_t lba; + uint32_t numblocks; + uint64_t offset; + uint32_t ref_tag; + uint16_t tag_mask; + int timeout; + int verbose; + int wrprotect; + ssize_t xfer_bytes; /* derived value: bs*numblocks */ +}; + + + +static void +usage() +{ + pr2serr("Usage: sg_write_atomic [--16] [--32] [--app-tag=AT] " + "[--boundary=AB]\n" + " [--bs=LBS] [--dld=DLD] [--dpo] " + "[--fua] " + "[--grpnum=GN]\n" + " [--help] --in=IF [--lba=LBA] " + "[--non-atomic] [--num=NUM]\n" + " [--offset=OFF] [--ref-tag=RT] " + "[--strict]\n" + " [--tag-mask=TM] [--timeout=TO] " + "[--verbose] [--version]\n" + " [--wrprotect=WRP] DEVICE\n" + " where:\n" + " --16|-S send WRITE ATOMIC(16) or WRITE(16) " + "(default)\n" + " --32|-T send WRITE ATOMIC(32) or WRITE(32)\n" + " --app-tag=AT|-a AT set expected application tag field " + "in 32 cdb\n" + " --boundary=AB|-B AB set atomic boundary field\n" + " --bs=LBS|-b LBS logical block size (def: use READ " + "CAPACITY)\n" + " --dld=DLD|-D DLD set duration limit descriptor (dld) " + "(def: 0)\n" + " --dpo|-d set DPO (disable page out) field " + "(def: clear)\n" + " --fua|-f set FUA (force unit access) field " + "(def: clear)\n" + " --grpnum=GN|-g GN GN is group number field (def: 0)\n" + " --help|-h print out usage message\n" + " --in=IF|-i IF IF is file to fetch NUM blocks of " + "data from.\n" + " Blocks written to DEVICE\n" + " --lba=LBA|-l LBA LBA is the logical block address to " + "start (def: 0)\n" + " --non-atomic|-N do normal WRITE(16) or WRITE(32) " + "(def: send\n" + " WRITE ATOMIC(16 or 32)\n" + " --num=NUM|-n NUM NUM is number of logical blocks to " + "write (def: 0)\n" + " --offset=OFF|-o OFF byte offset in IF to start reading " + "from\n" + " --ref-tag=RT|-r RT set expected reference tag field in " + "32 byte cdb\n" + " --strict|-s exit if read less than requested from " + "IF\n" + " --tag-mask=TM|-M TM set tag mask field in 32 byte cdb\n" + " --timeout=TO|-t TO command timeout (unit: seconds) (def: " + "120)\n" + " --verbose|-v increase verbosity\n" + " --version|-V print version string then exit\n" + " --wrprotect=WPR|-w WPR WPR is the WRPROTECT field value " + "(def: 0)\n\n" + "Performs a SCSI WRITE ATOMIC (16 or 32) command. The --in=IF " + "option is\nrequired. If --non-atomic option is given then " + "normal WRITE(16 or 32)\nis performed. The --num=NUM field " + "defaults to 0 (do nothing) for safety.\n" + ); +} + +static int +do_write_atomic(int sg_fd, const struct opts_t * op, const void * dataoutp) +{ + int k, ret, res, sense_cat, cdb_len; + unsigned char wa_cdb[WRITE_ATOMIC32_LEN]; + unsigned char sense_b[SENSE_BUFF_LEN]; + struct sg_pt_base * ptvp; + + cdb_len = op->do_16 ? WRITE_ATOMIC16_LEN : WRITE_ATOMIC32_LEN; + if (WRITE_ATOMIC16_LEN == cdb_len) { + if (op->numblocks > UINT16_MAX) { + pr2serr("Need WRITE ATOMIC(32) since blocks exceed 65535\n"); + return -1; + } + } + memset(wa_cdb, 0, sizeof(wa_cdb)); + switch (cdb_len) { + case WRITE_ATOMIC16_LEN: + wa_cdb[0] = WRITE_ATOMIC16_OP; + wa_cdb[1] = ((op->wrprotect & 0x7) << 5); + if (op->dpo) + wa_cdb[1] |= 0x10; + if (op->fua) + wa_cdb[1] |= 0x8; + sg_put_unaligned_be64(op->lba, wa_cdb + 2); + sg_put_unaligned_be16(op->atomic_boundary, wa_cdb + 10); + sg_put_unaligned_be16((uint16_t)op->numblocks, wa_cdb + 12); + wa_cdb[14] = (op->grpnum & 0x1f); + break; + case WRITE_ATOMIC32_LEN: + wa_cdb[0] = VARIABLE_LEN_OP; + sg_put_unaligned_be16(op->atomic_boundary, wa_cdb + 4); + wa_cdb[6] = (op->grpnum & 0x1f); + wa_cdb[7] = WRITE_ATOMIC32_ADD; + sg_put_unaligned_be16((uint16_t)WRITE_ATOMIC32_SA, wa_cdb + 8); + wa_cdb[10] = ((op->wrprotect & 0x7) << 5); + if (op->dpo) + wa_cdb[10] |= 0x10; + if (op->fua) + wa_cdb[10] |= 0x8; + sg_put_unaligned_be64(op->lba, wa_cdb + 12); + sg_put_unaligned_be32(op->ref_tag, wa_cdb + 20); + sg_put_unaligned_be16(op->app_tag, wa_cdb + 24); + sg_put_unaligned_be16(op->tag_mask, wa_cdb + 26); + sg_put_unaligned_be32(op->numblocks, wa_cdb + 28); + break; + default: + pr2serr("do_write_atomic: bad cdb length %d\n", cdb_len); + return -1; + } + + if (op->verbose > 1) { + pr2serr(" Write atomic(%d) cdb: ", cdb_len); + for (k = 0; k < cdb_len; ++k) + pr2serr("%02x ", wa_cdb[k]); + pr2serr("\n"); + } + if ((op->verbose > 3) && (op->xfer_bytes > 0)) { + pr2serr(" Data-out buffer contents:\n"); + dStrHexErr((const char *)dataoutp, op->xfer_bytes, 1); + } + ptvp = construct_scsi_pt_obj(); + if (NULL == ptvp) { + pr2serr("Write atomic(%d): out of memory\n", cdb_len); + return -1; + } + set_scsi_pt_cdb(ptvp, wa_cdb, cdb_len); + set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); + set_scsi_pt_data_out(ptvp, (unsigned char *)dataoutp, op->xfer_bytes); + res = do_scsi_pt(ptvp, sg_fd, op->timeout, op->verbose); + ret = sg_cmds_process_resp(ptvp, "Write atomic", res, 0, sense_b, + true /*noisy */, op->verbose, &sense_cat); + if (-1 == ret) + ; + else if (-2 == ret) { + switch (sense_cat) { + case SG_LIB_CAT_RECOVERED: + case SG_LIB_CAT_NO_SENSE: + ret = 0; + break; + case SG_LIB_CAT_MEDIUM_HARD: + { + int valid, slen; + uint64_t ull = 0; + + slen = get_scsi_pt_sense_len(ptvp); + valid = sg_get_sense_info_fld(sense_b, slen, &ull); + if (valid) + pr2serr("Medium or hardware error starting at lba=%" + PRIu64 " [0x%" PRIx64 "]\n", ull, ull); + } + ret = sense_cat; + break; + default: + ret = sense_cat; + break; + } + } else + ret = 0; + + destruct_scsi_pt_obj(ptvp); + return ret; +} + +static int +do_write_normal(int sg_fd, const struct opts_t * op, const void * dataoutp) +{ + int k, ret, res, sense_cat, cdb_len; + unsigned char wr_cdb[WRITE_32_LEN]; + unsigned char sense_b[SENSE_BUFF_LEN]; + struct sg_pt_base * ptvp; + + cdb_len = op->do_16 ? WRITE_16_LEN : WRITE_32_LEN; + if (WRITE_16_LEN == cdb_len) { + if (op->numblocks > UINT16_MAX) { + pr2serr("Need WRITE(32) since blocks exceed 65535\n"); + return -1; + } + } + memset(wr_cdb, 0, sizeof(wr_cdb)); + switch (cdb_len) { + case WRITE_16_LEN: + wr_cdb[0] = WRITE_16_OP; + wr_cdb[1] = ((op->wrprotect & 0x7) << 5); + if (op->dpo) + wr_cdb[1] |= 0x10; + if (op->fua) + wr_cdb[1] |= 0x8; + if (op->dld) { + if (op->dld & 1) + wr_cdb[14] |= 0x40; + if (op->dld & 2) + wr_cdb[14] |= 0x80; + if (op->dld & 4) + wr_cdb[1] |= 0x1; + } + sg_put_unaligned_be64(op->lba, wr_cdb + 2); + sg_put_unaligned_be32(op->numblocks, wr_cdb + 10); + wr_cdb[14] = (op->grpnum & 0x1f); + break; + case WRITE_32_LEN: + wr_cdb[0] = VARIABLE_LEN_OP; + wr_cdb[6] = (op->grpnum & 0x1f); + wr_cdb[7] = WRITE_32_ADD; + sg_put_unaligned_be16((uint16_t)WRITE_32_SA, wr_cdb + 8); + wr_cdb[10] = ((op->wrprotect & 0x7) << 5); + if (op->dpo) + wr_cdb[10] |= 0x10; + if (op->fua) + wr_cdb[10] |= 0x8; + sg_put_unaligned_be64(op->lba, wr_cdb + 12); + sg_put_unaligned_be32(op->ref_tag, wr_cdb + 20); + sg_put_unaligned_be16(op->app_tag, wr_cdb + 24); + sg_put_unaligned_be16(op->tag_mask, wr_cdb + 26); + sg_put_unaligned_be32(op->numblocks, wr_cdb + 28); + break; + default: + pr2serr("%s: bad cdb length %d\n", __func__, cdb_len); + return -1; + } + + if (op->verbose > 1) { + pr2serr(" Write(%d) cdb: ", cdb_len); + for (k = 0; k < cdb_len; ++k) + pr2serr("%02x ", wr_cdb[k]); + pr2serr("\n"); + } + if ((op->verbose > 3) && (op->xfer_bytes > 0)) { + pr2serr(" Data-out buffer contents:\n"); + dStrHexErr((const char *)dataoutp, op->xfer_bytes, 1); + } + ptvp = construct_scsi_pt_obj(); + if (NULL == ptvp) { + pr2serr("Write(%d): out of memory\n", cdb_len); + return -1; + } + set_scsi_pt_cdb(ptvp, wr_cdb, cdb_len); + set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); + set_scsi_pt_data_out(ptvp, (unsigned char *)dataoutp, op->xfer_bytes); + res = do_scsi_pt(ptvp, sg_fd, op->timeout, op->verbose); + ret = sg_cmds_process_resp(ptvp, "Write", res, 0, sense_b, + true /*noisy */, op->verbose, &sense_cat); + if (-1 == ret) + ; + else if (-2 == ret) { + switch (sense_cat) { + case SG_LIB_CAT_RECOVERED: + case SG_LIB_CAT_NO_SENSE: + ret = 0; + break; + case SG_LIB_CAT_MEDIUM_HARD: + { + int valid, slen; + uint64_t ull = 0; + + slen = get_scsi_pt_sense_len(ptvp); + valid = sg_get_sense_info_fld(sense_b, slen, &ull); + if (valid) + pr2serr("Medium or hardware error starting at lba=%" + PRIu64 " [0x%" PRIx64 "]\n", ull, ull); + } + ret = sense_cat; + break; + default: + ret = sense_cat; + break; + } + } else + ret = 0; + + destruct_scsi_pt_obj(ptvp); + return ret; +} + + +int +main(int argc, char * argv[]) +{ + int c, j, prot_en, vb; + ssize_t res; + int sg_fd = -1; + int infd = -1; + bool got_stdin = false; + int64_t ll; + const char * device_name = NULL; + char ebuff[EBUFF_SZ]; + char b[80]; + unsigned char resp_buff[RCAP16_RESP_LEN]; + unsigned char * wBuff = NULL; + int ret = -1; + struct opts_t opts; + struct opts_t * op; + + op = &opts; + memset(op, 0, sizeof(opts)); + op->numblocks = DEF_WA_NUMBLOCKS; + op->timeout = DEF_TIMEOUT_SECS; + + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "a:b:B:dD:fg:hi:l:M:n:No:r:sSt:TvVw:", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'a': + j = sg_get_num(optarg); + if ((j < 0) || (j > UINT16_MAX)) { + pr2serr("bad argument to '--app-tag='. Expect 0 to 0xffff " + "inclusive\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->app_tag = (uint16_t)j; + break; + case 'b': /* logical block size in bytes */ + j = sg_get_num(optarg); /* 0 -> look up with READ CAPACITY */ + if ((j < 0) || (j > (1 << 28))) { + pr2serr("bad argument to '--bs='. Expect 0 or greater\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->bs = (uint32_t)j; + break; + case 'B': /* atomic boundary */ + j = sg_get_num(optarg); + if ((j < 0) || (j > UINT16_MAX)) { + pr2serr("bad argument to '--boundary='. Expect 0 to 0xffff " + "inclusive\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->atomic_boundary = (uint16_t)j; + break; + case 'd': + op->dpo = true; + break; + case 'D': + op->dld = sg_get_num(optarg); + if ((op->dld < 0) || (op->dld > 7)) { + pr2serr("bad argument to '--dld=', expect 0 to 7 " + "inclusive\n"); + return SG_LIB_SYNTAX_ERROR; + } + break; + case 'f': + op->fua = true; + break; + case 'g': + op->grpnum = sg_get_num(optarg); + if ((op->grpnum < 0) || (op->grpnum > 63)) { + pr2serr("bad argument to '--grpnum'\n"); + return SG_LIB_SYNTAX_ERROR; + } + break; + case 'h': + case '?': + usage(); + return 0; + case 'i': + op->ifilename = optarg; + break; + case 'l': + ll = sg_get_llnum(optarg); + if (-1 == ll) { + pr2serr("bad argument to '--lba='\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->lba = (uint64_t)ll; + break; + case 'M': /* same as --tag-mask= */ + j = sg_get_num(optarg); + if ((j < 0) || (j > UINT16_MAX)) { + pr2serr("bad argument to '--tag-mask='. Expect 0 to 0xffff " + "inclusive\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->tag_mask = (uint16_t)j; + break; + case 'n': + ll = sg_get_llnum(optarg); + if ((ll < 0) || (ll > UINT32_MAX)) { + pr2serr("bad argument to '--num='\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->numblocks = (uint32_t)ll; + break; + case 'N': + op->non_atomic = true; + break; + case 'o': + ll = sg_get_llnum(optarg); + if (-1 == ll) { + pr2serr("bad argument to '--offset='\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->offset = (uint64_t)ll; + break; + case 'r': + ll = sg_get_llnum(optarg); + if ((ll < 0) || (ll > UINT32_MAX)) { + pr2serr("bad argument to '--ref-tag='. Expect 0 to " + "0xffffffff inclusive\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->ref_tag = (uint32_t)ll; + break; + case 's': + op->strict = true; + break; + case 'S': /* same as --16 */ + op->do_16 = true; + break; + case 't': + op->timeout = sg_get_num(optarg); + if (op->timeout < 0) { + pr2serr("bad argument to '--timeout='\n"); + return SG_LIB_SYNTAX_ERROR; + } + break; + case 'T': /* same as --32 */ + op->do_32 = true; + break; + case 'v': + ++op->verbose; + break; + case 'V': + pr2serr(ME "version: %s\n", version_str); + return 0; + case 'w': + op->wrprotect = sg_get_num(optarg); + if ((op->wrprotect < 0) || (op->wrprotect > 7)) { + pr2serr("bad argument to '--wrprotect'\n"); + return SG_LIB_SYNTAX_ERROR; + } + break; + default: + pr2serr("unrecognised option code 0x%x ??\n", c); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + } + if (optind < argc) { + if (NULL == device_name) { + device_name = argv[optind]; + ++optind; + } + if (optind < argc) { + for (; optind < argc; ++optind) + pr2serr("Unexpected extra argument: %s\n", argv[optind]); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + } + if ((! op->do_16) && (! op->do_32)) { + op->do_16 = true; + if (op->verbose > 1) + pr2serr("Since neither --16 nor --32 given, choose --16\n"); + } else if (op->do_16 && op->do_32) { + op->do_16 = false; + if (op->verbose > 1) + pr2serr("Since both --16 and --32 given, choose --32\n"); + } + if (NULL == op->ifilename) { + pr2serr("Need --if=FN option to be given, exiting. Add -h for " + "help\n"); + if (op->verbose > 1) + pr2serr("To write zeros use --in=/dev/zero\n"); + return SG_LIB_SYNTAX_ERROR; + } + if (NULL == device_name) { + pr2serr("missing device name!\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + vb = op->verbose; + if (vb) { + if (op->do_16 && (op->app_tag | op->ref_tag | op->tag_mask)) + pr2serr("--app-tag=, --ref-tag= and --tag-mask= options ignored " + "with 16 byte commands\n"); + if (op->non_atomic) + pr2serr("Doing normal (non-atomic) WRITE(%d) because " + "--non-atomic option given\n", op->do_16 ? 16 : 32); + } + if ((1 == strlen(op->ifilename)) && ('-' == op->ifilename[0])) + got_stdin = true; + if (got_stdin) { + infd = STDIN_FILENO; + if (sg_set_binary_mode(STDIN_FILENO) < 0) + perror("sg_set_binary_mode"); + } else { + if ((infd = open(op->ifilename, O_RDONLY)) < 0) { + snprintf(ebuff, EBUFF_SZ, "could not open %s for reading", + op->ifilename); + perror(ebuff); + return SG_LIB_FILE_ERROR; + } else if (sg_set_binary_mode(infd) < 0) + perror("sg_set_binary_mode"); + } + if (op->offset > 0) { + off64_t off = op->offset; + +/* lseek64() won't work with stdin or pipes, for example */ + if (lseek64(infd, off, SEEK_SET) < 0) { + snprintf(ebuff, EBUFF_SZ, + "couldn't offset to required position on %s", + op->ifilename); + perror(ebuff); + return SG_LIB_FILE_ERROR; + } + } + + sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, vb); + if (sg_fd < 0) { + pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); + return SG_LIB_FILE_ERROR; + } + if (0 == op->bs) { /* ask DEVICE about logical/actual block size */ + res = sg_ll_readcap_16(sg_fd, 0 /* pmi */, 0 /* llba */, resp_buff, + RCAP16_RESP_LEN, true, (vb ? (vb - 1): 0)); + if (SG_LIB_CAT_UNIT_ATTENTION == res) { + pr2serr("Read capacity(16) unit attention, try again\n"); + res = sg_ll_readcap_16(sg_fd, 0, 0, resp_buff, + RCAP16_RESP_LEN, true, + (vb ? (vb - 1): 0)); + } + if (0 == res) { + if (vb > 3) + dStrHexErr((const char *)resp_buff, RCAP16_RESP_LEN, 1); + op->bs = sg_get_unaligned_be32(resp_buff + 8); + prot_en = !!(resp_buff[12] & 0x1); + if (prot_en && (op->wrprotect > 0)) { + op->bs += 8; + if (vb > 1) + pr2serr("Bumping block size to %u (from %u) because " + "PROT_EN=1 and WRPROTECT>0\n", op->bs, + op->bs -8); + } + } else if ((SG_LIB_CAT_INVALID_OP == res) || + (SG_LIB_CAT_ILLEGAL_REQ == res)) { + if (vb) + pr2serr("Read capacity(16) not supported, try Read " + "capacity(10)\n"); + res = sg_ll_readcap_10(sg_fd, 0 /* pmi */, 0 /* lba */, + resp_buff, RCAP10_RESP_LEN, true, + (vb ? (vb - 1): 0)); + if (0 == res) { + if (vb > 3) + dStrHexErr((const char *)resp_buff, RCAP10_RESP_LEN, 1); + op->bs = sg_get_unaligned_be32(resp_buff + 4); + } else { + sg_get_category_sense_str(res, sizeof(b), b, vb); + pr2serr("Read capacity(10): %s\n", b); + pr2serr("Unable to calculate block size\n"); + } + } else if (vb) { + sg_get_category_sense_str(res, sizeof(b), b, vb); + pr2serr("Read capacity(16): %s\n", b); + pr2serr("Unable to calculate block size\n"); + } + } + op->xfer_bytes = op->numblocks * op->bs; + + if (op->xfer_bytes > 0) { + /* fill allocated buffer with zeros */ + wBuff = (unsigned char*)calloc(op->numblocks, op->bs); + if (NULL == wBuff) { + pr2serr("unable to allocate %zd bytes of memory with " + "calloc()\n", op->xfer_bytes); + ret = SG_LIB_SYNTAX_ERROR; + goto err_out; + } + res = read(infd, wBuff, op->xfer_bytes); + if (res < 0) { + snprintf(ebuff, EBUFF_SZ, "couldn't read from %s", op->ifilename); + perror(ebuff); + ret = SG_LIB_FILE_ERROR; + goto err_out; + } + if (op->strict && (res != op->xfer_bytes)) { + if (vb) + pr2serr("Wanted to read %zd bytes but got %zd bytes and " + "--strict given\n", op->xfer_bytes, res); + ret = SG_LIB_FILE_ERROR; + goto err_out; + } + } else if (op->xfer_bytes < 0) { + pr2serr("Product of block size (%" PRIu32 ") and number of blocks " + "(%" PRIu32 ") too\nlarge for single read\n", op->bs, + op->numblocks); + ret = SG_LIB_SYNTAX_ERROR; + goto err_out; + } + + if (op->non_atomic) + ret = do_write_normal(sg_fd, op, wBuff); + else + ret = do_write_atomic(sg_fd, op, wBuff); + if (ret) { + sg_get_category_sense_str(ret, sizeof(b), b, vb); + pr2serr("Write%s(%d): %s\n", (op->non_atomic ? "" : " atomic"), + op->do_16 ? 16 : 32, b); + } + +err_out: + if (wBuff) + free(wBuff); + if (sg_fd >= 0) { + res = sg_cmds_close_device(sg_fd); + if (res < 0) { + pr2serr("sg_fd close error: %s\n", safe_strerror(-res)); + if (0 == ret) + return SG_LIB_FILE_ERROR; + } + } + if ((! got_stdin) && (infd >= 0)) { + if (close(infd) < 0) { + perror("infd close error"); + if (0 == ret) + return SG_LIB_FILE_ERROR; + } + } + return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; +} diff --git a/src/sg_write_same.c b/src/sg_write_same.c index cb5d8b89..2955f939 100644 --- a/src/sg_write_same.c +++ b/src/sg_write_same.c @@ -29,7 +29,7 @@ #include "sg_unaligned.h" #include "sg_pr2serr.h" -static const char * version_str = "1.15 20170917"; +static const char * version_str = "1.16 20170924"; #define ME "sg_write_same: " @@ -68,7 +68,7 @@ static struct option long_options[] = { {"ndob", no_argument, 0, 'N'}, {"num", required_argument, 0, 'n'}, {"pbdata", no_argument, 0, 'P'}, - {"timeout", required_argument, 0, 'r'}, + {"timeout", required_argument, 0, 't'}, {"unmap", no_argument, 0, 'U'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, @@ -221,8 +221,6 @@ do_write_same(int sg_fd, const struct opts_t * op, const void * dataoutp, ws_cdb[14] = (op->grpnum & 0x1f); break; case WRITE_SAME32_LEN: - /* Note: In Linux at this time the sg driver does not support - * cdb_s > 16 bytes long, but the bsg driver does. */ ws_cdb[0] = VARIABLE_LEN_OP; ws_cdb[6] = (op->grpnum & 0x1f); ws_cdb[7] = WRITE_SAME32_ADD; @@ -340,7 +338,7 @@ main(int argc, char * argv[]) break; case 'g': op->grpnum = sg_get_num(optarg); - if ((op->grpnum < 0) || (op->grpnum > 31)) { + if ((op->grpnum < 0) || (op->grpnum > 63)) { pr2serr("bad argument to '--grpnum'\n"); return SG_LIB_SYNTAX_ERROR; } diff --git a/src/sg_write_verify.c b/src/sg_write_verify.c index 3f12e1b2..1ffa7cfb 100644 --- a/src/sg_write_verify.c +++ b/src/sg_write_verify.c @@ -35,7 +35,7 @@ #include "sg_unaligned.h" #include "sg_pr2serr.h" -static const char * version_str = "1.10 20170917"; +static const char * version_str = "1.10 20170924"; #define ME "sg_write_verify: " @@ -312,8 +312,8 @@ main(int argc, char * argv[]) break; case 'g': group = sg_get_num(optarg); - if ((group < 0) || (group > 31)) { - pr2serr("argument to '--group' expected to be 0 to 31\n"); + if ((group < 0) || (group > 63)) { + pr2serr("argument to '--group' expected to be 0 to 63\n"); return SG_LIB_SYNTAX_ERROR; } break; |