aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2017-09-25 21:57:43 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2017-09-25 21:57:43 +0000
commit35242f73d10cb0720c59eeb7343d437ff53fb29a (patch)
treed3a60b32d29909f09b0862be55122826f7df04d6 /src
parentea54f8e189eb93c93a236b80c8b91c9f93603aa3 (diff)
downloadsg3_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.am10
-rw-r--r--src/Makefile.in33
-rw-r--r--src/sg_compare_and_write.c6
-rw-r--r--src/sg_get_lba_status.c5
-rw-r--r--src/sg_logs.c2
-rw-r--r--src/sg_opcodes.c111
-rw-r--r--src/sg_sync.c4
-rw-r--r--src/sg_unmap.c6
-rw-r--r--src/sg_verify.c6
-rw-r--r--src/sg_write_atomic.c744
-rw-r--r--src/sg_write_same.c8
-rw-r--r--src/sg_write_verify.c6
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;