diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2018-01-28 06:50:39 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2018-01-28 06:50:39 +0000 |
commit | 3a7e1666843ba386946f65d8ea89fe4ddf9ed9bf (patch) | |
tree | ec2d3a035ff39e5f5786460ac09f31df45d5469f /src | |
parent | 6293187a432dd0bbf85961a897755bd0260f28ad (diff) | |
download | sg3_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.am | 13 | ||||
-rw-r--r-- | src/Makefile.in | 48 | ||||
-rw-r--r-- | src/sg_bg_ctl.c | 11 | ||||
-rw-r--r-- | src/sg_compare_and_write.c | 11 | ||||
-rw-r--r-- | src/sg_inq.c | 23 | ||||
-rw-r--r-- | src/sg_inq_data.c | 2 | ||||
-rw-r--r-- | src/sg_scan_win32.c | 42 | ||||
-rw-r--r-- | src/sg_seek.c | 372 | ||||
-rw-r--r-- | src/sg_ses.c | 41 | ||||
-rw-r--r-- | src/sg_stream_ctl.c | 477 | ||||
-rw-r--r-- | src/sg_turs.c | 19 | ||||
-rw-r--r-- | src/sg_vpd.c | 16 |
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"); |