aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2018-01-28 06:50:39 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2018-01-28 06:50:39 +0000
commit3a7e1666843ba386946f65d8ea89fe4ddf9ed9bf (patch)
treeec2d3a035ff39e5f5786460ac09f31df45d5469f /src
parent6293187a432dd0bbf85961a897755bd0260f28ad (diff)
downloadsg3_utils-3a7e1666843ba386946f65d8ea89fe4ddf9ed9bf.tar.gz
add sg_seek and sg_stream_ctl utilities; properly identify vendor-specific sense; documentation cleanup
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@747 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am13
-rw-r--r--src/Makefile.in48
-rw-r--r--src/sg_bg_ctl.c11
-rw-r--r--src/sg_compare_and_write.c11
-rw-r--r--src/sg_inq.c23
-rw-r--r--src/sg_inq_data.c2
-rw-r--r--src/sg_scan_win32.c42
-rw-r--r--src/sg_seek.c372
-rw-r--r--src/sg_ses.c41
-rw-r--r--src/sg_stream_ctl.c477
-rw-r--r--src/sg_turs.c19
-rw-r--r--src/sg_vpd.c16
12 files changed, 1005 insertions, 70 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 6ee7d0ac..9996d015 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,10 +6,11 @@ bin_PROGRAMS = \
sg_read_attr sg_read_block_limits sg_read_buffer sg_read_long \
sg_readcap sg_reassign sg_referrals sg_rep_zones sg_requests \
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_write_x sg_zone
+ sg_sat_phy_event sg_sat_read_gplog sg_sat_set_features sg_seek \
+ sg_senddiag sg_ses sg_ses_microcode sg_start sg_stpg sg_stream_ctl \
+ 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_write_x sg_zone
sg_scan_SOURCES =
@@ -138,6 +139,8 @@ sg_sat_set_features_LDADD = ../lib/libsgutils2.la
# sg_scan_SOURCES list is already set above in the platform-specific sections
sg_scan_LDADD = ../lib/libsgutils2.la
+sg_seek_LDADD = ../lib/libsgutils2.la @RT_LIB@
+
sg_senddiag_LDADD = ../lib/libsgutils2.la
sg_ses_LDADD = ../lib/libsgutils2.la
@@ -148,6 +151,8 @@ sg_start_LDADD = ../lib/libsgutils2.la
sg_stpg_LDADD = ../lib/libsgutils2.la
+sg_stream_ctl_LDADD = ../lib/libsgutils2.la
+
sg_sync_LDADD = ../lib/libsgutils2.la
sg_test_rwbuf_LDADD = ../lib/libsgutils2.la
diff --git a/src/Makefile.in b/src/Makefile.in
index 2b79f871..999c0f4b 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -102,14 +102,14 @@ bin_PROGRAMS = sg_bg_ctl$(EXEEXT) sg_compare_and_write$(EXEEXT) \
sg_rtpg$(EXEEXT) sg_safte$(EXEEXT) sg_sanitize$(EXEEXT) \
sg_sat_identify$(EXEEXT) sg_sat_phy_event$(EXEEXT) \
sg_sat_read_gplog$(EXEEXT) sg_sat_set_features$(EXEEXT) \
- sg_senddiag$(EXEEXT) sg_ses$(EXEEXT) sg_ses_microcode$(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_write_x$(EXEEXT) sg_zone$(EXEEXT) $(am__EXEEXT_1) \
- $(am__EXEEXT_2) $(am__EXEEXT_3)
+ sg_seek$(EXEEXT) sg_senddiag$(EXEEXT) sg_ses$(EXEEXT) \
+ sg_ses_microcode$(EXEEXT) sg_start$(EXEEXT) sg_stpg$(EXEEXT) \
+ sg_stream_ctl$(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_write_x$(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
@@ -278,6 +278,9 @@ am_sg_scan_OBJECTS = $(am__objects_1) $(am__objects_2) \
$(am__objects_3)
sg_scan_OBJECTS = $(am_sg_scan_OBJECTS)
sg_scan_DEPENDENCIES = ../lib/libsgutils2.la
+sg_seek_SOURCES = sg_seek.c
+sg_seek_OBJECTS = sg_seek.$(OBJEXT)
+sg_seek_DEPENDENCIES = ../lib/libsgutils2.la
sg_senddiag_SOURCES = sg_senddiag.c
sg_senddiag_OBJECTS = sg_senddiag.$(OBJEXT)
sg_senddiag_DEPENDENCIES = ../lib/libsgutils2.la
@@ -293,6 +296,9 @@ sg_start_DEPENDENCIES = ../lib/libsgutils2.la
sg_stpg_SOURCES = sg_stpg.c
sg_stpg_OBJECTS = sg_stpg.$(OBJEXT)
sg_stpg_DEPENDENCIES = ../lib/libsgutils2.la
+sg_stream_ctl_SOURCES = sg_stream_ctl.c
+sg_stream_ctl_OBJECTS = sg_stream_ctl.$(OBJEXT)
+sg_stream_ctl_DEPENDENCIES = ../lib/libsgutils2.la
sg_sync_SOURCES = sg_sync.c
sg_sync_OBJECTS = sg_sync.$(OBJEXT)
sg_sync_DEPENDENCIES = ../lib/libsgutils2.la
@@ -392,9 +398,10 @@ SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c sg_dd.c \
sg_requests.c sg_reset.c sg_reset_wp.c sg_rmsn.c sg_rtpg.c \
sg_safte.c sg_sanitize.c sg_sat_identify.c sg_sat_phy_event.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_seek.c sg_senddiag.c sg_ses.c sg_ses_microcode.c sg_start.c \
+ sg_stpg.c sg_stream_ctl.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_write_x.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 \
@@ -408,9 +415,9 @@ DIST_SOURCES = sg_bg_ctl.c sg_compare_and_write.c sg_copy_results.c \
sg_requests.c sg_reset.c sg_reset_wp.c sg_rmsn.c sg_rtpg.c \
sg_safte.c sg_sanitize.c sg_sat_identify.c sg_sat_phy_event.c \
sg_sat_read_gplog.c sg_sat_set_features.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 \
+ $(am__sg_scan_SOURCES_DIST) sg_seek.c sg_senddiag.c sg_ses.c \
+ sg_ses_microcode.c sg_start.c sg_stpg.c sg_stream_ctl.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_write_x.c \
sg_xcopy.c sg_zone.c sginfo.c sgm_dd.c sgp_dd.c
@@ -501,6 +508,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PTHREAD_LIB = @PTHREAD_LIB@
RANLIB = @RANLIB@
+RT_LIB = @RT_LIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -618,11 +626,13 @@ sg_sat_set_features_LDADD = ../lib/libsgutils2.la
# sg_scan_SOURCES list is already set above in the platform-specific sections
sg_scan_LDADD = ../lib/libsgutils2.la
+sg_seek_LDADD = ../lib/libsgutils2.la @RT_LIB@
sg_senddiag_LDADD = ../lib/libsgutils2.la
sg_ses_LDADD = ../lib/libsgutils2.la
sg_ses_microcode_LDADD = ../lib/libsgutils2.la
sg_start_LDADD = ../lib/libsgutils2.la
sg_stpg_LDADD = ../lib/libsgutils2.la
+sg_stream_ctl_LDADD = ../lib/libsgutils2.la
sg_sync_LDADD = ../lib/libsgutils2.la
sg_test_rwbuf_LDADD = ../lib/libsgutils2.la
sg_timestamp_LDADD = ../lib/libsgutils2.la
@@ -894,6 +904,10 @@ sg_scan$(EXEEXT): $(sg_scan_OBJECTS) $(sg_scan_DEPENDENCIES) $(EXTRA_sg_scan_DEP
@rm -f sg_scan$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sg_scan_OBJECTS) $(sg_scan_LDADD) $(LIBS)
+sg_seek$(EXEEXT): $(sg_seek_OBJECTS) $(sg_seek_DEPENDENCIES) $(EXTRA_sg_seek_DEPENDENCIES)
+ @rm -f sg_seek$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sg_seek_OBJECTS) $(sg_seek_LDADD) $(LIBS)
+
sg_senddiag$(EXEEXT): $(sg_senddiag_OBJECTS) $(sg_senddiag_DEPENDENCIES) $(EXTRA_sg_senddiag_DEPENDENCIES)
@rm -f sg_senddiag$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sg_senddiag_OBJECTS) $(sg_senddiag_LDADD) $(LIBS)
@@ -914,6 +928,10 @@ sg_stpg$(EXEEXT): $(sg_stpg_OBJECTS) $(sg_stpg_DEPENDENCIES) $(EXTRA_sg_stpg_DEP
@rm -f sg_stpg$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sg_stpg_OBJECTS) $(sg_stpg_LDADD) $(LIBS)
+sg_stream_ctl$(EXEEXT): $(sg_stream_ctl_OBJECTS) $(sg_stream_ctl_DEPENDENCIES) $(EXTRA_sg_stream_ctl_DEPENDENCIES)
+ @rm -f sg_stream_ctl$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sg_stream_ctl_OBJECTS) $(sg_stream_ctl_LDADD) $(LIBS)
+
sg_sync$(EXEEXT): $(sg_sync_OBJECTS) $(sg_sync_DEPENDENCIES) $(EXTRA_sg_sync_DEPENDENCIES)
@rm -f sg_sync$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sg_sync_OBJECTS) $(sg_sync_LDADD) $(LIBS)
@@ -1037,11 +1055,13 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_set_features.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_scan_linux.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_scan_win32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_seek.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_senddiag.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ses.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ses_microcode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_start.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_stpg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_stream_ctl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sync.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_test_rwbuf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_timestamp.Po@am__quote@
diff --git a/src/sg_bg_ctl.c b/src/sg_bg_ctl.c
index ef9e6d5f..3f0b7997 100644
--- a/src/sg_bg_ctl.c
+++ b/src/sg_bg_ctl.c
@@ -33,7 +33,7 @@
* device. Based on sbc4r10.pdf .
*/
-static const char * version_str = "1.03 20180118";
+static const char * version_str = "1.04 20180126";
#define BACKGROUND_CONTROL_SA 0x15
@@ -115,9 +115,12 @@ sg_ll_background_control(int sg_fd, unsigned int bo_ctl, unsigned int bo_time,
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, cmd_name, res, SG_NO_DATA_IN, sense_b,
noisy, verbose, &sense_cat);
- if (-1 == ret)
- ;
- else if (-2 == ret) {
+ if (-1 == ret) {
+ int os_err = get_scsi_pt_os_err(ptvp);
+
+ if ((os_err > 0) && (os_err < 47))
+ ret = SG_LIB_OS_BASE_ERR + os_err;
+ } else if (-2 == ret) {
switch (sense_cat) {
case SG_LIB_CAT_RECOVERED:
case SG_LIB_CAT_NO_SENSE:
diff --git a/src/sg_compare_and_write.c b/src/sg_compare_and_write.c
index c2b16a47..4a254807 100644
--- a/src/sg_compare_and_write.c
+++ b/src/sg_compare_and_write.c
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2012-2017, Kaminario Technologies LTD
+* Copyright (c) 2012-2018, Kaminario Technologies LTD
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -54,7 +54,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "1.19 20171020";
+static const char * version_str = "1.20 20180123";
#define DEF_BLOCK_SIZE 512
#define DEF_NUM_BLOCKS (1)
@@ -73,6 +73,7 @@ static struct option long_options[] = {
{"fua", no_argument, 0, 'f'},
{"fua_nv", no_argument, 0, 'F'},
{"group", required_argument, 0, 'g'},
+ {"grpnum", required_argument, 0, 'g'},
{"help", no_argument, 0, 'h'},
{"in", required_argument, 0, 'i'},
{"inc", required_argument, 0, 'C'},
@@ -115,7 +116,7 @@ static void
usage()
{
pr2serr("Usage: sg_compare_and_write [--dpo] [--fua] [--fua_nv] "
- "[--group=GN] [--help]\n"
+ "[--grpnum=GN] [--help]\n"
" --in=IF|--inc=IF [--inw=WF] "
"--lba=LBA "
"[--num=NUM]\n"
@@ -130,7 +131,7 @@ usage()
"clear)\n"
" --fua_nv|-F set the fua_nv bit in cdb (def: "
"clear)\n"
- " --group=GN|-g GN GN is GROUP NUMBER to set in "
+ " --grpnum=GN|-g GN GN is GROUP NUMBER to set in "
"cdb (def: 0)\n"
" --help|-h print out usage message\n"
" --in=IF|-i IF IF is a file containing a compare "
@@ -207,7 +208,7 @@ parse_args(int argc, char* argv[], struct opts_t * op)
op->flags.group = sg_get_num(optarg);
if ((op->flags.group < 0) ||
(op->flags.group > 63)) {
- pr2serr("argument to '--group' expected to "
+ pr2serr("argument to '--grpnum=' expected to "
"be 0 to 63\n");
goto out_err_no_usage;
}
diff --git a/src/sg_inq.c b/src/sg_inq.c
index c15539b7..3e194859 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -46,7 +46,7 @@
#include "sg_pt_nvme.h"
#endif
-static const char * version_str = "1.84 20180118"; /* SPC-5 rev 18 */
+static const char * version_str = "1.85 20180127"; /* SPC-5 rev 18 */
/* INQUIRY notes:
* It is recommended that the initial allocation length given to a
@@ -104,6 +104,7 @@ static const char * version_str = "1.84 20180118"; /* SPC-5 rev 18 */
#define VPD_BLOCK_DEV_C_EXTENS 0xb5 /* sbc4r02 */
#define VPD_ZBC_DEV_CHARS 0xb6 /* zbc-r01b */
#define VPD_BLOCK_LIMITS_EXT 0xb7 /* sbc4r08 */
+#define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */
/* Vendor specific VPD pages (typically >= 0xc0) */
#define VPD_UPR_EMC 0xc0
@@ -155,6 +156,7 @@ struct svpd_values_name_t {
const char * name;
};
+/* Note that this table is sorted by acronym */
static struct svpd_values_name_t vpd_pg[] = {
{VPD_ATA_INFO, 0, -1, 0, "ai", "ATA information (SAT)"},
{VPD_BLOCK_DEV_CHARS, 0, 0, 0, "bdc",
@@ -191,6 +193,7 @@ static struct svpd_values_name_t vpd_pg[] = {
"protection types (SBC)"},
{VPD_SCSI_FEATURE_SETS, 0, -1, 0, "sfs", "SCSI Feature sets"},
{VPD_SOFTW_INF_ID, 0, -1, 0, "sii", "Software interface identification"},
+ {VPD_NOPE_WANT_STD_INQ, 0, -1, 0, "sinq", "Standard inquiry response"},
{VPD_UNIT_SERIAL_NUM, 0, -1, 0, "sn", "Unit serial number"},
{VPD_SCSI_PORTS, 0, -1, 0, "sp", "SCSI ports"},
{VPD_SUPPORTED_VPDS, 0, -1, 0, "sv", "Supported VPD pages"},
@@ -995,9 +998,13 @@ enumerate_vpds()
const struct svpd_values_name_t * vnp;
for (vnp = vpd_pg; vnp->acron; ++vnp) {
- if (vnp->name)
- printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value,
- vnp->name);
+ if (vnp->name) {
+ if (vnp->value < 0)
+ printf(" %-10s -1 %s\n", vnp->acron, vnp->name);
+ else
+ printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value,
+ vnp->name);
+ }
}
}
@@ -4213,9 +4220,9 @@ main(int argc, char * argv[])
op->do_decode = true;
op->page_num = vnp->value;
op->page_pdt = vnp->pdt;
- } else if ('-' == op->page_arg[0]) {
- op->page_num = -2; /* request standard INQUIRY response */
- } else {
+ } else if ('-' == op->page_arg[0])
+ op->page_num = VPD_NOPE_WANT_STD_INQ;
+ else {
#ifdef SG_SCSI_STRINGS
if (op->opt_new) {
n = sg_get_num(op->page_arg);
@@ -4310,7 +4317,7 @@ main(int argc, char * argv[])
usage_for(op);
return SG_LIB_SYNTAX_ERROR;
}
- if (-2 == op->page_num) /* from --page=-<num> to force standard INQUIRY */
+ if (VPD_NOPE_WANT_STD_INQ == op->page_num)
op->page_num = -1; /* now past guessing, set to normal indication */
if (op->do_export) {
diff --git a/src/sg_inq_data.c b/src/sg_inq_data.c
index f86659f6..cc53a46f 100644
--- a/src/sg_inq_data.c
+++ b/src/sg_inq_data.c
@@ -1,5 +1,5 @@
/* A utility program originally written for the Linux OS SCSI subsystem.
-* Copyright (C) 2000-2017 D. Gilbert
+* Copyright (C) 2000-2018 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
diff --git a/src/sg_scan_win32.c b/src/sg_scan_win32.c
index 1433a46f..efdcd03e 100644
--- a/src/sg_scan_win32.c
+++ b/src/sg_scan_win32.c
@@ -40,7 +40,7 @@
#include "sg_pt_win32.h"
-static const char * version_str = "1.19 (win32) 20180118";
+static const char * version_str = "1.20 (win32) 20180119";
#define MAX_SCSI_ELEMS 2048
#define MAX_ADAPTER_NUM 128
@@ -79,10 +79,38 @@ typedef enum _STORAGE_BUS_TYPE {
BusTypeMmc = 0x0D,
BusTypeVirtual = 0xE,
BusTypeFileBackedVirtual = 0xF,
- BusTypeMax,
+ BusTypeSpaces = 0x10,
+ BusTypeMax = 0x11,
BusTypeMaxReserved = 0x7F
} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
+typedef enum _STORAGE_PROTOCOL_TYPE {
+ ProtocolTypeUnknown = 0,
+ ProtocolTypeScsi,
+ ProtocolTypeAta,
+ ProtocolTypeNvme,
+ ProtocolTypeSd
+} STORAGE_PROTOCOL_TYPE;
+
+typedef enum _STORAGE_PROTOCOL_NVME_DATA_TYPE {
+ NVMeDataTypeUnknown = 0,
+ NVMeDataTypeIdentify,
+ NVMeDataTypeLogPage,
+ NVMeDataTypeFeature
+} STORAGE_PROTOCOL_NVME_DATA_TYPE;
+
+typedef struct _STORAGE_PROTOCOL_SPECIFIC_DATA {
+ STORAGE_PROTOCOL_TYPE ProtocolType;
+ ULONG DataType;
+ ULONG ProtocolDataRequestValue;
+ ULONG ProtocolDataRequestSubValue;
+ ULONG ProtocolDataOffset;
+ ULONG ProtocolDataLength;
+ ULONG FixedProtocolReturnData;
+ ULONG Reserved[3];
+} STORAGE_PROTOCOL_SPECIFIC_DATA;
+
+
typedef struct _STORAGE_DEVICE_DESCRIPTOR {
ULONG Version;
ULONG Size;
@@ -262,6 +290,8 @@ get_bus_type(int bt)
return "Virt ";
case BusTypeFileBackedVirtual:
return "FBVir";
+ case BusTypeSpaces:
+ return "Spaces";
case BusTypeMax:
return "Max ";
default:
@@ -527,7 +557,8 @@ enum_pds(void)
} else {
err = GetLastError();
if ((0 == k) && (ERROR_ACCESS_DENIED == err))
- pr2serr("Access denied on %s, may need Administrator\n");
+ pr2serr("Access denied on %s, may need Administrator\n",
+ adapter_name);
if (ERROR_SHARING_VIOLATION == err)
pr2serr("%s: in use by other process (sharing violation "
"[34])\n", adapter_name);
@@ -693,12 +724,13 @@ sg_do_wscan(char letter, bool show_bt, int scsi_scan)
printf("%s", sp->qp_descriptor.raw + j);
printf("\n");
if (verbose > 2)
- hex2stderr(sp->qp_descriptor.raw, 144, 0);
+ hex2stderr((const uint8_t *)sp->qp_descriptor.raw, 144, 0);
} else
printf("\n");
if ((verbose > 3) && sp->qp_uid_valid) {
printf(" UID valid, in hex:\n");
- hex2stderr(sp->qp_uid.raw, sizeof(sp->qp_uid.raw), 1);
+ hex2stderr((const uint8_t *)sp->qp_uid.raw,
+ sizeof(sp->qp_uid.raw), 1);
}
}
}
diff --git a/src/sg_seek.c b/src/sg_seek.c
new file mode 100644
index 00000000..061a2ca3
--- /dev/null
+++ b/src/sg_seek.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2018 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 <ctype.h>
+#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#include <time.h>
+#elif defined(HAVE_GETTIMEOFDAY)
+#include <time.h>
+#include <sys/time.h>
+#endif
+
+#include "sg_lib.h"
+#include "sg_lib_data.h"
+#include "sg_cmds_basic.h"
+#include "sg_cmds_extra.h"
+#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
+
+/*
+ * This program issues one or more SCSI SEEK(10), PRE-FETCH(10) or
+ * PRE-FETCH(16) commands. Both PRE-FETCH commands are current and appear
+ * in the most recent SBC-4 draft (sbc4r15.pdf at time of writing) while
+ * SEEK(10) has been obsolete since SBC-2 (2004). Currently more hard disks
+ * and SSDs support SEEK(10) than PRE-FETCH. It is even unclear what
+ * SEEK(10) means (defined in SBC-1 as moving the hard disk heads to the
+ * track containing the given LBA) for a SSD. But if the manufacturers'
+ * support it, then it must have a use, presumably to speed the next access
+ * to that LBA ...
+ */
+
+static const char * version_str = "1.00 20180127";
+
+#define BACKGROUND_CONTROL_SA 0x15
+
+#define CMD_ABORT_TIMEOUT 60 /* 60 seconds */
+
+
+static struct option long_options[] = {
+ {"10", no_argument, 0, 'T'},
+ {"count", required_argument, 0, 'c'},
+ {"grpnum", required_argument, 0, 'g'},
+ {"help", no_argument, 0, 'h'},
+ {"immed", no_argument, 0, 'i'},
+ {"lba", required_argument, 0, 'l'},
+ {"num-blocks", required_argument, 0, 'n'},
+ {"num_blocks", required_argument, 0, 'n'},
+ {"pre-fetch", no_argument, 0, 'p'},
+ {"pre_fetch", no_argument, 0, 'p'},
+ {"readonly", no_argument, 0, 'r'},
+ {"skip", required_argument, 0, 's'},
+ {"time", required_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"wrap-offset", required_argument, 0, 'w'},
+ {"wrap_offset", required_argument, 0, 'w'},
+ {0, 0, 0, 0},
+};
+
+
+static void
+usage()
+{
+ pr2serr("Usage: "
+ "sg_seek [--10] [--count=NC] [--grpnum=GN] [--help] [--immed]\n"
+ " [--lba=LBA] [--num-blocks=NUM] [--pre-fetch] "
+ "[--readonly]\n"
+ " [--skip=SB] [--time] [--verbose] [--version]\n"
+ " [--wrap-offset=WO] DEVICE\n");
+ pr2serr(" where:\n"
+ " --10|-T do PRE-FETCH(10) command (def: "
+ "SEEK(10), or\n"
+ " PRE-FETCH(16) if --pre-fetch also "
+ "given)\n"
+ " --count=NC|-c NC NC is number of commands to execute "
+ "(def: 1)\n"
+ " --grpnum=GN|-g GN GN is group number to place in "
+ "PRE-FETCH\n"
+ " cdb; 0 to 63 (def: 0)\n"
+ " --help|-h print out usage message\n"
+ " --immed|-i set IMMED bit in PRE-FETCH command\n"
+ " --lba=LBA|-l LBA starting Logical Block Address (LBA) "
+ "(def: 0)\n"
+ " --num-blocks=NUM|-n NUM number of blocks to cache (for "
+ "PRE-FETCH)\n"
+ " (def: 1). Ignored by "
+ "SEEK(10)\n");
+ pr2serr(" --pre-fetch|-p do PRE-FETCH command, 16 byte variant if "
+ "--10 not\n"
+ " given (def: do SEEK(10))\n"
+ " --readonly|-r open DEVICE read-only (if supported)\n"
+ " --skip=SB|-s SB when NC>1 skip SB blocks to next LBA "
+ "(def: 1)\n"
+ " --time|-t time the command(s) and if NC>1 show "
+ "usecs/command\n"
+ " (def: don't time)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n"
+ " --wrap-offset=WO|-w WO if SB>0 and WO>0 then if "
+ "LBAn>LBA+WO\n"
+ " then reset LBAn back to LBA (def: 0)\n\n"
+ "Performs SCSI SEEK(10), PRE-FETCH(10) or PRE-FETCH(16) "
+ "command(s).If no\noptions are given does one SEEK(10) command "
+ "with an LBA of 0 . If NC>1\nthen a tally is kept of successes, "
+ "'condition-met's and errors that is\nprinted on completion. "
+ "'condition-met' is from PRE-FETCH when NUM blocks\nfit in "
+ "the DEVICE's cache.\n"
+ );
+}
+
+
+int
+main(int argc, char * argv[])
+{
+ bool cdb10 = false;
+ bool do_time = false;
+ bool immed = false;
+ bool prefetch = false;
+ bool readonly = false;
+ bool start_tm_valid = false;
+ int sg_fd, res, c;
+ int first_err = 0;
+ int last_err = 0;
+ int ret = 0;
+ int verbose = 0;
+ uint32_t count = 1;
+ int32_t l;
+ uint32_t grpnum = 0;
+ uint32_t k;
+ uint32_t num_cond_met = 0;
+ uint32_t num_err = 0;
+ uint32_t numblocks = 1;
+ uint32_t skip = 1;
+ uint32_t wrap_offs = 0;
+ int64_t ll;
+ int64_t elapsed_usecs = 0;
+ uint64_t lba = 0;
+ uint64_t lba_n;
+ const char * device_name = NULL;
+ const char * cdb_name = NULL;
+ char b[64];
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ struct timespec start_tm, end_tm;
+#elif defined(HAVE_GETTIMEOFDAY)
+ struct timeval start_tm, end_tm;
+#endif
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "c:g:hil:n:prs:tTvVw:", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'c':
+ l = sg_get_num(optarg);
+ if (l < 0) {
+ pr2serr("--count= unable to decode argument, want 0 or "
+ "higher\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ count = (uint32_t)l;
+ break;
+ case 'g':
+ l = sg_get_num(optarg);
+ if ((l > 63) || (l < 0)) {
+ pr2serr("--grpnum= expect argument in range 0 to 63\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ grpnum = (uint32_t)l;
+ break;
+ case 'h':
+ case '?':
+ usage();
+ return 0;
+ case 'i':
+ immed = true;
+ break;
+ case 'l':
+ ll = sg_get_llnum(optarg);
+ if (-1 == ll) {
+ pr2serr("--lba= unable to decode argument\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ lba = (uint64_t)ll;
+ break;
+ case 'n':
+ l = sg_get_num(optarg);
+ if (-1 == l) {
+ pr2serr("--num= unable to decode argument\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ numblocks = (uint32_t)l;
+ break;
+ case 'p':
+ prefetch = true;
+ break;
+ case 'r':
+ readonly = true;
+ break;
+ case 's':
+ l = sg_get_num(optarg);
+ if (-1 == l) {
+ pr2serr("--skip= unable to decode argument\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ skip = (uint32_t)l;
+ break;
+ case 't':
+ do_time = true;
+ break;
+ case 'T':
+ cdb10 = true;
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'V':
+ pr2serr("version: %s\n", version_str);
+ return 0;
+ case 'w':
+ l = sg_get_num(optarg);
+ if (-1 == l) {
+ pr2serr("--wrap-offset= unable to decode argument\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ wrap_offs = (uint32_t)l;
+ 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 (NULL == device_name) {
+ pr2serr("Missing device name!\n\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ if (prefetch) {
+ if (cdb10)
+ cdb_name = "Pre-fetch(10)";
+ else
+ cdb_name = "Pre-fetch(16)";
+ } else
+ cdb_name = "Seek(10)";
+
+ sg_fd = sg_cmds_open_device(device_name, readonly, verbose);
+ if (sg_fd < 0) {
+ pr2serr("open error: %s: %s %s\n", device_name, cdb_name,
+ safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ if (do_time) {
+ start_tm.tv_sec = 0;
+ start_tm.tv_nsec = 0;
+ if (0 == clock_gettime(CLOCK_MONOTONIC, &start_tm))
+ start_tm_valid = true;
+ }
+#elif defined(HAVE_GETTIMEOFDAY)
+ if (do_time) {
+ start_tm.tv_sec = 0;
+ start_tm.tv_usec = 0;
+ gettimeofday(&start_tm, NULL);
+ start_tm_valid = true;
+ }
+#else
+ start_tm_valid = false;
+#endif
+
+ for (k = 0, lba_n = lba; k < count; ++k, lba_n += skip) {
+ if (wrap_offs && (lba_n > lba) && ((lba_n - lba) > wrap_offs))
+ lba_n = lba;
+ res = sg_ll_pre_fetch_x(sg_fd, ! prefetch, ! cdb10, immed, lba_n,
+ numblocks, grpnum, 0, (verbose > 0), verbose);
+ if (SG_LIB_CAT_CONDITION_MET == res)
+ ++num_cond_met;
+ else if (res) {
+ ++num_err;
+ if (0 == first_err)
+ first_err = res;
+ last_err = res;
+ }
+ }
+
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ if ((count > 0) && start_tm_valid &&
+ (start_tm.tv_sec || start_tm.tv_nsec)) {
+ res = clock_gettime(CLOCK_MONOTONIC, &end_tm);
+ elapsed_usecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000000;
+ elapsed_usecs += (end_tm.tv_nsec - start_tm.tv_nsec) / 1000;
+ }
+#elif defined(HAVE_GETTIMEOFDAY)
+ if ((count > 0) && start_tm_valid &&
+ (start_tm.tv_sec || start_tm.tv_usec)) {
+ gettimeofday(&end_tm, NULL);
+ elapsed_usecs = (end_tm.tv_sec - start_tm.tv_sec) * 1000000;
+ elapsed_usecs += (end_tm.tv_usec - start_tm.tv_usec);
+ }
+#endif
+
+ if (elapsed_usecs > 0) {
+ if (elapsed_usecs > 1000000)
+ snprintf(b, sizeof(b), " (over %d seconds)",
+ (int)elapsed_usecs / 1000000);
+ else
+ b[0] = '\0';
+ printf("Elapsed time: %" PRId64 " microseconds%s, per command time: "
+ "%" PRId64 "\n", elapsed_usecs, b, elapsed_usecs / count);
+ }
+
+ printf("Command count=%u number condition mets=%u number errors=%d\n",
+ count, num_cond_met, num_err);
+ if (first_err) {
+ int err;
+
+ if ((first_err > SG_LIB_OS_BASE_ERR) && (first_err < 97)) {
+ err = first_err - SG_LIB_OS_BASE_ERR;
+ printf(" first error: %s [%d]\n", safe_strerror(err), err);
+ } else
+ printf(" first error=%d\n", first_err);
+ if (num_err > 1) {
+ if ((last_err > SG_LIB_OS_BASE_ERR) && (last_err < 97)) {
+ err = last_err - SG_LIB_OS_BASE_ERR;
+ printf(" last error: %s [%d]\n", safe_strerror(err), err);
+ } else
+ printf(" last error=%d\n", last_err);
+ }
+ }
+ res = sg_cmds_close_device(sg_fd);
+ if (res < 0) {
+ pr2serr("close error: %s\n", safe_strerror(-res));
+ if (0 == ret)
+ return SG_LIB_FILE_ERROR;
+ }
+ return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+}
diff --git a/src/sg_ses.c b/src/sg_ses.c
index 405d1195..2d16e438 100644
--- a/src/sg_ses.c
+++ b/src/sg_ses.c
@@ -36,7 +36,7 @@
* commands tailored for SES (enclosure) devices.
*/
-static const char * version_str = "2.30 20180118"; /* ses4r01 */
+static const char * version_str = "2.31 20180127"; /* ses4r01 */
#define MX_ALLOC_LEN ((64 * 1024) - 4) /* max allowable for big enclosures */
#define MX_ELEM_HDR 1024
@@ -160,7 +160,8 @@ struct opts_t {
int num_cgs; /* number of --clear-, --get= and --set= options */
int arr_len;
uint8_t sas_addr[8];
- uint8_t data_arr[MX_DATA_IN + 16];
+ uint8_t * data_arr;
+ uint8_t * free_data_arr;
const char * desc_name;
const char * dev_name;
const char * index_str;
@@ -1317,7 +1318,6 @@ parse_cmd_line(struct opts_t *op, int argc, char *argv[])
}
}
if (data_arg) {
- memset(op->data_arr, 0, sizeof(op->data_arr));
if (read_hex(data_arg, op->data_arr + 4, &op->arr_len, op->verbose)) {
pr2serr("bad argument to '--data'\n");
return SG_LIB_SYNTAX_ERROR;
@@ -5252,20 +5252,28 @@ main(int argc, char * argv[])
op->ind_indiv_last = -1;
op->maxlen = MX_ALLOC_LEN;
pg_sz = sg_get_page_size();
+ op->data_arr = sg_memalign(MX_DATA_IN + 16, pg_sz, &op->free_data_arr,
+ false);
+ if (NULL == op->data_arr) {
+ pr2serr("unable to allocate %u bytes on heap\n", MX_DATA_IN + 16);
+ return SG_LIB_OS_BASE_ERR + ENOMEM;
+ }
res = parse_cmd_line(op, argc, argv);
- if (res)
- return SG_LIB_SYNTAX_ERROR;
+ if (res) {
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto early_out;
+ }
if (op->do_version) {
pr2serr("version: %s\n", version_str);
- return 0;
+ goto early_out;
}
if (op->do_help) {
usage(op->do_help);
- return 0;
+ goto early_out;
}
if (op->enumerate || op->do_list) {
enumerate_work(op);
- return 0;
+ goto early_out;
}
enc_stat_rsp = sg_memalign(op->maxlen, pg_sz, &free_enc_stat_rsp,
op->verbose > 3);
@@ -5305,20 +5313,23 @@ main(int argc, char * argv[])
pr2serr("--clear, --get or --set options only supported for the "
"Enclosure\nControl/Status, Threshold In/Out and "
"Additional Element Status pages\n");
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto err_out;
}
if (! (op->ind_given || op->desc_name || (op->dev_slot_num >= 0) ||
saddr_non_zero(op->sas_addr))) {
pr2serr("with --clear, --get or --set option need either\n "
"--index, --descriptor, --dev-slot-num or --sas-addr\n");
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto err_out;
}
for (k = 0, cgs_clp = op->cgs_cl_arr, tavp = tav_arr; k < op->num_cgs;
++k, ++cgs_clp, ++tavp) {
if (parse_cgs_str(cgs_clp->cgs_str, tavp)) {
pr2serr("unable to decode STR argument to: %s\n",
cgs_clp->cgs_str);
- return SG_LIB_SYNTAX_ERROR;
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto err_out;
}
if ((GET_OPT == cgs_clp->cgs_sel) && tavp->val_str)
pr2serr("--get option ignoring =<val> at the end of STR "
@@ -5369,7 +5380,8 @@ main(int argc, char * argv[])
if (sg_fd < 0) {
pr2serr("open error: %s: %s\n", op->dev_name,
safe_strerror(-sg_fd));
- return SG_LIB_FILE_ERROR;
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
}
if (! (op->do_raw || have_cgs || (op->do_hex > 2))) {
if (sg_simple_inquiry(sg_fd, &inq_resp, 1, op->verbose)) {
@@ -5514,7 +5526,10 @@ err_out:
if (res < 0) {
pr2serr("close error: %s\n", safe_strerror(-res));
if (0 == ret)
- return SG_LIB_FILE_ERROR;
+ ret = SG_LIB_FILE_ERROR;
}
+early_out:
+ if (op->free_data_arr)
+ free(op->free_data_arr);
return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
diff --git a/src/sg_stream_ctl.c b/src/sg_stream_ctl.c
new file mode 100644
index 00000000..032d40b4
--- /dev/null
+++ b/src/sg_stream_ctl.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2018 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 <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sg_lib.h"
+#include "sg_lib_data.h"
+#include "sg_pt.h"
+#include "sg_cmds_basic.h"
+#include "sg_unaligned.h"
+#include "sg_pr2serr.h"
+
+/*
+ * This program issues the SCSI STREAM CONTROL or GET STREAM STATUS command
+ * to the given SCSI device. Based on sbc4r15.pdf .
+ */
+
+static const char * version_str = "1.00 20180126";
+
+#define STREAM_CONTROL_SA 0x14
+#define GET_STREAM_STATUS_SA 0x16
+
+#define STREAM_CONTROL_OPEN 0x1
+#define STREAM_CONTROL_CLOSE 0x2
+
+#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
+#define DEF_PT_TIMEOUT 60 /* 60 seconds */
+
+
+static struct option long_options[] = {
+ {"brief", no_argument, 0, 'b'},
+ {"close", no_argument, 0, 'c'},
+ {"ctl", required_argument, 0, 'C'},
+ {"get", no_argument, 0, 'g'},
+ {"help", no_argument, 0, 'h'},
+ {"id", required_argument, 0, 'i'},
+ {"maxlen", required_argument, 0, 'm'},
+ {"open", no_argument, 0, 'o'},
+ {"readonly", no_argument, 0, 'r'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+
+static void
+usage()
+{
+ pr2serr("Usage: "
+ "sg_stream_ctl [-brief] [--close] [--ctl=CTL] [-get] [--help]\n"
+ " [--id=SID] [--maxlen=LEN] [--open] "
+ "[--readonly]\n"
+ " [--verbose] [--version] DEVICE\n");
+ pr2serr(" where:\n"
+ " --brief|-b for open, output assigned stream id to "
+ "stdout, or\n"
+ " -1 if error; for close, output 0, or "
+ "-1; for get\n"
+ " output list of stream id, 1 per line\n"
+ " --close|-c close stream given by --id=SID\n"
+ " --ctl=CTL|-C CTL CTL is stream control value, "
+ "(STR_CTL field)\n"
+ " 1 -> open; 2 -> close\n"
+ " --get|-g do GET STREAM STATUS command (default "
+ "if no other)\n"
+ " --help|-h print out usage message\n"
+ " --id=SID|-i SID for close, SID is stream_id to close; "
+ "for get,\n"
+ " list from and include this stream id\n"
+ " --maxlen=LEN|-m LEN length in bytes of buffer to "
+ "receive data-in\n"
+ " (def: 8 (for open and close); 252 "
+ "(for get,\n"
+ " but increase if needed)\n"
+ " --open|-o open a new stream, return assigned "
+ "stream id\n"
+ " --readonly|-r open DEVICE read-only (if supported)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Performs a SCSI STREAM CONTROL or GET STREAM STATUS command. "
+ "If --open,\n--close or --ctl=CTL given (only one) then "
+ "performs STREAM CONTROL\ncommand. If --get or no other "
+ "selecting option given then performs a\nGET STREAM STATUS "
+ "command. A successful --open will output the assigned\nstream "
+ "id to stdout (and ignore --id=SID , if given).\n"
+ );
+}
+
+/* Invokes a SCSI GET STREAM STATUS command (SBC-4). Return of 0 -> success,
+ * various SG_LIB_CAT_* positive values or -1 -> other errors */
+static int
+sg_ll_get_stream_status(int sg_fd, uint16_t s_str_id, uint8_t * resp,
+ uint32_t alloc_len, int * residp, bool noisy,
+ int verbose)
+{
+ int k, ret, res, sense_cat;
+ unsigned char gssCdb[16] = {SG_SERVICE_ACTION_IN_16,
+ GET_STREAM_STATUS_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_pt_base * ptvp;
+ static const char * const cmd_name = "Get stream status";
+
+ if (s_str_id) /* starting stream id, fetch from and including */
+ sg_put_unaligned_be16(s_str_id, gssCdb + 4);
+ sg_put_unaligned_be32(alloc_len, gssCdb + 10);
+ if (verbose) {
+ pr2serr(" %s cdb: ", cmd_name);
+ for (k = 0; k < (int)sizeof(gssCdb); ++k)
+ pr2serr("%02x ", gssCdb[k]);
+ pr2serr("\n");
+ }
+
+ ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
+ if (NULL == ptvp) {
+ pr2serr("%s: out of memory\n", cmd_name);
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, gssCdb, sizeof(gssCdb));
+ set_scsi_pt_data_in(ptvp, resp, alloc_len);
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, cmd_name, res, alloc_len, sense_b,
+ noisy, verbose, &sense_cat);
+ if (-1 == ret) {
+ int os_err = get_scsi_pt_os_err(ptvp);
+
+ if ((os_err > 0) && (os_err < 47))
+ ret = SG_LIB_OS_BASE_ERR + os_err;
+ } else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = sense_cat;
+ break;
+ }
+ } else
+ ret = 0;
+ k = ret ? (int)alloc_len : get_scsi_pt_resid(ptvp);
+ if (residp)
+ *residp = k;
+ if ((verbose > 2) && ((alloc_len - k) > 0)) {
+ pr2serr("%s: parameter data returned:\n", cmd_name);
+ hex2stderr((const uint8_t *)resp, alloc_len - k,
+ ((verbose > 3) ? -1 : 1));
+ }
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+/* Invokes a SCSI STREAM CONTROL command (SBC-4). Return of 0 -> success,
+ * various SG_LIB_CAT_* positive values or -1 -> other errors */
+static int
+sg_ll_stream_control(int sg_fd, uint32_t str_ctl, uint16_t str_id,
+ uint8_t * resp, uint32_t alloc_len, int * residp,
+ bool noisy, int verbose)
+{
+ int k, ret, res, sense_cat;
+ unsigned char scCdb[16] = {SG_SERVICE_ACTION_IN_16,
+ STREAM_CONTROL_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_pt_base * ptvp;
+ static const char * const cmd_name = "Stream control";
+
+ if (str_ctl)
+ scCdb[1] |= (str_ctl & 0x3) << 5;
+ if (str_id) /* Only used for close, stream id to close */
+ sg_put_unaligned_be16(str_id, scCdb + 4);
+ sg_put_unaligned_be32(alloc_len, scCdb + 10);
+ if (verbose) {
+ pr2serr(" %s cdb: ", cmd_name);
+ for (k = 0; k < (int)sizeof(scCdb); ++k)
+ pr2serr("%02x ", scCdb[k]);
+ pr2serr("\n");
+ }
+
+ ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
+ if (NULL == ptvp) {
+ pr2serr("%s: out of memory\n", cmd_name);
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, scCdb, sizeof(scCdb));
+ set_scsi_pt_data_in(ptvp, resp, alloc_len);
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, cmd_name, res, alloc_len, sense_b,
+ noisy, verbose, &sense_cat);
+ if (-1 == ret) {
+ int os_err = get_scsi_pt_os_err(ptvp);
+
+ if ((os_err > 0) && (os_err < 47))
+ ret = SG_LIB_OS_BASE_ERR + os_err;
+ } else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = sense_cat;
+ break;
+ }
+ } else
+ ret = 0;
+ k = ret ? (int)alloc_len : get_scsi_pt_resid(ptvp);
+ if (residp)
+ *residp = k;
+ if ((verbose > 2) && ((alloc_len - k) > 0)) {
+ pr2serr("%s: parameter data returned:\n", cmd_name);
+ hex2stderr((const uint8_t *)resp, alloc_len - k,
+ ((verbose > 3) ? -1 : 1));
+ }
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+
+int
+main(int argc, char * argv[])
+{
+ bool do_brief = false;
+ bool do_close = false;
+ bool do_get = false;
+ bool do_open = false;
+ bool ctl_given = false;
+ bool maxlen_given = false;
+ bool read_only = false;
+ int c, k, sg_fd, res, resid;
+ int maxlen = 0;
+ int ret = 0;
+ int verbose = 0;
+ uint16_t stream_id = 0;
+ uint16_t num_streams = 0;
+ uint32_t ctl = 0;
+ uint32_t pg_sz = sg_get_page_size();
+ uint32_t param_dl;
+ const char * device_name = NULL;
+ const char * cmd_name = NULL;
+ uint8_t * arr;
+ uint8_t * free_arr;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "bcC:ghi:m:orvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'b':
+ do_brief = true;
+ break;
+ case 'c':
+ do_close = true;
+ break;
+ case 'C':
+ if ((1 != sscanf(optarg, "%4u", &ctl)) || (ctl > 3)) {
+ pr2serr("--ctl= expects a number from 0 to 3\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ ctl_given = true;
+ break;
+ case 'g':
+ do_get = true;
+ break;
+ case 'h':
+ case '?':
+ usage();
+ return 0;
+ case 'i':
+ k = sg_get_num(optarg);
+ if ((k < 0) || (k > UINT16_MAX)) {
+ pr2serr("--id= expects a number from 0 to 65535\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ stream_id = (uint16_t)k;
+ break;
+ case 'm':
+ k = sg_get_num(optarg);
+ if (k < 0) {
+ pr2serr("--maxlen= unable to decode argument\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ maxlen_given = true;
+ if (k > 0)
+ maxlen = k;
+ break;
+ case 'o':
+ do_open = true;
+ break;
+ case 'r':
+ read_only = true;
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'V':
+ pr2serr("version: %s\n", version_str);
+ return 0;
+ 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 (NULL == device_name) {
+ pr2serr("missing device name!\n\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ k = (int)do_close + (int)do_get + (int)do_open + (int)ctl_given;
+ if (k > 1) {
+ pr2serr("Can only have one of: --close, --ctl==, --get, or --open\n");
+ return SG_LIB_SYNTAX_ERROR;
+ } else if (0 == k)
+ do_get = true;
+ if (do_close)
+ ctl = STREAM_CONTROL_CLOSE;
+ else if (do_open)
+ ctl = STREAM_CONTROL_OPEN;
+
+ if (maxlen_given) {
+ if (0 == maxlen)
+ maxlen = do_get ? 248 : 8;
+ } else
+ maxlen = do_get ? 248 : 8;
+
+ if (verbose) {
+ if (read_only && (! do_get))
+ pr2serr("Probably need to open %s read-write\n", device_name);
+ if (do_open && (stream_id > 0))
+ pr2serr("With --open the --id-SID option is ignored\n");
+ }
+
+ sg_fd = sg_cmds_open_device(device_name, read_only, verbose);
+ if (sg_fd < 0) {
+ pr2serr("open error: %s: %s\n", device_name,
+ safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+
+ if (maxlen > (int)pg_sz)
+ arr = sg_memalign(maxlen, pg_sz, &free_arr, verbose > 3);
+ else
+ arr = sg_memalign(pg_sz, pg_sz, &free_arr, verbose > 3);
+ if (NULL == arr) {
+ pr2serr("Unable to allocate space for response\n");
+ return SG_LIB_OS_BASE_ERR + ENOMEM;
+ }
+
+ resid = 0;
+ if (do_get) { /* Get stream status */
+ cmd_name = "Get stream status";
+ ret = sg_ll_get_stream_status(sg_fd, stream_id, arr, maxlen,
+ &resid, false, verbose);
+ if (ret) {
+ if (SG_LIB_CAT_INVALID_OP == ret)
+ pr2serr("%s command not supported\n", cmd_name);
+ else {
+ char b[80];
+
+ sg_get_category_sense_str(ret, sizeof(b), b, verbose);
+ pr2serr("%s command: %s\n", cmd_name, b);
+ }
+ goto fini;
+ }
+ if ((maxlen - resid) < 4) {
+ pr2serr("Response too short (%d bytes) assigned stream id\n",
+ k);
+ printf("-1\n");
+ ret = SG_LIB_CAT_MALFORMED;
+ goto fini;
+ } else
+ maxlen -= resid;
+ param_dl = sg_get_unaligned_be32(arr + 0) + 4;
+ if (param_dl > (uint32_t)maxlen) {
+ pr2serr("Response truncated, need to set --maxlen=%u\n",
+ param_dl);
+ if (maxlen < (8 /* header */ + 4 /* enough of first */)) {
+ pr2serr("Response too short to continue\n");
+ goto fini;
+ }
+ }
+ num_streams = sg_get_unaligned_be16(arr + 6);
+ if (! do_brief) {
+ if (stream_id > 0)
+ printf("Starting at stream id: %u\n", stream_id);
+ printf("Number of open streams: %u\n", num_streams);
+ }
+ maxlen = ((uint32_t)maxlen < param_dl) ? maxlen : (int)param_dl;
+ for (k = 8; k < (maxlen - 4); k += 8) {
+ stream_id = sg_get_unaligned_be16(arr + k + 2);
+ if (do_brief)
+ printf("%u\n", stream_id);
+ else
+ printf("Open stream id: %u\n", stream_id);
+ }
+ } else { /* Stream control */
+ cmd_name = "Stream control";
+ ret = sg_ll_stream_control(sg_fd, ctl, stream_id, arr, maxlen,
+ &resid, false, verbose);
+ if (ret) {
+ if (SG_LIB_CAT_INVALID_OP == ret)
+ pr2serr("%s command not supported\n", cmd_name);
+ else {
+ char b[80];
+
+ sg_get_category_sense_str(ret, sizeof(b), b, verbose);
+ pr2serr("%s command: %s\n", cmd_name, b);
+ }
+ goto fini;
+ }
+ if (do_open) {
+ k = arr[0] + 1;
+ k = (k < (maxlen - resid)) ? k : (maxlen - resid);
+ if (k < 5) {
+ pr2serr("Response too short (%d bytes) assigned stream id\n",
+ k);
+ printf("-1\n");
+ ret = SG_LIB_CAT_MALFORMED;
+ } else {
+ stream_id = sg_get_unaligned_be16(arr + 4);
+ if (do_brief)
+ printf("%u\n", stream_id);
+ else
+ printf("Assigned stream id: %u\n", stream_id);
+ }
+ }
+ }
+
+fini:
+ if (free_arr)
+ free(free_arr);
+ res = sg_cmds_close_device(sg_fd);
+ if (res < 0) {
+ pr2serr("close error: %s\n", safe_strerror(-res));
+ if (0 == ret)
+ return SG_LIB_FILE_ERROR;
+ }
+ return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+}
diff --git a/src/sg_turs.c b/src/sg_turs.c
index 2578378d..7b8b0567 100644
--- a/src/sg_turs.c
+++ b/src/sg_turs.c
@@ -1,8 +1,4 @@
-/* This program sends a user specified number of TEST UNIT READY commands
- * to the given sg device. Since TUR is a simple command involing no
- * data transfer (and no REQUEST SENSE command iff the unit is ready)
- * then this can be used for timing per SCSI command overheads.
- *
+/*
* Copyright (C) 2000-2018 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -11,6 +7,13 @@
*
*/
+/*
+ * This program sends a user specified number of TEST UNIT READY commands
+ * to the given sg device. Since TUR is a simple command involing no
+ * data transfer (and no REQUEST SENSE command iff the unit is ready)
+ * then this can be used for timing per SCSI command overheads.
+ */
+
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
@@ -33,7 +36,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "3.37 20180116";
+static const char * version_str = "3.38 20180123";
#if defined(MSC_VER) || defined(__MINGW32__)
#define HAVE_MS_SLEEP
@@ -83,12 +86,12 @@ usage()
" --number=NUM|-n NUM number of test_unit_ready commands "
"(def: 1)\n"
" --num=NUM|-n NUM same action as '--number=NUM'\n"
+ " --old|-O use old interface (use as first option)\n"
" --progress|-p outputs progress indication (percentage) "
"if available\n"
" --time|-t outputs total duration and commands per "
"second\n"
" --verbose|-v increase verbosity\n"
- " --old|-O use old interface (use as first option)\n"
" --version|-V print version string then exit\n\n"
"Performs a SCSI TEST UNIT READY command (or many of them).\n");
}
@@ -367,7 +370,7 @@ main(int argc, char * argv[])
}
}
#ifndef SG_LIB_MINGW
- if ((op->do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
+ if (op->do_time && (start_tm.tv_sec || start_tm.tv_usec)) {
struct timeval res_tm;
double den, num;
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 010aca56..6eafd4f4 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -38,7 +38,7 @@
*/
-static const char * version_str = "1.34 20180118"; /* spc5r18 + sbc4r14 */
+static const char * version_str = "1.35 20180127"; /* spc5r18 + sbc4r14 */
/* standard VPD pages, in ascending page number order */
#define VPD_SUPPORTED_VPDS 0x0
@@ -77,7 +77,7 @@ static const char * version_str = "1.34 20180118"; /* spc5r18 + sbc4r14 */
#define VPD_LB_PROTECTION 0xb5 /* SSC-5 */
#define VPD_ZBC_DEV_CHARS 0xb6 /* zbc-r01b */
#define VPD_BLOCK_LIMITS_EXT 0xb7 /* sbc4r08 */
-#define VPD_NO_RATHER_STD_INQ -2 /* request for standard inquiry */
+#define VPD_NOPE_WANT_STD_INQ -2 /* request for standard inquiry */
/* Device identification VPD page associations */
#define VPD_ASSOC_LU 0
@@ -222,7 +222,7 @@ static struct svpd_values_name_t standard_vpd_pg[] = {
"protection types (SBC)"},
{VPD_SCSI_FEATURE_SETS, 0, -1, "sfs", "SCSI feature sets"},
{VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"},
- {VPD_NO_RATHER_STD_INQ, 0, -1, "sinq", "Standard inquiry response"},
+ {VPD_NOPE_WANT_STD_INQ, 0, -1, "sinq", "Standard inquiry response"},
{VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"},
{VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"},
{VPD_SECURITY_TOKEN, 0, 0x11, "st", "Security token (OSD)"},
@@ -2779,7 +2779,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
allow_name = true;
rp = rsp_buff + off;
if (sg_fd != -1 && !op->do_force &&
- pn != VPD_NO_RATHER_STD_INQ &&
+ pn != VPD_NOPE_WANT_STD_INQ &&
pn != VPD_SUPPORTED_VPDS) {
res = vpd_fetch_page_from_dev(sg_fd, rp, VPD_SUPPORTED_VPDS,
op->maxlen, vb, &len);
@@ -2799,7 +2799,7 @@ svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off)
return SG_LIB_CAT_ILLEGAL_REQ;
}
switch(pn) {
- case VPD_NO_RATHER_STD_INQ: /* -2 (want standard inquiry response) */
+ case VPD_NOPE_WANT_STD_INQ: /* -2 (want standard inquiry response) */
if (sg_fd >= 0) {
if (op->maxlen > 0)
alloc_len = op->maxlen;
@@ -3655,7 +3655,7 @@ main(int argc, char * argv[])
if (op->page_str) {
if ((0 == strcmp("-1", op->page_str)) ||
(0 == strcmp("-2", op->page_str)))
- op->vpd_pn = VPD_NO_RATHER_STD_INQ;
+ op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
else if (isdigit(op->page_str[0])) {
op->vpd_pn = sg_get_num_nomult(op->page_str);
if ((op->vpd_pn < 0) || (op->vpd_pn > 255)) {
@@ -3683,7 +3683,7 @@ main(int argc, char * argv[])
if (op->page_str) {
if ((0 == strcmp("-1", op->page_str)) ||
(0 == strcmp("-2", op->page_str)))
- op->vpd_pn = VPD_NO_RATHER_STD_INQ;
+ op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
else if (isalpha(op->page_str[0])) {
vnp = sdp_find_vpd_by_acron(op->page_str);
if (NULL == vnp) {
@@ -3784,7 +3784,7 @@ main(int argc, char * argv[])
pr2serr("Guessing from --inhex this is VPD page "
"0x%x\n", rsp_buff[1]);
} else {
- op->vpd_pn = VPD_NO_RATHER_STD_INQ;
+ op->vpd_pn = VPD_NOPE_WANT_STD_INQ;
if (op->verbose)
pr2serr("page number unclear from --inhex, hope "
"it's a standard INQUIRY response\n");