aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2007-06-27 03:51:21 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2007-06-27 03:51:21 +0000
commit7502647d46389b2e0e659f658b51f56abd1f9511 (patch)
treedc0c45bcd01d5f6ddeac34258c765efe417c70ac
parent130627841138672bf26e9b4b5a1f70a240e910a6 (diff)
downloadsg3_utils-7502647d46389b2e0e659f658b51f56abd1f9511.tar.gz
Load sg3_utils-1.23 into trunk/.
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@74 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--CHANGELOG30
-rw-r--r--COVERAGE6
-rw-r--r--CREDITS6
-rw-r--r--INSTALL48
-rw-r--r--Makefile22
-rw-r--r--Makefile.asroot22
-rw-r--r--Makefile.freebsd16
-rw-r--r--Makefile.mingw140
-rw-r--r--Makefile.osf146
-rw-r--r--Makefile.win3234
-rw-r--r--README47
-rw-r--r--README.freebsd7
-rw-r--r--README.tru646
-rw-r--r--README.win3230
-rw-r--r--archive/sg3_utils_123o.spec193
-rw-r--r--debian/changelog6
-rw-r--r--debian/control23
-rw-r--r--debian/docs2
-rw-r--r--debian/libsgutils1.postinst8
-rw-r--r--debian/libsgutils1.postrm8
-rwxr-xr-xdebian/rules11
-rw-r--r--doc/sg3_utils.html567
-rw-r--r--doc/sg_dd.html347
-rw-r--r--doc/tools.html16
-rw-r--r--examples/Makefile.freebsd4
-rw-r--r--examples/reassign_addr.txt4
-rw-r--r--examples/scsi_inquiry.c21
-rw-r--r--examples/sg__sat_identify.c10
l---------examples/sg_io_linux.h1
-rw-r--r--examples/sg_io_linux.hh1
-rw-r--r--examples/sg_iovec_tst.c6
l---------examples/sg_lib.h1
-rw-r--r--examples/sg_lib.hh1
l---------examples/sg_linux_inc.h1
-rw-r--r--examples/sg_linux_inc.hh1
l---------examples/sg_pt.h1
-rw-r--r--examples/sg_pt.hh1
-rw-r--r--examples/sg_sat_chk_power.c33
-rw-r--r--examples/sg_sat_set_features.c28
-rw-r--r--examples/sg_sat_smart_rd_data.c20
-rw-r--r--examples/sg_simple4.c6
-rwxr-xr-xmake_no_lib_win32.sh2
-rw-r--r--no_lib/Makefile.freebsd15
-rw-r--r--no_lib/Makefile.linux22
-rw-r--r--no_lib/Makefile.linux_static22
-rw-r--r--no_lib/Makefile.osf146
-rw-r--r--no_lib/Makefile.win32166
-rw-r--r--no_lib/sg3_utils.spec14
-rw-r--r--scripts/README45
-rwxr-xr-xscripts/sas_disk_blink104
-rwxr-xr-xscripts/scsi_logging_level295
-rwxr-xr-xscripts/scsi_mandat120
-rwxr-xr-xscripts/scsi_readcap49
-rwxr-xr-xscripts/scsi_ready48
-rwxr-xr-xscripts/scsi_satl128
-rwxr-xr-xscripts/scsi_start50
-rwxr-xr-xscripts/scsi_stop50
-rwxr-xr-xscripts/scsi_temperature46
-rw-r--r--sg3_utils.8175
-rw-r--r--sg3_utils.spec96
-rw-r--r--sg_cmds_basic.c37
-rw-r--r--sg_cmds_basic.h14
-rw-r--r--sg_cmds_extra.c228
-rw-r--r--sg_cmds_extra.h69
-rw-r--r--sg_dd.8291
-rw-r--r--sg_dd.c221
-rw-r--r--sg_emc_trespass.834
-rw-r--r--sg_emc_trespass.c6
-rw-r--r--sg_format.8222
-rw-r--r--sg_format.c100
-rw-r--r--sg_get_config.8115
-rw-r--r--sg_get_config.c45
-rw-r--r--sg_ident.888
-rw-r--r--sg_ident.c41
-rw-r--r--sg_inq.8454
-rw-r--r--sg_inq.c1296
-rw-r--r--sg_io_linux.h9
-rw-r--r--sg_lib.c22
-rw-r--r--sg_lib.h15
-rw-r--r--sg_logs.8357
-rw-r--r--sg_logs.c1299
-rw-r--r--sg_luns.850
-rw-r--r--sg_luns.c20
-rw-r--r--sg_map.841
-rw-r--r--sg_map.c33
-rw-r--r--sg_map26.869
-rw-r--r--sg_map26.c39
-rw-r--r--sg_modes.8320
-rw-r--r--sg_modes.c857
-rw-r--r--sg_opcodes.8192
-rw-r--r--sg_opcodes.c1248
-rw-r--r--sg_persist.8310
-rw-r--r--sg_persist.c143
-rw-r--r--sg_prevent.865
-rw-r--r--sg_prevent.c18
-rw-r--r--sg_pt.h9
-rw-r--r--sg_pt_freebsd.c59
-rw-r--r--sg_pt_linux.c45
-rw-r--r--sg_pt_win32.c3
-rw-r--r--sg_rbuf.8190
-rw-r--r--sg_rbuf.c431
-rw-r--r--sg_rdac.819
-rw-r--r--sg_rdac.c36
-rw-r--r--sg_read.8115
-rw-r--r--sg_read.c43
-rw-r--r--sg_read_buffer.872
-rw-r--r--sg_read_buffer.c334
-rw-r--r--sg_read_long.879
-rw-r--r--sg_read_long.c46
-rw-r--r--sg_readcap.8158
-rw-r--r--sg_readcap.c418
-rw-r--r--sg_reassign.8119
-rw-r--r--sg_reassign.c71
-rw-r--r--sg_requests.862
-rw-r--r--sg_requests.c18
-rw-r--r--sg_reset.842
-rw-r--r--sg_reset.c6
-rw-r--r--sg_rmsn.836
-rw-r--r--sg_rmsn.c22
-rw-r--r--sg_rtpg.831
-rw-r--r--sg_rtpg.c59
-rw-r--r--sg_sat_identify.865
-rw-r--r--sg_sat_identify.c37
-rw-r--r--sg_scan.841
-rw-r--r--sg_scan.8l41
-rw-r--r--sg_scan.8w34
-rw-r--r--sg_scan.c88
-rw-r--r--sg_senddiag.8277
-rw-r--r--sg_senddiag.c589
-rw-r--r--sg_ses.8106
-rw-r--r--sg_ses.c86
-rw-r--r--sg_start.8276
-rw-r--r--sg_start.c642
-rw-r--r--sg_sync.893
-rw-r--r--sg_sync.c21
-rw-r--r--sg_test_rwbuf.869
-rw-r--r--sg_test_rwbuf.c29
-rw-r--r--sg_turs.8100
-rw-r--r--sg_turs.c294
-rw-r--r--sg_verify.889
-rw-r--r--sg_verify.c56
-rw-r--r--sg_vpd.8115
-rw-r--r--sg_vpd.c52
-rw-r--r--sg_vpd_vendor.c2
-rw-r--r--sg_wr_mode.8151
-rw-r--r--sg_wr_mode.c40
-rw-r--r--sg_write_buffer.8106
-rw-r--r--sg_write_buffer.c395
-rw-r--r--sg_write_long.8117
-rw-r--r--sg_write_long.c58
-rw-r--r--sginfo.8234
-rw-r--r--sginfo.c14
-rw-r--r--sgm_dd.8205
-rw-r--r--sgm_dd.c101
-rw-r--r--sgp_dd.8216
-rw-r--r--sgp_dd.c99
-rw-r--r--utils/Makefile.freebsd2
-rw-r--r--utils/Makefile.mingw33
-rw-r--r--utils/README20
l---------utils/sg_lib.h1
-rw-r--r--utils/sg_lib.hh307
161 files changed, 13417 insertions, 6049 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 002c2e20..7db75b0f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,36 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
+Changelog for sg3_utils-1.23 [20070131]
+ - sg_read_buffer: new utility
+ - sg_write_buffer: new utility
+ - sg_opcodes, sg_senddiag, sg_logs, sg_modes, sg_start, sg_inq,
+ sg_turs, sg_readcap, sg_rbuf: add getopt_long() based cli;
+ old and new cli selectable, new getopt_long cli is default
+ - scripts: new subdirectory containing some bash scripts
+ - add scripts/README file
+ - sg_reassign: add '--hex' option for grown and primary lists
+ - sg_rtpg: add '--raw' option
+ - sg_lib.h, sg_cmds_basic.h + sg_cmds_extra.h: add C++
+ 'extern "C" ' wrappers
+ - cleanup C code so it will compile as C++
+ - sg_lib: sync with spc4r08
+ - include <inttypes.h>, use PRId64 instead of %lld form
+ - fix sg_get_sense_str() when empty sense buffer
+ - win32 port: add Makefile.mingw + related support for MinGW
+ - sg_cmds_extra: add sg_ll_read_buffer() and sg_ll_write_buffer()
+ - sg_dd, sgp_dd, sgm_dd, sg_read: use lseek64() instead of llseek.c
+ - sgm_dd: accept coe=<n> for interworking with sg_dd
+ - sg_rdac: fix on non-linux ports
+ - sg_ses: fix spurious warning in additional element status page
+ - '-rr' option outputs a diagnostic page in binary to stdout
+ - sg_opcodes: add command timeout descriptor support (spc4r08)
+ - change linux specific pass through to generic pass through
+ - sg_logs: add 'name=value' decoding for SAS specific lpage
+ - examples+utils subdirectories: remove symlinks
+ - synchronize man pages with usage messages
+ - sg3_utils.spec: rework
+
Changelog for sg3_utils-1.22 [20061016]
- sgp_dd: accept verbose=<n> as well as deb=<n> to ease
interworking with sg_dd and sgm_dd
diff --git a/COVERAGE b/COVERAGE
index f4e49e1b..d126cada 100644
--- a/COVERAGE
+++ b/COVERAGE
@@ -33,7 +33,7 @@ READ(6) sg_dd, sgm_dd, sgp_dd, sg_read
READ(10) sg_dd, sgm_dd, sgp_dd, sg_read
READ(12) sg_dd, sgm_dd, sgp_dd, sg_read
READ(16) sg_dd, sgm_dd, sgp_dd, sg_read
-READ BUFFER sg_rbuf, sg_test_rwbuf
+READ BUFFER sg_rbuf, sg_test_rwbuf, sg_read_buffer
READ CAPACITY(10) sg_readcap, sg_dd, sgm_dd, sgp_dd, sg_format, ++
READ CAPACITY(16) sg_readcap, sg_dd, sgm_dd, sgp_dd, sg_format, ++
READ DEFECT(10) sginfo, sg_reassign('-g'), ++
@@ -59,7 +59,7 @@ WRITE(6) sg_dd, sgm_dd, sgp_dd
WRITE(10) sg_dd, sgm_dd, sgp_dd
WRITE(12) sg_dd, sgm_dd, sgp_dd
WRITE(16) sg_dd, sgm_dd, sgp_dd
-WRITE BUFFER sg_test_rwbuf
+WRITE BUFFER sg_test_rwbuf, sg_write_buffer
WRITE LONG (10) sg_write_long, ++
WRITE LONG (16) sg_write_long, ++
@@ -83,4 +83,4 @@ SMART READ DATA examples/sg_sat_smart_rd_data
Doug Gilbert
-14th October 2006
+2nd November 2006
diff --git a/CREDITS b/CREDITS
index 3ca8b654..8acbc04b 100644
--- a/CREDITS
+++ b/CREDITS
@@ -47,6 +47,7 @@ Lars Marowsky-Brée <lmb at suse dot de> contributed Unit Path Report VPD
Luben Tuikov <ltuikov at yahoo dot com>
help with documentation and other suggestions [20061014]
+ contribution sg_read_buffer and sg_write_buffer [20061103]
Martin Schwenke <martin at meltin dot net> added the raw switch "-r" to sg_inq
@@ -59,9 +60,6 @@ Pat LaVarre <p.lavarre at ieee dot org> pointed out danger of negative bpt
Peter Allworth <linsol at zeta dot org dot au> original dd clone design used
by sg3_utils's dd variants (e.g. sg_dd).
-Remy Card has his copyright notice on llseek.c which is borrowed from the
- util-linux package.
-
Saeed Bishara contributed sg_write_long
Time Hunt <tim at timhunt dot net> increased number of (sd and sg) devices
@@ -75,4 +73,4 @@ Trent Piepho <xyzzy at speakeasy dot org> print out some "sense key specific"
Doug Gilbert
-14th October 2006
+31st October 2006
diff --git a/INSTALL b/INSTALL
index d1ad5eb0..71fb126d 100644
--- a/INSTALL
+++ b/INSTALL
@@ -100,21 +100,33 @@ Tru64.
Windows
=======
-In Windows only the Windows 2000, 2003 and XP operating systems (and their
-variants) are currently supported. The source tarball can be built in a
-cygwin environment on Windows. See http://www.cygwin.com for more
-information. Various extras such as 'gcc' (the GNU C compiler) and 'make'
-need to be loaded as they are not in the minimal cygwin default distribution.
-The build command is "make -f Makefile.win32" and to install (for a cygwin
-environment) use "make -f Makefile.win32 install". Currently the make
-doesn't build a dll (cf shared libraries are built on Linux and FreeBSD) so
-the executable files are bigger than they need to be. Once built, the
-various ".exe" commands can either be executed in a cygwin shell (typically
-"bash") or a DOS shell. If cygwin has not been installed on the target
-machine then the "cygwin1.dll" (obtained from www.cygwin.com ) is required.
-The various device names that the sg3_utils utilities will accept in Windows
-can be seen by running the sg_scan utility (and perhaps looking at its man
-page (i.e. sg_scan.8 or sg_scan.8w)).
-
-
-5th October 2006
+In Windows only the Windows NT, 2000, 2003 and XP operating systems (and
+their variants) are currently supported. The various device names that the
+sg3_utils utilities will accept in Windows can be seen by running the
+sg_scan utility (and perhaps looking at its man page (i.e. sg_scan.8 or
+sg_scan.8w)).
+
+The source tarball can be built in a cygwin or MinGW environment on Windows.
+
+For cygwin see http://www.cygwin.com for more information. Various extras
+such as 'gcc' (the GNU C compiler) and 'make' need to be loaded as they are
+not in the minimal cygwin default distribution. The build command
+is "make -f Makefile.win32" and to install (for a cygwin environment)
+use "make -f Makefile.win32 install". Currently the make doesn't build a
+dll (cf shared libraries are built on Linux and FreeBSD) so the executable
+files are bigger than they need to be. Once built, the various ".exe"
+commands can either be executed in a cygwin shell (typically "bash") or a
+DOS shell. If cygwin has not been installed on the target machine then
+the "cygwin1.dll" (obtained from http://www.cygwin.com ) is required.
+
+There is also the "Minimalist Gnu for Windows" (MinGW) and its associated
+shell (MSYS) that can serve as a build environment for sg3_utils. This
+removes the dependence on the proprietary cygwin1.dll at the expense
+of some timing features. In a MSYS shell untar the sg3_utils tarball and
+in its top level directory use "make -f Makefile.mingw". The executables
+will be placed in that directory. They can be executed in a MSYS or "cmd"
+shell.
+
+
+21st January 2007
+Doug Gilbert
diff --git a/Makefile b/Makefile
index dff7f51d..0254cfff 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,8 @@ EXECS = sg_dd sgp_dd sgm_dd sg_read sg_map sg_scan sg_rbuf \
sg_persist sg_write_long sg_read_long sg_requests sg_ses \
sg_verify sg_emc_trespass sg_luns sg_sync sg_prevent \
sg_get_config sg_wr_mode sg_rtpg sg_reassign sg_format \
- sg_rmsn sg_ident sg_map26 sg_rdac sg_vpd sg_sat_identify
+ sg_rmsn sg_ident sg_map26 sg_rdac sg_vpd sg_sat_identify \
+ sg_read_buffer sg_write_buffer
MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sginfo.8 sg_readcap.8 sg_turs.8 sg_inq.8 sg_test_rwbuf.8 \
@@ -24,7 +25,8 @@ MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8 \
sg_luns.8 sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
- sg_map26.8 sg_rdac.8 sg_vpd.8 sg3_utils.8 sg_sat_identify.8
+ sg_map26.8 sg_rdac.8 sg_vpd.8 sg3_utils.8 sg_sat_identify.8 \
+ sg_read_buffer.8 sg_write_buffer.8
MAN_PREF = man8
HEADERS = sg_lib.h sg_cmds.h sg_cmds_basic.h sg_cmds_extra.h sg_pt.h \
@@ -85,7 +87,7 @@ libsgutils.la: sg_lib.lo sg_cmds_basic.lo sg_cmds_extra.lo sg_pt_linux.lo
sg_inq: sg_inq.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
-sg_dd: sg_dd.o llseek.o sg_io_linux.o libsgutils.la
+sg_dd: sg_dd.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
sg_scan: sg_scan.o sg_io_linux.o libsgutils.la
@@ -107,10 +109,10 @@ sgp_dd.o: sgp_dd.c
$(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) $(CFLAGS_PTHREADS) \
-c -o sgp_dd.o $<
-sgp_dd: sgp_dd.o llseek.o sg_io_linux.o libsgutils.la
+sgp_dd: sgp_dd.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^ -lpthread
-sgm_dd: sgm_dd.o llseek.o sg_io_linux.o libsgutils.la
+sgm_dd: sgm_dd.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
sg_map: sg_map.o sg_io_linux.o libsgutils.la
@@ -122,7 +124,7 @@ sg_turs: sg_turs.o libsgutils.la
sg_test_rwbuf: sg_test_rwbuf.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
-sg_read: sg_read.o llseek.o sg_io_linux.o libsgutils.la
+sg_read: sg_read.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
sg_reset: sg_reset.o
@@ -137,7 +139,7 @@ sg_logs: sg_logs.o libsgutils.la
sg_senddiag: sg_senddiag.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
-sg_opcodes: sg_opcodes.o sg_io_linux.o libsgutils.la
+sg_opcodes: sg_opcodes.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
sg_persist: sg_persist.o libsgutils.la
@@ -203,6 +205,12 @@ sg_vpd: sg_vpd.o sg_vpd_vendor.o libsgutils.la
sg_sat_identify: sg_sat_identify.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+sg_read_buffer: sg_read_buffer.o libsgutils.la
+ libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+
+sg_write_buffer: sg_write_buffer.o libsgutils.la
+ libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
diff --git a/Makefile.asroot b/Makefile.asroot
index 7bd14a3e..1f6a5f02 100644
--- a/Makefile.asroot
+++ b/Makefile.asroot
@@ -15,7 +15,8 @@ EXECS = sg_dd sgp_dd sgm_dd sg_read sg_map sg_scan sg_rbuf \
sg_persist sg_write_long sg_read_long sg_requests sg_ses \
sg_verify sg_emc_trespass sg_luns sg_sync sg_prevent \
sg_get_config sg_wr_mode sg_rtpg sg_reassign sg_format \
- sg_rmsn sg_ident sg_map26 sg_rdac sg_vpd sg_sat_identify
+ sg_rmsn sg_ident sg_map26 sg_rdac sg_vpd sg_sat_identify \
+ sg_read_buffer sg_write_buffer
MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sginfo.8 sg_readcap.8 sg_turs.8 sg_inq.8 sg_test_rwbuf.8 \
@@ -24,7 +25,8 @@ MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8 \
sg_luns.8 sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
- sg_map26.8 sg_rdac.8 sg_vpd.8 sg3_utils.8 sg_sat_identify.8
+ sg_map26.8 sg_rdac.8 sg_vpd.8 sg3_utils.8 sg_sat_identify.8 \
+ sg_read_buffer.8 sg_write_buffer.8
MAN_PREF = man8
HEADERS = sg_lib.h sg_cmds.h sg_cmds_basic.h sg_cmds_extra.h sg_pt.h \
@@ -85,7 +87,7 @@ libsgutils.la: sg_lib.lo sg_cmds_basic.lo sg_cmds_extra.lo sg_pt_linux.lo
sg_inq: sg_inq.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
-sg_dd: sg_dd.o llseek.o sg_io_linux.o libsgutils.la
+sg_dd: sg_dd.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
sg_scan: sg_scan.o sg_io_linux.o libsgutils.la
@@ -107,10 +109,10 @@ sgp_dd.o: sgp_dd.c
$(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) $(CFLAGS_PTHREADS) \
-c -o sgp_dd.o $<
-sgp_dd: sgp_dd.o llseek.o sg_io_linux.o libsgutils.la
+sgp_dd: sgp_dd.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^ -lpthread
-sgm_dd: sgm_dd.o llseek.o sg_io_linux.o libsgutils.la
+sgm_dd: sgm_dd.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
sg_map: sg_map.o sg_io_linux.o libsgutils.la
@@ -122,7 +124,7 @@ sg_turs: sg_turs.o libsgutils.la
sg_test_rwbuf: sg_test_rwbuf.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
-sg_read: sg_read.o llseek.o sg_io_linux.o libsgutils.la
+sg_read: sg_read.o sg_io_linux.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
sg_reset: sg_reset.o
@@ -137,7 +139,7 @@ sg_logs: sg_logs.o libsgutils.la
sg_senddiag: sg_senddiag.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
-sg_opcodes: sg_opcodes.o sg_io_linux.o libsgutils.la
+sg_opcodes: sg_opcodes.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
sg_persist: sg_persist.o libsgutils.la
@@ -203,6 +205,12 @@ sg_vpd: sg_vpd.o sg_vpd_vendor.o libsgutils.la
sg_sat_identify: sg_sat_identify.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+sg_read_buffer: sg_read_buffer.o libsgutils.la
+ libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+
+sg_write_buffer: sg_write_buffer.o libsgutils.la
+ libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
diff --git a/Makefile.freebsd b/Makefile.freebsd
index 173f218d..7fa14dfe 100644
--- a/Makefile.freebsd
+++ b/Makefile.freebsd
@@ -17,14 +17,15 @@ EXECS = sg_readcap sg_turs sg_inq sg_start sg_modes sg_logs \
sg_sync sg_prevent sg_get_config sg_wr_mode \
sg_rtpg sg_reassign sg_format sg_rmsn sg_ident \
sg_read_long sg_write_long sg_verify sg_rdac sg_vpd \
- sg_sat_identify
+ sg_sat_identify sg_read_buffer sg_write_buffer sg_opcodes
MAN_PGS = sg_readcap.8 sg_turs.8 sg_inq.8 sg_start.8 sg_modes.8 sg_logs.8 \
sg_senddiag.8 sg_persist.8 sg_requests.8 sg_ses.8 sg_luns.8 \
sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
sg_read_long.8 sg_write_long.8 sg_verify.8 sg_rdac.8 sg_vpd.8 \
- sg3_utils.8 sg_sat_identify.8
+ sg3_utils.8 sg_sat_identify.8 sg_read_buffer.8 sg_write_buffer.8 \
+ sg_opcodes.8
MAN_PREF = man8
@@ -157,7 +158,16 @@ sg_vpd: sg_vpd.o sg_vpd_vendor.o libsgutils.la
$(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o sg_vpd_vendor.o libsgutils.la
sg_sat_identify: sg_sat_identify.o libsgutils.la
- $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o sg_vpd_vendor.o libsgutils.la
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+
+sg_read_buffer: sg_read_buffer.o libsgutils.la
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+
+sg_write_buffer: sg_write_buffer.o libsgutils.la
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+
+sg_opcodes: sg_opcodes.o libsgutils.la
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
install: $(EXECS)
install -d $(INSTDIR)
diff --git a/Makefile.mingw b/Makefile.mingw
new file mode 100644
index 00000000..1e44cfb9
--- /dev/null
+++ b/Makefile.mingw
@@ -0,0 +1,140 @@
+# Assumes makefile is used in a MSYS shell with a MinGW compiler available.
+
+SHELL = /bin/sh
+
+PREFIX=/usr/local
+INSTDIR=$(PREFIX)/bin
+MANDIR=$(PREFIX)/man
+
+CC = gcc
+LD = gcc
+
+EXECS = sg_readcap sg_turs sg_inq sg_start sg_modes sg_logs sg_senddiag \
+ sg_persist sg_requests sg_ses sg_luns sg_scan \
+ sg_sync sg_prevent sg_get_config sg_wr_mode \
+ sg_rtpg sg_reassign sg_format sg_rmsn sg_ident \
+ sg_read_long sg_write_long sg_verify sg_rdac sg_vpd \
+ sg_sat_identify sg_read_buffer sg_write_buffer sg_opcodes
+
+EXE_S = sg_readcap.exe sg_turs.exe sg_inq.exe sg_start.exe sg_modes.exe \
+ sg_logs.exe sg_senddiag.exe sg_persist.exe sg_requests.exe \
+ sg_ses.exe sg_luns.exe sg_scan.exe sg_sync.exe sg_prevent.exe \
+ sg_get_config.exe sg_wr_mode.exe sg_rtpg.exe sg_reassign.exe \
+ sg_format.exe sg_rmsn.exe sg_ident.exe sg_read_long.exe \
+ sg_write_long.exe sg_verify.exe sg_rdac.exe sg_vpd.exe \
+ sg_sat_identify.exe sg_read_buffer.exe sg_write_buffer.exe \
+ sg_opcodes.exe
+
+OS_FLAGS = -DSG3_UTILS_WIN32 -DSG3_UTILS_MINGW -DSPTD
+# OS_FLAGS = -DSG3_UTILS_WIN32 -DSG3_UTILS_MINGW
+LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+EXTRA_FLAGS = $(OS_FLAGS) $(LARGE_FILE_FLAGS)
+
+# CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS)
+CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS)
+# CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS)
+
+O_FILES = sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_win32.o
+O_BFILES = sg_lib.o sg_cmds_basic.o sg_pt_win32.o
+O_SFILES = sg_lib.o
+
+LDFLAGS =
+
+all: $(EXECS)
+
+clean:
+ rm *.o $(EXE_S)
+
+.c.o:
+ $(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) -c -o $@ $<
+
+sg_readcap: sg_readcap.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_turs: sg_turs.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_inq: sg_inq.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_start: sg_start.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_modes: sg_modes.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_logs: sg_logs.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_senddiag: sg_senddiag.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_persist: sg_persist.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_requests: sg_requests.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_ses: sg_ses.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_luns: sg_luns.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_scan: sg_scan.o $(O_SFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_SFILES)
+
+sg_sync: sg_sync.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_prevent: sg_prevent.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_get_config: sg_get_config.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_wr_mode: sg_wr_mode.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_rtpg: sg_rtpg.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_reassign: sg_reassign.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_format: sg_format.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_rmsn: sg_rmsn.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_ident: sg_ident.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_read_long: sg_read_long.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_write_long: sg_write_long.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_verify: sg_verify.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_rdac: sg_rdac.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_vpd: sg_vpd.o sg_vpd_vendor.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o sg_vpd_vendor.o $(O_BFILES)
+
+sg_sat_identify: sg_sat_identify.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_read_buffer: sg_read_buffer.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_write_buffer: sg_write_buffer.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_opcodes: sg_opcodes.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
diff --git a/Makefile.osf1 b/Makefile.osf1
index 133065ef..f57c9d28 100644
--- a/Makefile.osf1
+++ b/Makefile.osf1
@@ -15,14 +15,16 @@ EXECS = sg_readcap sg_turs sg_inq sg_start sg_modes sg_logs \
sg_senddiag sg_persist sg_requests sg_ses sg_luns \
sg_sync sg_prevent sg_get_config sg_wr_mode \
sg_rtpg sg_reassign sg_format sg_rmsn sg_ident \
- sg_read_long sg_write_long sg_verify sg_rdac sg_vpd
+ sg_read_long sg_write_long sg_verify sg_rdac sg_vpd \
+ sg_sat_identify sg_read_buffer sg_write_buffer sg_opcodes
MAN_PGS = sg_readcap.8 sg_turs.8 sg_inq.8 sg_start.8 sg_modes.8 sg_logs.8 \
sg_senddiag.8 sg_persist.8 sg_requests.8 sg_ses.8 sg_luns.8 \
sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
sg_read_long.8 sg_write_long.8 sg_verify.8 sg_rdac.8 sg_vpd.8 \
- sg3_utils.8
+ sg3_utils.8 sg_sat_identify.8 sg_read_buffer.8 sg_write_buffer.8 \
+ sg_opcodes.8
MAN_PREF = man8
@@ -80,26 +82,26 @@ libsgutils.la: sg_lib.lo sg_cmds_basic.lo sg_cmds_extra.lo sg_pt_osf1.lo
# $(LIBTOOL) --mode=link $(LD) -o libsgutils.la sg_lib.lo
# sg_cmds_basic.lo sg_cmds_extra.lo -rpath $(LIBDIR) -release $(RELEASE)
-sg_readcap: sg_readcap.o libsgutils.la
- $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+sg_readcap: sg_readcap.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
-sg_turs: sg_turs.o libsgutils.la
- $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+sg_turs: sg_turs.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
-sg_inq: sg_inq.o libsgutils.la
- $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+sg_inq: sg_inq.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
-sg_start: sg_start.o libsgutils.la
- $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+sg_start: sg_start.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
-sg_modes: sg_modes.o libsgutils.la
- $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+sg_modes: sg_modes.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
-sg_logs: sg_logs.o libsgutils.la
- $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+sg_logs: sg_logs.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
-sg_senddiag: sg_senddiag.o libsgutils.la
- $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la
+sg_senddiag: sg_senddiag.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
sg_persist: sg_persist.o libsgutils.la getopt_long/getopt_long.o
$(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
@@ -155,6 +157,18 @@ sg_rdac: sg_rdac.o libsgutils.la
sg_vpd: sg_vpd.o sg_vpd_vendor.o libsgutils.la getopt_long/getopt_long.o
$(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o sg_vpd_vendor.o libsgutils.la getopt_long/getopt_long.o
+sg_sat_identify: sg_sat_identify.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
+
+sg_read_buffer: sg_read_buffer.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
+
+sg_write_buffer: sg_write_buffer.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
+
+sg_opcodes: sg_opcodes.o libsgutils.la getopt_long/getopt_long.o
+ $(LIBTOOL) $(LT_EXTRA) --mode=link $(LD) -o $@ $(LDFLAGS) $@.o libsgutils.la getopt_long/getopt_long.o
+
install: $(EXECS)
test -d $(INSTDIR) || mkdir -p $(INSTDIR)
test -d $(LIBDIR) || mkdir -p $(LIBDIR)
diff --git a/Makefile.win32 b/Makefile.win32
index 1ad9bed4..64b70569 100644
--- a/Makefile.win32
+++ b/Makefile.win32
@@ -12,14 +12,25 @@ EXECS = sg_readcap sg_turs sg_inq sg_start sg_modes sg_logs sg_senddiag \
sg_sync sg_prevent sg_get_config sg_wr_mode \
sg_rtpg sg_reassign sg_format sg_rmsn sg_ident \
sg_read_long sg_write_long sg_verify sg_rdac sg_vpd \
- sg_sat_identify
+ sg_sat_identify sg_read_buffer sg_write_buffer sg_opcodes
+
+EXE_S = sg_readcap.exe sg_turs.exe sg_inq.exe sg_start.exe sg_modes.exe \
+ sg_logs.exe sg_senddiag.exe sg_persist.exe sg_requests.exe \
+ sg_ses.exe sg_luns.exe sg_scan.exe sg_sync.exe sg_prevent.exe \
+ sg_get_config.exe sg_wr_mode.exe sg_rtpg.exe sg_reassign.exe \
+ sg_format.exe sg_rmsn.exe sg_ident.exe sg_read_long.exe \
+ sg_write_long.exe sg_verify.exe sg_rdac.exe sg_vpd.exe \
+ sg_sat_identify.exe sg_read_buffer.exe sg_write_buffer.exe \
+ sg_opcodes.exe
MAN_PGS = sg_readcap.8 sg_turs.8 sg_inq.8 sg_start.8 sg_modes.8 sg_logs.8 \
sg_senddiag.8 sg_persist.8 sg_requests.8 sg_ses.8 sg_luns.8 \
sg_scan.8 sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
sg_read_long.8 sg_write_long.8 sg_verify.8 sg_rdac.8 sg_vpd.8 \
- sg3_utils.8 sg_sat_identify.8
+ sg3_utils.8 sg_sat_identify.8 sg_read_buffer.8 sg_write_buffer.8 \
+ sg_opcodes.8
+
MAN_PREF = man8
OS_FLAGS = -DSG3_UTILS_WIN32 -DSPTD
@@ -33,10 +44,9 @@ CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS)
O_FILES = sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_win32.o
O_BFILES = sg_lib.o sg_cmds_basic.o sg_pt_win32.o
+O_SFILES = sg_lib.o
LDFLAGS =
-# LDFLAGS = -lcam
-# LDFLAGS = -v -lm
all: $(EXECS)
cp sg_scan.8w sg_scan.8
@@ -46,8 +56,7 @@ depend dep:
done > .depend
clean:
- /bin/rm -f *.o $(EXECS) core* .depend *.a *.la *.lo
- /bin/rm -rf .libs
+ /bin/rm -f *.o $(EXE_S) core* .depend *.a
.c.o:
$(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) -c -o $@ $<
@@ -85,8 +94,8 @@ sg_ses: sg_ses.o $(O_FILES)
sg_luns: sg_luns.o $(O_BFILES)
$(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
-sg_scan: sg_scan.o $(O_BFILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+sg_scan: sg_scan.o $(O_SFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_SFILES)
sg_sync: sg_sync.o $(O_BFILES)
$(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
@@ -133,6 +142,15 @@ sg_vpd: sg_vpd.o sg_vpd_vendor.o $(O_BFILES)
sg_sat_identify: sg_sat_identify.o $(O_FILES)
$(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+sg_read_buffer: sg_read_buffer.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_write_buffer: sg_write_buffer.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_opcodes: sg_opcodes.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
install: $(EXECS)
cp sg_scan.8w sg_scan.8
install -d $(INSTDIR)
diff --git a/README b/README
index b29f5d5d..13364916 100644
--- a/README
+++ b/README
@@ -5,8 +5,8 @@ Introduction
This package contains low level utilities for devices that use a SCSI
command set. Apart from SCSI parallel interface (SPI) devices, the SCSI
command set is used by ATAPI devices (CD/DVDs and tapes), USB
-mass storage devices, Fibre Channel disks and IEEE 1394 storage
-devices (that use the "SBP" protocol).
+mass storage devices, Fibre Channel disks, IEEE 1394 storage
+devices (that use the "SBP" protocol), SAS and iSCSI.
This package originally targetted the Linux SCSI subsystem. Since most
operating systems contain a SCSI command pass-through mechanism, many
@@ -152,9 +152,10 @@ of the sg3_utils directory:
- sginfo, sgm_dd, sgp_dd, sg_dd, sg_emc_trespass, sg_get_config,
sg_format, sg_ident, sg_inq, sg_logs, sg_luns, sg_map, sg_map26,
sg_modes, sg_opcodes, sg_persist, sg_prevent, sg_rbuf, sg_rdac, sg_read,
- sg_readcap, sg_read_long, sg_reassign, sg_request, sg_reset, sg_rmsn,
- sg_rtpg, sg_scan, sg_senddiag, sg_ses, sg_start, sg_sync,
- sg_test_rwbuff, sg_turs, sg_verify, sg_vpd, sg_write_long, sg_wr_mode
+ sg_readcap, sg_read_buffer, sg_read_long, sg_reassign, sg_request,
+ sg_reset, sg_rmsn, sg_rtpg, sg_sat_identify, sg_scan, sg_senddiag,
+ sg_ses, sg_start, sg_sync, sg_test_rwbuff, sg_turs, sg_verify, sg_vpd,
+ sg_write_buffer, sg_write_long, sg_wr_mode
These utilities and the libsgutils.so library which they depend on are built
by the Makefile in the main directory. This Makefile does not invoke the
@@ -181,7 +182,7 @@ Some of these utilities have man pages.
Here is a list in alphabetical order of utilities found in the examples
subdirectory:
- sg_excl.c, scsi_inquiry, sg_iovec_tst.c, sg_sat_chk_power.c,
- sg_sat_identify.c, sg_sat_set_features.c, sg_sat_smart_rd_data.c,
+ sg__sat_identify.c, sg_sat_set_features.c, sg_sat_smart_rd_data.c,
sg_simple1, sg_simple2, sg_simple3, sg_simple4, sg_simple5 and
sg_simple16.c
@@ -207,6 +208,11 @@ the sg3_utils package. Currently it contains:
at differences between the lk 2.4 and 2.6 series;
including its use with block devices
- tools.html : a list of SCSI and storage tools with a summary and url
+
+The "scripts" subdirectory contains some bourne (bash) shell scripts
+that rely on utilities in the main directory. One script uses the sdparm
+utility. These scripts are described in the scripts/README file and have
+usage messages.
Notes for utilities without man pages
@@ -246,11 +252,6 @@ scsi device. This is only supported for lk >= 2.4.15 and for adapter
drivers that indicate that they have 16 byte CDB capability (otherwise
DID_ABORT will appear in the host_status).
-"sg_sat_identify" attempts to push an ATA IDENTIFY DEVICE or
-IDENTIFY PACKET DEVICE command through the SAT-defined ATA
-PASS- THROUGH (16) SCSI command. If successful, the 256 word (512 byte)
-response is output.
-
"sg_sat_chk_power" attempts to push an ATA CHECK POWER MODE command
through the SAT-defined ATA PASS_THROUGH (16) SCSI command. That
ATA command needs to read the "FIS" registers after the command is
@@ -276,11 +277,25 @@ command line arguments is considered:
type command lines. These have short form (starting with "-")
and corresponding longer form (starting with "--") options.
-The recent utilities that use "getopt_long" are, in alphabetical
-order:
+The older utilities that use ad hoc options, in alphabetical order:
+ - sg_emc_trespass, sginfo(1/2), sg_inq, sg_logs, sg_map, sg_modes,
+ sg_opcodes, sg_rbuf, sg_rdac, sg_readcap, sg_reset, sg_scan (linux),
+ sg_senddiag, sg_start, sg_test_rwbuf, sg_turs
+In sg3_utils version 1.23 the following utilities from this group were
+converted to have a dual getopt_long/ad_hoc interface, defaulting to
+the getop_long interface:
+ - sg_inq, sg_logs, sg_modes, sg_opcodes, sg_rbuf, sg_readcap,
+ sg_senddiag, sg_start, sg_turs
+These can be switched back to the older (backward compatible) ad hoc
+interface by defining the SG3_UTILS_OLD_OPTS environment variable
+or using '-O' as the first command line option.
+
+The more recent utilities that use "getopt_long" only are:
- sg_format sg_get_config sg_ident sg_luns sg_map26 sg_persist
- sg_prevent sg_read_long sg_reassign sg_requests sg_rmsn sg_rtpg
- sg_ses sg_sync sg_test_rwbuf sg_verify sg_vpd sg_write_long sg_wr_mode
+ sg_prevent sg_read_buffer sg_read_long sg_reassign sg_requests
+ sg_rmsn sg_rtpg sg_sat_identify sg_scan (w), sg_ses sg_sync
+ sg_test_rwbuf sg_verify sg_vpd sg_write_buffer sg_write_long
+ sg_wr_mode
Linux header file problems
@@ -328,4 +343,4 @@ user). It is available for Linux and other operating systems.
See http://members.aol.com/plscsi .
Doug Gilbert
-16th October 2006
+31st January 2007
diff --git a/README.freebsd b/README.freebsd
index 0bf743e7..53e769db 100644
--- a/README.freebsd
+++ b/README.freebsd
@@ -16,8 +16,10 @@ Here is a list of utilities that have been ported:
sg_luns
sg_modes
sg_persist
+ sg_opcodes
sg_prevent
sg_rdac
+ sg_read_buffer
sg_read_long
sg_readcap
sg_reassign
@@ -33,6 +35,7 @@ Here is a list of utilities that have been ported:
sg_verify
sg_vpd
sg_wr_mode
+ sg_write_buffer
sg_write_long
Most utility names are indicative of the main SCSI command
@@ -70,9 +73,9 @@ command. To access ATAPI devices (e.g. ATAPI DVD drives) the
kernel may need to be configured with the "atapicam" device.
At the present time these utilities have been lightly tested on a
-FreeBSD version 5.3 system with some SCSI disks, a SCSI tape
+FreeBSD version 6.2 system with some SCSI disks, a SCSI tape
drive and an ATAPI CD drive.
Doug Gilbert
-11th October 2006
+15th January 2007
diff --git a/README.tru64 b/README.tru64
index 71f26850..f8d90b67 100644
--- a/README.tru64
+++ b/README.tru64
@@ -15,15 +15,18 @@ Here is a list of utilities that have been ported:
sg_logs
sg_luns
sg_modes
+ sg_opcodes
sg_persist
sg_prevent
sg_rdac
+ sg_read_buffer
sg_read_long
sg_readcap
sg_reassign
sg_requests
sg_rmsn
sg_rtpg
+ sg_sat_identify
sg_senddiag
sg_ses
sg_start
@@ -32,6 +35,7 @@ Here is a list of utilities that have been ported:
sg_verify
sg_vpd
sg_wr_mode
+ sg_write_buffer
sg_write_long
Most utility names are indicative of the main SCSI command
@@ -75,4 +79,4 @@ subdirectory. Currently only the Tru64 port uses it.
Doug Gilbert
-5th October 2006
+12th January 2006
diff --git a/README.win32 b/README.win32
index 79e46a68..34f8bc1a 100644
--- a/README.win32
+++ b/README.win32
@@ -5,6 +5,17 @@ to Linux. In some cases a utility could be ported but requires more work. An
example is sg_dd which needs more work beyond the SCSI command pass through
mechanism.
+Two build environments are caterered for: cygwin (see www.cygwin.com) and
+MinGW ("Minimalist GNU for Windows", see www.mingw.org). Both are based in
+the gcc compiler (although other C compilers should have little problem with
+the source code). Cygwin is a more sophisticated, commercial product that
+results in executables that depend on cygwin1.dll . No licensing is required
+since sg3_utils is open source (with either BSD or GPL licenses) but users
+will need to fetch that dll. On the other hand MinGW (and its companion MSYS
+shell) builds freestanding console executables. The Unix library support is
+not as advanced with MinGW which has led to some timing functions being
+compiled out when sg3_utils is built for MinGW.
+
Supported Utilities
===================
Here is a list of utilities that have been ported:
@@ -16,8 +27,10 @@ Here is a list of utilities that have been ported:
sg_luns
sg_modes
sg_persist
+ sg_opcodes
sg_prevent
sg_rdac
+ sg_read_buffer
sg_read_long
sg_readcap
sg_reassign
@@ -34,6 +47,7 @@ Here is a list of utilities that have been ported:
sg_verify
sg_vpd
sg_wr_mode
+ sg_write_buffer
sg_write_long
Most utility names are indicative of the main SCSI command that they execute.
@@ -97,9 +111,21 @@ shown in Windows documentation, may be used but "PD" is obviously
quicker to type.
Finally sg_scan does not manage to put all device names for USB and
-ISS 1394 devices on one line. The last two lines of output are actually
+IEEE 1394 devices on one line. The last two lines of output are actually
the same device.
+Several utilities have conditional compilation sections based on
+the SG3_UTILS_MINGW define. For those who want to try native C compilers
+on Windows setting the SG3_UTILS_MINGW define may help.
+
+Build environments
+==================
+This package has various Makefiles so that these utilities can be built
+in either a cygwin and MinGW environment, called Makefile.win32 and
+Makefile.mingw respectively. The executables produced are console
+applications that can be executed in either a cygwin, MSYS or "cmd" shell.
+See the INSTALL file for more details.
+
Doug Gilbert
-16th October 2006
+21st January 2007
diff --git a/archive/sg3_utils_123o.spec b/archive/sg3_utils_123o.spec
new file mode 100644
index 00000000..ee8295fa
--- /dev/null
+++ b/archive/sg3_utils_123o.spec
@@ -0,0 +1,193 @@
+%define name sg3_utils
+%define version 1.23
+%define release 1
+
+%define major 1
+%define minor 0
+%define libname %{_lib}sgutils-%{major}_%{minor}
+
+Summary: Utilities for SCSI devices in Linux
+Name: %{name}
+Version: %{version}
+Release: %{release}
+License: GPL/FreeBSD
+Group: Utilities/System
+URL: http://www.torque.net/sg/sg3_utils.html
+Source0: http://www.torque.net/sg/p/%{name}-%{version}.tgz
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+Packager: Douglas Gilbert <dgilbert at interlog dot com>
+
+%description
+Collection of Linux utilities for devices that use the SCSI command set.
+Includes utilities to copy data based on "dd" syntax and semantics (called
+sg_dd, sgp_dd and sgm_dd); check INQUIRY data and VPD pages (sg_inq); check
+mode and log pages (sginfo, sg_modes and sg_logs); spin up and down
+disks (sg_start); do self tests (sg_senddiag); and various other functions.
+See the README, CHANGELOG and COVERAGE files. Requires the linux kernel 2.4
+series or later. In the 2.4 series SCSI generic device names (e.g. /dev/sg0)
+must be used. In the 2.6 series other device names may be used as
+well (e.g. /dev/sda).
+
+Warning: Some of these tools access the internals of your system
+and the incorrect usage of them may render your system inoperable.
+
+%package -n %{libname}
+Summary: Shared library for %{name}
+Group: System/Libraries
+
+%description -n %{libname}
+This package contains the shared library for %{name}.
+
+%package -n %{libname}-devel
+Summary: Static library and header files for the sgutils library
+Group: Development/C
+Obsoletes: %{name}-devel
+Provides: %{name}-devel
+Provides: libsgutils-devel
+Requires: %{libname} = %{version}-%{release}
+
+%description -n %{libname}-devel
+This package contains the static sgutils library and its header
+files.
+
+%prep
+
+%setup -q
+
+%build
+
+make \
+ CFLAGS="%{optflags}" \
+ LIBDIR="%{_libdir}"
+
+%install
+[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
+
+make install \
+ PREFIX=%{_prefix} \
+ LIBDIR=%{buildroot}/%{_libdir} \
+ INSTDIR=%{buildroot}/%{_bindir} \
+ MANDIR=%{buildroot}/%{_mandir} \
+ INCLUDEDIR=%{buildroot}/%{_includedir} \
+ LIB_VINFO=1:0:0
+
+%post -n %{libname} -p /sbin/ldconfig
+
+%postun -n %{libname} -p /sbin/ldconfig
+
+%clean
+[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
+
+%files
+%defattr(-,root,root)
+%doc CHANGELOG COPYING COVERAGE CREDITS INSTALL README README.sg_start
+%attr(0755,root,root) %{_bindir}/*
+%{_mandir}/man8/*
+
+%files -n %{libname}
+%defattr(-,root,root)
+%{_libdir}/*.so.*
+
+%files -n %{libname}-devel
+%defattr(-,root,root)
+%{_includedir}/scsi/*.h
+%{_libdir}/*.so
+%{_libdir}/*.a
+%{_libdir}/*.la
+
+%changelog
+* Tue Jan 30 2007 - dgilbert at interlog dot com
+- add sg_read_buffer + sg_write_buffer
+ * sg3_utils-1.23
+
+* Mon Oct 16 2006 - dgilbert at interlog dot com
+- add sg_sat_identify, expand sg_format and sg_requests
+ * sg3_utils-1.22
+
+* Thu Jul 06 2006 - dgilbert at interlog dot com
+- add sg_vpd and sg_rdac, uniform exit statuses
+ * sg3_utils-1.21
+
+* Tue Apr 18 2006 - dgilbert at interlog dot com
+- sg_logs: sas port specific page decoding, sg*_dd updates
+ * sg3_utils-1.20
+
+* Fri Jan 27 2006 - dgilbert at interlog dot com
+- sg_get_config: resync features with mmc5 rev 1
+ * sg3_utils-1.19
+
+* Fri Nov 18 2005 - dgilbert at interlog dot com
+- add sg_map26; sg_inq '-rr' option to play with hdparm
+ * sg3_utils-1.18
+
+* Thu Sep 22 2005 - dgilbert at interlog dot com
+- add ATA information VPD page to sg_inq
+ * sg3_utils-1.17
+
+* Wed Aug 10 2005 - dgilbert at interlog dot com
+- add sg_ident, sg_inq VPD page extensions
+ * sg3_utils-1.16
+
+* Sun Jun 05 2005 - dgilbert at interlog dot com
+- use O_NONBLOCK on all fds that use SG_IO ioctl
+ * sg3_utils-1.15
+
+* Fri May 06 2005 - dgilbert at interlog dot com
+- produce libsgutils (+ -devel variant) as well as sg3_utils binary rpm
+ * sg3_utils-1.14
+
+* Sun Mar 13 2005 - dgilbert at interlog dot com
+- add sg_format, sg_dd extensions
+ * sg3_utils-1.13
+
+* Fri Jan 21 2005 - dgilbert at interlog dot com
+- add sg_wr_mode, sg_rtpg + sg_reassign; sginfo sas tweaks
+ * sg3_utils-1.12
+
+* Fri Nov 26 2004 - dgilbert at interlog dot com
+- add sg_sync, sg_prevent and sg_get_config; fix sg_requests
+ * sg3_utils-1.11
+
+* Sat Oct 30 2004 - dgilbert at interlog dot com
+- fix read capacity (10+16), add sg_luns
+ * sg3_utils-1.10
+
+* Thu Oct 21 2004 - dgilbert at interlog dot com
+- sg_requests, sg_ses, sg_verify, libsgutils(sg_lib.c+sg_cmds.c), devel rpm
+ * sg3_utils-1.09
+
+* Tue Aug 31 2004 - dgilbert at interlog dot com
+- 'register+move' in sg_persist, sg_opcodes sorts, sg_write_long
+ * sg3_utils-1.08
+
+* Thu Jul 08 2004 - dgilbert at interlog dot com
+- add '-fHead' to sginfo, '-i' for sg_inq, new sg_opcodes + sg_persist
+ * sg3_utils-1.07
+
+* Mon Apr 26 2004 - dgilbert at interlog dot com
+- sg3_utils.spec for mandrake; more sginfo work, sg_scan, sg_logs
+ * sg3_utils-1.06
+
+* Wed Nov 12 2003 - dgilbert at interlog dot com
+- sg_readcap: sizes; sg_logs: double fetch; sg_map 256 sg devices; sginfo
+ * sg3_utils-1.05
+
+* Tue May 13 2003 - dgilbert at interlog dot com
+- default sg_turs '-n=' to 1, sg_logs gets '-t' for temperature, CREDITS
+ * sg3_utils-1.04
+
+* Wed Apr 02 2003 - dgilbert at interlog dot com
+- 6 byte CDBs for sg_modes, sg_start on block devs, sg_senddiag, man pages
+ * sg3_utils-1.03
+
+* Wed Jan 01 2003 - dgilbert at interlog dot com
+- interwork with block SG_IO, fix in sginfo, '-t' for sg_turs
+ * sg3_utils-1.02
+
+* Wed Aug 14 2002 - dgilbert at interlog dot com
+- raw switch in sg_inq
+ * sg3_utils-1.01
+
+* Sun Jul 28 2002 - dgilbert at interlog dot com
+- decode sg_logs pages, add dio to sgm_dd, drop "gen=1" arg, "of=/dev/null"
+ * sg3_utils-1.00
diff --git a/debian/changelog b/debian/changelog
index 1f6b56e0..5642bd70 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+sg3-utils (1.23-0.1) unstable; urgency=low
+
+ * New upstream version
+
+ -- Doug Gilbert <dgilbert@interlog.com> Wed, 31 Jan 2007 11:00:00 -0500
+
sg3-utils (1.22-0.1) unstable; urgency=low
* New upstream version
diff --git a/debian/control b/debian/control
index 8735a1f8..ee0040be 100644
--- a/debian/control
+++ b/debian/control
@@ -2,12 +2,12 @@ Source: sg3-utils
Section: admin
Priority: optional
Maintainer: Eric Schwartz (Skif) <emschwar@debian.org>
-Build-Depends: debhelper (>> 4.0.0)
-Standards-Version: 3.6.1
+Build-Depends: debhelper (>> 4.0.0), chrpath, libtool
+Standards-Version: 3.7.2
Package: sg3-utils
Architecture: any
-Depends: ${shlibs:Depends}, libsgutils1-0
+Depends: ${shlibs:Depends}
Conflicts: sg-utils, cdwrite
Replaces: sg-utils
Description: Collection of Linux utilities for devices that use the
@@ -38,6 +38,7 @@ Description: Collection of Linux utilities for devices that use the
* sg_rbuf - tests SCSI bus speed
* sg_rdac - vendor specific for RDAC hardware
* sg_read - reads multiple blocks, useful for timing
+ * sg_read_buffer - READ BUFFER
* sg_read_long - read a "long" block from the given device
* sg_readcap - prints the output of a READ CAPACITY command
* sg_reassign - issues a REASSIGN BLOCKS command (map out bad sectors)
@@ -49,29 +50,31 @@ Description: Collection of Linux utilities for devices that use the
* sg_scan - displays the SCSI bus on stdout
* sg_senddiag - runs SCSI self tests
* sg_ses - fetches status and send control to a SES device
- * sg_start - spins up (or down) disks and cd/dvds
+ * sg_start - spins up (or down) disks and optical drives
* sg_sync - issues a SYNCHRONIZE CACHE command
* sg_test_rwbuf - tests the SCSI host adapter
* sg_turs - execute a TEST UNIT READY command on the given device
* sg_verify - issues VERIFY command on SCSI disks
- * sg_vpd - decode VPD pages
+ * sg_vpd - utility for decoding VPD pages
+ * sg_write_buffer - WRITE BUFFER, may be used to load firmware
* sg_write_long - write a "long" block to the given device
* sg_wr_mode - low level utility to change mode pages
.
It also includes source code for some example programs that demonstrate
how to use the scsi generic driver.
-Package: libsgutils1-0
-Section: libraries
+Package: libsgutils1
+Section: libs
+Depends: ${shlibs:Depends}
Architecture: any
Recommends: sg3-utils
Description: Utilities for working with generic SCSI devices (shared libraries)
- This package contains the shared libraries.
+ This package contains the shared libraries that allow other programs to use it.
-Package: libsgutils1-0-dev
+Package: libsgutils1-dev
Section: devel
Architecture: any
-Depends: libsgutils1-0
+Depends: libsgutils1, ${shlibs:Depends}
Recommends: sg3-utils
Description: Utilities for working with generic SCSI devices (developer files)
This package contains the <scsi/sg_cmds.h> , <scsi/sg_lib.h> ,
diff --git a/debian/docs b/debian/docs
index 0d16aea8..34ad7eeb 100644
--- a/debian/docs
+++ b/debian/docs
@@ -6,3 +6,5 @@ README
README.sg_start
doc/sg3_utils.html
doc/sg_dd.html
+doc/sg_io.html
+doc/tools.html
diff --git a/debian/libsgutils1.postinst b/debian/libsgutils1.postinst
new file mode 100644
index 00000000..2be47db4
--- /dev/null
+++ b/debian/libsgutils1.postinst
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/libsgutils1.postrm b/debian/libsgutils1.postrm
new file mode 100644
index 00000000..2be47db4
--- /dev/null
+++ b/debian/libsgutils1.postrm
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/rules b/debian/rules
index 52d66a97..b873367b 100755
--- a/debian/rules
+++ b/debian/rules
@@ -7,9 +7,9 @@
# package.
# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
+# export DH_VERBOSE=1
-# This is the debhelper compatability version to use.
+# Debhelper compatibility level
export DH_COMPAT=4
configure: configure-stamp
@@ -30,11 +30,12 @@ build-stamp:
clean:
dh_testdir
dh_testroot
- rm -f build-stamp configure-stamp
# Add here commands to clean up after the build process.
-$(MAKE) clean
+ rm -f build-stamp configure-stamp debian/substvars
+
dh_clean
install: DH_OPTIONS=
@@ -47,6 +48,7 @@ install: build
# Add here commands to install the package into debian/tmp
$(MAKE) -e install DESTDIR=$(CURDIR)/debian/tmp PREFIX=/usr
+ find debian/tmp/usr/bin debian/tmp/usr/lib -type f -exec chrpath -d {} \;
dh_install --autodest --sourcedir=debian/tmp
dh_installman
@@ -67,8 +69,9 @@ binary-arch: build install
dh_link -a
dh_compress -a -X archive -X .c -X .h
dh_fixperms -a
+ dh_makeshlibs -V -v
dh_installdeb -a
- dh_shlibdeps -a
+ dh_shlibdeps -ldebian/tmp/usr/lib -L libsgutils1
dh_gencontrol -a
dh_md5sums -a
dh_builddeb -a
diff --git a/doc/sg3_utils.html b/doc/sg3_utils.html
index 0c47ce2e..5016a9f8 100644
--- a/doc/sg3_utils.html
+++ b/doc/sg3_utils.html
@@ -16,12 +16,13 @@ sg3_utils package</h1>
</center>
<a href="#intro"></a>
<ol id="mozToc">
-<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6--><li><a href="#mozTocId697451">
-The&nbsp; Linux
+<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6-->
+ <li><a href="#mozTocId697451"> The&nbsp; Linux
sg3_utils package</a>
<ol>
<li><a href="#mozTocId746876"> Introduction</a></li>
<li><a href="#mozTocId832900"> Contents of sg3_utils</a></li>
+ <li><a href="#mozTocId736867">Exit status</a></li>
<li><a href="#mozTocId143590">Changing mode page
settings</a></li>
<li><a href="#mozTocId301018">Examples</a></li>
@@ -33,11 +34,14 @@ settings</a></li>
<h2><a class="mozTocH2" name="mozTocId746876"></a> Introduction</h2>
The <span style="font-weight: bold;">sg3_utils</span> package contains
utilities
-that send SCSI commands to "SCSI" devices. As well as devices on
-transports associated with SCSI (e.g. Fibre Channel (FCP) and the SCSI
+that send SCSI commands to devices. As well as devices on
+transports traditionally associated with SCSI (e.g. Fibre Channel
+(FCP), Serial
+Attached SCSI (SAS) and the SCSI
Parallel Interface(SPI)) many
other devices use SCSI command sets. ATAPI cd/dvd drives
-and SATA disks that use a translation layer or bridge device are
+and SATA disks that connect via a translation layer or a bridge device
+are
examples of devices that use SCSI command sets.<br>
<br>
SCSI command sets are divided into a common set and several device
@@ -60,9 +64,10 @@ targeted the linux kernel 2.2 series with some support for the
2.0 series. See an earlier version of this web <a href="uu_index.html">page</a>
for further information about sg_utils.&nbsp; This
document describes
-<span style="font-weight: bold;">version 1.22</span> of <span
+<span style="font-weight: bold;">version 1.23</span> of <span
style="font-weight: bold;">sg3_utils</span> .&nbsp; A subset of these
-utilities have been ported to the FreeBSD, Tru64 and Windows operating
+utilities have been ported to the FreeBSD, Tru64 and the Windows
+operating
systems.<br>
<br>
In the linux kernel 2.4 series most of these utilities must be
@@ -84,12 +89,20 @@ of this page has been moved to the <a href="tools.html">tools</a> page.<span
style="font-weight: bold;"><br>
</span></p>
<h2><a class="mozTocH2" name="mozTocId832900"></a> Contents of sg3_utils</h2>
-Here is a listing in alphabetical order of the utilities in the
+This package contains over 30 utilities, their "man" pages, build files
+and general documentation (e.g. several README files). The utilities
+have a command line interface which in general has this form:<br>
+<br>
+<span style="font-family: monospace;">UTILITY_NAME [OPTIONS] DEVICE</span><br>
+<br>
+No more than one DEVICE name can be given (and in a few cases, no
+DEVICE name is required). Here is a listing in alphabetical order of
+the utilities in the
sg3_utils package:<br>
<br>
<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
cellspacing="2">
- <caption align="bottom"><span style="font-weight: bold;">Table 1
+ <caption><span style="font-weight: bold;">Table 1
Utilities in sg3_utils</span><br>
</caption> <tbody>
<tr>
@@ -98,8 +111,10 @@ Utilities in sg3_utils</span><br>
<td style="vertical-align: top;"><span style="font-weight: bold;">Main
SCSI commands</span><br>
</td>
- <td style="vertical-align: top;"><span style="font-weight: bold;">subdirectory<br>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">directory<br>
</span> </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">CLI</span><br>
+ </td>
<td style="vertical-align: top;"><span style="font-weight: bold;">Ported</span><br>
</td>
<td style="vertical-align: top;"><span style="font-weight: bold;">Notes</span><br>
@@ -112,10 +127,12 @@ SCSI commands</span><br>
</td>
<td style="vertical-align: top;">utils<br>
</td>
- <td style="vertical-align: top;"><br>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
+ <td style="vertical-align: top;">fb<br>
</td>
<td style="vertical-align: top;">converts stdin (assumed binary)
-to ASCII hex and ASCII, sending its output to stdout (like Unix <span
+to ASCII hex and ASCII, sending its output to stdout (like the Unix <span
style="font-weight: bold;">od</span> command)<br>
</td>
</tr>
@@ -126,6 +143,8 @@ to ASCII hex and ASCII, sending its output to stdout (like Unix <span
</td>
<td style="vertical-align: top;">archive<br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">copy of Kurt Garloff's useful
@@ -139,6 +158,8 @@ script<br>
</td>
<td style="vertical-align: top;">examples<br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">uses deprecated
@@ -150,9 +171,11 @@ SCSI_IOCTL_SEND_COMMAND ioctl<br>
</td>
<td style="vertical-align: top;">MODE SENSE/SELECT, INQUIRY<br>
</td>
- <td style="vertical-align: top;">****<br>
+ <td style="vertical-align: top;">--&gt;<br>
</td>
- <td style="vertical-align: top;"><br>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
+ <td style="vertical-align: top;">fb,t64,w<br>
</td>
<td style="vertical-align: top;">was in sg3_utils for a short
time; now in own package, see <a href="sdparm.html">sdparm</a> .
@@ -167,10 +190,13 @@ commands.<br>
</td>
<td style="vertical-align: top;">utils<br>
</td>
- <td style="vertical-align: top;"><br>
+ <td style="vertical-align: top;">getopt<br>
</td>
- <td style="vertical-align: top;">check asc/ascq codes from
-www.t10.org page against sg3_utils table<br>
+ <td style="vertical-align: top;">fb<br>
+ </td>
+ <td style="vertical-align: top;">check asc/ascq codes from <a
+ href="http://www.t10.org">www.t10.org</a> page against
+sg3_utils table<br>
</td>
</tr>
<tr>
@@ -180,13 +206,16 @@ www.t10.org page against sg3_utils table<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">symbolic decoding (optional
changing) of mode pages. Can also output (disk) defect lists. In lk 2.4
-can be given primary device nodes (e.g. /dev/sda) as well as sg device
-nodes. See <span style="font-weight: bold;">scsiinfo</span> package
-notes below.<br>
+can be given primary device nodes (e.g. <span
+ style="font-family: monospace;">/dev/sda</span>) as well as sg device
+nodes. Port of older <span style="font-weight: bold;">scsiinfo</span>
+utility.<br>
</td>
</tr>
<tr>
@@ -196,10 +225,12 @@ notes below.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">dd<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">sg_dd variant that uses memory
-mapped IO (only on sg devices)<br>
+mapped IO (only on linux sg devices)<br>
</td>
</tr>
<tr>
@@ -209,6 +240,8 @@ mapped IO (only on sg devices)<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">dd<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">sg_dd variant that uses POSIX
@@ -222,6 +255,8 @@ threads<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">dd<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">Unix <span
@@ -236,6 +271,8 @@ SG_IO ioctl to send SCSI commands to copy data. See the <a
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">utility specialized for EMC
@@ -249,6 +286,8 @@ Clariion series<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w<br>
</td>
<td style="vertical-align: top;">format or resize a SCSI disk<br>
@@ -261,6 +300,8 @@ Clariion series<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">fetch features and profiles of a
cd/dvd drive and/or its current media<br>
@@ -269,13 +310,17 @@ cd/dvd drive and/or its current media<br>
<tr>
<td style="vertical-align: top;">sg_ident<br>
</td>
- <td style="vertical-align: top;">REPORT/SET DEVICE IDENTIFIER<br>
+ <td style="vertical-align: top;">REPORT/SET IDENTIFYING
+INFORMATION<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">default is to report (fetch) the
-device identifier. With the '--set' option a new identifier is sent
+device identifier. With the '<span style="font-family: monospace;">--set</span>'
+option a new identifier is sent
to the device.<br>
</td>
</tr>
@@ -286,11 +331,13 @@ to the device.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">fetch standard response, VPD
-pages (including device identification) or version descriptors. Also
-can perform IDENTIFY (PACKET) DEVICE ATA command. VPD page decoding now
-also performed by sg_vpd .<br>
+pages or version descriptors. Also
+can perform IDENTIFY (PACKET) DEVICE ATA command. VPD page decoding
+also performed by sg_vpd and sdparm.<br>
</td>
</tr>
<tr>
@@ -300,9 +347,11 @@ also performed by sg_vpd .<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">fetch log sense pages, decode
-standard pages<br>
+standard and some vendor pages<br>
</td>
</tr>
<tr>
@@ -312,6 +361,8 @@ standard pages<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">fetch luns reported by a device
(lun 0 or "well known lu")<br>
@@ -324,6 +375,8 @@ standard pages<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">shows mapping between sg devices
@@ -338,9 +391,12 @@ and primary device node (if any). In lk 2.6 see <a
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
- <td style="vertical-align: top;">maps between single sg device
+ <td style="vertical-align: top;">maps between single linux sg
+device
and primary device node (and vice versa). Also does mapping in to, and
out of, sysfs. For the linux 2.6 series.<br>
</td>
@@ -352,8 +408,10 @@ out of, sysfs. For the linux 2.6 series.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
- <td style="vertical-align: top;">dump mode pages (mainly in hex)<br>
+ <td style="vertical-align: top;">fetch mode pages (mainly in hex)<br>
</td>
</tr>
<tr>
@@ -363,7 +421,9 @@ out of, sysfs. For the linux 2.6 series.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
- <td style="vertical-align: top;"><br>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
+ <td style="vertical-align: top;">fb,t64,w<br>
</td>
<td style="vertical-align: top;">fetch supported SCSI commands or
supported task management functions<br>
@@ -376,6 +436,8 @@ supported task management functions<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">control persistent reservations
and report
@@ -389,6 +451,8 @@ reservation status<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">control media removal, mainly
for those SCSI devices which have removable media (e.g. CD/DVD and tape
@@ -402,6 +466,8 @@ drives)<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">read from SCSI device cache.
@@ -415,6 +481,8 @@ Typically for testing the SCSI transport (for throughput or errors)<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w</td>
<td style="vertical-align: top;">display or modify RDAC redundant
controller mode page<br>
@@ -427,11 +495,13 @@ controller mode page<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">dd<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">read continually from same
offset. Syntax similar to sg_dd (without write side). Can test SCSI
-device cache and transport performance (like sg_rbuf).<br>
+device cache and transport performance.<br>
</td>
</tr>
<tr>
@@ -441,18 +511,36 @@ device cache and transport performance (like sg_rbuf).<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">fetch the number of blocks and
the individual block size for disks and CD/DVD media<br>
</td>
</tr>
<tr>
+ <td style="vertical-align: top;">sg_read_buffer<br>
+ </td>
+ <td style="vertical-align: top;">READ BUFFER<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
+ <td style="vertical-align: top;">fb,t64,w<br>
+ </td>
+ <td style="vertical-align: top;">read descriptors or data<br>
+ </td>
+ </tr>
+ <tr>
<td style="vertical-align: top;">sg_read_long<br>
</td>
<td style="vertical-align: top;">READ LONG<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">read data from given lba which
includes the block and ECC data.<br>
@@ -465,6 +553,8 @@ includes the block and ECC data.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">reassign a lba from one sector
on a disk (typically damaged) to a new (spare) sector. User data copied
@@ -478,10 +568,12 @@ if it is recoverable.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">fetch sense data from the given
-SCSI device. Useful if no autosense , to get progress indication (e.g.
-during a format) or find the power condition state.<br>
+device. Modern uses include getting a progress indication (e.g.
+during a format) or finding the power condition state.<br>
</td>
</tr>
<tr>
@@ -491,6 +583,8 @@ during a format) or find the power condition state.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">Issue a driver, (SCSI) bus or
@@ -504,6 +598,8 @@ device (target or lun?) reset.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">Relatively new command
added to SPC-3. Format of response is vendor specific so this utility
@@ -517,6 +613,8 @@ outputs it in hex (default) or binary.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">Specialized for multi-ported
SCSI devices where one port (or a group of them) is preferred for IO
@@ -529,6 +627,8 @@ over another (or others).<br>
<td style="vertical-align: top;">ATA PASS-THROUGH</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w<br>
</td>
<td style="vertical-align: top;">Sends IDENTIFY DEVICE or
@@ -542,6 +642,8 @@ IDENTIFY PACKET DEVICE ATA commands via the SAT ATA PASS-THROUGH (16 or
</td>
<td style="vertical-align: top;">examples<br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">Simpler version of
@@ -557,10 +659,14 @@ examples subdirectory.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+[win:<br>
+getopt]<br>
+ </td>
<td style="vertical-align: top;">w<br>
</td>
<td style="vertical-align: top;">maps each sg device name to
-the corresponding numeric &lt;host, channel, target', lun&gt; tuple. In
+the corresponding numeric &lt;host, channel, target, lun&gt; tuple. In
lk 2.6 series the "<a href="scsi/lsscsi.html">lsscsi</a> -g" command is
similar. In Windows shows one device per line, with the device's
various names and INQUIRY response string on that line.<br>
@@ -573,6 +679,8 @@ various names and INQUIRY response string on that line.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">Issues either a default self
test or a short/extended foreground/background self test. With no
@@ -588,6 +696,8 @@ pages.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">Fetches status diagnostic
pages from, and sends some control pages to, a SCSI Enclosure Services
@@ -601,6 +711,8 @@ pages from, and sends some control pages to, a SCSI Enclosure Services
</td>
<td style="vertical-align: top;">examples<br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">Simple code examples of using
@@ -614,6 +726,8 @@ the scsi generic (sg) driver interface<br>
</td>
<td style="vertical-align: top;">examples<br>
</td>
+ <td style="vertical-align: top;">adhoc<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">Simple code example of sending a
@@ -627,9 +741,12 @@ the scsi generic (sg) driver interface<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">Controls the power condition
-state of a SCSI device. Primary use is to spin up and down SCSI disks.<br>
+state of a SCSI device. Primary use is to spin up and down SCSI disks.
+Can also load and eject removable media.<br>
</td>
</tr>
<tr>
@@ -639,6 +756,8 @@ state of a SCSI device. Primary use is to spin up and down SCSI disks.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">Causes disk caches to be flushed
to media<br>
@@ -651,6 +770,8 @@ to media<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">Random pattern written to SCSI
@@ -665,6 +786,8 @@ corruption.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt+<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">Issue one or more Test Unit
Ready commands. Can be used to time SCSI command overhead.<br>
@@ -675,6 +798,8 @@ Ready commands. Can be used to time SCSI command overhead.<br>
<td style="vertical-align: top;">VERIFY</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">reads indicated blocks on a SCSI
disks, stops on the first error found. Does not yield any data. Useful
@@ -687,6 +812,8 @@ for media scans.</td>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w<br>
</td>
<td style="vertical-align: top;">Decodes standard and some vendor
@@ -694,12 +821,29 @@ Vital Product Data (VPD) pages.<br>
</td>
</tr>
<tr>
+ <td style="vertical-align: top;">sg_write_buffer<br>
+ </td>
+ <td style="vertical-align: top;">WRITE BUFFER<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
+ <td style="vertical-align: top;">fb,t64,w<br>
+ </td>
+ <td style="vertical-align: top;">write data; can be used to
+download firmware<br>
+ </td>
+ </tr>
+ <tr>
<td style="vertical-align: top;">sg_write_long<br>
</td>
<td style="vertical-align: top;">WRITE LONG<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">writes to a lba, data which
includes the block and ECC data. Suitable data typically fetched by
@@ -714,19 +858,23 @@ sg_read_long utility.<br>
</td>
<td style="vertical-align: top;"><br>
</td>
+ <td style="vertical-align: top;">getopt<br>
+ </td>
<td style="vertical-align: top;">fb,t64,w </td>
<td style="vertical-align: top;">writes mode pages supplied in
-ASCII hex (e.g. from "sg_modes -r") to the given SCSI device. See <a
- href="sdparm.html">sdparm</a> for another method of setting mode page
+ASCII hex (e.g. from "<span style="font-family: monospace;">sg_modes -r</span>")
+to the&nbsp; SCSI device. See <a href="sdparm.html">sdparm</a> for
+another method of setting mode page
parameters.<br>
</td>
</tr>
</tbody>
</table>
<br>
-More SCSI commands may be issued than shown in the "main SCSI
-commands" column. For example many utilities issue a SCSI INQUIRY
-command to find out the peripheral device type of the given SCSI
+More SCSI commands may be issued than shown in the <span
+ style="font-weight: bold;">Main SCSI
+commands</span> column. For example many utilities issue a SCSI INQUIRY
+command to find out the peripheral device type of the given
device. Some SCSI commands listed above are only relevant to a specific
device type (e.g. FORMAT UNIT) and should not be sent to a device
belonging to other peripheral device types (and in some cases these
@@ -736,23 +884,51 @@ directory of the tarball for a more exhaustive list of SCSI (and ATA)
commands
issued by the sg3_utils utilities.<br>
<br>
-If the "subdirectory"
+If the <span style="font-weight: bold;">directory</span>
column is empty in the above table then that utility is in the main
directory and more
-documentation can be found in its "man" page. All utilities in the main
-directory have "man" pages and some in the subdirectories have "man"
-pages. <br>
+documentation can be found in its "man" page. Some utilities in the
+subdirectories have "man"
+pages.<br>
+<br>
+The <span style="font-weight: bold;">CLI</span> column indicates what
+kind of command line interface the utility has. Recent utilities have a
+cli based on the getopt_long() function which offers both long option
+names (e.g. "<span style="font-family: monospace;">--verbose</span>")
+and a short form (e.g. '<span style="font-family: monospace;">-v</span>'),
+both forms can
+take an argument. Experience has led to consistent use of various
+options such as "<span style="font-family: monospace;">--help</span>", "<span
+ style="font-family: monospace;">--verbose</span>" and "<span
+ style="font-family: monospace;">--version</span>" across these
+utilities. Utilities with this type of cli are marked with "getopt".
+The original utilities had an "ad hoc" type cli that unfortunately
+lacked consistency and had a mix of long and short forms (with the long
+form sometime prefixed with "-" and on other occasions with "--".
+Utilities with this type of cli are marked with "adhoc". There is also
+a group of utilities that are related to the Unix dd command and share
+its quirky cli. Finally a group of well used utilities with ad hoc
+command line interfaces had a getop_long() based interface added in
+sg3_utils version 1.23 . These utilities include sg_inq, sg_logs and
+sg_modes. The default cli for this group is "getopt" but by using
+"<span style="font-family: monospace;">--old</span>" or "-O" as the
+first option the older ad hoc options can be
+used. This group will default to the older ad hoc interface if the
+environment variable SG3_UTILS_OLD_OPTS is defined. Utilities with this
+type of cli are marked with "getopt+".<br>
<br>
-If the "Ported" column is empty then the utility is only found in
+If the <span style="font-weight: bold;">Ported</span> column is empty
+then the utility is only found in
Linux. Support for other ports is indicated by "fb" for FreeBSD, "t64"
for Tru64 (OSF) and "w" for Windows. See the README.freebsd,
README.tru64 and README.win32 files
for more information.<br>
<br>
-This paragraph contains Linux specific information. In the above table
-all utilities in the main directory except sgp_dd
-issue SG_IO ioctls when they want to send SCSI commands to the given
-device. The sgp_dd utility issues SCSI commands using the sg
+This paragraph contains Linux specific information. All utilities that
+issue SCSI commands and that appear in the main directory of table 1,
+with the exception of sgp_dd,
+issue SG_IO ioctls. The sgp_dd utility issues SCSI commands using the
+sg
driver's asynchronous ( write()/read() ) interface to device nodes that
have the sg driver's major device number (i.e. "char" major 21). This
means that all utilities in the main directory are "safe" with any
@@ -766,14 +942,20 @@ nodes.]<br>
<br>
Irrespective of the device node used to access a device, care
should be taken not to interfere with a device while it is "active".
-For example invoking a "sg_format -F" utility on a disk with mounted
+For example invoking a "<span style="font-family: monospace;">sg_format
+-F</span>" utility on a disk with mounted
file
-systems on it is going to cause damage.<br>
-<br>
-Each process containing one of these command line utilities completes
-with an exit status 0 when
+systems on it is obviously going to cause damage.<br>
+<h2><a class="mozTocH2" name="mozTocId736867"></a>Exit status</h2>
+Each process containing one of sg3_utils' command line utilities
+completes
+with an exit status of 0 when
successful. Prior to version 1.21 all errors yielded an exit status of
-1. From version 1.21 the exit status is one of:<br>
+1. Having finer grain error reporting via the exit status from
+relatively low level sg3_utils utilities allows higher level scripts
+and other program wrappers to do more useful error processing.<br>
+<br>
+From version 1.22 the exit status value is one of:<br>
<ul>
<li><span style="font-weight: bold;">1</span>&nbsp;&nbsp; syntax
error in command line options or their arguments, or an illegal
@@ -810,10 +992,11 @@ successful.<br>
</li>
<li><span style="font-weight: bold;">15</span> &nbsp; the utility is
unable to open, close or use the given device. The given file name
-could be incorrect or there may be permission problems. Adding the '-v'
+could be incorrect or there may be permission problems. Adding the '<span
+ style="font-family: monospace;">-v</span>'
option may give more information.</li>
- <li><span style="font-weight: bold;">20</span>&nbsp;&nbsp; the
-&lt;scsi_device&gt; reports it has a check condition but "no sense".
+ <li><span style="font-weight: bold;">20</span>&nbsp;&nbsp; the DEVICE
+reports it has a check condition but "no sense".
Some polling commands (e.g. REQUEST SENSE) can react this way. It is
unlikely that this value will occur as an exit status.</li>
<li><span style="font-weight: bold;">21</span>&nbsp;&nbsp; the device
@@ -835,10 +1018,13 @@ This includes transport and operating system errors.<br>
</li>
</ul>
Many of the above exit statuses will be repeatable so executing the
-utility again with one or more '-v' options may yield more information.
+utility again with one or more '<span style="font-family: monospace;">-v</span>'
+options may yield more information.
Unit attentions (exit status 6) are only reported once per condition.
Notice that some of the lower exit status values correspond to the SCSI
-sense key values that they correspond to.<br>
+sense key values. Some examples of bash scripts that use these exit
+values see the <span style="font-style: italic;">scripts</span>
+subdirectory.<br>
<h2><a class="mozTocH2" name="mozTocId143590"></a>Changing mode page
settings</h2>
SCSI devices store settings (metadata) that could possibly be changed
@@ -1049,7 +1235,8 @@ transport: Serial Attached SCSI (SAS)</span><br
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Relative target port: 0x2</span><br>
<br>
-The sg_scan and sg_map utilities show the relationships between sg
+The sg_scan and sg_map utilities show the relationships between linux
+sg
devices and their &lt;bus, channel, target, lun&gt; tuples and their
primary device node names:<br>
<p>Example: given these 3 SCSI devices: <br>
@@ -1104,63 +1291,245 @@ lun=0&nbsp; type=0</tt><span style="font-family: monospace;"> </span><tt
style="font-family: monospace;">
<tt style="font-family: monospace;">/dev/sg2: scsi2 channel=0 id=6
lun=0&nbsp; type=5</tt> </p>
-<p>INQUIRY data can be added to that output with the "-i" option. The
+<p>INQUIRY data can be added to that output with the '<span
+ style="font-family: monospace;">-i</span>' option. The
sg_map utility shows the mapping between scsi generic (sg) devices and
the corresponding primary device node. For some peripheral device
types, SCSI enclosures for example, there is no mapping and the
enclosure device must be accessed via a sg device node.<br>
</p>
-<p style="font-family: monospace;">$ sg_map <br>
+<p></p>
+<p style="font-family: monospace;"><code>$ sg_map <br>
/dev/sg0&nbsp; /dev/sda <br>
/dev/sg1&nbsp; /dev/scd0 <br>
-/dev/sg2&nbsp; /dev/scd1</p>
+/dev/sg2&nbsp; /dev/scd1</code></p>
In the lk 2.6 series of kernels sg_scan and sg_map are less important
as most
utilities in the sg3_utils package can be issued directly against the
-primary device node (e.g. /dev/sda).&nbsp; However the sg driver is
+primary device node (e.g. <span style="font-family: monospace;">/dev/sda</span>).&nbsp;
+However the sg driver is
still needed to "talk" to devices such as enclosures which have no
specialized driver in linux.<br>
+<br>
+The Windows port has its own sg_scan utility which attempts to place
+all the device names for one device on a line. Here is an example:<br>
+<span style="font-family: monospace;">$ sg_scan</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">SCSI0:0,0,0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+C:&nbsp;&nbsp;&nbsp; PD0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+IC25N040ATCS05-0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CS4O&nbsp; *</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">SCSI1:0,0,0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+D:&nbsp;&nbsp;&nbsp; CDROM0&nbsp;&nbsp; HITACHI DVD-ROM GD-S200 0034</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">SCSI2:0,0,0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+I: +&nbsp; PD5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; QUANTUM
+LPS525S&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3110</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">SCSI2:0,6,0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+TAPE0&nbsp;&nbsp;&nbsp; SONY&nbsp;&nbsp;&nbsp;
+SDT-7000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0192</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+E:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Generic USB SD Reader&nbsp;&nbsp; 1.00&nbsp; pdt=0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+PD1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Generic USB SD Reader&nbsp;&nbsp; 1.00</span><br>
+<br>
+The first half of each line contains the various device names for a
+device. The second half are INQUIRY reponse strings. So device names
+like "PD1" (or the longer "physicalDrive1" form), "D:" and "TAPE0" can
+be used in the Windows port. <br>
<h2><a class="mozTocH2" name="mozTocId585558"></a> Notes</h2>
-Starting with sg3_utils-1.09 a library called libsgutils is built and
-is required by most utilities. The library is made up of two source
-files: sg_lib.c and sg_cmds.c; and their associated header files . The
-sg_lib.c file contains SCSI
-command,
+Starting with sg3_utils-1.09 a library called libsgutils is built in
+some environments and
+is required by most utilities. The library is made up of three source
+files: <span style="font-family: monospace;">sg_lib.c</span>, <span
+ style="font-family: monospace;">sg_cmds_basic.c</span> and <span
+ style="font-family: monospace;">sg_cmds_extra.c</span>; and their
+associated header files . The
+<span style="font-family: monospace;">sg_lib.c</span> file contains
+tables of SCSI
+command names,
sense key and additional sense code strings and various related helper
-functions. The sg_cmds.c file contains low level wrapper functions for
-commonly used SCSI commands. The library is built both as a shared
+functions. The <span style="font-family: monospace;">sg_cmds_basic.c</span>
+file contains low level wrapper
+functions for
+commonly used SCSI commands. The <span style="font-family: monospace;">sg_cmds_extra.c</span>
+file contains low
+level wrapper functions for
+less commonly used SCSI commands. The library can be built both as a
+shared
object and a static library. The binary rpm package only contains the
shared library while the sg3_utils-devel rpm package contains the
-static library, sg_lib.h and sg_cmds.h . If users do not want libraries
+static library, <span style="font-family: monospace;">sg_lib.h</span>,
+<span style="font-family: monospace;">sg_cmds.h</span>, <span
+ style="font-family: monospace;">sg_cmds_basic.h</span>, <span
+ style="font-family: monospace;">sg_cmds_extra.h</span>
+and some header files associated with the generic SCSI pass through
+interface. If users do not want libraries
(shared or static) then they can refer to the "no_lib" subdirectory
in the tarball which contains "no_lib" versions of the Makefile and the
rpm "spec" file.<br>
<br>
-Many of the utilities in the sg3_utils package use the SG_IO ioctl
+In Linux many of the utilities in the sg3_utils package ultimately use
+the SG_IO ioctl
(rather than the older write()/read() interface) in the sg driver. In
the lk 2.6&nbsp; series the SG_IO ioctl (or at least a stripped
-down version of it) has been implemented in the block subsystem. That
-means that commands that previously only worked on sg device names will
-now work on block device names as well (e.g. "sg_inq /dev/sda"). To use
+down version of it) has been implemented in the block subsystem (see <a
+ href="sg_io.html">sg_io.html</a> for more information). This
+means that commands which previously only worked on sg device names
+will
+now work on block device names as well (e.g. "<span
+ style="font-family: monospace;">sg_inq /dev/sda</span>"). To use
this facility safely version sg3_utils-1.02 or later should be used.
Note that SCSI tape devices (both st and osst device drivers) are char
devices and support the SG_IO ioctl from lk 2.6.6 onwards.<br>
<p>See the notes about header file problems in the README file inside
each package. </p>
<h2><a class="mozTocH2" name="mozTocId479511"></a> Download</h2>
-Various tarballs that include the source, a README, CHANGELOG, INSTALL
-and a Makefile can be found in the <a
- href="http://www.torque.net/sg/index.html#mozTocId566194"><span
- style="text-decoration: underline;">table 2</span></a> on the <a
- href="index.html">main</a>
-page. There are also source,
-i386 binary rpm and deb packages available. There is no './configure'
-logic so the correct Makefile must be chosen for the OS.<br>
+Several recent versions of the sg3_utils package are listed below. The
+tarballs contain README, CHANGELOG, INSTALL
+files and man pages as well as source and build files. The build files
+include Makefiles for various architectures, a linux rpm "spec" file
+and a debian directory for building "deb" packages.&nbsp; Here is the
+most recently released sg3_utils <a href="p/sg3_utils.CHANGELOG">CHANGELOG</a>
+.<br>
+<br>
+<table border="1" width="100%">
+ <caption><b>Table 2. sg3_utils tarballs and packages</b></caption> <tbody>
+ <tr>
+ <td><span style="font-weight: bold;">sg3_utils version</span><br>
+release date<br>
+ </td>
+ <td valign="top">&nbsp; <b>tarballs</b>&nbsp;<br>
+ </td>
+ <td><b>rpm source rpms **<br>
+ </b></td>
+ <td><b>i386 rpm binaries **<br>
+ </b></td>
+ <td valign="top">&nbsp;&nbsp; <span style="font-weight: bold;">debian
+packages</span><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">1.20</span><br>
+20060418<br>
+ </td>
+ <td style="vertical-align: top;"><a href="p/sg3_utils-1.20.tgz">sg3_utils-1.20.tgz</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3_utils-1.20-1.src.rpm">sg3_utils-1.20-1.src.rpm</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3_utils-1.20-1.i386.rpm">sg3_utils-1.20-1.i386.rpm</a><br>
+ <a href="p/libsgutils-1_0-1.20-1.i386.rpm">libsgutils-1_0-1.20-1.i386.rpm</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3-utils_1.20-0.1_i386.deb">sg3-utils_1.20-0.1_i386.deb</a><br>
+ <a href="p/libsgutils1-0_1.20-0.1_i386.deb">libsgutils1-0_1.20-0.1_i386.deb</a></td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">1.21<br>
+ </span>20060706<span style="font-weight: bold;"><br>
+ </span></td>
+ <td style="vertical-align: top;"><a href="p/sg3_utils-1.21.tgz">sg3_utils-1.21.tgz</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3_utils-1.21-1.src.rpm">sg3_utils-1.21-1.src.rpm</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3_utils-1.21-1.i386.rpm">sg3_utils-1.21-1.i386.rpm</a><br>
+ <a href="p/libsgutils-1_0-1.21-1.i386.rpm">libsgutils-1_0-1.21-1.i386.rpm</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3-utils_1.21-0.1_i386.deb">sg3-utils_1.21-0.1_i386.deb</a><br>
+ <a href="p/libsgutils1-0_1.21-0.1_i386.deb">libsgutils1-0_1.21-0.1_i386.deb</a></td>
+ </tr>
+ <tr>
+ <td><b>1.22<br>
+ </b>20061016<b><br>
+ </b></td>
+ <td valign="top"><a href="p/sg3_utils-1.22.tgz">sg3_utils-1.22.tgz</a><br>
+ </td>
+ <td><a href="p/sg3_utils-1.22-1.src.rpm">sg3_utils-1.22-1.src.rpm</a></td>
+ <td><a href="p/sg3_utils-1.22-1.i386.rpm">sg3_utils-1.22-1.i386.rpm</a><br>
+ <a href="p/libsgutils-1_0-1.22-1.i386.rpm">libsgutils-1_0-1.22-1.i386.rpm</a><br>
+ </td>
+ <td valign="top"><a href="p/sg3-utils_1.22-0.1_i386.deb">sg3-utils_1.22-0.1_i386.deb</a><br>
+ <a href="p/libsgutils1-0_1.22-0.1_i386.deb">libsgutils1-0_1.22-0.1_i386.deb</a><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">1.23</span><br>
+20070127<br>
+ <b> </b></td>
+ <td style="vertical-align: top;"><a href="p/sg3_utils-1.23.tgz">sg3_utils-1.23.tgz</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3_utils-1.23-1.src.rpm">sg3_utils-1.23-1.src.rpm</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3_utils-1.23-1.i386.rpm">sg3_utils-1.23-1.i386.rpm</a><br>
+ <a href="p/sg3_utils-libs-1.23-1.i386.rpm">sg3_utils-libs-1.23-1.i386.rpm</a><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="p/sg3-utils_1.23-0.1_i386.deb">sg3-utils_1.23-0.1_i386.deb</a><br>
+ <a href="p/libsgutils1-0_1.23-0.1_i386.deb">libsgutils1-0_1.23-0.1_i386.deb</a></td>
+ </tr>
+ </tbody>
+</table>
+<br>
+This <a href="p/sg3_utils_exe.zip">sg3_utils_exe.zip</a> file is a zip
+archive of the most recent version Windows executables made in a MinGW
+environment. This <a href="p/sg3_utils_man_html.tgz">sg3_utils_man_html.tgz</a>
+file is a tarball of man pages converted to html by man2html.<br>
+<br>
+Version 1.14 of sg3_utils introduced a shared object (library) called
+libsgutils. When binary packages are built then libsgutils is in its
+own package (and there is another "libsgutils*-devel" package which
+contains C header files and a static libsgutils.o library). The
+sg3_utils binaries for version 1.14 to 1.23 normally require the
+libsgutils library but can be built without it. In the future
+other utilities such as <a href="sdparm.html">sdparm</a> may also
+depend on the libsgutils
+package.<br>
+<br>
+** Some browsers (e.g. firefox) may interpret a file with an extension
+of "rpm" as an audio file. In which case press the right button over
+the link and select "Save link as ..." to download the file.<br>
+<br>
+Below is the most recent version of the sg_utils package which targets
+the linux kernel 2.2 series with some support for the lk 2.0 series. No
+further work is being done on this package.<br>
+<table border="1" width="100%">
+ <caption><b>Table 3.&nbsp; sg_utils tarballs and packages</b></caption>
+ <tbody>
+ <tr>
+ <td><span style="font-weight: bold;">sg_utils</span><br
+ style="font-weight: bold;">
+ <span style="font-weight: bold;">version</span><br>
+ </td>
+ <td valign="top">&nbsp; <b>tarballs</b>&nbsp;<br>
+ </td>
+ <td><b>rpm source rpms **<br>
+ </b></td>
+ <td><b>i386 rpm binaries **<br>
+ </b></td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;"><b>1.02</b></td>
+ <td style="vertical-align: top;"><a href="p/sg_utils-1.02.tgz">sg_utils-1.02.tgz</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg_utils-1.02-1.src.rpm">sg_utils-1.02-1.src.rpm</a></td>
+ <td style="vertical-align: top;"><a
+ href="p/sg_utils-1.02-1.i386.rpm">sg_utils-1.02-1.i386.rpm</a></td>
+ </tr>
+ </tbody>
+</table>
+<br>
+There is no '<span style="font-family: monospace;">./configure</span>'
+logic in sg3_utils so the correct Makefile must be chosen taking into
+account the
+operating system and several other attributes.<br>
<br>
<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
cellspacing="2">
- <caption align="bottom"><span style="font-weight: bold;">Table 2
-Building from source tarball</span><br>
+ <caption><span style="font-weight: bold;">Table 4.&nbsp;
+Building from a source tarball</span><br>
</caption><tbody>
<tr>
<td style="vertical-align: top;"><span style="font-weight: bold;">OS</span><br>
@@ -1224,22 +1593,40 @@ subdirectory included<br>
</td>
<td style="vertical-align: top;">&nbsp;<br>
</td>
- <td style="vertical-align: top;">Windows NT and latter supported
+ <td style="vertical-align: top;">Windows NT and later supported
(uses SPT interface). Builds in a cygwin environment and requires
cygwin1.dll to run.<br>
</td>
</tr>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Windows</span><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">make -f Makefile.mingw<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">Builds in a MinGW/MSYS
+environment and requires no third party dll<br>
+ </td>
+ </tr>
</tbody>
</table>
<br>
<br>
Both sg3_utils and the
older sg_utils packages can
-be found on http://freshmeat.net .<br>
+be found on <a href="http://freshmeat.net">http://freshmeat.net</a> .
+Most of the above invocations can
+take the name of a specific utility (e.g. "<span
+ style="font-family: monospace;">make sg_inq</span>") to build only
+that utility. There are also
+"install", "uninstall" and "clean" targets in most Makefiles.<br>
<br>
<p>Return to <a href="index.html">main</a> page. </p>
<center>
-<p>Last updated: 14th October 2006<br>
+<p>Last updated: 31st January 2007<br>
<br>
</p>
</center>
diff --git a/doc/sg_dd.html b/doc/sg_dd.html
index 7c007611..0250541e 100644
--- a/doc/sg_dd.html
+++ b/doc/sg_dd.html
@@ -17,12 +17,13 @@ sg_dd utility<br>
</center>
<a href="#Conclusion"></a>
<ol id="mozToc">
-<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6--><li><a href="#mozTocId228087">
-The&nbsp; Linux
-sg_dd utility </a>
+<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6-->
+ <li><a href="#mozTocId228087"> The&nbsp; Linux
+sg_dd utility
+ </a>
<ol>
<li><a href="#mozTocId370866">Introduction</a></li>
- <li><a href="#mozTocId352668">&nbsp;dd like features</a></li>
+ <li><a href="#mozTocId352668">dd like features</a></li>
<li><a href="#mozTocId703997">sg_dd extras</a></li>
<li><a href="#mozTocId657084">Retries</a></li>
<li><a href="#mozTocId437677">Continue on error
@@ -45,7 +46,8 @@ found in the <a href="sg3_utils.html">sg3_utils</a> package which
targets the linux kernel 2.4 and
2.6 series and has ports to various other operating systems.<br>
<br>
-Not all SCSI device types are supported by the sg_dd utility. Obviously
+Only block oriented SCSI peripheral device types are supported by the
+sg_dd utility. Obviously
those device types that deal with enclosures and medium changers don't
have addressable blocks and are not supported. The supported device
types are direct access devices (e.g. disks) and cd/dvd devices. The
@@ -62,7 +64,7 @@ as SCSI devices to an operating system via a protocol conversion in an
external enclosure and via some transport such as USB or IEEE 1394. The
sg_dd utility should work with most of these devices as it tends to use
exactly the same SCSI commands that the normal block layer would use.
-However, advanced options (e.g. using the 'cdbsz' and 'iflag=fua') most
+However, advanced options (e.g. using the cdbsz=16 and iflag=fua) most
likely will be ignored. Apart from CD players over 10 years old, almost
all CD/DVD players use the Multi Media Command set (MMC or&nbsp;
MMC-2,3,4,5) as their native command set. The fact that the most common
@@ -71,16 +73,16 @@ irrelevant to
the
sg_dd utility; they use SCSI command sets.<br>
<br>
-This page outlines the features of the sg_dd utility version 5.56 found
-in the <a href="sg3_utils.html">sg3_utils</a> version 1.22 package.<br>
-<h2><a class="mozTocH2" name="mozTocId352668"></a>&nbsp;dd like features</h2>
+This page outlines the features of the sg_dd utility version 5.60 found
+in the <a href="sg3_utils.html">sg3_utils</a> version 1.23 package.<br>
+<h2><a class="mozTocH2" name="mozTocId352668"></a>dd like features</h2>
The basic syntax of the sg_dd utility is the same as the dd command in
Unix. That said, the syntax of the dd command in Unix is different from
almost all other standard Unix commands. Those familiar with the dd
command
should not be too surprised by the syntax and semantics of the sg_dd
utility. Those not familiar with the dd syntax should be very careful,
-especially with the 'of' and 'seek' options, both with dd and sg_dd.
+especially with the 'of=' and 'seek=' options, both with dd and sg_dd.
The recent GNU implementation of the dd command is used as a reference
point.<br>
<br>
@@ -100,34 +102,40 @@ description</span><br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">bs=&lt;block_size&gt;<br>
+ <td style="vertical-align: top;">bs=<span
+ style="font-style: italic;">BS</span><br>
</td>
<td style="vertical-align: top;">512<br>
</td>
- <td style="vertical-align: top;">Number of bytes in each block<br>
+ <td style="vertical-align: top;">Number of bytes in each block.<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">count=&lt;count_of_blocks&gt;</td>
- <td style="vertical-align: top;">blocks in input file<br>
+ <td style="vertical-align: top;">count=<span
+ style="font-style: italic;">COUNT</span></td>
+ <td style="vertical-align: top;">blocks in <span
+ style="font-style: italic;">IFILE</span><br>
</td>
- <td style="vertical-align: top;">Number of blocks to copy<br>
+ <td style="vertical-align: top;">Number of blocks to copy.<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">if=&lt;input_file&gt;</td>
+ <td style="vertical-align: top;">if=<span
+ style="font-style: italic;">IFILE</span></td>
<td style="vertical-align: top;">stdin<br>
</td>
- <td style="vertical-align: top;">file (or device) to read from<br>
+ <td style="vertical-align: top;">file (or device) to read from.<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">of=&lt;output_file&gt;</td>
+ <td style="vertical-align: top;">of=<span
+ style="font-style: italic;">OFILE</span></td>
<td style="vertical-align: top;">stdout<br>
</td>
<td style="vertical-align: top;">file (or device) to write to.
-sg_dd doesn't bother writing anything if &lt;output_file&gt; is
-/dev/null or
+sg_dd doesn't bother writing anything if <span
+ style="font-style: italic;">OFILE</span> is <span
+ style="font-family: monospace;">/dev/null</span> or
. (period).<br>
</td>
</tr>
@@ -137,28 +145,39 @@ sg_dd doesn't bother writing anything if &lt;output_file&gt; is
<br>
When either dd or sg_dd are given these options with suitable
arguments, they will copy
-(&lt;block_size&gt; *&lt;count_of_blocks&gt;) bytes from the beginning
-of &lt;input_file&gt; to the
-beginning of &lt;output_file&gt;. One restriction that sg_dd imposes
-when either the &lt;input_file&gt; or &lt;output_file&gt; are accessed
-via SCSI commands is that &lt;block_size&gt; must match that of the
-device. Further, if both the &lt;input_file&gt; and &lt;output_file&gt;
-are accessed via SCSI commands then &lt;block_size&gt; must match that
+(<span style="font-style: italic;">BS</span> * <span
+ style="font-style: italic;">COUNT</span>) bytes from the beginning
+of <span style="font-style: italic;">IFILE</span> to the
+beginning of <span style="font-style: italic;">OFILE</span>. One
+restriction that sg_dd imposes
+when either the <span style="font-style: italic;">IFILE</span> or <span
+ style="font-style: italic;">OFILE</span> are accessed
+via SCSI commands is that <span style="font-style: italic;">BS</span>
+(i.e. the block size) must match that of the
+device. Further, if both the <span style="font-style: italic;">IFILE</span>
+and <span style="font-style: italic;">OFILE</span>
+are accessed via SCSI commands then <span style="font-style: italic;">BS</span>
+must match that
of both devices. <br>
<br>
-The following extensions are found in sg_dd. An &lt;input_file&gt; of
-"-" is interpreted as stdin; an &lt;output_file&gt; of "-" is
-interpreted as stdout while an &lt;output_file&gt; of "." is
+The following extensions are found in sg_dd. An <span
+ style="font-style: italic;">IFILE</span> of
+"-" is interpreted as stdin; an <span style="font-style: italic;">OFILE</span>
+of "-" is
+interpreted as stdout while an <span style="font-style: italic;">OFILE</span>
+of "." is
interpreted as <span style="font-family: monospace;">/dev/null</span>.
[dd interprets input and output file names of
-"-" literally. dd interprets an output file of "." as the current
+"-" literally; dd interprets an output file of "." as the current
directory and will not accept it.] The sg_dd utility does not truncate
-the &lt;output_file&gt; before starting the copy (the dd command does
+the <span style="font-style: italic;">OFILE</span> before starting the
+copy (the dd command does
if it is a normal file). Hence a user may need to delete the output
file before using the sg_dd utility (if the size of that file is
greater than what sg_dd is going to copy over it).<br>
<br>
-If the 'count' option is not given then an attempt is made to determine
+If the 'count=' option is not given then an attempt is made to
+determine
the remaining blocks in the file, device or partition. If the input
file is stdin and no count is given then a copy will continue until an
EOF is detected on the input stream (or something else goes wrong). If
@@ -195,52 +214,60 @@ description</span><br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">ibs=&lt;block_size&gt;</td>
- <td style="vertical-align: top;">same as bs<br>
+ <td style="vertical-align: top;">ibs=<span
+ style="font-style: italic;">BS</span></td>
+ <td style="vertical-align: top;">same as bs=<span
+ style="font-style: italic;">BS</span><br>
</td>
<td style="vertical-align: top;">number of bytes in each block of
-&lt;input_file&gt;<br>
+ <span style="font-style: italic;">IFILE</span><br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">iflag=&lt;flags&gt;<br>
+ <td style="vertical-align: top;">iflag=<span
+ style="font-style: italic;">FLAGS</span><br>
</td>
<td style="vertical-align: top;"><br>
</td>
- <td style="vertical-align: top;">[new in sg3_utils 1.18] similar
+ <td style="vertical-align: top;">similar
to option found in recent GNU dd versions, see below<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">obs=&lt;block_size&gt;</td>
- <td style="vertical-align: top;">same as bs<br>
+ <td style="vertical-align: top;">obs=<span
+ style="font-style: italic;">BS</span></td>
+ <td style="vertical-align: top;">same as bs=<span
+ style="font-style: italic;">BS</span><br>
</td>
<td style="vertical-align: top;">number of bytes in each block of
-&lt;output_file&gt;</td>
+ <span style="font-style: italic;">OFILE</span></td>
</tr>
<tr>
- <td style="vertical-align: top;">oflag=&lt;flags&gt;<br>
+ <td style="vertical-align: top;">oflag=<span
+ style="font-style: italic;">FLAGS</span><br>
</td>
<td style="vertical-align: top;"><br>
</td>
- <td style="vertical-align: top;">[new in sg3_utils 1.18] similar
+ <td style="vertical-align: top;">similar
to option found in recent GNU dd versions, see below<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">seek=&lt;n_blocks_of&gt;</td>
+ <td style="vertical-align: top;">seek=<span
+ style="font-style: italic;">SEEK</span></td>
<td style="vertical-align: top;">0<br>
</td>
- <td style="vertical-align: top;">block number (origin 0) in
-&lt;output_file&gt; to commence writing<br>
+ <td style="vertical-align: top;">block number (origin 0) in <span
+ style="font-style: italic;">OFILE</span> to commence writing<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">skip=&lt;n_blocks_of&gt;</td>
+ <td style="vertical-align: top;">skip=<span
+ style="font-style: italic;">SKIP</span></td>
<td style="vertical-align: top;">0<br>
</td>
- <td style="vertical-align: top;">block number (origin 0) in
-&lt;input_file&gt; to commence reading</td>
+ <td style="vertical-align: top;">block number (origin 0) in <span
+ style="font-style: italic;">IFILE</span> to commence reading</td>
</tr>
<tr>
<td style="vertical-align: top;">--help<br>
@@ -262,11 +289,12 @@ date then exit<br>
</tbody>
</table>
<br>
-If either ibs and/or obs are given to sg_dd then they must be the same
-as bs
-(i.e. they are essentially dummies).&nbsp; The 'skip' option cannot be
+If either ibs= and/or obs= are given to sg_dd then they must have the
+same value
+as bs=
+(i.e. they are essentially dummies).&nbsp; The skip= option cannot be
used on an input stream
-(e.g. stdin) while the 'seek' option cannot be used on an output stream
+(e.g. stdin) while the seek= option cannot be used on an output stream
(e.g. stdout).<br>
<br>
All numeric arguments can take a multiplier suffix. From sg3_utils
@@ -368,10 +396,11 @@ as hexadecimal 9 [not (0 * 9)==0]. This is valid "2x4x0xa" and yields
80 (but it isn't very clear).<br>
<br>
From sg3_utils version 1.19 (sg_dd version 5.46) hexadecimal numbers
-can also be indicated by a trailing "h" or "H". The "h" suffiz cannot
+can also be indicated by a trailing "h" or "H". The "h" suffix cannot
be used together with a suffix multiplier.<br>
<br>
-The "&lt;flags&gt;" argument of "iflag=" and "oflag=" is a comma
+The <span style="font-style: italic;">FLAGS</span> argument of
+"iflag=" and "oflag=" is a comma
separated list of items chosen from one or more entries in this table:<br>
<br>
<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
@@ -397,12 +426,15 @@ file</span><br>
</td>
<td style="vertical-align: top;">ignored<br>
</td>
- <td style="vertical-align: top;">applied on &lt;ofile&gt;<br>
+ <td style="vertical-align: top;">applied on <span
+ style="font-style: italic;">OFILE</span><br>
</td>
- <td style="vertical-align: top;">applied on &lt;ofile&gt;<br>
+ <td style="vertical-align: top;">applied on <span
+ style="font-style: italic;">OFILE</span><br>
</td>
<td style="vertical-align: top;">use O_APPEND open flag.
-Conflicts with 'seek=&lt;n&gt;' when "n &gt; 0"<br>
+Conflicts with 'seek=<span style="font-style: italic;">SEEK</span>'
+when "<span style="font-style: italic;">SEEK</span> &gt; 0"<br>
</td>
</tr>
<tr>
@@ -531,44 +563,38 @@ description</span><br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">append=0|1<br>
- </td>
- <td style="vertical-align: top;">0<br>
- </td>
- <td style="vertical-align: top;">both<br>
- </td>
- <td style="vertical-align: top;">append to output file (rather
-than overwrite). Better to use 'iflag=append' and/or 'oflag=append'.<br>
- </td>
- </tr>
- <tr>
- <td style="vertical-align: top;">blk_sgio=0|1<br>
+ <td style="vertical-align: top;">blk_sgio=0 | 1<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">when set access devices via SCSI
-commands (SG_IO ioctl). May use 'iflag=sgio' and/or 'oflag=sgio'
+commands (SG_IO ioctl). May use iflag=sgio and/or oflag=sgio
instead.<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">bpt<br>
+ <td style="vertical-align: top;">bpt=<span
+ style="font-style: italic;">BPT</span><br>
</td>
<td style="vertical-align: top;">128 or 32<br>
</td>
<td style="vertical-align: top;">both<br>
</td>
- <td style="vertical-align: top;">blocks_per_transfer (granularity
-of each IO). Default is 128 when bs &lt; 2048 (bytes) else the default
-is 32. For block devices (bpt * bs) is constrained by <span
+ <td style="vertical-align: top;">where <span
+ style="font-style: italic;">BPT</span> is the blocks per transfer
+(granularity
+of each IO). Default is 128 when <span style="font-style: italic;">BS</span>
+&lt; 2048 (bytes) else the default
+is 32. For block devices (<span style="font-style: italic;">BPT</span>
+* <span style="font-style: italic;">BS</span>) is constrained by <span
style="font-family: monospace;">/sys/block/&lt;device&gt;/queue/max_sectors_kb</span>
.<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">cdbsz=6|10|12|16<br>
+ <td style="vertical-align: top;">cdbsz=6 | 10 | 12 | 16<br>
</td>
<td style="vertical-align: top;">10 or 16<br>
</td>
@@ -582,7 +608,7 @@ case a 16 cdb is used.<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">coe=0|1|2|3<br>
+ <td style="vertical-align: top;">coe=0 | 1 | 2 | 3<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
@@ -590,13 +616,14 @@ case a 16 cdb is used.<br>
</td>
<td style="vertical-align: top;">when non-zero, continue_on_error
for
-sg devices and block devices using the SG_IO ioctl. May use 'iflag=coe'
-and/or 'oflag=coe'
-instead. An equivalent of 'coe=2' is 'iflag=coe,coe'<br>
+sg devices and block devices using the SG_IO ioctl. May use iflag=coe
+and/or oflag=coe
+instead. An equivalent of coe=2 is 'iflag=coe,coe'<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">coe_limit=&lt;n&gt;<br>
+ <td style="vertical-align: top;">coe_limit=<span
+ style="font-style: italic;">CL</span><br>
</td>
<td style="vertical-align: top;">0<br>
</td>
@@ -608,7 +635,7 @@ interpreted as no limit.<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">dio=0|1<br>
+ <td style="vertical-align: top;">dio=0 | 1<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
@@ -619,27 +646,18 @@ nodes)<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">fua=0|1|2|3<br>
- </td>
- <td style="vertical-align: top;">0<br>
- </td>
- <td style="vertical-align: top;">both<br>
- </td>
- <td style="vertical-align: top;">force_unit_access, 1-&gt;of,
-2-&gt;if, 3-&gt;of+if . Better to use 'iflag=fua' and/or 'oflag=fua'. </td>
- </tr>
- <tr>
- <td style="vertical-align: top;">odir=0|1<br>
+ <td style="vertical-align: top;">odir=0 | 1<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">O_DIRECT flag on open() when
-set. Better to use 'iflag=direct' and/or 'oflag=direct'. </td>
+set. Better to use iflag=direct and/or oflag=direct. </td>
</tr>
<tr>
- <td style="vertical-align: top;">retries=&lt;n&gt;<br>
+ <td style="vertical-align: top;">retries=<span
+ style="font-style: italic;">RETR</span><br>
</td>
<td style="vertical-align: top;">0<br>
</td>
@@ -650,19 +668,20 @@ error on a sg device READ or WRITE command<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">sync=0|1<br>
+ <td style="vertical-align: top;">sync=0 | 1<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
<td style="vertical-align: top;">both<br>
</td>
<td style="vertical-align: top;">when set, sends SYNCHRONIZE
-CACHE SCSI command to &lt;ofile&gt; if it is a sg device or accessed
+CACHE SCSI command to <span style="font-style: italic;">OFILE</span>
+if it is a sg device or accessed
via the SG_IO ioctl.<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">time=0|1<br>
+ <td style="vertical-align: top;">time=0 | 1<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
@@ -673,13 +692,15 @@ throughput calculation at the completion of the copy<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">verbose=&lt;n&gt;<br>
+ <td style="vertical-align: top;">verbose=<span
+ style="font-style: italic;">VERB</span><br>
</td>
<td style="vertical-align: top;">0<br>
</td>
<td style="vertical-align: top;">sgm_dd<br>
</td>
- <td style="vertical-align: top;">larger &lt;n&gt; is the greater
+ <td style="vertical-align: top;">larger <span
+ style="font-style: italic;">VERB</span> is the greater
the debug output. 1 and 2 print the cdbs for setup commands; 3 and 4
print the cdbs for all commands<br>
</td>
@@ -689,8 +710,9 @@ print the cdbs for all commands<br>
<br>
<br>
The sg_dd utility examines the files it is given and treats them
-differently depending on their file type. Depending on
-'iflag=&lt;flags&gt;' and 'oflag=&lt;flags&gt;' settings: O_DIRECT,
+differently depending on their file type. Depending on iflag=<span
+ style="font-style: italic;">FLAGS</span> and oflag=<span
+ style="font-style: italic;">FLAGS</span> settings: O_DIRECT,
O_SYNC, O_APPEND and O_EXCL flags may be added to the relevant open()
command.<br>
<br>
@@ -741,7 +763,8 @@ effect (e.g. 'oflag=direct' is ignored)<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">/dev/null or . (period)<br>
+ <td style="vertical-align: top;"><span
+ style="font-family: monospace;">/dev/null</span> or . (period)<br>
</td>
<td style="vertical-align: top;">O_RDONLY</td>
<td style="vertical-align: top;">[do nothing]<br>
@@ -769,8 +792,8 @@ written<br>
<td style="vertical-align: top;">O_RDWR</td>
<td style="vertical-align: top;">SCSI commands</td>
<td style="vertical-align: top;">Opens input O_RDONLY if O_RDWR
-fails.&nbsp; The 'blk_sgio=1' option equates to both 'iflag=sgio' and
-'oflag=sgio'. Partitions ignored. </td>
+fails.&nbsp; The blk_sgio=1 option equates to both iflag=sgio and
+oflag=sgio. Partitions ignored. </td>
</tr>
<tr>
<td style="vertical-align: top;">sg device<br>
@@ -811,10 +834,10 @@ series is a replacement for raw devices<br>
</tbody>
</table>
<br>
-Some of the above combinations are not sensible (e.g. 'append=1' on a
+Some of the above combinations are not sensible (e.g. append=1 on a
block device). Raw devices were introduced in the lk 2.4 series and are
still available in the lk 2.6 series but opening a block device or a
-normal file with O_DIRECT (in sg_dd using the option 'odir=1') is
+normal file with O_DIRECT (in sg_dd using the option odir=1) is
preferred in the lk 2.6 series. If either the input or output file is a
raw device, or 'odir=1' is given then the internal buffers used by
sg_dd are aligned to a memory page boundary. A memory page is 4
@@ -822,31 +845,36 @@ kilobytes in the i386 architecture. This memory alignment is required
by both raw devices and normal block devices that
implement O_DIRECT.<br>
<br>
-The 'blk_sgio=1' option (or 'iflag=sgio' and/or 'oflag=sgio') is only
+The blk_sgio=1 option (or iflag=sgio and/or oflag=sgio) is only
valid in the lk 2.6 series. This option
instructs the sg_dd utility to use the SG_IO ioctl to issue SCSI
commands even though the file type is not a scsi generic (sg) device.
Currently this will work for all cd/dvd devices irrespective of the
transport (except for some very old devices ( &gt; 10 years old)) and
-block devices representing SCSI disks (e.g. /dev/sda). Even though SCSI
+block devices representing SCSI disks (e.g. <span
+ style="font-family: monospace;">/dev/sda</span>). Even though SCSI
tape (st) devices now accept the SG_IO ioctl in the lk 2.6 series, the
sg_dd utility expects direct access devices (whereas tapes are
sequential access) so sg_dd generates an error if a st device is
detected. When the input or output file is a sg device then the
-'blk_sgio' option is ignored as IO with that file is always via SCSI
-commands. When 'blk_sgio=1' is used with a block device and the value
-given to 'bpt'
+blk_sgio option is ignored as IO with that file is always via SCSI
+commands. When blk_sgio=1 is used with a block device and the <span
+ style="font-style: italic;">BPT</span> value
is too high then the first read may report an EIO (input/output)
-error; the solution is to lower the 'bpt' value. [The EIO error
+error; the solution is to lower the <span style="font-style: italic;">BPT</span>
+value. [The EIO error
occurred often with CD/DVD drives which have 2048 bytes sectors, so the
-'bpt' default value was reduced for block size &gt;= 2048 bytes.]<br>
+<span style="font-style: italic;">BPT</span> default value was reduced
+for block size &gt;= 2048 bytes.]<br>
<br>
-If a partition of block device is accessed (e.g. /dev/sda2) when
-'blk_sgio=0' (or is not given) then logical block address 0 for the
+If a partition of block device is accessed (e.g. <span
+ style="font-family: monospace;">/dev/sda2</span>) when blk_sgio=0 (or
+is not given) then logical block address 0 for the
purposes of sg_dd (and its skip and seek options) is the beginning of
that partition while the calculated count (e.g. when a 'count' option
is not given) is the extent of that partition. However if a partition
-of block device is accessed (e.g. /dev/sda2) when 'blk_sgio=1' then the
+of block device is accessed (e.g. <span style="font-family: monospace;">/dev/sda2</span>)
+when blk_sgio=1 then the
partition is ignored and the underlying device is accessed. This means
logical block address 0 for the purposes of sg_dd (and its skip and
seek options) is the beginning of the device while the calculated count
@@ -866,7 +894,8 @@ If a SIGUSR1 signal is sent to the process identifier (pid) of a
running sg_dd utility then the number of blocks copied to that point is
output. The copy continues.<br>
<br>
-When the 'time' option is set, the elapsed time for the copy plus the
+When the 'time=1' option is given, the elapsed time for the copy plus
+the
throughput measured in megabytes (10**6 bytes)&nbsp; per second is
output when the copy is complete (or an error stops the copy). If a
SIGUSR1 signal is sent to the process identifier (pid) of a running
@@ -878,22 +907,25 @@ device has probably already done multiple retries (probably
interspersed with moving the heads to the extreme ends of the media)
before the medium error is reported. However a transport error (e.g.
causing a CRC error in returned data) is not necessarily seen by the
-device and a retry may quickly solve the problem. In SAS a transport
-layer retries (TLR) state machine is optional and requires both the
+device and a retry may quickly solve the problem. In SAS a Transport
+Layer Retries (TLR) state machine is optional and requires both the
initiator and target to implement the capability. Most first generation
SAS disks do not implement TLR. So transport errors in the form of
"aborted commands" can be reported due to corruption (marginal cables)
or congestion.<br>
<br>
-When the 'retries=&lt;n&gt;' option is given and &lt;n&gt; is greater
+When the retries=<span style="font-style: italic;">RETR</span> option
+is given and <span style="font-style: italic;">RETR</span> is greater
than 0 then most errors on a READ or WRITE SCSI command are retried up
-to &lt;n&gt; times. Device not ready errors are not retried and "unit
+to <span style="font-style: italic;">RETR</span> times. Device not
+ready errors are not retried and "unit
attention" conditions are automatically retried (without looking at or
-decrementing &lt;n&gt;). Once the number of retries is exhausted on the
+decrementing <span style="font-style: italic;">RETR</span>). Once the
+number of retries is exhausted on the
same operation without success then sg_dd will refer to the 'coe'
option as to what to do next. Each new operation,<br>
READ or WRITE, or to a different logical block address has its own
-retry count initialized to &lt;n&gt;.<br>
+retry count initialized to <span style="font-style: italic;">RETR</span>.<br>
<h2><a class="mozTocH2" name="mozTocId437677"></a>Continue on error
(coe)</h2>
Recent additions to the sg_dd utility allow it to be used as a copy "of
@@ -903,18 +935,19 @@ Write errors from SCSI commands are reported and ignored and the sg_dd
utility continues when the 'coe' option is non-zero. [In the case where
media errors are causing write errors the user should check the setting
of the AWRE bit in the SCSI "read write
-error recovery" mode page (see SBC-2 at http://www.t10.org).]<br>
+error recovery" mode page (see SBC-2 at <a href="http://www.t10.org">http://www.t10.org</a>).]<br>
<br>
When a SCSI READ command detects an unrecoverable read error it
responds with a sense key of MEDIUM ERROR or HARDWARE ERROR.
Additionally it responds with the logical block address of the first
(lowest) block that it failed to read in the current READ command. Any
valid blocks prior to the "bad" block may or may not have been
-transferred (depending on several other settings). If 'coe=0' then the
+transferred (depending on several other settings). If coe=0 then the
sg_dd utility will simply terminate at this point (with a reasonable
amount of debug information sent to stderr) <span
style="font-weight: bold;">and</span> good blocks prior to the bad
-block may not be copied (depending on the setting of 'bpt'). If 'coe'
+block may not be copied (depending on the setting of <span
+ style="font-style: italic;">BPT</span>). If 'coe'
is non-zero then the first
thing sg_dd will try to do is a truncated read up to, but not
including,
@@ -927,14 +960,14 @@ readable then most likely the associated ECC data indicates that it is
corrupt and the ECC data cannot recover it. [It is possible that all
the corruption is in the ECC data and the payload data is ok.] Such
blocks can be retrieved with the READ LONG command. If the READ LONG
-fails then a block of zeroes is
+fails then a block of zeros is
substituted for the bad block in the transfer buffer. When 'coe=1' then
-READ LONG is not attempted and the "bad" block is replaced by zeroes.
-When 'coe=2' (or 'iflag=coe,coe') then a READ LONG is attempted. When
-'coe=3' then a READ LONG with its CORRCT bit set is attempted. Only SBC
+READ LONG is not attempted and the "bad" block is replaced by zeros.
+When coe=2'(or 'iflag=coe,coe') then a READ LONG is attempted. When
+coe=3 then a READ LONG with its CORRCT bit set is attempted. Only SBC
devices (primarily SCSI disks) optionally support READ LONG. CD/DVD
devices (covered in the MMC-4 (draft) standard) do not, so a block of
-zeroes is substituted for them. Even if READ LONG succeeds on a "bad"
+zeros is substituted for them. Even if READ LONG succeeds on a "bad"
block, the recovered data may not be useful. There are no guarantees
that the user data will appear "as is" in the first 512 bytes.<br>
<br>
@@ -943,7 +976,7 @@ fetched. Further bad blocks may be detected and if so
the algorithm in the last two paragraphs is repeated. The result of
this
process is an imperfect copy with blocks that were read properly placed
-in the correct relative position in the output. When the 'coe=1' option
+in the correct relative position in the output. When the coe=1 option
is given two addition counters are output on completion:<br>
<ul>
<li>unrecovered errors (number of bad blocks)<br>
@@ -957,12 +990,14 @@ second counter (always less than or equal to the first) is the number
of "successful" READ LONG SCSI commands performed. If the source media
is a CD or DVD then this number will be zero.<br>
<br>
-The 'coe_limit=&lt;n&gt;' option is meant to stop sg_dd continuing ad
+The coe_limit=<span style="font-style: italic;">CL</span> option is
+meant to stop sg_dd continuing ad
nausum if errors are being detected during reading. The input media may
be blank (unrecorded) or beyond its logical block address limit. The
-'coe_limit=&lt;n&gt;' option is only active on read operations when
+coe_limit=<span style="font-style: italic;">CL</span> option is only
+active on read operations when
'coe &gt; 0' which itself is only active on sg device nodes (or block
-devices when 'blk_sgio=1' (or 'iflag=sgio') is given).<br>
+devices when blk_sgio=1 (or iflag=sgio) is given).<br>
<br>
<h2><a class="mozTocH2" name="mozTocId566094"></a>Recovered errors</h2>
Often errors are recovered using ECC data or by the device retrying
@@ -976,7 +1011,9 @@ the "Read error counter" and "Write error counter" logs pages which can
be viewed with smartctl (from smartmontools) and sg_logs (from the same
sg3_utils package that sg_dd comes from). Any block that is
automatically or manually re-assigned adds a new entry to the "grown"
-defect list which can be viewed with 'sginfo -G' or 'sg_reassign -g'
+defect list which can be viewed with '<span
+ style="font-family: monospace;">sginfo -G</span>' or '<span
+ style="font-family: monospace;">sg_reassign -g</span>'
(both found in the
sg3_utils package).<br>
<br>
@@ -986,7 +1023,7 @@ clear. When sg_dd detects RECOVERED ERRORs it reports them, counts
them and continues the copy. Only the lba of the last recovered error
in a READ or WRITE SCSI
command is reported so there could be more than one recovered error per
-SCSI command. The 'bpt=1' option
+SCSI command. The bpt=1 option
could be chosen to limit every SCSI command to a single block transfer
(but that would slow things down a fair amount). If the count of
recovered errors is greater than zero at the end of the copy then this
@@ -1027,12 +1064,14 @@ lot of output.</li>
All verbose output is sent to stderr (so that sg_dd usage with "of=-"
(copy output to stdout) is not corrupted).<br>
<br>
-Following is an example of using 'verbose=1' to find information about
-/dev/sda . If no copy is required then setting 'count=0' will see to
-that. Since "dev/sda" is a block device then it would normally be
-accessed via Unix system commands. The 'verbose=1' output is relatively
-short when 'blk_sgio=0' (its default value). The second invocation is
-with 'blk_sgio=1' and a lot more is output. That includes INQUIRY
+Following is an example of using verbose=1 to find information about
+<span style="font-family: monospace;">/dev/sda</span> . If no copy is
+required then setting count=0 will see to
+that. Since <span style="font-family: monospace;">/dev/sda</span> is a
+block device then it would normally be
+accessed via Unix system commands. The verbose=1 output is relatively
+short when blk_sgio=0 (its default value). The second invocation is
+with blk_sgio=1 and a lot more is output. That includes INQUIRY
standard response data (e.g. "SEAGATE ..." line).
See the SBC-2 drafts at <a href="http://www.t10.org/">www.t10.org</a>
for more information.<br>
@@ -1088,8 +1127,10 @@ have their own man pages.<br>
(default: 4 threads) to potentially speed the copy. The syntax and
semantics of sgp_dd are very similar to sg_dd. The "continue on error"
processing in sgp_dd is simpler than what is described above for sg_dd.
-Instead of the 'verbose=&lt;n&gt;' option used by sg_dd, sgp_dd uses
-'deb=&lt;n&gt;' which does a similar thing.<br>
+Instead of the verbose=<span style="font-style: italic;">VERB</span>
+option used by sg_dd, sgp_dd uses
+'deb=<span style="font-style: italic;">VERB</span>' which does a
+similar thing.<br>
<br>
<span style="font-weight: bold;">sgm_dd</span> uses memory mapped IO to
speed copies from or to sg device nodes. Memory mapped IO will bypass
@@ -1101,13 +1142,17 @@ there are various low level details (e.g. alignment and signal
processing) that complicate the picture.<br>
<br>
<span style="font-weight: bold;">sg_read</span> uses a similar syntax
-to sg_dd but has no 'of=&lt;ofile&gt;'. It is designed to measure the
+to sg_dd but has no 'of=<span style="font-style: italic;">OFILE</span>'.
+It is designed to measure the
performance of device (e.g. disk) caches, the throughput of the
transport and command overhead. It perform a read (either a SCSI READ
command or a Unix read()) from the given skip block address (default is
-logical block address 0) and continues doing reads until
-'count=&lt;blocks&gt;' is exhausted. If multiple reads are&nbsp;
-performed (i.e. when "count &gt; bpt") then they are all from the same
+logical block address 0) and continues doing reads until count=<span
+ style="font-style: italic;">COUNT</span> is exhausted. If multiple
+reads are&nbsp;
+performed (i.e. when "<span style="font-style: italic;">COUNT</span>
+&gt; <span style="font-style: italic;">BPT</span>") then they are all
+from the same
logical address. For example, with SCSI READs, exactly the same READ
cdb is issued for each read operation. The data is thrown away. Zero
block reads can also be issued using a negative count value. This is
@@ -1122,7 +1167,7 @@ MEDIUM errors, while recovering as much data as possible.<br>
<br>
<p>Return to <a href="index.html">main</a> page. </p>
<center>
-<p>Last updated: 15th October 2006<br>
+<p>Last updated: 24th January 2007<br>
<br>
</p>
</center>
diff --git a/doc/tools.html b/doc/tools.html
index de38f74a..71c60b3e 100644
--- a/doc/tools.html
+++ b/doc/tools.html
@@ -17,9 +17,10 @@ and SCSI<br>
</center>
<a href="#intro"></a>
<ol id="mozToc">
-<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6--><li><a href="#mozTocId697451">
-Tools for storage
-and SCSI </a>
+<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6-->
+ <li><a href="#mozTocId697451"> Tools for storage
+and SCSI
+ </a>
<ol>
<li><a href="#mozTocId746876"> Introduction</a></li>
<li><a href="#mozTocId520511">blktool</a></li>
@@ -47,6 +48,7 @@ and SCSI </a>
<li><a href="#mozTocId143073"> smartsuite</a></li>
<li><a href="#mozTocId53551">smp_utils</a></li>
<li><a href="#mozTocId440267">spew</a></li>
+ <li><a href="#mozTocId45065">testdisk</a></li>
<li><a href="#mozTocId708282">udev</a></li>
<li><a href="#mozTocId728109">Conclusion</a></li>
</ol>
@@ -284,7 +286,11 @@ to use and is flexible. No configuration files or complicated
client/server configurations are needed. Spew also generates its own
data patterns that are designed to make it easy to find and debug data
integrity problems. See <a href="http://spew.berlios.de">spew.berlios.de</a>
-.
+.<br>
+<h2><a class="mozTocH2" name="mozTocId45065"></a>testdisk</h2>
+For those occasion when the master boot record is overwritten, <a
+ href="http://www.cgsecurity.org/wiki/TestDisk">testdisk</a> can find
+many different types of partitions and help with data recovery.<br>
<h2><a class="mozTocH2" name="mozTocId708282"></a>udev</h2>
<a href="http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html">udev</a>
provides a dynamic device directory containing only the files for
@@ -304,7 +310,7 @@ Gilbert</a> can
be emailed at this address (also at dougg at torque dot net). <br>
</div>
<center>
-<p>Last updated: 11th June 2006<br>
+<p>Last updated: 10th January 2007<br>
<br>
</p>
</center>
diff --git a/examples/Makefile.freebsd b/examples/Makefile.freebsd
index 966af32c..a7b2797a 100644
--- a/examples/Makefile.freebsd
+++ b/examples/Makefile.freebsd
@@ -21,6 +21,8 @@ CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS)
CFLAGS_PTHREADS = -D_REENTRANT
+# there is no rule to make the following in the parent directory,
+# it is assumed they are already built.
D_FILES = ../sg_lib.o ../sg_pt_freebsd.o
O_FILES = sg_lib.o sg_pt_freebsd.o
@@ -38,7 +40,7 @@ clean:
/bin/rm -rf .libs
sg_simple5: sg_simple5.o $(D_FILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(D_FILES)
install: $(EXECS)
install -d $(INSTDIR)
diff --git a/examples/reassign_addr.txt b/examples/reassign_addr.txt
index 47915852..9d48d005 100644
--- a/examples/reassign_addr.txt
+++ b/examples/reassign_addr.txt
@@ -4,8 +4,8 @@
# To see logical block addresses placed in the command parameter block
# without executing them command try something like:
-# 'sg_reassign --address=- -d -vv /dev/sda < reassign_addr.txt
+# 'sg_reassign --address=- --dummy -vv /dev/sda < reassign_addr.txt
1,34,0x33,0X444 0x89abcde 0xdeadbeef # 6 lba's
-# dpg 20060824
+# dpg 20070130
diff --git a/examples/scsi_inquiry.c b/examples/scsi_inquiry.c
index 6b6e79d0..aae8e374 100644
--- a/examples/scsi_inquiry.c
+++ b/examples/scsi_inquiry.c
@@ -53,7 +53,8 @@ int main(int argc, char * argv[])
int s_fd, res, k, to;
unsigned char inqCmdBlk [INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0,
INQUIRY_REPLY_LEN, 0};
- unsigned char * inqBuff = malloc(OFF + sizeof(inqCmdBlk) + 512);
+ unsigned char * inqBuff = (unsigned char *)
+ malloc(OFF + sizeof(inqCmdBlk) + 512);
unsigned char * buffp = inqBuff + OFF;
My_Scsi_Ioctl_Command * ishp = (My_Scsi_Ioctl_Command *)inqBuff;
char * file_name = 0;
@@ -61,15 +62,15 @@ int main(int argc, char * argv[])
int oflags = 0;
for (k = 1; k < argc; ++k) {
- if (0 == strcmp(argv[k], "-n"))
- do_nonblock = 1;
- else if (*argv[k] != '-')
+ if (0 == strcmp(argv[k], "-n"))
+ do_nonblock = 1;
+ else if (*argv[k] != '-')
file_name = argv[k];
- else {
- printf("Unrecognized argument '%s'\n", argv[k]);
- file_name = 0;
- break;
- }
+ else {
+ printf("Unrecognized argument '%s'\n", argv[k]);
+ file_name = 0;
+ break;
+ }
}
if (0 == file_name) {
printf("Usage: 'scsi_inquiry [-n] <scsi_device>'\n");
@@ -81,7 +82,7 @@ int main(int argc, char * argv[])
}
if (do_nonblock)
- oflags = O_NONBLOCK;
+ oflags = O_NONBLOCK;
s_fd = open(file_name, oflags | O_RDWR);
if (s_fd < 0) {
if ((EROFS == errno) || (EACCES == errno)) {
diff --git a/examples/sg__sat_identify.c b/examples/sg__sat_identify.c
index bdf4d826..06ecfe6f 100644
--- a/examples/sg__sat_identify.c
+++ b/examples/sg__sat_identify.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Douglas Gilbert.
+ * Copyright (c) 2006-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -56,7 +56,7 @@
#define SAT_ATA_PASS_THROUGH16 0x85
#define SAT_ATA_PASS_THROUGH16_LEN 16
-#define SAT_STATUS_RETURN_DESC 9 /* ATA status return (sense) descriptor */
+#define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */
#define ATA_IDENTIFY_DEVICE 0xec
#define ATA_IDENTIFY_PACKET_DEVICE 0xa1
@@ -64,7 +64,7 @@
#define EBUFF_SZ 256
-static char * version_str = "1.01 20061014";
+static char * version_str = "1.02 20070130";
static void usage()
{
@@ -179,11 +179,11 @@ int main(int argc, char * argv[])
ok = 1;
break;
case SG_LIB_CAT_RECOVERED:
- /* check for ATA status return descriptor */
if (verbose)
sg_chk_n_print3(">>> ATA_16 command", &io_hdr, 1);
+ /* check for ATA Return Descriptor */
cucp = sg_scsi_sense_desc_find(io_hdr.sbp, io_hdr.sb_len_wr,
- SAT_STATUS_RETURN_DESC);
+ SAT_ATA_RETURN_DESC);
if (cucp && (cucp[3])) {
if (cucp[3] & 0x4) {
printf("error in returned FIS: aborted command\n");
diff --git a/examples/sg_io_linux.h b/examples/sg_io_linux.h
deleted file mode 120000
index 6c9c2ba9..00000000
--- a/examples/sg_io_linux.h
+++ /dev/null
@@ -1 +0,0 @@
-../sg_io_linux.h \ No newline at end of file
diff --git a/examples/sg_io_linux.hh b/examples/sg_io_linux.hh
new file mode 100644
index 00000000..459a7cd9
--- /dev/null
+++ b/examples/sg_io_linux.hh
@@ -0,0 +1 @@
+#include "../sg_io_linux.h"
diff --git a/examples/sg_iovec_tst.c b/examples/sg_iovec_tst.c
index 8732f1bc..83ccf593 100644
--- a/examples/sg_iovec_tst.c
+++ b/examples/sg_iovec_tst.c
@@ -13,7 +13,7 @@
/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg")
device driver.
-* Copyright (C) 2003 D. Gilbert
+* Copyright (C) 2003-2007 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)
@@ -24,7 +24,7 @@
normal file. The purpose is to test the sg_iovec mechanism within the
sg_io_hdr structure.
- Version 0.11 (20060622)
+ Version 0.12 (20070121)
*/
@@ -171,7 +171,7 @@ int main(int argc, char * argv[])
return 1;
}
dxfer_len = count * blk_size;
- buffp = malloc(dxfer_len);
+ buffp = (unsigned char *)malloc(dxfer_len);
if (buffp) {
if (0 == sg_read(sg_fd, buffp, count, 0, blk_size)) {
if (write(fd, buffp, dxfer_len) < 0)
diff --git a/examples/sg_lib.h b/examples/sg_lib.h
deleted file mode 120000
index f6ce0761..00000000
--- a/examples/sg_lib.h
+++ /dev/null
@@ -1 +0,0 @@
-../sg_lib.h \ No newline at end of file
diff --git a/examples/sg_lib.hh b/examples/sg_lib.hh
new file mode 100644
index 00000000..e2f826a1
--- /dev/null
+++ b/examples/sg_lib.hh
@@ -0,0 +1 @@
+#include "../sg_lib.h"
diff --git a/examples/sg_linux_inc.h b/examples/sg_linux_inc.h
deleted file mode 120000
index 55808134..00000000
--- a/examples/sg_linux_inc.h
+++ /dev/null
@@ -1 +0,0 @@
-../sg_linux_inc.h \ No newline at end of file
diff --git a/examples/sg_linux_inc.hh b/examples/sg_linux_inc.hh
new file mode 100644
index 00000000..a5bf738d
--- /dev/null
+++ b/examples/sg_linux_inc.hh
@@ -0,0 +1 @@
+#include "../sg_linux_inc.h"
diff --git a/examples/sg_pt.h b/examples/sg_pt.h
deleted file mode 120000
index 508f66d3..00000000
--- a/examples/sg_pt.h
+++ /dev/null
@@ -1 +0,0 @@
-../sg_pt.h \ No newline at end of file
diff --git a/examples/sg_pt.hh b/examples/sg_pt.hh
new file mode 100644
index 00000000..2be7b43b
--- /dev/null
+++ b/examples/sg_pt.hh
@@ -0,0 +1 @@
+#include "../sg_pt.h"
diff --git a/examples/sg_sat_chk_power.c b/examples/sg_sat_chk_power.c
index 355150c9..d6d09286 100644
--- a/examples/sg_sat_chk_power.c
+++ b/examples/sg_sat_chk_power.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Douglas Gilbert.
+ * Copyright (c) 2006-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,7 +41,7 @@
/* This program performs a ATA PASS-THROUGH (16) SCSI command in order
to perform an ATA CHECK POWER MODE command. See http://www.t10.org
- SAT draft at time of writing: sat-r08.pdf
+ SAT draft at time of writing: sat-r09.pdf
Invocation: sg_sat_chk_power [-v] [-V] <device>
@@ -49,13 +49,13 @@
#define SAT_ATA_PASS_THROUGH16 0x85
#define SAT_ATA_PASS_THROUGH16_LEN 16
-#define SAT_STATUS_RETURN_DESC 9 /* ATA status return (sense) descriptor */
+#define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */
#define ATA_CHECK_POWER_MODE 0xe5
#define EBUFF_SZ 256
-static char * version_str = "1.02 20061014";
+static char * version_str = "1.03 20070129";
int main(int argc, char * argv[])
{
@@ -81,6 +81,8 @@ int main(int argc, char * argv[])
++verbose;
else if (0 == strcmp(argv[k], "-vv"))
verbose += 2;
+ else if (0 == strcmp(argv[k], "-vvv"))
+ verbose += 3;
else if (0 == strcmp(argv[k], "-V")) {
fprintf(stderr, "version: %s\n", version_str);
exit(0);
@@ -146,15 +148,18 @@ int main(int argc, char * argv[])
switch (sg_err_category3(&io_hdr)) {
case SG_LIB_CAT_CLEAN:
break;
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
+ case SG_LIB_CAT_RECOVERED: /* sat-r09 (latest) uses this sk */
+ case SG_LIB_CAT_NO_SENSE: /* earlier SAT drafts used this */
/* XXX: Until the spec decides which one to go with. 20060607 */
ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
- SAT_STATUS_RETURN_DESC);
- if (NULL == ucp)
+ SAT_ATA_RETURN_DESC);
+ if (NULL == ucp) {
+ if (verbose > 1)
+ printf("ATA Return Descriptor expected in sense but not "
+ "found\n");
sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
- else if (verbose)
- sg_chk_n_print3("status return descriptor, as expected",
+ } else if (verbose)
+ sg_chk_n_print3("ATA Return Descriptor, as expected",
&io_hdr, 1);
if (ucp && ucp[3]) {
if (ucp[3] & 0x4)
@@ -166,11 +171,11 @@ int main(int argc, char * argv[])
default:
fprintf(stderr, "unexpected SCSI sense category\n");
ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
- SAT_STATUS_RETURN_DESC);
+ SAT_ATA_RETURN_DESC);
if (NULL == ucp)
sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
else if (verbose)
- sg_chk_n_print3("status return descriptor, as expected",
+ sg_chk_n_print3("ATA Return Descriptor, as expected",
&io_hdr, 1);
if (ucp && ucp[3]) {
if (ucp[3] & 0x4)
@@ -203,8 +208,8 @@ int main(int argc, char * argv[])
break;
}
} else
- fprintf(stderr, "Expecting a special error return and didn't "
- "receive it\n");
+ fprintf(stderr, "Expecting a ATA Return Descriptor in sense and "
+ "didn't receive it\n");
close(sg_fd);
return 0;
diff --git a/examples/sg_sat_set_features.c b/examples/sg_sat_set_features.c
index d0b82adb..0ae6738d 100644
--- a/examples/sg_sat_set_features.c
+++ b/examples/sg_sat_set_features.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Douglas Gilbert.
+ * Copyright (c) 2006-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,13 +50,13 @@
#define SAT_ATA_PASS_THROUGH16 0x85
#define SAT_ATA_PASS_THROUGH16_LEN 16
-#define SAT_STATUS_RETURN_DESC 9 /* ATA status return (sense) descriptor */
+#define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */
#define ATA_SET_FEATURES 0xef
#define EBUFF_SZ 256
-static char * version_str = "1.01 20061014";
+static char * version_str = "1.02 20070130";
int main(int argc, char * argv[])
{
@@ -106,6 +106,8 @@ int main(int argc, char * argv[])
++verbose;
else if (0 == strcmp(argv[k], "-vv"))
verbose += 2;
+ else if (0 == strcmp(argv[k], "-vvv"))
+ verbose += 3;
else if (0 == strcmp(argv[k], "-V")) {
fprintf(stderr, "version: %s\n", version_str);
exit(0);
@@ -176,15 +178,17 @@ int main(int argc, char * argv[])
switch (sg_err_category3(&io_hdr)) {
case SG_LIB_CAT_CLEAN:
break;
- case SG_LIB_CAT_RECOVERED:
- case SG_LIB_CAT_NO_SENSE:
- /* XXX: Until the spec decides which one to go with. 20060607 */
+ case SG_LIB_CAT_RECOVERED: /* sat-r09 uses this sk */
+ case SG_LIB_CAT_NO_SENSE: /* earlier SAT drafts used this */
ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
- SAT_STATUS_RETURN_DESC);
- if (NULL == ucp)
+ SAT_ATA_RETURN_DESC);
+ if (NULL == ucp) {
+ if (verbose > 1)
+ printf("ATA Return Descriptor expected in sense but not "
+ "found\n");
sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
- else if (verbose)
- sg_chk_n_print3("status return descriptor", &io_hdr, 1);
+ } else if (verbose)
+ sg_chk_n_print3("ATA Return Descriptor", &io_hdr, 1);
if (ucp && ucp[3]) {
if (ucp[3] & 0x4)
printf("error in returned FIS: aborted command\n");
@@ -195,11 +199,11 @@ int main(int argc, char * argv[])
default:
fprintf(stderr, "unexpected SCSI sense category\n");
ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
- SAT_STATUS_RETURN_DESC);
+ SAT_ATA_RETURN_DESC);
if (NULL == ucp)
sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
else if (verbose)
- sg_chk_n_print3("status return descriptor, as expected",
+ sg_chk_n_print3("ATA Return Descriptor, as expected",
&io_hdr, 1);
if (ucp && ucp[3]) {
if (ucp[3] & 0x4)
diff --git a/examples/sg_sat_smart_rd_data.c b/examples/sg_sat_smart_rd_data.c
index a5122baf..dcf4b41e 100644
--- a/examples/sg_sat_smart_rd_data.c
+++ b/examples/sg_sat_smart_rd_data.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Douglas Gilbert.
+ * Copyright (c) 2006-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,7 @@
#define SAT_ATA_PASS_THROUGH16 0x85
#define SAT_ATA_PASS_THROUGH16_LEN 16
-#define SAT_STATUS_RETURN_DESC 9 /* ATA status return (sense) descriptor */
+#define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */
#define ATA_SMART 0xb0
#define ATA_SMART_READ_DATA 0xd0
@@ -57,7 +57,7 @@
#define EBUFF_SZ 256
-static char * version_str = "1.01 20061014";
+static char * version_str = "1.02 20070130";
int main(int argc, char * argv[])
{
@@ -84,6 +84,8 @@ int main(int argc, char * argv[])
++verbose;
else if (0 == strcmp(argv[k], "-vv"))
verbose += 2;
+ else if (0 == strcmp(argv[k], "-vvv"))
+ verbose += 3;
else if (0 == strcmp(argv[k], "-V")) {
fprintf(stderr, "version: %s\n", version_str);
exit(0);
@@ -157,12 +159,14 @@ int main(int argc, char * argv[])
break;
case SG_LIB_CAT_RECOVERED:
ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
- SAT_STATUS_RETURN_DESC);
- if (NULL == ucp)
+ SAT_ATA_RETURN_DESC);
+ if (NULL == ucp) {
+ if (verbose > 1)
+ printf("ATA Return Descriptor expected in sense but not "
+ "found\n");
sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
- else if (verbose)
- sg_chk_n_print3("ATA status return descriptor",
- &io_hdr, 1);
+ } else if (verbose)
+ sg_chk_n_print3("ATA Return Descriptor", &io_hdr, 1);
if (ucp && ucp[3])
printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]);
else
diff --git a/examples/sg_simple4.c b/examples/sg_simple4.c
index 20d8d7f5..df36f3f0 100644
--- a/examples/sg_simple4.c
+++ b/examples/sg_simple4.c
@@ -97,7 +97,8 @@ int main(int argc, char * argv[])
/* since I know this program will only read from inqBuff then I use
PROT_READ rather than PROT_READ | PROT_WRITE */
- inqBuff = mmap(NULL, 8000, PROT_READ | PROT_WRITE, MAP_SHARED, sg_fd, 0);
+ inqBuff = (unsigned char *)mmap(NULL, 8000, PROT_READ | PROT_WRITE,
+ MAP_SHARED, sg_fd, 0);
if (MAP_FAILED == inqBuff) {
snprintf(ebuff, EBUFF_SZ, "sg_simple4: error using mmap() on "
"file: %s", file_name);
@@ -205,7 +206,8 @@ int main(int argc, char * argv[])
/* could call munmap(inqBuff, INQ_REPLY_LEN) here but following close()
causes this too happen anyway */
#if 1
- inqBuff2 = mmap(NULL, 8000, PROT_READ | PROT_WRITE, MAP_SHARED, sg_fd, 0);
+ inqBuff2 = (unsigned char *)mmap(NULL, 8000, PROT_READ | PROT_WRITE,
+ MAP_SHARED, sg_fd, 0);
if (MAP_FAILED == inqBuff2) {
snprintf(ebuff, EBUFF_SZ, "sg_simple4: error using mmap() 2 on "
"file: %s", file_name);
diff --git a/make_no_lib_win32.sh b/make_no_lib_win32.sh
index 2160db17..24f6953a 100755
--- a/make_no_lib_win32.sh
+++ b/make_no_lib_win32.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-make -f Makefile.win32 $@
+make -f no_lib/Makefile.win32 $@
diff --git a/no_lib/Makefile.freebsd b/no_lib/Makefile.freebsd
index ab79f6a0..dae08b74 100644
--- a/no_lib/Makefile.freebsd
+++ b/no_lib/Makefile.freebsd
@@ -12,14 +12,16 @@ EXECS = sg_readcap sg_turs sg_inq sg_start sg_modes sg_logs sg_senddiag \
sg_sync sg_prevent sg_get_config sg_wr_mode \
sg_rtpg sg_reassign sg_format sg_rmsn sg_ident \
sg_read_long sg_write_long sg_verify sg_rdac sg_vpd \
- sg_sat_identify
+ sg_sat_identify sg_read_buffer sg_write_buffer sg_opcodes
MAN_PGS = sg_readcap.8 sg_turs.8 sg_inq.8 sg_start.8 sg_modes.8 sg_logs.8 \
sg_senddiag.8 sg_persist.8 sg_requests.8 sg_ses.8 sg_luns.8 \
sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
sg_read_long.8 sg_write_long.8 sg_verify.8 sg_rdac.8 sg_vpd.8 \
- sg3_utils.8 sg_sat_identify.8
+ sg3_utils.8 sg_sat_identify.8 sg_read_buffer.8 sg_write_buffer.8 \
+ sg_opcodes.8
+
MAN_PREF = man8
OS_FLAGS = -DSG3_UTILS_FREEBSD
@@ -124,6 +126,15 @@ sg_vpd: sg_vpd.o sg_vpd_vendor.o $(O_BFILES)
sg_sat_identify: sg_sat_identify.o $(O_FILES)
$(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+sg_read_buffer: sg_read_buffer.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_write_buffer: sg_write_buffer.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_opcodes: sg_opcodes.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
install: $(EXECS)
install -d $(INSTDIR)
for name in $(EXECS); \
diff --git a/no_lib/Makefile.linux b/no_lib/Makefile.linux
index 3e2b8a25..d4537326 100644
--- a/no_lib/Makefile.linux
+++ b/no_lib/Makefile.linux
@@ -15,7 +15,8 @@ EXECS = sg_dd sgp_dd sgm_dd sg_read sg_map sg_scan sg_rbuf \
sg_persist sg_write_long sg_read_long sg_requests sg_ses \
sg_verify sg_emc_trespass sg_luns sg_sync sg_prevent \
sg_get_config sg_wr_mode sg_rtpg sg_reassign sg_format \
- sg_rmsn sg_ident sg_map26 sg_rdac sg_vpd sg_sat_identify
+ sg_rmsn sg_ident sg_map26 sg_rdac sg_vpd sg_sat_identify \
+ sg_read_buffer sg_write_buffer
MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sginfo.8 sg_readcap.8 sg_turs.8 sg_inq.8 sg_test_rwbuf.8 \
@@ -24,7 +25,8 @@ MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8 \
sg_luns.8 sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
- sg_map26.8 sg_rdac.8 sg_vpd.8 sg3_utils.8 sg_sat_identify.8
+ sg_map26.8 sg_rdac.8 sg_vpd.8 sg3_utils.8 sg_sat_identify.8 \
+ sg_read_buffer.8 sg_write_buffer.8
MAN_PREF = man8
OS_FLAGS = -DSG3_UTILS_LINUX
@@ -51,7 +53,7 @@ clean:
/bin/rm -f *.o $(EXECS) core* .depend *.a *.la *.lo
/bin/rm -rf .libs
-sg_dd: sg_dd.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o sg_io_linux.o llseek.o
+sg_dd: sg_dd.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o sg_io_linux.o
$(LD) -o $@ $(LDFLAGS) $^
sg_scan: sg_scan.o sg_io_linux.o sg_lib.o
@@ -72,10 +74,10 @@ sg_readcap: sg_readcap.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o
sgp_dd.o: sgp_dd.c
$(CC) $(INCLUDES) $(CFLAGS) $(CFLAGS_PTHREADS) -c $<
-sgp_dd: sgp_dd.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o llseek.o
+sgp_dd: sgp_dd.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o
$(LD) -o $@ $(LDFLAGS) $^ -lpthread
-sgm_dd: sgm_dd.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o llseek.o
+sgm_dd: sgm_dd.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o
$(LD) -o $@ $(LDFLAGS) $^
sg_map: sg_map.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o
@@ -90,7 +92,7 @@ sg_test_rwbuf: sg_test_rwbuf.o sg_lib.o sg_io_linux.o
sg_inq: sg_inq.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o
$(LD) -o $@ $(LDFLAGS) $^
-sg_read: sg_read.o sg_lib.o sg_io_linux.o llseek.o
+sg_read: sg_read.o sg_lib.o sg_io_linux.o
$(LD) -o $@ $(LDFLAGS) $^
sg_reset: sg_reset.o
@@ -105,7 +107,7 @@ sg_logs: sg_logs.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o
sg_senddiag: sg_senddiag.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
$(LD) -o $@ $(LDFLAGS) $^
-sg_opcodes: sg_opcodes.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o sg_io_linux.o
+sg_opcodes: sg_opcodes.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
$(LD) -o $@ $(LDFLAGS) $^
sg_persist: sg_persist.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
@@ -171,6 +173,12 @@ sg_vpd: sg_vpd.o sg_vpd_vendor.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o
sg_sat_identify: sg_sat_identify.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
$(LD) -o $@ $(LDFLAGS) $^
+sg_read_buffer: sg_read_buffer.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
+ $(LD) -o $@ $(LDFLAGS) $^
+
+sg_write_buffer: sg_write_buffer.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
+ $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
for name in $^; \
diff --git a/no_lib/Makefile.linux_static b/no_lib/Makefile.linux_static
index a7fb03e9..b3f5f0f9 100644
--- a/no_lib/Makefile.linux_static
+++ b/no_lib/Makefile.linux_static
@@ -15,7 +15,8 @@ EXECS = sg_dd sgp_dd sgm_dd sg_read sg_map sg_scan sg_rbuf \
sg_persist sg_write_long sg_read_long sg_requests sg_ses \
sg_verify sg_emc_trespass sg_luns sg_sync sg_prevent \
sg_get_config sg_wr_mode sg_rtpg sg_reassign sg_format \
- sg_rmsn sg_ident sg_map26 sg_rdac sg_vpd sg_sat_identify
+ sg_rmsn sg_ident sg_map26 sg_rdac sg_vpd sg_sat_identify \
+ sg_read_buffer sg_write_buffer
MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sginfo.8 sg_readcap.8 sg_turs.8 sg_inq.8 sg_test_rwbuf.8 \
@@ -24,7 +25,8 @@ MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8 \
sg_luns.8 sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
- sg_map26.8 sg_rdac.8 sg_vpd.8 sg3_utils.8 sg_sat_identify.8
+ sg_map26.8 sg_rdac.8 sg_vpd.8 sg3_utils.8 sg_sat_identify.8 \
+ sg_read_buffer.8 sg_write_buffer.8
MAN_PREF = man8
OS_FLAGS = -DSG3_UTILS_LINUX
@@ -51,7 +53,7 @@ clean:
/bin/rm -f *.o $(EXECS) core* .depend *.a *.la *.lo
/bin/rm -rf .libs
-sg_dd: sg_dd.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o sg_io_linux.o llseek.o
+sg_dd: sg_dd.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o sg_io_linux.o
$(LD) -o $@ $(LDFLAGS) $^
sg_scan: sg_scan.o sg_io_linux.o sg_lib.o
@@ -72,10 +74,10 @@ sg_readcap: sg_readcap.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o
sgp_dd.o: sgp_dd.c
$(CC) $(INCLUDES) $(CFLAGS) $(CFLAGS_PTHREADS) -c $<
-sgp_dd: sgp_dd.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o llseek.o
+sgp_dd: sgp_dd.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o
$(LD) -o $@ $(LDFLAGS) $^ -lpthread
-sgm_dd: sgm_dd.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o llseek.o
+sgm_dd: sgm_dd.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o
$(LD) -o $@ $(LDFLAGS) $^
sg_map: sg_map.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o sg_io_linux.o
@@ -90,7 +92,7 @@ sg_test_rwbuf: sg_test_rwbuf.o sg_lib.o sg_io_linux.o
sg_inq: sg_inq.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o
$(LD) -o $@ $(LDFLAGS) $^
-sg_read: sg_read.o sg_lib.o sg_io_linux.o llseek.o
+sg_read: sg_read.o sg_lib.o sg_io_linux.o
$(LD) -o $@ $(LDFLAGS) $^
sg_reset: sg_reset.o
@@ -105,7 +107,7 @@ sg_logs: sg_logs.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o
sg_senddiag: sg_senddiag.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
$(LD) -o $@ $(LDFLAGS) $^
-sg_opcodes: sg_opcodes.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o sg_io_linux.o
+sg_opcodes: sg_opcodes.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
$(LD) -o $@ $(LDFLAGS) $^
sg_persist: sg_persist.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
@@ -171,6 +173,12 @@ sg_vpd: sg_vpd.o sg_vpd_vendor.o sg_lib.o sg_cmds_basic.o sg_pt_linux.o
sg_sat_identify: sg_sat_identify.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
$(LD) -o $@ $(LDFLAGS) $^
+sg_read_buffer: sg_read_buffer.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
+ $(LD) -o $@ $(LDFLAGS) $^
+
+sg_write_buffer: sg_write_buffer.o sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_linux.o
+ $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
for name in $^; \
diff --git a/no_lib/Makefile.osf1 b/no_lib/Makefile.osf1
index 971bcbce..ab02bb7c 100644
--- a/no_lib/Makefile.osf1
+++ b/no_lib/Makefile.osf1
@@ -11,14 +11,16 @@ EXECS = sg_readcap sg_turs sg_inq sg_start sg_modes sg_logs sg_senddiag \
sg_persist sg_requests sg_ses sg_luns \
sg_sync sg_prevent sg_get_config sg_wr_mode \
sg_rtpg sg_reassign sg_format sg_rmsn sg_ident \
- sg_read_long sg_write_long sg_verify sg_rdac sg_vpd
+ sg_read_long sg_write_long sg_verify sg_rdac sg_vpd \
+ sg_sat_identify sg_read_buffer sg_write_buffer sg_opcodes
MAN_PGS = sg_readcap.8 sg_turs.8 sg_inq.8 sg_start.8 sg_modes.8 sg_logs.8 \
sg_senddiag.8 sg_persist.8 sg_requests.8 sg_ses.8 sg_luns.8 \
sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
sg_read_long.8 sg_write_long.8 sg_verify.8 sg_rdac.8 sg_vpd.8 \
- sg3_utils.8
+ sg3_utils.8 sg_sat_identify.8 sg_read_buffer.8 sg_write_buffer.8 \
+ sg_opcodes.8
MAN_PREF = man8
@@ -51,26 +53,26 @@ clean:
.c.o:
$(CC) $(CFLAGS) -c -o $@ $<
-sg_readcap: sg_readcap.o $(O_BFILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+sg_readcap: sg_readcap.o $(O_BFILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES) $(O_GETOPT_LONG)
-sg_turs: sg_turs.o $(O_BFILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+sg_turs: sg_turs.o $(O_BFILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES) $(O_GETOPT_LONG)
-sg_inq: sg_inq.o $(O_BFILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+sg_inq: sg_inq.o $(O_BFILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES) $(O_GETOPT_LONG)
-sg_start: sg_start.o $(O_BFILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+sg_start: sg_start.o $(O_BFILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES) $(O_GETOPT_LONG)
-sg_modes: sg_modes.o $(O_BFILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+sg_modes: sg_modes.o $(O_BFILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES) $(O_GETOPT_LONG)
-sg_logs: sg_logs.o $(O_BFILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+sg_logs: sg_logs.o $(O_BFILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES) $(O_GETOPT_LONG)
-sg_senddiag: sg_senddiag.o $(O_FILES)
- $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+sg_senddiag: sg_senddiag.o $(O_FILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES) $(O_GETOPT_LONG)
sg_persist: sg_persist.o $(O_FILES) $(O_GETOPT_LONG)
$(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES) $(O_GETOPT_LONG)
@@ -126,6 +128,18 @@ sg_rdac: sg_rdac.o $(O_BFILES) $(O_GETOPT_LONG)
sg_vpd: sg_vpd.o sg_vpd_vendor.o $(O_BFILES) $(O_GETOPT_LONG)
$(LD) -o $@ $(LDFLAGS) $@.o sg_vpd_vendor.o $(O_BFILES) $(O_GETOPT_LONG)
+sg_sat_identify: sg_sat_identify.o $(O_FILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES) $(O_GETOPT_LONG)
+
+sg_read_buffer: sg_read_buffer.o $(O_FILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES) $(O_GETOPT_LONG)
+
+sg_write_buffer: sg_write_buffer.o $(O_FILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES) $(O_GETOPT_LONG)
+
+sg_opcodes: sg_opcodes.o $(O_BFILES) $(O_GETOPT_LONG)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES) $(O_GETOPT_LONG)
+
install: $(EXECS)
test -d $(INSTDIR) || mkdir -p $(INSTDIR)
for name in $(EXECS); \
diff --git a/no_lib/Makefile.win32 b/no_lib/Makefile.win32
new file mode 100644
index 00000000..22cc0fb6
--- /dev/null
+++ b/no_lib/Makefile.win32
@@ -0,0 +1,166 @@
+SHELL = /bin/sh
+
+PREFIX=/usr/local
+INSTDIR=$(PREFIX)/bin
+MANDIR=$(PREFIX)/man
+
+CC = gcc
+LD = gcc
+
+EXECS = sg_readcap sg_turs sg_inq sg_start sg_modes sg_logs sg_senddiag \
+ sg_persist sg_requests sg_ses sg_luns sg_scan \
+ sg_sync sg_prevent sg_get_config sg_wr_mode \
+ sg_rtpg sg_reassign sg_format sg_rmsn sg_ident \
+ sg_read_long sg_write_long sg_verify sg_rdac sg_vpd \
+ sg_sat_identify sg_read_buffer sg_write_buffer sg_opcodes
+
+MAN_PGS = sg_readcap.8 sg_turs.8 sg_inq.8 sg_start.8 sg_modes.8 sg_logs.8 \
+ sg_senddiag.8 sg_persist.8 sg_requests.8 sg_ses.8 sg_luns.8 \
+ sg_scan.8 sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
+ sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
+ sg_read_long.8 sg_write_long.8 sg_verify.8 sg_rdac.8 sg_vpd.8 \
+ sg3_utils.8 sg_sat_identify.8 sg_read_buffer.8 sg_write_buffer.8 \
+ sg_opcodes.8
+
+MAN_PREF = man8
+
+OS_FLAGS = -DSG3_UTILS_WIN32 -DSPTD
+# OS_FLAGS = -DSG3_UTILS_WIN32
+LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+EXTRA_FLAGS = $(OS_FLAGS) $(LARGE_FILE_FLAGS)
+
+# CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS)
+CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS)
+# CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS)
+
+O_FILES = sg_lib.o sg_cmds_basic.o sg_cmds_extra.o sg_pt_win32.o
+O_BFILES = sg_lib.o sg_cmds_basic.o sg_pt_win32.o
+O_SFILES = sg_lib.o
+
+LDFLAGS = -static
+
+all: $(EXECS)
+ cp sg_scan.8w sg_scan.8
+
+depend dep:
+ for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \
+ done > .depend
+
+clean:
+ /bin/rm -f *.o $(EXECS) core* .depend *.a *.la *.lo
+ /bin/rm -rf .libs
+
+.c.o:
+ $(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) -c -o $@ $<
+
+sg_readcap: sg_readcap.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_turs: sg_turs.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_inq: sg_inq.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_start: sg_start.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_modes: sg_modes.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_logs: sg_logs.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_senddiag: sg_senddiag.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_persist: sg_persist.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_requests: sg_requests.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_ses: sg_ses.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_luns: sg_luns.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_scan: sg_scan.o $(O_SFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_SFILES)
+
+sg_sync: sg_sync.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_prevent: sg_prevent.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_get_config: sg_get_config.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_wr_mode: sg_wr_mode.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_rtpg: sg_rtpg.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_reassign: sg_reassign.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_format: sg_format.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_rmsn: sg_rmsn.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_ident: sg_ident.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_read_long: sg_read_long.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_write_long: sg_write_long.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_verify: sg_verify.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_rdac: sg_rdac.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+sg_vpd: sg_vpd.o sg_vpd_vendor.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o sg_vpd_vendor.o $(O_BFILES)
+
+sg_sat_identify: sg_sat_identify.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_read_buffer: sg_read_buffer.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_write_buffer: sg_write_buffer.o $(O_FILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_FILES)
+
+sg_opcodes: sg_opcodes.o $(O_BFILES)
+ $(LD) -o $@ $(LDFLAGS) $@.o $(O_BFILES)
+
+install: $(EXECS)
+ cp sg_scan.8w sg_scan.8
+ install -d $(INSTDIR)
+ for name in $(EXECS); \
+ do install -s -m 755 $$name $(INSTDIR); \
+ done
+ install -d $(MANDIR)/$(MAN_PREF)
+ for mp in $(MAN_PGS); \
+ do install -m 644 $$mp $(MANDIR)/$(MAN_PREF); \
+ gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \
+ done
+
+uninstall:
+ dists="$(EXECS)"; \
+ for name in $$dists; do \
+ rm -f $(INSTDIR)/$$name; \
+ done
+ for mp in $(MAN_PGS); do \
+ rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \
+ done
+
diff --git a/no_lib/sg3_utils.spec b/no_lib/sg3_utils.spec
index 218f262e..6056b517 100644
--- a/no_lib/sg3_utils.spec
+++ b/no_lib/sg3_utils.spec
@@ -1,6 +1,6 @@
-Summary: Utilities for SCSI devices in Linux
+Summary: Utilities for devices that use SCSI command sets
Name: sg3_utils
-Version: 1.22
+Version: 1.23
Release: 1
Packager: Douglas Gilbert <dgilbert at interlog dot com>
License: GPL/FreeBSD
@@ -86,6 +86,9 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root) %{_bindir}/sg_map26
%attr(755,root,root) %{_bindir}/sg_vpd
%attr(755,root,root) %{_bindir}/sg_rdac
+%attr(755,root,root) %{_bindir}/sg_sat_identify
+%attr(755,root,root) %{_bindir}/sg_read_buffer
+%attr(755,root,root) %{_bindir}/sg_write_buffer
# Mandrake compresses man pages with bzip2, RedHat with gzip
%attr(-,root,root) %doc %{_mandir}/man8/sg_dd.8*
%attr(-,root,root) %doc %{_mandir}/man8/sgp_dd.8*
@@ -125,10 +128,17 @@ rm -rf $RPM_BUILD_ROOT
%attr(-,root,root) %doc %{_mandir}/man8/sg_map26.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg_vpd.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg_rdac.8*
+%attr(-,root,root) %doc %{_mandir}/man8/sg_sat_identify.8*
+%attr(-,root,root) %doc %{_mandir}/man8/sg_read_buffer.8*
+%attr(-,root,root) %doc %{_mandir}/man8/sg_write_buffer.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg3_utils.8*
%changelog
+* Wed Jan 31 2007 - dgilbert at interlog dot com
+- add sg_read_buffer + sg_write_buffer
+ * sg3_utils-1.23
+
* Mon Oct 16 2006 - dgilbert at interlog dot com
- add sg_sat_identify, expand sg_format and sg_requests
* sg3_utils-1.22
diff --git a/scripts/README b/scripts/README
new file mode 100644
index 00000000..00526447
--- /dev/null
+++ b/scripts/README
@@ -0,0 +1,45 @@
+ README for sg3_utils/scripts
+ ============================
+Introduction
+============
+This directory contains bash shell scripts. Most of them call one or
+more utilities from the sg3_utils package. They assume the sg3_utils
+package utilities are on the PATH of the user.
+
+scsi_logging_level is written by Andreas Herrmann <aherrman at de dot ibm
+dot com>. It sets the logging level of the SCSI subsystem in the linux
+2.6 series kernels. See that file for more information.
+
+The other scripts are written by the author. Some do testing while others
+do bulk tasks (e.g. stopping multiple disks).
+
+Details
+=======
+Each script supplies more information, typically by supplying a '-h'
+or '--help' option. The script source often contains explanatory
+information. Following is a usage summary with a one line description:
+ sas_disk_blink [-h] [-s <n>] <device>
+ - blink LED on <device> using RLM bit in SAS targets
+ scsi_logging_level [OPTIONS]
+ - set Linux SCSI subsystem logging level
+ scsi_mandat [-h] [-L] [-q] <device>
+ - check for mandatory SCSI command support
+ scsi_readcap [-b] [-h] [-v] <device>+
+ - fetch capacity/size information for each <device>
+ scsi_ready [-h] [-v] <device>+
+ - check the media ready status on each <device>
+ scsi_satl [-h] [-L] [-q] <device>
+ - check <device> for SCSI to ATA Translation Layer (SATL)
+ scsi_start [-h] [-v] <device>+
+ - start media (i.e. spin up) in each <device>
+ scsi_stop [-h] [-v] <device>+
+ - stop media (i.e. spin down) in each <device>
+ scsi_temperature [-h] [-v] <device>+
+ - check temperature in each <device>
+
+These scripts assume that the main sg3_utils utilities are installed
+and are on the user's PATH. The sas_disk_blink script relies on the
+sdparm utility.
+
+Douglas Gilbert
+25th January 2007
diff --git a/scripts/sas_disk_blink b/scripts/sas_disk_blink
new file mode 100755
index 00000000..d569fb00
--- /dev/null
+++ b/scripts/sas_disk_blink
@@ -0,0 +1,104 @@
+#!/bin/bash
+# sas_disk_blink
+#
+# Script to blink the LED on a SAS disk.
+# By default it blinks the LED for 30 seconds, thereafter leaving
+# the LED in the state it was prior to this command being called.
+# The blink is one second on, one second off, etc.
+#
+# Uses sdparm rather than sg3_utils as the former is simpler to
+# use for setting mode page value.
+#
+# Douglas Gilbert 20061208
+
+
+seconds=30
+
+usage()
+{
+ echo "Usage: sas_disk_blink [-h] [-s <n>] <sas_device>"
+ echo " where:"
+ echo " -h, --help print usage message"
+ echo " -s <n>, --set <n> where <n> is:"
+ echo " 0 - set RLM to 0"
+ echo " 1 - set RLM to 1"
+ echo " >1 - blink LED for <n> seconds"
+ echo " (default: blink for 30 seconds)"
+ echo ""
+ echo "Use Ready LED Meaning (RLM) mode page field to blink SAS device LED"
+}
+
+if (( $# < 1 ))
+ then
+ usage
+ exit 1
+fi
+
+opt="$1"
+while test ! -z "$opt" -a -z "${opt##-*}"; do
+ opt=${opt#-}
+ case "$opt" in
+ h|-help) usage ; exit 0 ;;
+ s|-set) shift ; let seconds=$1 ;;
+ *) echo "Unknown option: -$opt " ; exit 1 ;;
+ esac
+ shift
+ opt="$1"
+done
+
+if ( which sdparm >/dev/null 2>&1 ) ; then
+ true
+else
+ echo "sdparm not found"
+ sdparm
+fi
+
+if [ $seconds = "0" ]
+then
+ sdparm -t sas -c RLM $1
+ exit $?
+elif [ $seconds = "1" ]
+then
+ sdparm -t sas -s RLM $1
+ exit $?
+elif [ $seconds -gt 1 ]
+then
+ outt=$(sdparm -t sas -g RLM -H $1)
+ let res=$?
+ if [ $res -ne 0 ]
+ then
+ exit $res
+ fi
+ if [ ${outt:0:4} = "0x00" ]
+ then
+ let start=0
+ else
+ let start=1
+ fi
+ echo "start blinking for $seconds seconds"
+ for (( times = 1; times < $seconds; times=$times+2 )); do
+ if [ $start -eq 0 ]
+ then
+ sdparm -q -t sas -s RLM $1
+ let res=$?
+ if [ $res -ne 0 ]
+ then
+ exit $res
+ fi
+ sleep 1
+ sdparm -q -t sas -c RLM $1
+ sleep 1
+ else
+ sdparm -q -t sas -c RLM $1
+ let res=$?
+ if [ $res -ne 0 ]
+ then
+ exit $res
+ fi
+ sleep 1
+ sdparm -q -t sas -s RLM $1
+ sleep 1
+ fi
+ done
+ echo "stop blinking"
+fi
diff --git a/scripts/scsi_logging_level b/scripts/scsi_logging_level
new file mode 100755
index 00000000..ecbc8277
--- /dev/null
+++ b/scripts/scsi_logging_level
@@ -0,0 +1,295 @@
+#! /bin/bash
+###############################################################################
+# Conveniently create and set scsi logging level, show SCSI_LOG fields in human
+# readable form.
+#
+# Copyright (C) IBM Corp. 2006
+#
+# 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 of the License, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+###############################################################################
+
+# Contributed by Andreas Herrmann <aherrman@de.ibm.com> 2006/08/18
+
+SCRIPTNAME="scsi_logging_level"
+
+declare -i LOG_ERROR=0
+declare -i LOG_TIMEOUT=0
+declare -i LOG_SCAN=0
+declare -i LOG_MLQUEUE=0
+declare -i LOG_MLCOMPLETE=0
+declare -i LOG_LLQUEUE=0
+declare -i LOG_LLCOMPLETE=0
+declare -i LOG_HLQUEUE=0
+declare -i LOG_HLCOMPLETE=0
+declare -i LOG_IOCTL=0
+
+declare -i LEVEL=0
+
+_ERROR_SHIFT=0
+_TIMEOUT_SHIFT=3
+_SCAN_SHIFT=6
+_MLQUEUE_SHIFT=9
+_MLCOMPLETE_SHIFT=12
+_LLQUEUE_SHIFT=15
+_LLCOMPLETE_SHIFT=18
+_HLQUEUE_SHIFT=21
+_HLCOMPLETE_SHIFT=24
+_IOCTL_SHIFT=27
+
+SET=0
+GET=0
+CREATE=0
+
+OPTS=`getopt -o hvcgsa:E:T:S:I:M:L:H: --long \
+help,version,create,get,set,all:,error:,timeout:,scan:,ioctl:,\
+midlevel:,mlqueue:,mlcomplete:,lowlevel:,llqueue:,llcomplete:,\
+highlevel:,hlqueue:,hlcomplete: -n \'$SCRIPTNAME\' -- "$@"`
+eval set -- "$OPTS"
+
+# print version info
+printversion()
+{
+ cat <<EOF
+$SCRIPTNAME (s390-tools) %S390_TOOLS_VERSION%
+(C) Copyright IBM Corp. 2006
+EOF
+}
+
+# print usage and help
+printhelp()
+{
+ cat <<EOF
+Usage: $SCRIPTNAME [OPTIONS]
+
+Create, get or set scsi logging level.
+
+Options:
+
+ -h, --help print this help
+ -v, --version print version information
+ -s, --set create and set logging level as specified on
+ command line
+ -g, --get get current logging level and display it
+ -c, --create create logging level as specified on command line
+ -a, --all specify value for all SCSI_LOG fields
+ -E, --error specify SCSI_LOG_ERROR
+ -T, --timeout specify SCSI_LOG_TIMEOUT
+ -S, --scan specify SCSI_LOG_SCAN
+ -M, --midlevel specify SCSI_LOG_MLQUEUE and SCSI_LOG_MLCOMPLETE
+ --mlqueue specify SCSI_LOG_MLQUEUE
+ --mlcomplete specify SCSI_LOG_MLCOMPLETE
+ -L, --lowlevel specify SCSI_LOG_LLQUEUE and SCSI_LOG_LLCOMPLETE
+ --llqueue specify SCSI_LOG_LLQUEUE
+ --llcomplete specify SCSI_LOG_LLCOMPLETE
+ -H, --highlevel specify SCSI_LOG_HLQUEUE and SCSI_LOG_HLCOMPLETE
+ --hlqueue specify SCSI_LOG_HLQUEUE
+ --hlcomplete specify SCSI_LOG_HLCOMPLETE
+ -I, --ioctl specify SCSI_LOG_IOCTL
+
+Exactly one of the options "-c", "-g" and "-s" has to be specified.
+Valid values for SCSI_LOG fields are integers from 0 to 7.
+
+Note: Several SCSI_LOG fields can be specified using several options.
+When multiple options specify same SCSI_LOG field the most specific
+option has precedence.
+
+Example: "scsi_logging_level --hlqueue 3 --hlcomplete 2 --all 1 -s" sets
+SCSI_LOG_HLQUEUE=3, SCSI_LOG_HLCOMPLETE=2 and assigns all other SCSI_LOG
+fields the value 1.
+EOF
+}
+
+check_level()
+{
+# something is wrong with the following if ... dpg 20061027
+# if [ `echo -n $1 | tr --complement [:digit:] 'a' | grep -s 'a'` ]
+# then
+# invalid_cmdline "log level '$1' out of range [0, 7]"
+# fi
+
+ if [ $1 -lt 0 -o $1 -gt 7 ]
+ then
+ invalid_cmdline "log level '$1' out of range [0, 7]"
+ fi
+}
+
+# check cmd line arguments
+check_cmdline()
+{
+ while true ; do
+ case "$1" in
+ -a|--all) _ALL=$2; check_level $2
+ shift 2;;
+ -c|--create) CREATE=1;
+ shift 1;;
+ -g|--get) GET=1
+ shift 1;;
+ -h|--help) printhelp
+ exit 0;;
+ -s|--set) SET=1
+ shift 1;;
+ -v|--version) printversion
+ exit 0;;
+ -E|--error) _ERROR=$2; check_level $2
+ shift 2;;
+ -T|--timeout) _TIMEOUT=$2; check_level $2
+ shift 2;;
+ -S|--scan) _SCAN=$2; check_level $2
+ shift 2;;
+ -M|--midlevel) _ML=$2; check_level $2
+ shift 2;;
+ --mlqueue) _MLQUEUE=$2; check_level $2
+ shift 2;;
+ --mlcomplete) _MLCOMPLETE=$2; check_level $2
+ shift 2;;
+ -L|--lowlevel) _LL=$2; check_level $2
+ shift 2;;
+ --llqueue) _LLQUEUE=$2; check_level $2
+ shift 2;;
+ --llcomplete) _LLCOMPLETE=$2; check_level $2
+ shift 2;;
+ -H|--highlevel) _HL=$2; check_level $2
+ shift 2;;
+ --hlqueue) _HLQUEUE=$2; check_level $2
+ shift 2;;
+ --hlcomplete) _HLCOMPLETE=$2; check_level $2
+ shift 2;;
+ -I|--ioctl) _IOCTL=$2; check_level $2
+ shift 2;;
+ --) shift; break;;
+ *) echo "Internal error!" ; exit 1;;
+ esac
+ done
+
+ if [ -n "$*" ]
+ then
+ invalid_cmdline invalid parameter $*
+ fi
+
+ if [ $GET = "1" -a $SET = "1" ]
+ then
+ invalid_cmdline options \'-c\', \'-g\' and \'-s\' are mutual exclusive
+ elif [ $GET = "1" -a $CREATE = "1" ]
+ then
+ invalid_cmdline options \'-c\', \'-g\' and \'-s\' are mutual exclusive
+ elif [ $SET = "1" -a $CREATE = "1" ]
+ then
+ invalid_cmdline options \'-c\', \'-g\' and \'-s\' are mutual exclusive
+ fi
+
+ LOG_ERROR=${_ERROR:-${_ALL:-0}}
+ LOG_TIMEOUT=${_TIMEOUT:-${_ALL:-0}}
+ LOG_SCAN=${_SCAN:-${_ALL:-0}}
+ LOG_MLQUEUE=${_MLQUEUE:-${_ML:-${_ALL:-0}}}
+ LOG_MLCOMPLETE=${_MLCOMPLETE:-${_ML:-${_ALL:-0}}}
+ LOG_LLQUEUE=${_LLQUEUE:-${_LL:-${_ALL:-0}}}
+ LOG_LLCOMPLETE=${_LLCOMPLETE:-${_LL:-${_ALL:-0}}}
+ LOG_HLQUEUE=${_HLQUEUE:-${_HL:-${_ALL:-0}}}
+ LOG_HLCOMPLETE=${_HLCOMPLETE:-${_HL:-${_ALL:-0}}}
+ LOG_IOCTL=${_IOCTL:-${_ALL:-0}}
+}
+
+invalid_cmdline()
+{
+ echo "$SCRIPTNAME: $*"
+ echo "$SCRIPTNAME: Try '$SCRIPTNAME --help' for more information."
+ exit 1
+}
+
+get_logging_level()
+{
+ echo "Current scsi logging level:"
+ LEVEL=`sysctl -n dev.scsi.logging_level`
+ if [ $? != 0 ]
+ then
+ echo "$SCRIPTNAME: could not read scsi logging level" \
+ "(kernel probably without SCSI_LOGGING support)"
+ exit 1
+ fi
+}
+
+show_logging_level()
+{
+ echo "dev.scsi.logging_level = $LEVEL"
+
+ LOG_ERROR=$((($LEVEL>>$_ERROR_SHIFT) & 7))
+ LOG_TIMEOUT=$((($LEVEL>>$_TIMEOUT_SHIFT) & 7))
+ LOG_SCAN=$((($LEVEL>>$_SCAN_SHIFT) & 7))
+ LOG_MLQUEUE=$((($LEVEL>>$_MLQUEUE_SHIFT) & 7))
+ LOG_MLCOMPLETE=$((($LEVEL>>$_MLCOMPLETE_SHIFT) & 7))
+ LOG_LLQUEUE=$((($LEVEL>>$_LLQUEUE_SHIFT) & 7))
+ LOG_LLCOMPLETE=$((($LEVEL>>$_LLCOMPLETE_SHIFT) & 7))
+ LOG_HLQUEUE=$((($LEVEL>>$_HLQUEUE_SHIFT) & 7))
+ LOG_HLCOMPLETE=$((($LEVEL>>$_HLCOMPLETE_SHIFT) & 7))
+ LOG_IOCTL=$((($LEVEL>>$_IOCTL_SHIFT) & 7))
+
+ echo "SCSI_LOG_ERROR=$LOG_ERROR"
+ echo "SCSI_LOG_TIMEOUT=$LOG_TIMEOUT"
+ echo "SCSI_LOG_SCAN=$LOG_SCAN"
+ echo "SCSI_LOG_MLQUEUE=$LOG_MLQUEUE"
+ echo "SCSI_LOG_MLCOMPLETE=$LOG_MLCOMPLETE"
+ echo "SCSI_LOG_LLQUEUE=$LOG_LLQUEUE"
+ echo "SCSI_LOG_LLCOMPLETE=$LOG_LLCOMPLETE"
+ echo "SCSI_LOG_HLQUEUE=$LOG_HLQUEUE"
+ echo "SCSI_LOG_HLCOMPLETE=$LOG_HLCOMPLETE"
+ echo "SCSI_LOG_IOCTL=$LOG_IOCTL"
+}
+
+set_logging_level()
+{
+ echo "New scsi logging level:"
+ sysctl -q -w dev.scsi.logging_level=$LEVEL
+ if [ $? != 0 ]
+ then
+ echo "$SCRIPTNAME: could not write scsi logging level" \
+ "(kernel probably without SCSI_LOGGING support)"
+ exit 1
+ fi
+}
+
+create_logging_level()
+{
+ LEVEL=$((($LOG_ERROR & 7)<<$_ERROR_SHIFT))
+ LEVEL=$(($LEVEL|(($LOG_TIMEOUT & 7)<<$_TIMEOUT_SHIFT)))
+ LEVEL=$(($LEVEL|(($LOG_SCAN & 7)<<$_SCAN_SHIFT)))
+ LEVEL=$(($LEVEL|(($LOG_MLQUEUE & 7)<<$_MLQUEUE_SHIFT)))
+ LEVEL=$(($LEVEL|(($LOG_MLCOMPLETE & 7)<<$_MLCOMPLETE_SHIFT)))
+ LEVEL=$(($LEVEL|(($LOG_LLQUEUE & 7)<<$_LLQUEUE_SHIFT)))
+ LEVEL=$(($LEVEL|(($LOG_LLCOMPLETE & 7)<<$_LLCOMPLETE_SHIFT)))
+ LEVEL=$(($LEVEL|(($LOG_HLQUEUE & 7)<<$_HLQUEUE_SHIFT)))
+ LEVEL=$(($LEVEL|(($LOG_HLCOMPLETE & 7)<<$_HLCOMPLETE_SHIFT)))
+ LEVEL=$(($LEVEL|(($LOG_IOCTL & 7)<<$_IOCTL_SHIFT)))
+}
+
+check_cmdline $*
+
+if [ $SET = "1" ]
+then
+ create_logging_level
+ set_logging_level
+ show_logging_level
+elif [ $GET = "1" ]
+then
+ get_logging_level
+ show_logging_level
+elif [ $CREATE = "1" ]
+then
+ create_logging_level
+ show_logging_level
+else
+ invalid_cmdline missing option \'-g\', \'-s\' or \'-c\'
+fi
+
diff --git a/scripts/scsi_mandat b/scripts/scsi_mandat
new file mode 100755
index 00000000..6e9e3c97
--- /dev/null
+++ b/scripts/scsi_mandat
@@ -0,0 +1,120 @@
+#!/bin/bash
+# scsi_mandat
+#
+# Script to test compliance with SCSI mandatory commands.
+# The vintage is SPC-3 and SPC-4 (see www.t10.org).
+#
+# Coverage:
+# Command Standard/Draft (is mandatory in)
+# -------------------------------------------------------
+# INQUIRY (standard) SCSI-2, SPC, SPC-2, SPC-3, SPC-4
+# INQUIRY (VPD pages 0, 0x83) SPC-2, SPC-3, SPC-4
+# REPORT LUNS SPC-3, SPC-4
+# TEST UNIT READY SCSI-2, SPC, SPC-2, SPC-3, SPC-4
+# REQUEST SENSE SCSI-2, SBC, SBC-2,3, MMC-4,5, SSC-2,3
+# SEND DIAGNOSTIC SBC, SBC-2,3, SSC-2,3
+#
+# This script uses utilities frim sg3_utils package (version
+# 1.21 or later) and sdparm (version 0.99 or later)
+#
+# Douglas Gilbert 20061230
+
+
+log=0
+quiet=0
+
+file_err=0
+inv_opcode=0
+illeg_req=0
+not_ready=0
+medium=0
+other_err=0
+recovered=0
+sanity=0
+syntax=0
+timeout=0
+unit_attention=0
+aborted_command=0
+
+total_err=0
+
+usage()
+{
+ echo "Usage: scsi_mandat [-h] [-L] [-q] <device>"
+ echo " where: -h print usage message"
+ echo " -L, --log append stderr to 'scsi_mandat.err'"
+ echo " -q suppress some output"
+ echo ""
+ echo "Check <device> for manadatory SCSI command support"
+}
+
+if (( $# < 1 ))
+ then
+ usage
+ exit 1
+fi
+
+# opt=$1
+# echo ${opt##-*}
+
+opt="$1"
+while test ! -z "$opt" -a -z "${opt##-*}"; do
+ opt=${opt#-}
+ case "$opt" in
+ h|-help) usage ; exit 0 ;;
+ L|-log) let log=$log+1 ;;
+ q|-quiet) let quiet=$quiet+1 ;;
+ *) echo "Unknown option: -$opt " ; exit 1 ;;
+ esac
+ shift
+ opt="$1"
+done
+
+for command in "sg_inq" "sg_luns" "sg_turs" "sg_requests" "sg_vpd" \
+ "sg_vpd -i" "sg_senddiag -t"
+do
+ if [ $quiet -eq 0 ]
+ then echo "$command" $1
+ fi
+
+ if [ $log -eq 0 ]
+ then
+ $command $1 > /dev/null 2>> /dev/null
+ else
+ $command $1 > /dev/null 2>> scsi_mandat.err
+ fi
+ res=$?
+ case "$res" in
+ 0) ;;
+ 1) echo " syntax error" ; let syntax=$syntax+1 ;;
+ 2) echo " not ready" ; let not_ready=$not_ready+1 ;;
+ 3) echo " medium error" ; let medium=$medium+1 ;;
+ 5) echo " illegal request, general" ; let illeg_req=$illeg_req+1 ;;
+ 6) echo " unit attention" ; let unit_attention=$unit_attention+1 ;;
+ 9) echo " illegal request, invalid opcode" ; let inv_opcode=$inv_opcode+1 ;;
+ 11) echo " aborted command" ; let aborted_command=$aborted_command+1 ;;
+ 15) echo " file error with $1 " ; let file_err=$file_err+1 ;;
+ 20) echo " no sense" ; let other_err=$other_err+1 ;;
+ 21) echo " recovered error" ; let recovered_err=$recovered_err+1 ;;
+ 33) echo " timeout" ; let timeout=$timeout+1 ;;
+ 97) echo " response fails sanity" ; let sanity=$sanity+1 ;;
+ 98) echo " other SCSI error" ; let other_err=$other_err+1 ;;
+ 99) echo " other error" ; let other_err=$other_err+1 ;;
+ *) echo " unknown exit status for sg_inq: $res" ; let other_err=$other_err+1 ;;
+ esac
+done
+
+echo ""
+let total_bad_err=$file_err+$inv_opcode+$illeg_req+$medium+$aborted_command
+let total_bad_err+=$other_err+$recovered+$sanity+$syntax+$timeout
+
+let total_allow_err=$not_ready+$unit_attention
+
+ echo "total number of bad errors: $total_bad_err "
+
+if [ $total_allow_err -gt 0 ]
+ then
+ echo "total number of allowable errors: $total_allow_err "
+fi
+
+exit $total_bad_err
diff --git a/scripts/scsi_readcap b/scripts/scsi_readcap
new file mode 100755
index 00000000..d4b21a5d
--- /dev/null
+++ b/scripts/scsi_readcap
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+###################################################################
+#
+# Fetch READ CAPACITY information for the given SCSI device(s).
+#
+# This script assumes the sg3_utils package is installed.
+#
+##################################################################
+
+verbose=""
+brief=""
+
+usage()
+{
+ echo "Usage: scsi_readcap [-b] [-h] [-v] <device>+"
+ echo " where:"
+ echo " -b, --brief output brief capacity data"
+ echo " -h, --help print usage message"
+ echo " -v, --verbose more verbose output"
+ echo ""
+ echo "Use SCSI READ CAPACITY command to fetch the size of each <device>"
+}
+
+if (( $# < 1 ))
+ then
+ usage
+ exit 1
+fi
+
+opt="$1"
+while test ! -z "$opt" -a -z "${opt##-*}"; do
+ opt=${opt#-}
+ case "$opt" in
+ b|-brief) brief="-b" ;;
+ h|-help) usage ; exit 0 ;;
+ v|-verbose) verbose="-v" ;;
+ vv) verbose="-vv" ;;
+ *) echo "Unknown option: -$opt " ; exit 1 ;;
+ esac
+ shift
+ opt="$1"
+done
+
+for i
+do
+ echo "sg_readcap $brief $verbose $i"
+ sg_readcap $brief $verbose $i
+done
diff --git a/scripts/scsi_ready b/scripts/scsi_ready
new file mode 100755
index 00000000..338f671c
--- /dev/null
+++ b/scripts/scsi_ready
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+################################################
+#
+# Send a TEST UNIT READY SCSI command to each given device.
+#
+# This script assumes the sg3_utils package is installed.
+#
+###############################################
+
+verbose=""
+
+usage()
+{
+ echo "Usage: scsi_ready [-h] [-v] <device>+"
+ echo " where:"
+ echo " -h, --help print usage message"
+ echo " -v, --verbose more verbose output"
+ echo ""
+ echo "Send SCSI TEST UNIT READY to each <device>"
+}
+
+if (( $# < 1 ))
+ then
+ usage
+ exit 1
+fi
+
+opt="$1"
+while test ! -z "$opt" -a -z "${opt##-*}"; do
+ opt=${opt#-}
+ case "$opt" in
+ h|-help) usage ; exit 0 ;;
+ v|-verbose) verbose="-v" ;;
+ *) echo "Unknown option: -$opt " ; exit 1 ;;
+ esac
+ shift
+ opt="$1"
+done
+
+for i
+do
+ echo "sg_turs $verbose $i"
+ echo -n " "
+ if sg_turs $verbose $i ; then
+ echo "ready"
+ fi
+done
diff --git a/scripts/scsi_satl b/scripts/scsi_satl
new file mode 100755
index 00000000..2758eae7
--- /dev/null
+++ b/scripts/scsi_satl
@@ -0,0 +1,128 @@
+#!/bin/bash
+# scsi_satl
+#
+# Script to test compliance of SCSI commands on a SCSI to ATA
+# Transaltion (SAT) Layer (SATL). This scripts was compiled using
+# sat-r09.pdf found at www.t10.org .
+# The vintage is SPC-3 and SPC-4 (see www.t10.org).
+#
+# Coverage:
+# Command SATL notes
+# -------------------------------------------------------
+# INQUIRY (standard)
+# INQUIRY (VPD: 0)
+# INQUIRY (VPD: 0x83) Device identification VPD page
+# INQUIRY (VPD: 0x89) ATA Information VPD page
+# REPORT LUNS SPC-3, SPC-4 (hardly mentioned in sat-r08c)
+# TEST UNIT READY
+# REQUEST SENSE
+# SEND DIAGNOSTIC default self test
+# MODE SENSE(10) draft unclear which mode pages, so ask for all
+# ATA PASS THROUGH(16) send IDENTIFY DEVICE command. Assume non-packet
+# device, if packet device add "-p" option
+#
+# This script uses utilities from sg3_utils package (version
+# 1.22 or later) and sdparm (version 0.99 or later)
+#
+# Douglas Gilbert 20061230
+
+
+quiet=0
+log=0
+
+file_err=0
+inv_opcode=0
+illeg_req=0
+not_ready=0
+medium=0
+other_err=0
+recovered=0
+sanity=0
+syntax=0
+timeout=0
+unit_attention=0
+aborted_command=0
+
+total_err=0
+
+usage()
+{
+ echo "Usage: scsi_satl [-h] [-L] [-q] <device>"
+ echo " where: -h, --help print usage message"
+ echo " -L, --log append stderr to 'scsi_satl.err'"
+ echo " -q, --quiet suppress some output"
+ echo ""
+ echo "Check <device> for SCSI to ATA Translation Layer (SATL) support"
+}
+
+if (( $# < 1 ))
+ then
+ usage
+ exit 1
+fi
+
+# opt=$1
+# echo ${opt##-*}
+
+opt="$1"
+while test ! -z "$opt" -a -z "${opt##-*}"; do
+ opt=${opt#-}
+ case "$opt" in
+ h|-help) usage ; exit 1 ;;
+ L|-log) let log=$log+1 ;;
+ q|-quiet) let quiet=$quiet+1 ;;
+ *) echo "Unknown option: -$opt " ; exit 1 ;;
+ esac
+ shift
+ opt="$1"
+done
+
+for command in "sg_inq" "sg_vpd" "sg_vpd -p di" "sg_vpd -p ai" "sg_luns" \
+ "sg_turs" "sg_requests -s" "sg_senddiag -t" "sg_modes -a" \
+ "sg_sat_identify"
+do
+ if [ $quiet -eq 0 ]
+ then echo "$command" $1
+ fi
+
+ if [ $log -eq 0 ]
+ then
+ $command $1 > /dev/null 2>> /dev/null
+ else
+ $command $1 > /dev/null 2>> scsi_satl.err
+ fi
+ res=$?
+ case "$res" in
+ 0) ;;
+ 1) echo " syntax error" ; let syntax=$syntax+1 ;;
+ 2) echo " not ready" ; let not_ready=$not_ready+1 ;;
+ 3) echo " medium error" ; let medium=$medium+1 ;;
+ 5) echo " illegal request, general" ; let illeg_req=$illeg_req+1 ;;
+ 6) echo " unit attention" ; let unit_attention=$unit_attention+1 ;;
+ 9) echo " illegal request, invalid opcode" ; let inv_opcode=$inv_opcode+1 ;;
+ 11) echo " aborted command" ; let aborted_command=$aborted_command+1 ;;
+ 15) echo " file error with $1 " ; let file_err=$file_err+1 ;;
+ 20) echo " no sense" ; let other_err=$other_err+1 ;;
+ 21) echo " recovered error" ; let recovered_err=$recovered_err+1 ;;
+ 33) echo " timeout" ; let timeout=$timeout+1 ;;
+ 97) echo " response fails sanity" ; let sanity=$sanity+1 ;;
+ 98) echo " other SCSI error" ; let other_err=$other_err+1 ;;
+ 99) echo " other error" ; let other_err=$other_err+1 ;;
+ *) echo " unknown exit status for sg_inq: $res" ; let other_err=$other_err+1 ;;
+ esac
+done
+
+echo ""
+let total_bad_err=$file_err+$inv_opcode+$illeg_req+$medium+$aborted_command
+let total_bad_err+=$other_err+$recovered+$sanity+$syntax+$timeout
+
+let total_allow_err=$not_ready+$unit_attention
+
+ echo "total number of bad errors: $total_bad_err "
+
+if [ $total_allow_err -gt 0 ]
+ then
+ echo "total number of allowable errors: $total_allow_err "
+fi
+
+exit $total_bad_err
diff --git a/scripts/scsi_start b/scripts/scsi_start
new file mode 100755
index 00000000..226e9f2a
--- /dev/null
+++ b/scripts/scsi_start
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+################################################
+#
+# Spin up the given SCSI disk(s).
+#
+# SCSI disks (or disks that understand SCSI commands)
+# are assumed. The immediate bit is set so the command
+# should return immediately. The disk however will take
+# 10 seconds or more to spin up.
+#
+# This script assumes the sg3_utils package is installed.
+#
+###############################################
+
+verbose=""
+
+usage()
+{
+ echo "Usage: scsi_start [-h] [-v] <device>+"
+ echo " where:"
+ echo " -h, --help print usage message"
+ echo " -v, --verbose more verbose output"
+ echo ""
+ echo "Send SCSI START STOP UNIT command to start each <device>"
+}
+
+if (( $# < 1 ))
+ then
+ usage
+ exit 1
+fi
+
+opt="$1"
+while test ! -z "$opt" -a -z "${opt##-*}"; do
+ opt=${opt#-}
+ case "$opt" in
+ h|-help) usage ; exit 0 ;;
+ v|-verbose) verbose="-v" ;;
+ *) echo "Unknown option: -$opt " ; exit 1 ;;
+ esac
+ shift
+ opt="$1"
+done
+
+for i
+do
+ echo "sg_start -i 1 $verbose $i"
+ sg_start -i 1 $verbose $i
+done
diff --git a/scripts/scsi_stop b/scripts/scsi_stop
new file mode 100755
index 00000000..c719ab30
--- /dev/null
+++ b/scripts/scsi_stop
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+################################################
+#
+# Spin down the given SCS disk(s).
+#
+# SCSI disks (or disks that understand SCSI commands)
+# are assumed. The immediate bit is set so the command
+# should return immediately. The disk however will take
+# 10 seconds or more to spin down.
+#
+# This script assumes the sg3_utils package is installed.
+#
+###############################################
+
+verbose=""
+
+usage()
+{
+ echo "Usage: scsi_stop [-h] [-v] <device>+"
+ echo " where:"
+ echo " -h, --help print usage message"
+ echo " -v, --verbose more verbose output"
+ echo ""
+ echo "Send SCSI START STOP UNIT command to stop each <device>"
+}
+
+if (( $# < 1 ))
+ then
+ usage
+ exit 1
+fi
+
+opt="$1"
+while test ! -z "$opt" -a -z "${opt##-*}"; do
+ opt=${opt#-}
+ case "$opt" in
+ h|-help) usage ; exit 0 ;;
+ v|-verbose) verbose="-v" ;;
+ *) echo "Unknown option: -$opt " ; exit 1 ;;
+ esac
+ shift
+ opt="$1"
+done
+
+for i
+do
+ echo "sg_start -i 0 $verbose $i"
+ sg_start -i 0 $verbose $i
+done
diff --git a/scripts/scsi_temperature b/scripts/scsi_temperature
new file mode 100755
index 00000000..31080ebc
--- /dev/null
+++ b/scripts/scsi_temperature
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+###################################################################
+#
+# Check the temperature of the given SCSI device(s).
+#
+# This script assumes the sg3_utils package is installed.
+#
+##################################################################
+
+verbose=""
+
+usage()
+{
+ echo "Usage: scsi_temperature [-h] [-v] <device>+"
+ echo " where:"
+ echo " -h, --help print usage message"
+ echo " -v, --verbose more verbose output"
+ echo ""
+ echo "Use SCSI LOG SENSE command to fetch temperature of each <device>"
+}
+
+if (( $# < 1 ))
+ then
+ usage
+ exit 1
+fi
+
+opt="$1"
+while test ! -z "$opt" -a -z "${opt##-*}"; do
+ opt=${opt#-}
+ case "$opt" in
+ h|-help) usage ; exit 0 ;;
+ v|-verbose) verbose="-v" ;;
+ vv) verbose="-vv" ;;
+ *) echo "Unknown option: -$opt " ; exit 1 ;;
+ esac
+ shift
+ opt="$1"
+done
+
+for i
+do
+ echo "sg_logs -t $verbose $i"
+ sg_logs -t $verbose $i
+done
diff --git a/sg3_utils.8 b/sg3_utils.8
index 4ba9749b..2a60c35a 100644
--- a/sg3_utils.8
+++ b/sg3_utils.8
@@ -1,57 +1,64 @@
-.TH SG3_UTILS "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG3_UTILS "8" "Jamuary 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
.B sg_*
-[\fI--help\fR] [\fI--verbose\fR] [\fI--version\fR]
-\fI<scsi_device>\fR
+[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] [\fIOTHER_OPTIONS\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-sg3_utils is a package of utilities that send SCSI commands to
-the given <scsi_device> via a SCSI pass through interface
-provided by the host operating system.
+sg3_utils is a package of utilities that send SCSI commands to the given
+\fIDEVICE\fR via a SCSI pass through interface provided by the host
+operating system.
.PP
-The names of all utilities start with "sg" and most start with "sg_"
-often followed by the abbreviation of the name of the SCSI command
-that they send. For example the "sg_verify" utility sends the SCSI
-VERIFY command. A mapping between SCSI commands and the sg3_utils
-utilities that issue them is given in the COVERAGE file.
+The names of all utilities start with "sg" and most start with "sg_" often
+followed by the name or a shortening of the name of the SCSI command that
+they send. For example the "sg_verify" utility sends the SCSI VERIFY
+command. A mapping between SCSI commands and the sg3_utils utilities that
+issue them is shown in the COVERAGE file.
.PP
-SCSI draft standards can be found at http://www.t10.org . The
-standards themselves can be purchased from ANSI and other
-standards organizations. A good overview of various SCSI
-standards can be seen at http://www.t10.org/scsi-3.htm with the
-SCSI command sets in the upper part of the diagram. SCSI commands
-in common with all device types can be found in SPC of which SPC-4
-is the latest major version. Block device specific commands (e.g.
-as used by disks) can be in SBC, those for tape drives in SSC
-and those for CD/DVD drives in MMC.
+SCSI draft standards can be found at http://www.t10.org . The standards
+themselves can be purchased from ANSI and other standards organizations.
+A good overview of various SCSI standards can be seen in
+http://www.t10.org/scsi\-3.htm with the SCSI command sets in the upper part
+of the diagram. SCSI commands in common with all device types can be found
+in SPC of which SPC\-4 is the latest major version. Block device specific
+commands (e.g. as used by disks) are in SBC, those for tape drives in
+SSC and those for CD/DVD drives in MMC.
.PP
-There are two generations of command line option usage. The older utilities
-such as sg_inq have individual command line processing code (often
-found at the top of the main() function) based on a single "-" followed
-by one or more characters. If an argument is needed then it follows
-a "=" (e.g. '-p=1f' in sg_modes). Various options can be elided as long
-as it is not ambiguous (e.g. '-vv' to increase the verbosity). The
-<scsi_device> is any device that can receive SCSI commands and is shown
-after the options in the synopsis. It may appear between other options.
+There are two generations of command line option usage. The newer
+utilities (written since July 2004) use the getopt_long() function to parse
+command line options. With that function, each option has two representations:
+a short form (e.g. '\-v') and a longer form (e.g. '\-\-verbose'). If an
+argument is required then it follows a space (optionally) in the short form
+and a "=" in the longer form (e.g. in the sg_verify utility '\-l 2a6h'
+and '\-\-lba=2a6h' are equivalent). Note that with getopt_long(), short form
+options can be elided, for example: '\-all' is equivalent to '\-a \-l \-l'.
+The \fIDEVICE\fR argument may appear after, between or prior to any options.
.PP
-The second generation of newer utilities uses the getopt_long() function
-to parse command line options. With that function, each option has two
-representations: a short form (e.g. '-v') and a longer
-form (e.g. '--verbose'). If an argument is required then it follows a
-space in the short form and a "=" in the longer form (e.g. in the
-sg_verify utility '-l 2a6h' and '--lba=2a6h' are equivalent). Again
-the <scsi_device> argument may appear between or prior to other options.
+The older utilities, such as sg_inq, had individual command line processing
+code (often found at the top of the main() function) based on a single "\-"
+followed by one or more characters. If an argument is needed then it follows
+a "=" (e.g. '\-p=1f' in sg_modes). Various options can be elided as long as
+it is not ambiguous (e.g. '\-vv' to increase the verbosity).
+.PP
+Over time the command line interface of these older utilities became messy
+and overloaded with options. So in sg3_utils version 1.23 the command line
+interface of these older utilities was altered to have both a cleaner
+getopt_long() interface and their older interface for backward compatibility.
+By default these older utilities use their getopt_long() based interface.
+That can be overridden by defining the SG3_UTILS_OLD_OPTS environment
+variable or using '\-O' or '\-\-old' as the first command line option. The
+man pages of the older utilities documents the details.
.PP
Several sg3_utils utilities are based on the Unix dd command (e.g. sg_dd)
-and share its rather quirky command line interface.
+and share dd's rather quirky command line interface.
.SH EXIT STATUS
-To aid scripts that call these utilities, the exit status is set to
-indicate success (0) or failure (1 or more). Note that some of the
-lower values correspond to the SCSI sense key values to which they
-correspond. The exit status values are:
+To aid scripts that call these utilities, the exit status is set to indicate
+success (0) or failure (1 or more). Note that some of the lower values
+correspond to the SCSI sense key values to which they correspond. The exit
+status values are:
.TP
.B 0
success
@@ -61,64 +68,62 @@ syntax error. Either illegal command line options, options with bad
arguments or a combination of options that is not permitted.
.TP
.B 2
-the <scsi_device> reports that it is not ready for the operation
+the \fIDEVICE\fR reports that it is not ready for the operation
requested. The device may be in the process of becoming ready (e.g.
spinning up but not at speed) so the utility may work after a wait.
.TP
.B 3
-the <scsi_device> reports a medium or hardware error (or a blank
-check). For example an attempt to read a corrupted block on a disk
-will yield this value.
+the \fIDEVICE\fR reports a medium or hardware error (or a blank check). For
+example an attempt to read a corrupted block on a disk will yield this value.
.TP
.B 5
-the <scsi_device> reports an "illegal request" with an additional
-sense code other than "invalid operation code". This is often a
-supported command with a field set requesting an unsupported
-capability. For commands that require a "service action" field
-this value can indicate that the command is not supported.
+the \fIDEVICE\fR reports an "illegal request" with an additional sense code
+other than "invalid operation code". This is often a supported command with
+a field set requesting an unsupported capability. For commands that require
+a "service action" field this value can indicate that the command with that
+service action value is not supported.
.TP
.B 6
-the <scsi_device> reports a "unit attention" condition. This usually
-indicates that something unrelated to the requested command has
-occurred (e.g. a device reset) potentially before the current SCSI
-command was sent. The requested command has not been executed by the
-device. Note that unit attention conditions are usually only reported
-once by a device.
+the \fIDEVICE\fR reports a "unit attention" condition. This usually indicates
+that something unrelated to the requested command has occurred (e.g. a device
+reset) potentially before the current SCSI command was sent. The requested
+command has not been executed by the device. Note that unit attention
+conditions are usually only reported once by a device.
.TP
.B 9
-the <scsi_device> reports an illegal request with an additional
-sense code of "invalid operation code" which means that it doesn't
-support the requested command.
+the \fIDEVICE\fR reports an illegal request with an additional sense code
+of "invalid operation code" which means that it doesn't support the
+requested command.
.TP
.B 11
-the <scsi_device> reports an aborted command. In some cases aborted
+the \fIDEVICE\fR reports an aborted command. In some cases aborted
commands can be retried immediately (e.g. if the transport aborted
the command due to congestion).
.TP
.B 15
-the utility is unable to open, close or use the given <scsi_device>.
+the utility is unable to open, close or use the given \fIDEVICE\fR.
The given file name could be incorrect or there may be permission
-problems. Adding the '-v' option may give more information.
+problems. Adding the '\-v' option may give more information.
.TP
.B 20
-the <scsi_device> reports it has a check condition but "no sense"
-and non-zero information in its additional sense codes. Some polling
+the \fIDEVICE\fR reports it has a check condition but "no sense"
+and non\-zero information in its additional sense codes. Some polling
commands (e.g. REQUEST SENSE) can receive this response.
.TP
.B 21
-the <scsi_device> reports a "recovered error". The requested command
+the \fIDEVICE\fR reports a "recovered error". The requested command
was successful. Most likely a utility will report a recovered error
to stderr and continue, probably leaving the utility with an exit
status of 0 .
.TP
.B 33
-the command sent to <scsi_device> has timed out.
+the command sent to \fIDEVICE\fR has timed out.
.TP
.B 97
the response to a SCSI command failed sanity checks.
.TP
.B 98
-the <scsi_device> reports it has a check condition but the error
+the \fIDEVICE\fR reports it has a check condition but the error
doesn't fit into any of the above categories.
.TP
.B 99
@@ -128,37 +133,51 @@ after the command has been sent to the device.
.PP
Most of the error conditions reported above will be repeatable (an
example of one that is not is "unit attention") so the utility can
-be run again with the '-v' option (or several) to obtain more
+be run again with the '\-v' option (or several) to obtain more
information.
.SH COMMON OPTIONS
+Arguments to long options are mandatory for short options as well. In the
+short form an argument to an option uses zero or more spaces as a
+separator (i.e. the short form does not use "=" as a separator).
+.PP
+If an option takes a numeric argument then that argument is assumed to
+be decimal unless otherwise indicated (e.g. with a leading "0x", a
+trailing "h" or as noted in the usage message).
.TP
---help | -h | -?
-output the usage message then exit. In a few older utilities the '-h'
-option requests hexadecimal output. In these cases the '-?' option will
+\fB\-h\fR, \fB\-?\fR, \fB\-\-help\fR
+output the usage message then exit. In a few older utilities the '\-h'
+option requests hexadecimal output. In these cases the '\-?' option will
output the usage message then exit.
.TP
---verbose | -v
+\fB\-H\fR, \fB\-\-hex\fR
+for SCSI commands that yield a non\-trivial response, print out that
+response in ASCII hexadecimal.
+.TP
+\fB\-r\fR, \fB\-\-raw\fR
+for SCSI commands that yield a non\-trivial response, output that response
+in binary to stdout. If any error messages or warning are produced they are
+usually sent to stderr. Some utilities that consume data to send to the
+device along with the SCSI command, use this option to provide that data
+or indicate that it can be read from stdin.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output). Can be used multiple
times to further increase verbosity. The additional output is usually sent
to stderr.
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit. Each utility has its own version
number and date of last code change.
-.PP
-Notice that the '--verbose' option can be used multiple times for more
-verbose output. Obviously the short form ('-vv') is more convenient than
-the longer form ('--verbose --verbose').
.SH AUTHORS
Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 1999-2006 Douglas Gilbert
+Copyright \(co 1999\-2007 Douglas Gilbert
.br
Some utilities are distributed under a GPL version 2 license while
others, usually more recent ones, are under a FreeBSD license. The files
-that are common to almost all utilities and thus have the most reusable
+that are common to almost all utilities and thus contain the most reusable
code, namely sg_lib.[hc], sg_cmds_basic.[hc] and sg_cmds_extra.[hc] are
under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 975dd885..390b7f46 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -1,21 +1,15 @@
-%define name sg3_utils
-%define version 1.22
-%define release 1
-
-%define major 1
-%define minor 0
-%define libname %{_lib}sgutils-%{major}_%{minor}
-
-Summary: Utilities for SCSI devices in Linux
-Name: %{name}
-Version: %{version}
-Release: %{release}
-License: GPL/FreeBSD
-Group: Utilities/System
-URL: http://www.torque.net/sg/sg3_utils.html
-Source0: http://www.torque.net/sg/p/%{name}-%{version}.tgz
-BuildRoot: %{_tmppath}/%{name}-%{version}-root
-Packager: Douglas Gilbert <dgilbert at interlog dot com>
+Summary: Utilities for devices that use SCSI command sets
+Name: sg3_utils
+Version: 1.23
+Release: 1%{?dist}
+License: GPL
+Group: Utilities/System
+Source: ftp://www.torque.net/sg/p/sg3_utils-%{version}.tgz
+Url: http://www.torque.net/sg/sg3_utils.html
+Provides: sg_utils
+BuildRequires: libtool
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+Packager: Douglas Gilbert <dougg@torque.net>
%description
Collection of Linux utilities for devices that use the SCSI command set.
@@ -31,64 +25,52 @@ well (e.g. /dev/sda).
Warning: Some of these tools access the internals of your system
and the incorrect usage of them may render your system inoperable.
-%package -n %{libname}
-Summary: Shared library for %{name}
-Group: System/Libraries
+%package libs
+Summary: Shared library for %{name}
+Group: System/Libraries
-%description -n %{libname}
+%description libs
This package contains the shared library for %{name}.
-%package -n %{libname}-devel
-Summary: Static library and header files for the sgutils library
-Group: Development/C
-Obsoletes: %{name}-devel
-Provides: %{name}-devel
-Provides: libsgutils-devel
-Requires: %{libname} = %{version}-%{release}
+%package devel
+Summary: Static library and header files for the sgutils library
+Group: Development/C
+Requires: %{name}-libs = %{version}-%{release}
-%description -n %{libname}-devel
-This package contains the static sgutils library and its header
-files.
+%description devel
+This package contains the static %{name} library and its header files for
+developing applications.
%prep
-
%setup -q
%build
-
-make \
- CFLAGS="%{optflags}" \
- LIBDIR="%{_libdir}"
+make
%install
-[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
-
-make install \
- PREFIX=%{_prefix} \
- LIBDIR=%{buildroot}/%{_libdir} \
- INSTDIR=%{buildroot}/%{_bindir} \
- MANDIR=%{buildroot}/%{_mandir} \
- INCLUDEDIR=%{buildroot}/%{_includedir} \
- LIB_VINFO=1:0:0
-
-%post -n %{libname} -p /sbin/ldconfig
-
-%postun -n %{libname} -p /sbin/ldconfig
+if [ "$RPM_BUILD_ROOT" != "/" ]; then
+ rm -rf $RPM_BUILD_ROOT
+fi
+%ifarch sparc64 ppc64 s390x x86_64
+make install PREFIX=$RPM_BUILD_ROOT/usr LIBDIR=$RPM_BUILD_ROOT/usr/lib64
+%else
+make install PREFIX=$RPM_BUILD_ROOT/usr
+%endif
%clean
-[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
+rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
-%doc CHANGELOG COPYING COVERAGE CREDITS INSTALL README README.sg_start
-%attr(0755,root,root) %{_bindir}/*
+%doc CHANGELOG COVERAGE CREDITS INSTALL README README.sg_start
+%attr(755,root,root) %{_bindir}/*
%{_mandir}/man8/*
-%files -n %{libname}
+%files libs
%defattr(-,root,root)
%{_libdir}/*.so.*
-%files -n %{libname}-devel
+%files devel
%defattr(-,root,root)
%{_includedir}/scsi/*.h
%{_libdir}/*.so
@@ -96,6 +78,10 @@ make install \
%{_libdir}/*.la
%changelog
+* Wed Jan 31 2007 - dgilbert at interlog dot com
+- add sg_read_buffer + sg_write_buffer
+ * sg3_utils-1.23
+
* Mon Oct 16 2006 - dgilbert at interlog dot com
- add sg_sat_identify, expand sg_format and sg_requests
* sg3_utils-1.22
diff --git a/sg_cmds_basic.c b/sg_cmds_basic.c
index a9651d1a..d9613e14 100644
--- a/sg_cmds_basic.c
+++ b/sg_cmds_basic.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2006 Douglas Gilbert.
+ * Copyright (c) 1999-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,14 +40,12 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <sys/ioctl.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_pt.h"
-static char * version_str = "1.35 20061012";
+static char * version_str = "1.38 20070124";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -244,7 +242,7 @@ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op,
fprintf(sg_warnings_strm, "\n");
}
if (resp && (mx_resp_len > 0)) {
- up = resp;
+ up = (unsigned char *)resp;
up[0] = 0x7f; /* defensive prefill */
if (mx_resp_len > 4)
up[4] = 0;
@@ -256,7 +254,7 @@ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op,
}
set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b,
noisy, verbose, &sense_cat);
@@ -570,7 +568,7 @@ int sg_ll_readcap_16(int sg_fd, int pmi, unsigned long long llba,
}
set_scsi_pt_cdb(ptvp, rcCmdBlk, sizeof(rcCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "read capacity (16)", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -636,7 +634,7 @@ int sg_ll_readcap_10(int sg_fd, int pmi, unsigned int lba,
}
set_scsi_pt_cdb(ptvp, rcCmdBlk, sizeof(rcCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "read capacity (10)", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -703,7 +701,7 @@ int sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
}
set_scsi_pt_cdb(ptvp, modesCmdBlk, sizeof(modesCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "mode sense (6)", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -730,7 +728,7 @@ int sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
if ((verbose > 2) && (ret > 0)) {
fprintf(sg_warnings_strm, " mode sense (6): response%s\n",
(ret > 256 ? ", first 256 bytes" : ""));
- dStrHex(resp, (ret > 256 ? 256 : ret), -1);
+ dStrHex((const char *)resp, (ret > 256 ? 256 : ret), -1);
}
ret = 0;
}
@@ -777,7 +775,7 @@ int sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code,
}
set_scsi_pt_cdb(ptvp, modesCmdBlk, sizeof(modesCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "mode sense (10)", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -804,7 +802,7 @@ int sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code,
if ((verbose > 2) && (ret > 0)) {
fprintf(sg_warnings_strm, " mode sense (10): response%s\n",
(ret > 256 ? ", first 256 bytes" : ""));
- dStrHex(resp, (ret > 256 ? 256 : ret), -1);
+ dStrHex((const char *)resp, (ret > 256 ? 256 : ret), -1);
}
ret = 0;
}
@@ -852,7 +850,7 @@ int sg_ll_mode_select6(int sg_fd, int pf, int sp, void * paramp,
}
set_scsi_pt_cdb(ptvp, modesCmdBlk, sizeof(modesCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, paramp, param_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "mode select (6)", res, 0, sense_b,
noisy, verbose, &sense_cat);
@@ -923,7 +921,7 @@ int sg_ll_mode_select10(int sg_fd, int pf, int sp, void * paramp,
}
set_scsi_pt_cdb(ptvp, modesCmdBlk, sizeof(modesCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, paramp, param_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "mode select (10)", res, 0, sense_b,
noisy, verbose, &sense_cat);
@@ -1008,7 +1006,7 @@ int sg_mode_page_offset(const unsigned char * resp, int resp_len,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
* SG_LIB_CAT_NOT_READY -> device not ready,
* SG_LIB_CAT_MALFORMED -> bad response, -1 -> other failure.
- * If success_mask pointer is not NULL then zeroes it then sets bit 0, 1,
+ * If success_mask pointer is not NULL then zeros it then sets bit 0, 1,
* 2 and/or 3 if the current, changeable, default and saved values
* respectively have been fetched. If error on current page
* then stops and returns that error; otherwise continues if an error is
@@ -1152,7 +1150,7 @@ int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len,
}
set_scsi_pt_cdb(ptvp, rsCmdBlk, sizeof(rsCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "request sense", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -1190,7 +1188,8 @@ int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len,
/* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> Report Luns not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
- * SG_LIB_CAT_ABORTED_COMMAND, -1 -> other failure */
+ * SG_LIB_CAT_ABORTED_COMMAND,
+ * SG_LIB_NOT_READY (shouldn't happen), -1 -> other failure */
int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
int mx_resp_len, int noisy, int verbose)
{
@@ -1221,7 +1220,7 @@ int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
}
set_scsi_pt_cdb(ptvp, rlCmdBlk, sizeof(rlCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "report luns", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -1232,13 +1231,13 @@ int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
case SG_LIB_CAT_INVALID_OP:
case SG_LIB_CAT_ILLEGAL_REQ:
case SG_LIB_CAT_ABORTED_COMMAND:
+ case SG_LIB_CAT_NOT_READY: /* shouldn't happen ?? */
ret = sense_cat;
break;
case SG_LIB_CAT_RECOVERED:
case SG_LIB_CAT_NO_SENSE:
ret = 0;
break;
- case SG_LIB_CAT_NOT_READY: /* shouldn't happen ?? */
default:
ret = -1;
break;
diff --git a/sg_cmds_basic.h b/sg_cmds_basic.h
index 3439b94e..c6890daf 100644
--- a/sg_cmds_basic.h
+++ b/sg_cmds_basic.h
@@ -2,7 +2,7 @@
#define SG_CMDS_BASIC_H
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,10 @@
*
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Invokes a SCSI INQUIRY command and yields the response
* Returns 0 when successful, SG_LIB_CAT_INVALID_OP -> not supported,
@@ -123,7 +127,7 @@ extern int sg_ll_readcap_16(int sg_fd, int pmi, unsigned long long llba,
/* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> Report Luns not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND,
- * -1 -> other failure */
+ * SG_LIB_NOT_READY (shouldn't happen), -1 -> other failure */
extern int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
int mx_resp_len, int noisy, int verbose);
@@ -217,7 +221,7 @@ extern int sg_mode_page_offset(const unsigned char * resp, int resp_len,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
* SG_LIB_CAT_NOT_READY -> device not ready,
* SG_LIB_CAT_MALFORMED -> bad response, -1 -> other failure.
- * If success_mask pointer is not NULL then zeroes it then sets bit 0, 1,
+ * If success_mask pointer is not NULL then zeros it then sets bit 0, 1,
* 2 and/or 3 if the current, changeable, default and saved values
* respectively have been fetched. If error on current page
* then stops and returns that error; otherwise continues if an error is
@@ -251,4 +255,8 @@ extern int sg_cmds_process_resp(void * ptvp, const char * leadin, int res,
int mx_resp_len, const unsigned char * sense_b,
int noisy, int verbose, int * o_sense_cat);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/sg_cmds_extra.c b/sg_cmds_extra.c
index df16aa09..d8c58192 100644
--- a/sg_cmds_extra.c
+++ b/sg_cmds_extra.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2006 Douglas Gilbert.
+ * Copyright (c) 1999-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,9 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <sys/ioctl.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
@@ -87,6 +88,10 @@
#define ATA_PT_12_CMDLEN 12
#define ATA_PT_16_CMD 0x85
#define ATA_PT_16_CMDLEN 16
+#define READ_BUFFER_CMD 0x3c
+#define READ_BUFFER_CMDLEN 10
+#define WRITE_BUFFER_CMD 0x3b
+#define WRITE_BUFFER_CMDLEN 10
@@ -125,7 +130,7 @@ int sg_ll_report_tgt_prt_grp(int sg_fd, void * resp,
}
set_scsi_pt_cdb(ptvp, rtpgCmdBlk, sizeof(rtpgCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "report Target port group", res,
mx_resp_len, sense_b, noisy, verbose,
@@ -186,7 +191,7 @@ int sg_ll_send_diag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
if ((verbose > 1) && paramp && param_len) {
fprintf(sg_warnings_strm, " Send diagnostic parameter "
"block:\n");
- dStrHex(paramp, param_len, -1);
+ dStrHex((const char *)paramp, param_len, -1);
}
}
@@ -197,7 +202,7 @@ int sg_ll_send_diag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
}
set_scsi_pt_cdb(ptvp, senddiagCmdBlk, sizeof(senddiagCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, paramp, param_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
res = do_scsi_pt(ptvp, sg_fd,
(long_duration ? LONG_PT_TIMEOUT : DEF_PT_TIMEOUT),
verbose);
@@ -265,7 +270,7 @@ int sg_ll_receive_diag(int sg_fd, int pcv, int pg_code, void * resp,
}
set_scsi_pt_cdb(ptvp, rcvdiagCmdBlk, sizeof(rcvdiagCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "receive diagnostic results", res,
mx_resp_len, sense_b, noisy, verbose,
@@ -334,7 +339,7 @@ int sg_ll_read_defect10(int sg_fd, int req_plist, int req_glist,
}
set_scsi_pt_cdb(ptvp, rdefCmdBlk, sizeof(rdefCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "read defect (10)", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -361,7 +366,7 @@ int sg_ll_read_defect10(int sg_fd, int req_plist, int req_glist,
if ((verbose > 2) && (ret > 0)) {
fprintf(sg_warnings_strm, " read defect (10): response%s\n",
(ret > 256 ? ", first 256 bytes" : ""));
- dStrHex(resp, (ret > 256 ? 256 : ret), -1);
+ dStrHex((const char *)resp, (ret > 256 ? 256 : ret), -1);
}
ret = 0;
}
@@ -405,7 +410,7 @@ int sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len,
}
set_scsi_pt_cdb(ptvp, rmsnCmdBlk, sizeof(rmsnCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "read media serial number", res,
mx_resp_len, sense_b, noisy, verbose,
@@ -433,7 +438,7 @@ int sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len,
if ((verbose > 2) && (ret > 0)) {
fprintf(sg_warnings_strm, " read media serial number: respon"
"se%s\n", (ret > 256 ? ", first 256 bytes" : ""));
- dStrHex(resp, (ret > 256 ? 256 : ret), -1);
+ dStrHex((const char *)resp, (ret > 256 ? 256 : ret), -1);
}
ret = 0;
}
@@ -480,7 +485,7 @@ int sg_ll_report_id_info(int sg_fd, int itype, void * resp,
}
set_scsi_pt_cdb(ptvp, riiCmdBlk, sizeof(riiCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, max_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, max_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "report identifying information", res,
max_resp_len, sense_b, noisy, verbose,
@@ -508,7 +513,7 @@ int sg_ll_report_id_info(int sg_fd, int itype, void * resp,
if ((verbose > 2) && (ret > 0)) {
fprintf(sg_warnings_strm, " report identifying information: "
"response%s\n", (ret > 256 ? ", first 256 bytes" : ""));
- dStrHex(resp, (ret > 256 ? 256 : ret), -1);
+ dStrHex((const char *)resp, (ret > 256 ? 256 : ret), -1);
}
ret = 0;
}
@@ -547,7 +552,7 @@ int sg_ll_set_id_info(int sg_fd, int itype, void * paramp,
if ((verbose > 1) && paramp && param_len) {
fprintf(sg_warnings_strm, " Set identifying information "
"parameter block:\n");
- dStrHex(paramp, param_len, -1);
+ dStrHex((const char *)paramp, param_len, -1);
}
}
@@ -559,7 +564,7 @@ int sg_ll_set_id_info(int sg_fd, int itype, void * paramp,
}
set_scsi_pt_cdb(ptvp, siiCmdBlk, sizeof(siiCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, paramp, param_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "set identifying information", res, 0,
sense_b, noisy, verbose, &sense_cat);
@@ -638,7 +643,7 @@ int sg_ll_format_unit(int sg_fd, int fmtpinfo, int rto_req, int longlist,
}
set_scsi_pt_cdb(ptvp, fuCmdBlk, sizeof(fuCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, paramp, param_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
ret = sg_cmds_process_resp(ptvp, "format unit", res, 0, sense_b,
noisy, verbose, &sense_cat);
@@ -703,7 +708,7 @@ int sg_ll_reassign_blocks(int sg_fd, int longlba, int longlist,
}
set_scsi_pt_cdb(ptvp, reassCmdBlk, sizeof(reassCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, paramp, param_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "reassign blocks", res, 0, sense_b,
noisy, verbose, &sense_cat);
@@ -781,7 +786,7 @@ int sg_ll_get_config(int sg_fd, int rt, int starting, void * resp,
}
set_scsi_pt_cdb(ptvp, gcCmdBlk, sizeof(gcCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "get configuration", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -807,7 +812,7 @@ int sg_ll_get_config(int sg_fd, int rt, int starting, void * resp,
if ((verbose > 2) && (ret > 0)) {
fprintf(sg_warnings_strm, " get configuration: response%s\n",
(ret > 256 ? ", first 256 bytes" : ""));
- dStrHex(resp, (ret > 256 ? 256 : ret), -1);
+ dStrHex((const char *)resp, (ret > 256 ? 256 : ret), -1);
}
ret = 0;
}
@@ -850,7 +855,7 @@ int sg_ll_persistent_reserve_in(int sg_fd, int rq_servact, void * resp,
}
set_scsi_pt_cdb(ptvp, prinCmdBlk, sizeof(prinCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "persistent reservation in", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
@@ -876,7 +881,7 @@ int sg_ll_persistent_reserve_in(int sg_fd, int rq_servact, void * resp,
if ((verbose > 2) && (ret > 0)) {
fprintf(sg_warnings_strm, " persistent reserve in: "
"response%s\n", (ret > 256 ? ", first 256 bytes" : ""));
- dStrHex(resp, (ret > 256 ? 256 : ret), -1);
+ dStrHex((const char *)resp, (ret > 256 ? 256 : ret), -1);
}
ret = 0;
}
@@ -913,7 +918,7 @@ int sg_ll_persistent_reserve_out(int sg_fd, int rq_servact, int rq_scope,
fprintf(sg_warnings_strm, "\n");
if (verbose > 1) {
fprintf(sg_warnings_strm, " Persistent Reservation Out parameters:\n");
- dStrHex(paramp, param_len, 0);
+ dStrHex((const char *)paramp, param_len, 0);
}
}
@@ -924,7 +929,7 @@ int sg_ll_persistent_reserve_out(int sg_fd, int rq_servact, int rq_scope,
}
set_scsi_pt_cdb(ptvp, proutCmdBlk, sizeof(proutCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, paramp, param_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "persistent reserve out", res, 0,
sense_b, noisy, verbose, &sense_cat);
@@ -1015,7 +1020,7 @@ int sg_ll_read_long10(int sg_fd, int pblock, int correct, unsigned long lba,
}
set_scsi_pt_cdb(ptvp, readLongCmdBlk, sizeof(readLongCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, xfer_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, xfer_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "read long (10)", res, xfer_len,
sense_b, noisy, verbose, &sense_cat);
@@ -1047,8 +1052,8 @@ int sg_ll_read_long10(int sg_fd, int pblock, int correct, unsigned long lba,
ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
} else {
if (verbose > 1)
- fprintf(sg_warnings_strm, " info field: 0x%llx, "
- " valid: %d, ili: %d\n", ull, valid, ili);
+ fprintf(sg_warnings_strm, " info field: 0x%" PRIx64
+ ", valid: %d, ili: %d\n", ull, valid, ili);
ret = SG_LIB_CAT_ILLEGAL_REQ;
}
}
@@ -1113,7 +1118,7 @@ int sg_ll_read_long16(int sg_fd, int pblock, int correct,
}
set_scsi_pt_cdb(ptvp, readLongCmdBlk, sizeof(readLongCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_in(ptvp, resp, xfer_len);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, xfer_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "read long (16)", res, xfer_len,
sense_b, noisy, verbose, &sense_cat);
@@ -1145,8 +1150,8 @@ int sg_ll_read_long16(int sg_fd, int pblock, int correct,
ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
} else {
if (verbose > 1)
- fprintf(sg_warnings_strm, " info field: 0x%llx, "
- " valid: %d, ili: %d\n", ull, valid, ili);
+ fprintf(sg_warnings_strm, " info field: 0x%" PRIx64
+ ", valid: %d, ili: %d\n", ull, valid, ili);
ret = SG_LIB_CAT_ILLEGAL_REQ;
}
}
@@ -1209,7 +1214,7 @@ int sg_ll_write_long10(int sg_fd, int cor_dis, int wr_uncor, int pblock,
}
set_scsi_pt_cdb(ptvp, writeLongCmdBlk, sizeof(writeLongCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, data_out, xfer_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, xfer_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "write long(10)", res, 0, sense_b,
noisy, verbose, &sense_cat);
@@ -1241,8 +1246,8 @@ int sg_ll_write_long10(int sg_fd, int cor_dis, int wr_uncor, int pblock,
ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
} else {
if (verbose > 1)
- fprintf(sg_warnings_strm, " info field: 0x%llx, "
- " valid: %d, ili: %d\n", ull, valid, ili);
+ fprintf(sg_warnings_strm, " info field: 0x%" PRIx64
+ ", valid: %d, ili: %d\n", ull, valid, ili);
ret = SG_LIB_CAT_ILLEGAL_REQ;
}
}
@@ -1311,7 +1316,7 @@ int sg_ll_write_long16(int sg_fd, int cor_dis, int wr_uncor, int pblock,
}
set_scsi_pt_cdb(ptvp, writeLongCmdBlk, sizeof(writeLongCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
- set_scsi_pt_data_out(ptvp, data_out, xfer_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, xfer_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "write long(16)", res, 0, sense_b,
noisy, verbose, &sense_cat);
@@ -1343,8 +1348,8 @@ int sg_ll_write_long16(int sg_fd, int cor_dis, int wr_uncor, int pblock,
ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
} else {
if (verbose > 1)
- fprintf(sg_warnings_strm, " info field: 0x%llx, "
- " valid: %d, ili: %d\n", ull, valid, ili);
+ fprintf(sg_warnings_strm, " info field: 0x%" PRIx64
+ ", valid: %d, ili: %d\n", ull, valid, ili);
ret = SG_LIB_CAT_ILLEGAL_REQ;
}
}
@@ -1405,7 +1410,7 @@ int sg_ll_verify10(int sg_fd, int dpo, int bytechk, unsigned long lba,
set_scsi_pt_cdb(ptvp, vCmdBlk, sizeof(vCmdBlk));
set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
if (data_out_len > 0)
- set_scsi_pt_data_out(ptvp, data_out, data_out_len);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, data_out_len);
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "verify (10)", res, 0, sense_b,
noisy, verbose, &sense_cat);
@@ -1525,9 +1530,9 @@ int sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
set_scsi_pt_sense(ptvp, sp, slen);
if (dlen > 0) {
if (dinp)
- set_scsi_pt_data_in(ptvp, dinp, dlen);
+ set_scsi_pt_data_in(ptvp, (unsigned char *)dinp, dlen);
else if (doutp)
- set_scsi_pt_data_out(ptvp, doutp, dlen);
+ set_scsi_pt_data_out(ptvp, (unsigned char *)doutp, dlen);
}
res = do_scsi_pt(ptvp, sg_fd,
((timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT),
@@ -1608,3 +1613,150 @@ out:
destruct_scsi_pt_obj(ptvp);
return ret;
}
+
+/* Invokes a SCSI READ BUFFER command (SPC). Return of 0 ->
+ * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
+ * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
+ * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
+ * -1 -> other failure */
+int sg_ll_read_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset,
+ void * resp, int mx_resp_len, int noisy, int verbose)
+{
+ int res, k, ret, sense_cat;
+ unsigned char rbufCmdBlk[READ_BUFFER_CMDLEN] =
+ {READ_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ void * ptvp;
+
+ rbufCmdBlk[1] = (unsigned char)(mode & 0x1f);
+ rbufCmdBlk[2] = (unsigned char)(buffer_id & 0xff);
+ rbufCmdBlk[3] = (unsigned char)((buffer_offset >> 16) & 0xff);
+ rbufCmdBlk[4] = (unsigned char)((buffer_offset >> 8) & 0xff);
+ rbufCmdBlk[5] = (unsigned char)(buffer_offset & 0xff);
+ rbufCmdBlk[6] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rbufCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rbufCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff);
+ if (NULL == sg_warnings_strm)
+ sg_warnings_strm = stderr;
+ if (verbose) {
+ fprintf(sg_warnings_strm, " read buffer cdb: ");
+ for (k = 0; k < READ_BUFFER_CMDLEN; ++k)
+ fprintf(sg_warnings_strm, "%02x ", rbufCmdBlk[k]);
+ fprintf(sg_warnings_strm, "\n");
+ }
+
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ fprintf(sg_warnings_strm, "read buffer: out of memory\n");
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, rbufCmdBlk, sizeof(rbufCmdBlk));
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
+ res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, "read buffer", res, mx_resp_len,
+ sense_b, noisy, verbose, &sense_cat);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_NOT_READY:
+ case SG_LIB_CAT_INVALID_OP:
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ ret = sense_cat;
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ } else {
+ if ((verbose > 2) && (ret > 0)) {
+ fprintf(sg_warnings_strm, " read buffer: response%s\n",
+ (ret > 256 ? ", first 256 bytes" : ""));
+ dStrHex((const char *)resp, (ret > 256 ? 256 : ret), -1);
+ }
+ ret = 0;
+ }
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+/* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 ->
+ * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
+ * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
+ * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
+ * -1 -> other failure */
+int sg_ll_write_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset,
+ void * paramp, int param_len, int noisy, int verbose)
+{
+ int k, res, ret, sense_cat;
+ unsigned char wbufCmdBlk[WRITE_BUFFER_CMDLEN] =
+ {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ void * ptvp;
+
+ wbufCmdBlk[1] = (unsigned char)(mode & 0x1f);
+ wbufCmdBlk[2] = (unsigned char)(buffer_id & 0xff);
+ wbufCmdBlk[3] = (unsigned char)((buffer_offset >> 16) & 0xff);
+ wbufCmdBlk[4] = (unsigned char)((buffer_offset >> 8) & 0xff);
+ wbufCmdBlk[5] = (unsigned char)(buffer_offset & 0xff);
+ wbufCmdBlk[6] = (unsigned char)((param_len >> 16) & 0xff);
+ wbufCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff);
+ wbufCmdBlk[8] = (unsigned char)(param_len & 0xff);
+ if (NULL == sg_warnings_strm)
+ sg_warnings_strm = stderr;
+ if (verbose) {
+ fprintf(sg_warnings_strm, " Write buffer cmd: ");
+ for (k = 0; k < WRITE_BUFFER_CMDLEN; ++k)
+ fprintf(sg_warnings_strm, "%02x ", wbufCmdBlk[k]);
+ fprintf(sg_warnings_strm, "\n");
+ if ((verbose > 1) && paramp && param_len) {
+ fprintf(sg_warnings_strm, " Write buffer parameter block%s:\n",
+ ((param_len > 256) ? " (first 256 bytes)" : ""));
+ dStrHex((const char *)paramp,
+ ((param_len > 256) ? 256 : param_len), -1);
+ }
+ }
+
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ fprintf(sg_warnings_strm, "write buffer: out of memory\n");
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, wbufCmdBlk, sizeof(wbufCmdBlk));
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
+ res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, "write buffer", res, 0, sense_b,
+ noisy, verbose, &sense_cat);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_NOT_READY:
+ case SG_LIB_CAT_INVALID_OP:
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ ret = sense_cat;
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ } else
+ ret = 0;
+
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
diff --git a/sg_cmds_extra.h b/sg_cmds_extra.h
index 52c15788..d4c091de 100644
--- a/sg_cmds_extra.h
+++ b/sg_cmds_extra.h
@@ -30,6 +30,9 @@
*
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
/*
* Additional sense data categories (to those defined in sg_lib.h).
@@ -43,6 +46,29 @@
/* [sk,asc,ascq: 0x3/0x4,*,*] */
+/* Invokes a ATA PASS-THROUGH (12 or 16) SCSI command (SAT). If cdb_len
+ * is 12 then a ATA PASS-THROUGH (12) command is called. If cdb_len is 16
+ * then a ATA PASS-THROUGH (16) command is called. If cdb_len is any other
+ * value -1 is returned. After copying from cdbp to an internal buffer,
+ * the first byte (i.e. offset 0) is set to 0xa1 if cdb_len is 12; or is
+ * set to 0x85 if cdb_len is 16. The last byte (offset 11 or offset 15) is
+ * set to 0x0 in the internal buffer. If timeout_secs <= 0 then the timeout
+ * is set to 60 seconds. For data in or out transfers set dinp or doutp,
+ * and dlen to the number of bytes to transfer. If dlen is zero then no data
+ * transfer is assumed. If sense buffer obtained then it is written to
+ * sensep, else sensep[0] is set to 0x0. If ATA return descriptor is obtained
+ * then written to ata_return_dp, else ata_return_dp[0] is set to 0x0. Either
+ * sensep or ata_return_dp (or both) may be NULL pointers. Returns SCSI
+ * status value (>= 0) or -1 if other error. Users are expected to check the
+ * sense buffer themselves. If available the data in resid is written to
+ * residp.
+ */
+extern int sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
+ int timeout_secs, void * dinp, void * doutp,
+ int dlen, unsigned char * sensep,
+ int max_sense_len, unsigned char * ata_return_dp,
+ int max_ata_return_len, int * residp, int verbose);
+
/* Invokes a FORMAT UNIT (SBC-3) command. Return of 0 -> success,
* SG_LIB_CAT_INVALID_OP -> Format unit not supported,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
@@ -78,6 +104,15 @@ extern int sg_ll_persistent_reserve_out(int sg_fd, int rq_servact,
void * paramp, int param_len,
int noisy, int verbose);
+/* Invokes a SCSI READ BUFFER command (SPC). Return of 0 ->
+ * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
+ * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
+ * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
+ * -1 -> other failure */
+extern int sg_ll_read_buffer(int sg_fd, int mode, int buffer_id,
+ int buffer_offset, void * resp,
+ int mx_resp_len, int noisy, int verbose);
+
/* Invokes a SCSI READ DEFECT DATA (10) command (SBC). Return of 0 ->
* success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
@@ -186,6 +221,15 @@ extern int sg_ll_verify10(int sg_fd, int dpo, int bytechk, unsigned long lba,
int veri_len, void * data_out, int data_out_len,
unsigned long * infop, int noisy, int verbose);
+/* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 ->
+ * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
+ * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
+ * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
+ * -1 -> other failure */
+extern int sg_ll_write_buffer(int sg_fd, int mode, int buffer_id,
+ int buffer_offset, void * paramp,
+ int param_len, int noisy, int verbose);
+
/* Invokes a SCSI WRITE LONG (10) command (SBC). Note that 'xfer_len'
* is in bytes. Returns 0 -> success,
* SG_LIB_CAT_INVALID_OP -> WRITE LONG(10) not supported,
@@ -212,27 +256,8 @@ extern int sg_ll_write_long16(int sg_fd, int cor_dis, int wr_uncor, int pblock,
int xfer_len, int * offsetp, int noisy,
int verbose);
-/* Invokes a ATA PASS-THROUGH (12 or 16) SCSI command (SAT). If cdb_len
- * is 12 then a ATA PASS-THROUGH (12) command is called. If cdb_len is 16
- * then a ATA PASS-THROUGH (16) command is called. If cdb_len is any other
- * value -1 is returned. After copying from cdbp to an internal buffer,
- * the first byte (i.e. offset 0) is set to 0xa1 if cdb_len is 12; or is
- * set to 0x85 if cdb_len is 16. The last byte (offset 11 or offset 15) is
- * set to 0x0 in the internal buffer. If timeout_secs <= 0 then the timeout
- * is set to 60 seconds. For data in or out transfers set dinp or doutp,
- * and dlen to the number of bytes to transfer. If dlen is zero then no data
- * transfer is assumed. If sense buffer obtained then it is written to
- * sensep, else sensep[0] is set to 0x0. If ATA return descriptor is obtained
- * then written to ata_return_dp, else ata_return_dp[0] is set to 0x0. Either
- * sensep or ata_return_dp (or both) may be NULL pointers. Returns SCSI
- * status value (>= 0) or -1 if other error. Users are expected to check the
- * sense buffer themselves. If available the data in resid is written to
- * residp.
- */
-extern int sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
- int timeout_secs, void * dinp, void * doutp,
- int dlen, unsigned char * sensep,
- int max_sense_len, unsigned char * ata_return_dp,
- int max_ata_return_len, int * residp, int verbose);
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/sg_dd.8 b/sg_dd.8
index 8d3e986c..7f8be021 100644
--- a/sg_dd.8
+++ b/sg_dd.8
@@ -1,33 +1,33 @@
-.TH SG_DD "8" "September 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_DD "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_dd \- copies data to and from files and devices. Specialised for
devices that understand the SCSI command set.
.SH SYNOPSIS
.B sg_dd
-[\fIbs=<n>\fR] [\fIcount=<n>\fR] [\fIibs=<n>\fR] [\fIif=<ifile>\fR]
-[\fIiflag=<flags>\fR] [\fIobs=<n>\fR] [\fIof=<ofile>\fR]
-[\fIoflag=<flags>\fR] [\fIseek=<n>\fR] [\fIskip=<n>\fR]
-[\fI--help\fR] [\fI--version\fR]
+[\fIbs=BS\fR] [\fIcount=COUNT\fR] [\fIibs=BS\fR] [\fIif=IFILE\fR]
+[\fIiflag=FLAGS\fR] [\fIobs=BS\fR] [\fIof=OFILE\fR] [\fIoflag=FLAGS\fR]
+[\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR] [\fI\-\-version\fR]
.PP
-[\fIblk_sgio=0|1\fR] [\fIbpt=<n>\fR] [\fIcdbsz=6|10|12|16\fR]
-[\fIcoe=0|1|2|3\fR] [\fIdio=0|1\fR] [\fIodir=0|1\fR] [\fIretries=<n>\fR]
-[\fIsync=0|1\fR] [\fItime=0|1\fR] [\fIverbose=<n>\fR]
+[\fIblk_sgio=\fR0|1] [\fIbpt=BPT\fR] [\fIcdbsz=\fR6|10|12|16]
+[\fIcoe=\fR0|1|2|3] [\fIcoe_limit=CL\fR] [\fIdio=\fR0|1] [\fIodir=\fR0|1]
+[\fIretries=RETR\fR] [\fIsync=\fR0|1] [\fItime=\fR0|1] [\fIverbose=VERB\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Copy data to and from any files. Specialised for "files" that are
-Linux SCSI generic (sg) devices, raw devices or other devices
-that support the SG_IO ioctl (which are only found in the lk 2.6
-series). Similar syntax and semantics to
+Copy data to and from any files. Specialized for "files" that are Linux SCSI
+generic (sg) devices, raw devices or other devices that support the SG_IO
+ioctl (which are only found in the lk 2.6 series). Similar syntax and
+semantics to
.B dd(1)
but does not perform any conversions.
.PP
The first group in the synopsis above are "standard" Unix
.B dd(1)
-arguments. The second group are extra arguments added by this utility.
+operands. The second group are extra options added by this utility.
Both groups are defined below.
+.SH OPTIONS
.TP
-blk_sgio=0 | 1
+\fBblk_sgio\fR=0 | 1
when set to 0, block devices (e.g. /dev/sda) are treated like normal
files (i.e.
.B read(2)
@@ -42,9 +42,9 @@ or output device is a block device partition (e.g. /dev/sda3) then setting
this option causes the partition information to be ignored (since access
is directly to the underlying device). Default is 0. See the 'sgio' flag.
.TP
-bpt=BLOCKS
-each IO transaction will be made using this number of blocks (or less if
-near the end of count). Default is 128 for block sizes less that 2048
+\fBbpt\fR=\fIBPT\fR
+each IO transaction will be made using \fIBPT\fR blocks (or less if near
+the end of the copy). Default is 128 for block sizes less that 2048
bytes, otherwise the default is 32. So for bs=512 the reads and writes
will each convey 64 KiB of data by default (less if near the end of the
transfer or memory restrictions). When cd/dvd drives are accessed, the
@@ -53,108 +53,118 @@ implies 64 KiB transfers. The block layer when the blk_sgio=1 option
is used has relatively low upper limits for transfer sizes (compared
to sg device nodes, see /sys/block/<dev_name>/queue/max_sectors_kb ).
.TP
-bs=BYTES
-this
+\fBbs\fR=\fIBS\fR
+where \fIBS\fR
.B must
be the block size of the physical device (if either the input or output
files are accessed via SCSI commands). Note that this differs from
.B dd(1)
-which permits 'bs' to be an integral multiple. Default is 512 which
+which permits \fIBS\fR to be an integral multiple. Default is 512 which
is usually correct for disks but incorrect for cdroms (which normally
have 2048 byte blocks). For this utility the maximum size of each individual
-IO operation is 'bs * bpt' bytes.
+IO operation is \fIBS\fR * \fIBPT\fR bytes.
.TP
-cdbsz=6 | 10 | 12 | 16
+\fBcdbsz\fR=6 | 10 | 12 | 16
size of SCSI READ and/or WRITE commands issued on sg device
names (or block devices when 'iflag=sgio' and/or 'oflag=sgio' is given).
Default is 10 byte SCSI command blocks (unless calculations indicate
-that a 4 byte block number may be exceeded or 'bpt' is greater than
+that a 4 byte block number may be exceeded or \fIBPT\fR is greater than
16 bits (65535), in which case it defaults to 16 byte SCSI commands).
.TP
-coe=0 | 1 | 2 | 3
+\fBcoe\fR=0 | 1 | 2 | 3
set to 1 or more for continue on error. Only applies to errors on sg
devices or block devices with the 'sgio' flag set. Thus errors on other
files will stop sg_dd. Default is 0 which implies stop on any error. See
the 'coe' flag for more information.
.TP
-count=BLOCKS
-copy this number of blocks from 'if' to 'of'. Default is the
-minimum (of 'if' and 'of') number of blocks that sg devices return from
-READ CAPACITY SCSI commands or that block devices (or their partitions)
-report. Normal files are not probed for their size. If 'skip'
-or 'seek' are given and the count is derived (i.e. not explicitly given)
-then the derived count is scaled back so that the copy will not overrun the
-device. If the file name is a block device partition and count is not given
-then the size of the partition rather than the size of the whole device is
-used. If count is not given and cannot be derived then an error message
-is issued and no copy takes place.
-.TP
-dio=0 | 1
+\fBcoe_limit\fR=\fICL\fR
+where \fICL\fR is the maximum number of consecutive bad blocks stepped
+over (due to "coe>0") on reads before the copy terminates. This only
+applies when \fIIFILE\fR is accessed via the SG_IO ioctl. The default
+is 0 which is interpreted as no limit. This option is meant to stop
+the copy soon after unrecorded media is detected while still
+offering "continue on error" capability.
+.TP
+\fBcount\fR=\fICOUNT\fR
+copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the
+minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices
+report from SCSI READ CAPACITY commands or that block devices (or their
+partitions) report. Normal files are not probed for their size. If
+\fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is derived (i.e.
+not explicitly given) then the derived count is scaled back so that the
+copy will not overrun the device. If the file name is a block device
+partition and \fICOUNT\fR is not given then the size of the partition
+rather than the size of the whole device is used. If \fICOUNT\fR is not
+given and cannot be derived then an error message is issued and no copy
+takes place.
+.TP
+\fBdio\fR=0 | 1
default is 0 which selects indirect (buffered) IO on sg devices. Value of 1
attempts direct IO which, if not available, falls back to indirect IO and
notes this at completion. If direct IO is selected and /proc/scsi/sg/allow_dio
has the value of 0 then a warning is issued (and indirect IO is performed).
.TP
-ibs=BYTES
-if given must be the same as bs
+\fBibs\fR=\fIBS\fR
+if given must be the same as \fIBS\fR given to 'bs=' option.
.TP
-if=FILE
-read from FILE instead of stdin. A file name of - is taken to be stdin.
-Starts reading at the beginning of FILE unless 'skip' is given.
+\fBif\fR=\fIIFILE\fR
+read from \fIIFILE\fR instead of stdin. If \fIIFILE\fR is '\-' then stdin
+is read. Starts reading at the beginning of \fIIFILE\fR unless \fISKIP\fR
+is given.
.TP
-iflag=FLAGS
-where FLAGS is a comma separated list of one or more flags outlined below.
-These flags are associated with <ifile> and are ignored when <ifile> is
-stdin.
+\fBiflag\fR=\fIFLAGS\fR
+where \fIFLAGS\fR is a comma separated list of one or more flags outlined
+below. These flags are associated with \fIIFILE\fR and are ignored when
+\fIIFILE\fR is stdin.
.TP
-obs=BYTES
-if given must be the same as bs
+\fBobs\fR=\fIBS\fR
+if given must be the same as \fIBS\fR given to 'bs=' option.
.TP
-odir=0 | 1
+\fBodir\fR=0 | 1
when set to one opens block devices (e.g. /dev/sda) with the O_DIRECT
-flag.
- User memory buffers are aligned to the page size when set. The
+flag. User memory buffers are aligned to the page size when set. The
default is 0 (i.e. the O_DIRECT flag is not used). Has no effect on sg,
normal or raw files. If blk_sgio is also set then both are honoured:
block devices are opened with the O_DIRECT flag and SCSI commands are
issued via the SG_IO ioctl.
.TP
-of=FILE
-write to FILE instead of stdout. A file name of - is taken to be stdout.
-If FILE is /dev/null then no actual writes are performed. If FILE is .
-(period) then it is treated the same way as /dev/null (this is a
-shorthand notation). If FILE exists then it is _not_ truncated; it is
-overwritten from the start of FILE unless 'oflag=append' or 'seek' is given.
+\fBof\fR=\fIOFILE\fR
+write to \fIOFILE\fR instead of stdout. If \fIOFILE\fR is '\-' then writes
+to stdout. If \fIOFILE\fR is /dev/null then no actual writes are performed.
+If \fIOFILE\fR is '.' (period) then it is treated the same way as
+/dev/null (this is a shorthand notation). If \fIOFILE\fR exists then it
+is _not_ truncated; it is overwritten from the start of \fIOFILE\fR
+unless 'oflag=append' or \fISEEK\fR is given.
.TP
-oflag=FLAGS
-where FLAGS is a comma separated list of one or more flags outlined below.
-These flags are associated with <ofile> and are ignored when <ofile>
-is /dev/null, . (period), or stdout.
+\fBoflag\fR=\fIFLAGS\fR
+where \fIFLAGS\fR is a comma separated list of one or more flags outlined
+below. These flags are associated with \fIOFILE\fR and are ignored when
+\fIOFILE\fR is /dev/null, '.' (period), or stdout.
.TP
-retries=<n>
+\fBretries\fR=\fIRETR\fR
sometimes retries at the host are useful, for example when there is a
-transport error. When <n> is greater than zero then SCSI READs and WRITEs
-are retried on error <n> times. Default value is zero.
+transport error. When \fIRETR\fR is greater than zero then SCSI READs and
+WRITEs are retried on error, \fIRETR\fR times. Default value is zero.
.TP
-seek=BLOCKS
-start writing BLOCKS bs-sized blocks from the start of the output file.
+\fBseek\fR=\fISEEK\fR
+start writing \fISEEK\fR bs\-sized blocks from the start of \fIOFILE\fR.
Default is block 0 (i.e. start of file).
.TP
-skip=BLOCKS
-start reading BLOCKS bs-sized blocks from the start of input file.
+\fBskip\fR=\fISKIP\fR
+start reading \fISKIP\fR bs\-sized blocks from the start of \fIIFILE\fR.
Default is block 0 (i.e. start of file).
.TP
-sync=0 | 1
-when 1, does SYNCHRONIZE CACHE command on 'of' at the end of the transfer.
-Only active when 'of' is a sg device file name or a block device
-and 'blk_sgio=1' is given.
+\fBsync\fR=0 | 1
+when 1, does SYNCHRONIZE CACHE command on \fIOFILE\fR at the end of the
+transfer. Only active when \fIOFILE\fR is a sg device file name or a block
+device and 'blk_sgio=1' is given.
.TP
-time=0 | 1
+\fBtime\fR=0 | 1
when 1, times transfer and does throughput calculation, outputting the
-results (to stderr) at completion. When 0 (default) doesn't perform timing
+results (to stderr) at completion. When 0 (default) doesn't perform timing.
.TP
-verbose=<n>
-as <n> increases so does the amount of debug output sent to stderr.
+\fBverbose\fR=\fIVERB\fR
+as \fIVERB\fR increases so does the amount of debug output sent to stderr.
Default value is zero which yields the minimum amount of debug output.
A value of 1 reports extra information that is not repetitive. A value
2 reports cdbs and responses for SCSI commands that are not repetitive
@@ -164,32 +174,33 @@ Unix read() and write() calls) so there can be a lot of output.
This only occurs for scsi generic (sg) devices and block devices when
the 'blk_sgio=1' option is set.
.TP
---help
-outputs usage message and exits
+\fB\-\-help\fR
+outputs usage message and exits.
.TP
---version
-outputs version number information and exits
+\fB\-\-version\fR
+outputs version number information and exits.
.SH FLAGS
Here is a list of flags and their meanings:
.TP
append
-causes the O_APPEND flag to be added to the open of <ofile>. For normal
+causes the O_APPEND flag to be added to the open of \fIOFILE\fR. For regular
files this will lead to data appended to the end of any existing data.
-Cannot be used together with the 'seek=<n>' option as they conflict.
+Cannot be used together with the \fIseek=SEEK\fR option as they conflict.
The default action of this utility is to overwrite any existing data
-from the beginning of the file or, if 'seek=<n>' is given, starting at
-block <n>.
+from the beginning of the file or, if \fISEEK\fR is given, starting at
+block \fISEEK\fR. Note that attempting to 'append' to a device file (e.g.
+a disk) will usually be ignored or may cause an error to be reported.
.TP
coe
continue on error. Only active for sg devices and block devices that
have the 'sgio' flag set. 'iflag=coe oflag=coe' and 'coe=1' are
equivalent. Use this flag twice (e.g. 'iflag=coe,coe') to have the
same action as the 'coe=2'. A medium, hardware or blank check error
-while reading will re-read blocks prior to the bad block, then try to
-recover the bad block, supplying zeroes if that fails, and finally reread
+while reading will re\-read blocks prior to the bad block, then try to
+recover the bad block, supplying zeros if that fails, and finally reread
the blocks after the bad block. A medium, hardware or blank check error
while writing is noted and ignored. The recovery of the bad block when
-reading uses the READ LONG SCSI command if 'coe' given twice or
+reading uses the SCSI READ LONG command if 'coe' given twice or
more (also with the command line option 'coe=2'). Further, the READ LONG
will set its CORRCT bit if 'coe' given thrice. SCSI disks may automatically
try and remap faulty sectors (see the AWRE and ARRE in the read write
@@ -201,34 +212,35 @@ in the
utility. See note about READ LONG below.
.TP
direct
-causes the O_DIRECT flag to be added to the open of <ifile> and/or <ofile>.
-This flag requires some memory alignment on IO. Hence user memory buffers
-are aligned to the page size. Has no effect on sg, normal or raw files.
-If 'iflag=sgio' and/or 'oflag=sgio' is also set then both are honoured:
-block devices are opened with the O_DIRECT flag and SCSI commands are
-issued via the SG_IO ioctl.
+causes the O_DIRECT flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR. This flag requires some memory alignment on IO. Hence user
+memory buffers are aligned to the page size. Has no effect on sg, normal
+or raw files. If 'iflag=sgio' and/or 'oflag=sgio' is also set then both
+are honoured: block devices are opened with the O_DIRECT flag and SCSI
+commands are issued via the SG_IO ioctl.
.TP
dpo
-set the DPO bit (disable page out) in READ and WRITE SCSI commands. Not
+set the DPO bit (disable page out) in SCSI READ and WRITE commands. Not
supported for 6 byte cdb variants of READ and WRITE. Indicates that
data is unlikely to be required to stay in device (e.g. disk) cache.
May speed media copy and/or cause a media copy to have less impact
on other device users.
.TP
dsync
-causes the O_SYNC flag to be added to the open of <ifile> and/or <ofile>.
-The 'd' is prepended to lower confusion with the 'sync=0|1' option which
-has another action (i.e. a synchronisation to media at the end of the
-transfer).
+causes the O_SYNC flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR. The 'd' is prepended to lower confusion with the 'sync=0|1'
+option which has another action (i.e. a synchronisation to media at the
+end of the transfer).
.TP
excl
-causes the O_EXCL flag to be added to the open of <ifile> and/or <ofile>.
+causes the O_EXCL flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR.
.TP
fua
-causes the FUA (force unit access) bit to be set in READ and/or WRITE
-SCSI commands. This only has an effect with sg devices or block devices
-that have the 'sgio' flag set. The 6 byte variants of the READ and
-WRITE SCSI commands do not support the FUA bit.
+causes the FUA (force unit access) bit to be set in SCSI READ and/or WRITE
+commands. This only has an effect with sg devices or block devices
+that have the 'sgio' flag set. The 6 byte variants of the SCSI READ and
+WRITE commands do not support the FUA bit.
.TP
sgio
causes block devices to be accessed via the SG_IO ioctl rather than
@@ -245,25 +257,37 @@ to overwrite the existing file (if it exists); this is the default.
See the 'append' flag.
.TP
fua=0 | 1 | 2 | 3
-force unit access bit. When 3, fua is set on both 'if' and 'of', when 2, fua
-is set on 'if', when 1, fua is set on 'of', when 0 (default), fua is cleared
-on both. See the 'fua' flag.
+force unit access bit. When 3, fua is set on both \fIIFILE\fR and
+\fIOFILE\fR; when 2, fua is set on \fIIFILE\fR;, when 1, fua is set on
+\fIOFILE\fR; when 0 (default), fua is cleared on both. See the 'fua' flag.
.SH NOTES
-BYTES and BLOCKS may be followed by one of these multiplicative suffixes:
+Block devices (e.g. /dev/sda and /dev/hda) can be given for \fIIFILE\fR.
+If neither '\-iflag=direct', 'iflag=sgio' nor 'blk_sgio=1' is given then
+normal block IO involving buffering and caching is performed. If
+only '\-iflag=direct' is given then the buffering and caching is
+bypassed (this is applicable to both SCSI devices and ATA disks).
+If 'iflag=sgio' or 'blk_sgio=1' is given then the SG_IO ioctl is used on
+the given file causing SCSI commands to be sent to the device and that also
+bypasses most of the actions performed by the block layer (this is only
+applicable to SCSI devices, not ATA disks). The same applies for block
+devices given for \fIOFILE\fR.
+.PP
+\fICOUNT\fR, \fISKIP\fR, \fISEEK\fR, \fIBPT\fR and \fIBS\fR may include one
+of these multiplicative suffixes:
c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
MB *1,000,000 . This pattern continues for "G", "T" and "P". The latter two
-suffixes can only be used for count, skip and seek values). Also a suffix of
-the form "x<n>" multiplies the leading number by <n>. These multiplicative
-suffixes are compatible with GNU's dd command (since 2002) which claims
-compliance with SI and with IEC 60027-2.
+suffixes can only be used for \fICOUNT\fR, \fISKIP\fR and \fISEEK\fR.
+Also a suffix of the form "x<n>" multiplies the leading number by <n>.
+These multiplicative suffixes are compatible with GNU's dd command (since
+2002) which claims compliance with SI and with IEC 60027\-2.
.PP
Alternatively numerical values can be given in hexadecimal preceded by
either "0x" or "0X" (or with a trailing "h" or "H"). When hex numbers are
given, multipliers cannot be used.
.PP
-The count, skip and seek parameters can take 64 bit values (i.e. very
-big numbers). Other values are limited to what can fit in a signed
-32 bit number.
+The \fICOUNT\fR, \fISKIP\fR and \fISEEK\fR arguments can take 64 bit
+values (i.e. very big numbers). Other values are limited to what can fit in
+a signed 32 bit number.
.PP
Data usually gets to the user space in a 2 stage process: first the
SCSI adapter DMAs into kernel buffers and then the sg driver copies
@@ -291,7 +315,21 @@ or sg_map before use.
.PP
Disk partition information can often be found with
.B fdisk(8)
-[the "-ul" argument is useful in this respect].
+[the "\-ul" argument is useful in this respect].
+.PP
+For sg devices (and block devices when blk_sgio=1 is given) this utility
+issues SCSI READ and WRITE (SBC) commands which
+are appropriate for disks and reading from CD/DVD drives. Those commands
+are not formatted correctly for tape devices so sg_dd should not be used on
+tape devices. If the largest block address of the requested transfer
+exceeds a 32 bit block number (i.e 0xffff) then a warning is issued and
+the sg device is accessed via SCSI READ(16) and WRITE(16) commands.
+.PP
+The attributes of a block device (partition) are ignored when 'blk_sgio=1'
+is used. Hence the whole device is read (rather than just the second
+partition) by this invocation:
+.PP
+ sg_dd if=/dev/sdb2 blk_sgio=1 of=t bs=512
.SH EXAMPLES
.PP
Looks quite similar in usage to dd:
@@ -303,10 +341,13 @@ This will copy 1 million 512 byte blocks from the device associated with
Assuming /dev/sda and /dev/sg0 are the same device then the above is
equivalent to:
.PP
- dd if=/dev/sda of=t bs=512 count=1000000
+ dd if=/dev/sda iflag=direct of=t bs=512 count=1000000
.PP
although dd's speed may improve if bs was larger and count was suitably
-reduced. Using a raw device to do something similar on a ATA disk:
+reduced. The use of the 'iflag=direct' option bypasses the buffering and
+caching that is usually done on a block device.
+.PP
+Using a raw device to do something similar on a ATA disk:
.PP
raw /dev/raw/raw1 /dev/hda
.br
@@ -333,20 +374,6 @@ this utility could be used:
On completion this will output a line like:
"time to transfer data was 18.779506 secs, 57.18 MB/sec". The "MB/sec"
in this case is 1,000,000 bytes per second.
-.SH NOTES
-For sg devices (and block devices when blk_sgio=1 is given) this utility
-issues READ and WRITE (SBC) SCSI commands which
-are appropriate for disks and reading from CD/DVD drives. Those commands
-are not formatted correctly for tape devices so sg_dd should not be used on
-tape devices. If the largest block address of the requested transfer
-exceeds a 32 bit block number (i.e 0xffff) then a warning is issued and
-the sg device is accessed via READ_16 and WRITE_16 SCSI commands.
-.PP
-The attributes of a block device (partition) are ignored when 'blk_sgio=1'
-is used. Hence the whole device is read (rather than just the second
-partition) by this invocation:
-.PP
- sg_dd if=/dev/sdb2 blk_sgio=1 of=t bs=512
.SH SIGNALS
The signal handling has been borrowed from dd: SIGINT, SIGQUIT and
SIGPIPE output the number of remaining blocks to be transferred and
@@ -364,7 +391,7 @@ Written by Doug Gilbert and Peter Allworth.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000-2006 Douglas Gilbert
+Copyright \(co 2000\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_dd.c b/sg_dd.c
index 94fe0eaa..2f4b6c44 100644
--- a/sg_dd.c
+++ b/sg_dd.c
@@ -1,5 +1,7 @@
#define _XOPEN_SOURCE 500
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* resolves u_char typedef in scsi/scsi.h [lk 2.4] */
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -21,12 +23,11 @@
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
#include "sg_io_linux.h"
-#include "llseek.h"
/* A utility program for copying files. Specialised for "files" that
* represent devices that understand the SCSI command set.
*
-* Copyright (C) 1999 - 2006 D. Gilbert and P. Allworth
+* Copyright (C) 1999 - 2007 D. Gilbert and P. Allworth
* 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)
@@ -50,7 +51,7 @@
This version is designed for the linux kernel 2.4 and 2.6 series.
*/
-static char * version_str = "5.56 20061012";
+static char * version_str = "5.60 20070124";
#define ME "sg_dd: "
@@ -103,6 +104,7 @@ static char * version_str = "5.56 20061012";
#define MIN_RESERVED_SIZE 8192
#define MAX_UNIT_ATTENTIONS 10
+#define MAX_ABORTED_CMDS 256
static int sum_of_resids = 0;
@@ -123,6 +125,7 @@ static int start_tm_valid = 0;
static struct timeval start_tm;
static int blk_sz = 0;
static int max_uas = MAX_UNIT_ATTENTIONS;
+static int max_aborted = MAX_ABORTED_CMDS;
static int coe_limit = 0;
static int coe_count = 0;
@@ -253,55 +256,65 @@ static char * dd_filetype_str(int ft, char * buff)
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_dd [bs=<n>] [count=<n>] [ibs=<n>] [if=<ifile>]"
- " [iflag=<flags>]\n"
- " [obs=<n>] [of=<ofile>] [oflag=<flags>]"
- "[seek=<n>] [skip=<n>]\n"
+ "sg_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]"
+ " [iflag=FLAGS]\n"
+ " [obs=BS] [of=OFILE] [oflag=FLAGS] "
+ "[seek=SEEK] [skip=SKIP]\n"
" [--help] [--version]\n\n"
- " [append=0|1] [blk_sgio=0|1] [bpt=<n>]"
- " [cdbsz=6|10|12|16]\n"
- " [coe=0|1|2|3] [coe_limit=<n>] [dio=0|1] "
- "[fua=0|1|2|3]\n"
- " [odir=0|1] [sync=0|1] [time=0|1] [verbose=<n>]\n"
- " where:\n"
- " append 1->append output to normal <ofile>, (default is 0)\n"
- " blk_sgio 0->block device use normal I/O(def), 1->use SG_IO\n"
- " bpt is blocks_per_transfer (default is 128 or 32 when bs="
- "2048)\n"
- " bs block size (default is 512)\n");
+ " [blk_sgio=0|1] [bpt=BPT] [cdbsz=6|10|12|16] "
+ "[coe=0|1|2|3]\n"
+ " [coe_limit=CL] [dio=0|1] [odir=0|1] "
+ "[retries=RETR] [sync=0|1]\n"
+ " [time=0|1] [verbose=VERB]\n"
+ " where:\n"
+ " blk_sgio 0->block device use normal I/O(def), 1->use "
+ "SG_IO\n"
+ " bpt is blocks_per_transfer (default is 128 or 32 "
+ "when BS>=2048)\n"
+ " bs block size (default is 512)\n");
fprintf(stderr,
- " cdbsz size of SCSI READ or WRITE command (default is 10)\n"
- " coe 0->exit on error (def), 1->continue on sg error (zero\n"
- " fill), 2->also try read_long on unrecovered reads,\n"
- " 3->and set the CORRCT bit on the read long\n"
- " coe_limit limit when reading of consecutive 'bad' blocks "
- "allowed\n"
- " when 'coe > 0' (default: 0 which is no limit)\n"
- " dio for direct IO, 1->attempt, 0->indirect IO (def)\n"
- " fua force unit access: 0->don't(def), 1->of, 2->if, "
- "3->of+if\n"
- " ibs input block size (if given must be same as 'bs')\n"
- " if file or device to read from (def stdin)\n"
- " iflag comma separated list from: [coe,direct,dpo,dsync,excl,"
- "fua,sgio]\n"
- " obs output block size (if given must be same as 'bs')\n"
- " odir 1->use O_DIRECT when opening block dev, 0->don't(def)\n"
- " of file or device to write to (def stdout), name '.' "
- "translated\n");
+ " cdbsz size of SCSI READ or WRITE cdb (default is "
+ "10)\n"
+ " coe 0->exit on error (def), 1->continue on sg "
+ "error (zero\n"
+ " fill), 2->also try read_long on unrecovered "
+ "reads,\n"
+ " 3->and set the CORRCT bit on the read long\n"
+ " coe_limit limit consecutive 'bad' blocks on reads to CL "
+ "times\n"
+ " when COE>1 (default: 0 which is no limit)\n"
+ " count number of blocks to copy (def: device size)\n"
+ " dio for direct IO, 1->attempt, 0->indirect IO (def)\n"
+ " ibs input block size (if given must be same as "
+ "'bs=')\n"
+ " if file or device to read from (def: stdin)\n"
+ " iflag comma separated list from: [coe,direct,dpo,"
+ "dsync,excl,fua,\n"
+ " sgio]\n"
+ " obs output block size (if given must be same as "
+ "'bs=')\n"
+ " odir 1->use O_DIRECT when opening block dev, "
+ "0->don't(def)\n"
+ " of file or device to write to (def: stdout), "
+ "OFILE of '.'\n");
fprintf(stderr,
- " to /dev/null\n"
- " oflag comma separated list from: [append,coe,direct,dpo,"
- "dsync,excl,\n"
- " fua,sgio]\n"
- " retries number of times to retry sgio errors (def: 0)\n"
- " seek block position to start writing to 'of'\n"
- " skip block position to start reading from 'if'\n"
- " sync 0->no sync(def), 1->SYNCHRONIZE CACHE after "
- "xfer\n"
- " time 0->no timing(def), 1->time plus calculate throughput\n"
- " verbose 0->quiet(def), 1->some noise, 2->more noise, etc\n"
- " --help print out this usage message then exit\n"
- " --version print version information then exit\n");
+ " treated as /dev/null\n"
+ " oflag comma separated list from: [append,coe,direct"
+ ",dpo,dsync,excl,\n"
+ " fua,sgio]\n"
+ " retries retry sgio errors RETR times (def: 0)\n"
+ " seek block position to start writing to OFILE\n"
+ " skip block position to start reading from IFILE\n"
+ " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on "
+ "OFILE after copy\n"
+ " time 0->no timing(def), 1->time plus calculate "
+ "throughput\n"
+ " verbose 0->quiet(def), 1->some noise, 2->more noise, "
+ "etc\n"
+ " --help print out this usage message then exit\n"
+ " --version print version information then exit\n\n"
+ "copy from IFILE to OFILE, similar to dd command; "
+ "specialized for SCSI devices\n");
}
/* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */
@@ -626,14 +639,20 @@ static int sg_read(int sg_fd, unsigned char * buff, int blocks,
fprintf(stderr, "Device (r) not ready\n");
return res;
case SG_LIB_CAT_ABORTED_COMMAND:
+ if (--max_aborted > 0) {
+ fprintf(stderr, "Aborted command, continuing (r)\n");
+ repeat = 1;
+ } else {
+ fprintf(stderr, "Aborted command, too many (r)\n");
+ return res;
+ }
+ break;
case SG_LIB_CAT_UNIT_ATTENTION:
if (--max_uas > 0) {
- fprintf(stderr, "Unit attention or aborted command, "
- "continuing (r)\n");
+ fprintf(stderr, "Unit attention, continuing (r)\n");
repeat = 1;
} else {
- fprintf(stderr, "Unit attention or aborted command, "
- "too many (r)\n");
+ fprintf(stderr, "Unit attention, too many (r)\n");
return res;
}
break;
@@ -739,7 +758,7 @@ static int sg_read(int sg_fd, unsigned char * buff, int blocks,
unsigned char * buffp;
int offset, nl, r, ok, corrct;
- buffp = malloc(bs * 2);
+ buffp = (unsigned char*)malloc(bs * 2);
if (NULL == buffp) {
fprintf(stderr, ">> heap problems\n");
return -1;
@@ -915,8 +934,7 @@ static int sg_write(int sg_fd, unsigned char * buff, int blocks,
fprintf(stderr, ">> ignored errors for out blk=%lld for "
"%d bytes\n", to_block, bs * blocks);
return 0; /* fudge success */
- }
- else
+ } else
return res;
}
if (diop && *diop &&
@@ -929,8 +947,10 @@ static void calc_duration_throughput(int contin)
{
struct timeval end_tm, res_tm;
double a, b;
+ long long blks;
if (start_tm_valid && (start_tm.tv_sec || start_tm.tv_usec)) {
+ blks = (in_full > out_full) ? in_full : out_full;
gettimeofday(&end_tm, NULL);
res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
@@ -940,7 +960,7 @@ static void calc_duration_throughput(int contin)
}
a = res_tm.tv_sec;
a += (0.000001 * res_tm.tv_usec);
- b = (double)blk_sz * (req_count - dd_count);
+ b = (double)blk_sz * blks;
fprintf(stderr, "time to transfer data%s: %d.%06d secs",
(contin ? " so far" : ""), (int)res_tm.tv_sec,
(int)res_tm.tv_usec);
@@ -1032,7 +1052,7 @@ int main(int argc, char * argv[])
oflag.cdbsz = DEF_SCSI_CDBSZ;
if (argc < 2) {
fprintf(stderr,
- "Can't have both 'if' as stdin _and_ 'of' as stdout\n");
+ "Won't default both IFILE to stdin _and_ OFILE to stdout\n");
fprintf(stderr, "For more information use '--help'\n");
return SG_LIB_SYNTAX_ERROR;
}
@@ -1041,8 +1061,7 @@ int main(int argc, char * argv[])
if (argv[k]) {
strncpy(str, argv[k], STR_SZ);
str[STR_SZ - 1] = '\0';
- }
- else
+ } else
continue;
for (key = str, buf = key; *buf && *buf != '=';)
buf++;
@@ -1057,14 +1076,14 @@ int main(int argc, char * argv[])
} else if (0 == strcmp(key, "bpt")) {
bpt = sg_get_num(buf);
if (-1 == bpt) {
- fprintf(stderr, ME "bad argument to 'bpt'\n");
+ fprintf(stderr, ME "bad argument to 'bpt='\n");
return SG_LIB_SYNTAX_ERROR;
}
bpt_given = 1;
} else if (0 == strcmp(key, "bs")) {
blk_sz = sg_get_num(buf);
if (-1 == blk_sz) {
- fprintf(stderr, ME "bad argument to 'bs'\n");
+ fprintf(stderr, ME "bad argument to 'bs='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key, "cdbsz")) {
@@ -1077,13 +1096,13 @@ int main(int argc, char * argv[])
} else if (0 == strcmp(key, "coe_limit")) {
coe_limit = sg_get_num(buf);
if (-1 == coe_limit) {
- fprintf(stderr, ME "bad argument to 'coe_limit'\n");
+ fprintf(stderr, ME "bad argument to 'coe_limit='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key, "count")) {
dd_count = sg_get_llnum(buf);
if (-1LL == dd_count) {
- fprintf(stderr, ME "bad argument to 'count'\n");
+ fprintf(stderr, ME "bad argument to 'count='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key, "dio"))
@@ -1096,13 +1115,13 @@ int main(int argc, char * argv[])
ibs = sg_get_num(buf);
else if (strcmp(key, "if") == 0) {
if ('\0' != inf[0]) {
- fprintf(stderr, "Second 'if=' argument??\n");
+ fprintf(stderr, "Second IFILE argument??\n");
return SG_LIB_SYNTAX_ERROR;
} else
strncpy(inf, buf, INOUTF_SZ);
} else if (0 == strcmp(key, "iflag")) {
if (process_flags(buf, &iflag)) {
- fprintf(stderr, ME "bad argument to 'iflag'\n");
+ fprintf(stderr, ME "bad argument to 'iflag='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key, "obs"))
@@ -1112,32 +1131,32 @@ int main(int argc, char * argv[])
oflag.direct = iflag.direct;
} else if (strcmp(key, "of") == 0) {
if ('\0' != outf[0]) {
- fprintf(stderr, "Second 'of=' argument??\n");
+ fprintf(stderr, "Second OFILE argument??\n");
return SG_LIB_SYNTAX_ERROR;
} else
strncpy(outf, buf, INOUTF_SZ);
} else if (0 == strcmp(key, "oflag")) {
if (process_flags(buf, &oflag)) {
- fprintf(stderr, ME "bad argument to 'oflag'\n");
+ fprintf(stderr, ME "bad argument to 'oflag='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key, "retries")) {
iflag.retries = sg_get_num(buf);
oflag.retries = iflag.retries;
if (-1 == iflag.retries) {
- fprintf(stderr, ME "bad argument to 'retries'\n");
+ fprintf(stderr, ME "bad argument to 'retries='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key, "seek")) {
seek = sg_get_llnum(buf);
if (-1LL == seek) {
- fprintf(stderr, ME "bad argument to 'seek'\n");
+ fprintf(stderr, ME "bad argument to 'seek='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key, "skip")) {
skip = sg_get_llnum(buf);
if (-1LL == skip) {
- fprintf(stderr, ME "bad argument to 'skip'\n");
+ fprintf(stderr, ME "bad argument to 'skip='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key, "sync"))
@@ -1258,8 +1277,7 @@ int main(int argc, char * argv[])
return SG_LIB_FILE_ERROR;
}
}
- }
- else {
+ } else {
flags = O_RDONLY;
if (iflag.direct)
flags |= O_DIRECT;
@@ -1273,24 +1291,24 @@ int main(int argc, char * argv[])
ME "could not open %s for reading", inf);
perror(ebuff);
return SG_LIB_FILE_ERROR;
- }
- else {
+ } else {
if (verbose)
fprintf(stderr, " open input, flags=0x%x\n",
flags);
if (skip > 0) {
- llse_loff_t offset = skip;
+ off64_t offset = skip;
offset *= blk_sz; /* could exceed 32 bits here! */
- if (llse_llseek(infd, offset, SEEK_SET) < 0) {
+ if (lseek64(infd, offset, SEEK_SET) < 0) {
snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to "
"required position on %s", inf);
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
if (verbose)
- fprintf(stderr, " >> skip: llseek SEEK_SET, "
- "byte offset=0x%llx\n", offset);
+ fprintf(stderr, " >> skip: lseek64 SEEK_SET, "
+ "byte offset=0x%llx\n",
+ (unsigned long long)offset);
}
}
}
@@ -1308,8 +1326,7 @@ int main(int argc, char * argv[])
if (FT_ST & out_type) {
fprintf(stderr, ME "unable to use scsi tape device %s\n", outf);
return SG_LIB_FILE_ERROR;
- }
- else if (FT_SG & out_type) {
+ } else if (FT_SG & out_type) {
flags = O_RDWR | O_NONBLOCK;
if (oflag.direct)
flags |= O_DIRECT;
@@ -1345,8 +1362,7 @@ int main(int argc, char * argv[])
return SG_LIB_FILE_ERROR;
}
}
- }
- else if (FT_DEV_NULL & out_type)
+ } else if (FT_DEV_NULL & out_type)
outfd = -1; /* don't bother opening */
else {
if (! (FT_RAW & out_type)) {
@@ -1365,8 +1381,7 @@ int main(int argc, char * argv[])
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
- }
- else {
+ } else {
flags = O_WRONLY;
if (oflag.direct)
flags |= O_DIRECT;
@@ -1384,18 +1399,19 @@ int main(int argc, char * argv[])
if (verbose)
fprintf(stderr, " open output, flags=0x%x\n", flags);
if (seek > 0) {
- llse_loff_t offset = seek;
+ off64_t offset = seek;
offset *= blk_sz; /* could exceed 32 bits here! */
- if (llse_llseek(outfd, offset, SEEK_SET) < 0) {
+ if (lseek64(outfd, offset, SEEK_SET) < 0) {
snprintf(ebuff, EBUFF_SZ,
ME "couldn't seek to required position on %s", outf);
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
if (verbose)
- fprintf(stderr, " >> seek: llseek SEEK_SET, "
- "byte offset=0x%llx\n", offset);
+ fprintf(stderr, " >> seek: lseek64 SEEK_SET, "
+ "byte offset=0x%llx\n",
+ (unsigned long long)offset);
}
}
}
@@ -1496,8 +1512,7 @@ int main(int argc, char * argv[])
in_num_sect;
else
dd_count = in_num_sect;
- }
- else
+ } else
dd_count = out_num_sect;
}
}
@@ -1524,16 +1539,15 @@ int main(int argc, char * argv[])
if (dio || iflag.direct || oflag.direct || (FT_RAW & in_type) ||
(FT_RAW & out_type)) {
size_t psz = getpagesize();
- wrkBuff = malloc(blk_sz * bpt + psz);
+ wrkBuff = (unsigned char*)malloc(blk_sz * bpt + psz);
if (0 == wrkBuff) {
fprintf(stderr, "Not enough user memory for raw\n");
return SG_LIB_CAT_OTHER;
}
wrkPos = (unsigned char *)(((unsigned long)wrkBuff + psz - 1) &
(~(psz - 1)));
- }
- else {
- wrkBuff = malloc(blk_sz * bpt);
+ } else {
+ wrkBuff = (unsigned char*)malloc(blk_sz * bpt);
if (0 == wrkBuff) {
fprintf(stderr, "Not enough user memory\n");
return SG_LIB_CAT_OTHER;
@@ -1593,8 +1607,7 @@ int main(int argc, char * argv[])
if (dio && (0 == dio_tmp))
dio_incomplete++;
}
- }
- else {
+ } else {
while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) &&
(EINTR == errno))
;
@@ -1606,8 +1619,7 @@ int main(int argc, char * argv[])
perror(ebuff);
ret = -1;
break;
- }
- else if (res < blocks * blk_sz) {
+ } else if (res < blocks * blk_sz) {
dd_count = 0;
blocks = res / blk_sz;
if ((res % blk_sz) > 0) {
@@ -1656,7 +1668,7 @@ int main(int argc, char * argv[])
break;
}
} else if ((SG_LIB_CAT_ABORTED_COMMAND == ret) && first) {
- if (--max_uas > 0)
+ if (--max_aborted > 0)
fprintf(stderr, "Aborted command, continuing (w)\n");
else {
fprintf(stderr, "Aborted command, too many (w)\n");
@@ -1679,8 +1691,7 @@ int main(int argc, char * argv[])
fprintf(stderr, "sg_write failed,%s seek=%lld\n",
((-2 == ret) ? " try reducing bpt," : ""), seek);
break;
- }
- else {
+ } else {
out_full += blocks;
if (dio && (0 == dio_tmp))
dio_incomplete++;
@@ -1699,8 +1710,7 @@ int main(int argc, char * argv[])
perror(ebuff);
ret = -1;
break;
- }
- else if (res < blocks * blk_sz) {
+ } else if (res < blocks * blk_sz) {
fprintf(stderr, "output file probably full, seek=%lld ", seek);
blocks = res / blk_sz;
out_full += blocks;
@@ -1708,8 +1718,7 @@ int main(int argc, char * argv[])
out_partial++;
ret = -1;
break;
- }
- else
+ } else
out_full += blocks;
}
if (dd_count > 0)
diff --git a/sg_emc_trespass.8 b/sg_emc_trespass.8
index 065bab94..6a46fe9f 100644
--- a/sg_emc_trespass.8
+++ b/sg_emc_trespass.8
@@ -1,46 +1,48 @@
-.TH SG_EMC_TRESPASS "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_EMC_TRESPASS "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_emc_trespass \- Changes ownership of a LUN from another
-Service-Processor to this one.
+Service\-Processor to this one.
.SH SYNOPSIS
.B sg_emc_trespass
-[\fI-d\fR] [\fI-hr\fR] [\fI-s\fR]
-[\fI-V\fR] \fI<sg_device>\fR
+[\fI\-d\fR] [\fI\-hr\fR] [\fI\-s\fR]
+[\fI\-V\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-sg_emc_trespass sends an EMC-specific Trespass Command to the given
-device with the selected options. This Mode Select changes the ownership
-of the LUN of the device from another Service-Processor to the one the
-command was received on.
+sg_emc_trespass sends an EMC-specific Trespass Command to the \fIDEVICE\fR
+with the selected options. This Mode Select changes the ownership of the LUN
+of the device from another Service-Processor to the one the command was
+received on.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
--d
+\fB\-d\fR
outputs some extra debug information associated with executing this command
.TP
--hr
+\fB\-hr\fR
Sets the 'Honor Reservation' bit in the command. If set, the trespass
will only succeed to change the ownership from the Peer SP if the Peer
SP does not have an outstanding SCSI reservation for the LUN. By
default, the reservation state will be ignored.
.TP
--s
+\fB\-s\fR
Send the short version of the trespass command instead of the long
version. The short version is supported on the EMC FC5300, FC4500 and
FC4700. The long version (default) is supported on the CLARiiON CX and
AX family arrays.
.TP
--V
+\fB\-V\fR
print out version string then exit.
.PP
-In the 2.4 series of Linux kernels the given device must be
-a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example "sg_start 0 /dev/sda"
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI
+generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks
+and DVD drives) can also be specified. For example "sg_start 0 /dev/sda"
will work in the 2.6 series kernels.
.SH EXIT STATUS
The exit status of sg_emc_trespass is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
.SH AUTHOR
-Written by Lars Marowsky-Bree, based on sg_start.
+Written by Lars Marowsky\-Bree, based on sg_start.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
diff --git a/sg_emc_trespass.c b/sg_emc_trespass.c
index 19cdb5f6..b3535c50 100644
--- a/sg_emc_trespass.c
+++ b/sg_emc_trespass.c
@@ -25,7 +25,7 @@
* any later version.
*/
-static char * version_str = "0.14 20060907";
+static char * version_str = "0.15 20070102";
static int debug = 0;
@@ -93,7 +93,7 @@ static int do_trespass(int fd, int hr, int short_cmd)
void usage ()
{
fprintf(stderr, "Usage: sg_emc_trespass [-d] [-hr] [-s] "
- " [-V] <device>\n"
+ " [-V] DEVICE\n"
" Change ownership of a LUN from another SP to this one.\n"
" EMC CLARiiON CX-/AX-family + FC5300/FC4500/FC4700.\n"
" -d : output debug\n"
@@ -101,7 +101,7 @@ void usage ()
" -s : Send Short Trespass Command page (default: long)\n"
" (for FC series)\n"
" -V: print version string then exit\n"
- " <device> sg or block device (latter in lk 2.6.*)\n"
+ " DEVICE sg or block device (latter in lk 2.6.*)\n"
" Example: sg_emc_trespass /dev/sda\n");
exit (1);
}
diff --git a/sg_format.8 b/sg_format.8
index 238454d8..e25d60be 100644
--- a/sg_format.8
+++ b/sg_format.8
@@ -1,12 +1,13 @@
-.TH SG_FORMAT "8" "September 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_FORMAT "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_format \- format or resize a SCSI disk (perhaps change its block size)
.SH SYNOPSIS
.B sg_format
-[\fI--cmplst=<n>\fR] [\fI--count=<n>\fR] [\fI--early\fR] [\fI--format\fR]
-[\fI--help\fR] [\fI--long\fR] [\fI--pfu=<n>\fR] [\fI--pinfo\fR]
-[\fI--resize\fR] [\fI--rto_req\fR] [\fI--six\fR] [\fI--size=<n>\fR]
-[\fI--verbose\fR] [\fI--version\fR] [\fI--wait\fR] \fI<scsi_device>\fR
+[\fI\-\-cmplst=\fR0|1] [\fI\-\-count=COUNT\fR] [\fI\-\-early\fR]
+[\fI\-\-format\fR] [\fI\-\-help\fR] [\fI\-\-long\fR] [\fI\-\-pfu=PFU\fR]
+[\fI\-\-pinfo\fR] [\fI\-\-resize\fR] [\fI\-\-rto_req\fR] [\fI\-\-six\fR]
+[\fI\-\-size=SIZE\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+[\fI\-\-wait\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -24,7 +25,7 @@ blocks on the media also known as "resizing"). Resizing a disk to less
than the manufacturer's recommended block count is sometimes called "short
stroking" (see NOTES section). Resizing the block count while not changing
the block size may not require a format operation. Recent changes to the
-SBC-2 draft standard (see www.t10.org) have obsoleted the "format device"
+SBC\-2 draft standard (see www.t10.org) have obsoleted the "format device"
mode page. Many of the low level details found in that mode page are now
left up to the discretion of the manufacturer.
.PP
@@ -35,8 +36,8 @@ to a MODE SENSE command and the response to a READ CAPACITY command.
The reason for this double check is to detect a "format corrupt"
state (see NOTES section).
.PP
-A recent addition in the SBC-2 is "protection information". See
-the section of that name (section 4.16 in draft SBC-2 rev 16). It adds
+A recent addition in the SBC\-2 is "protection information". See
+the section of that name (section 4.16 in draft SBC\-2 rev 16). It adds
an extra 8 bytes of protection information to each block (a 2 byte "logical
block guard" (CRC), a 2 byte "logical block application guard", and a
4 byte "logical block reference tag"). A device that supports
@@ -44,79 +45,81 @@ protection information sets the "protect" bit in a standard INQUIRY
response. The "FMTPINFO" and "RTO_REQ" bits in the FORMAT command cdb
are associated with protection information and can be set by this
utility.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---cmplst=<n> | -C <n>
-the value <n> sets the CMPLST ("complete list") bit in the FORMAT cdb.
-The value can be 0 or 1 . The default is 1 in which case the existing
-GLIST (grown list) is ignored. If the value is 0 then th existing
-GLIST is taken into account. See the LISTS section below. Active when
-the '--format' option is given. In most cases this bit should be
-left set; some MO disk drives need this bit cleared. The SCSI to ATA
-Translation (SAT) draft standard (sat-r09) requires this bit to be
-cleared.
+\fB\-C\fR, \fB\-\-cmplst\fR=0 | 1
+sets the CMPLST ("complete list") bit in the FORMAT cdb to 0 or 1.
+The default is 1 in which case the existing GLIST (grown list) is ignored.
+If the value is 0 then th existing GLIST is taken into account. See the
+LISTS section below. Active when the \fI\-\-format\fR option is given. In
+most cases this bit should be left set; some MO disk drives need this bit
+cleared. The SCSI to ATA Translation (SAT) draft standard (sat\-r09)
+requires this bit to be cleared.
.TP
---count=<n> | -c <n>
-count of blocks to be formatted or media to be resized to. Can be
-used with either "--format" or "--resize". With "--format" this
-option need not be given in which case it is assumed to be zero.
-With "--format" the interpretation of <n> is:
+\fB\-c\fR, \fB\-\-count\fR=\fICOUNT\fR
+where \fICOUNT\fR is the number of blocks to be formatted or media to be
+resized to. Can be used with either \fI\-\-format\fR or \fI\-\-resize\fR.
+With \fI\-\-format\fR this option need not be given in which case it is
+assumed to be zero. With \fI\-\-format\fR the interpretation of \fICOUNT\fR
+is:
.br
- (n > 0) : only format the first <n> blocks and READ
+ (\fICOUNT\fR > 0) : only format the first \fICOUNT\fR blocks and READ
.br
- CAPACITY will report <n> blocks after format
+ CAPACITY will report \fICOUNT\fR blocks after format
.br
- (n = 0) and block size unchanged : use existing block count
+ (\fICOUNT\fR = 0) and block size unchanged : use existing block count
.br
- (n = 0) and block size changed : recommended maximum block
+ (\fICOUNT\fR = 0) and block size changed : recommended maximum block
.br
- count for new block size
+ count for new block size
.br
- (n = -1) : use recommended maximum block count
+ (\fICOUNT\fR = \-1) : use recommended maximum block count
.br
- (n < -1) : illegal
+ (\fICOUNT\fR < \-1) : illegal
.br
-With "--resize" this option must be given and <n> has this
+With \fI\-\-resize\fR this option must be given and \fICOUNT\fR has this
interpretation:
.br
- (n > 0) : after resize READ CAPACITY will report <n>
+ (\fICOUNT\fR > 0) : after resize READ CAPACITY will report \fICOUNT\fR
.br
- blocks
+ blocks
.br
- (n = 0) : after resize READ CAPACITY will report 0 blocks
+ (\fICOUNT\fR = 0) : after resize READ CAPACITY will report 0 blocks
.br
- (n = -1) : after resize READ CAPACITY will report its
+ (\fICOUNT\fR = \-1) : after resize READ CAPACITY will report its
.br
- maximum number of blocks
+ maximum number of blocks
.br
- (n < -1) : illegal
+ (\fICOUNT\fR < \-1) : illegal
.br
-In both cases if the given <n> exceeds the maximum number of
+In both cases if the given \fICOUNT\fR exceeds the maximum number of
blocks (for the block size) then the disk reports an error.
See NOTES section below.
.TP
---early | -e
-this option is active when "--format" is given. The default action of this
-utility is to poll the disk every 30 seconds to determine the progress of
-the format operation until it is finished. When this option is given this
+\fB\-e\fR, \fB\-\-early\fR
+this option is active when \fI\-\-format\fR is given. The default action of
+this utility is to poll the disk every 30 seconds to determine the progress
+of the format operation until it is finished. When this option is given this
utility will exit "early" as soon as the format has commenced. Then the
user can monitor the progress of the ongoing format operation with other
-utilities (e.g. sg_turs or sg_requests). This option and "--wait" cannot
-both be given.
+utilities (e.g. sg_turs or sg_requests). This option and \fI\-\-wait\fR
+cannot both be given.
.TP
---format | -F
+\fB\-F\fR, \fB\-\-format\fR
issue a SCSI FORMAT command.
.B This will destroy all the data held on the media.
This option is required to change the block size of a disk.
The user is given a 10 second count down to ponder the wisdom
-of doing this, during which time control-C (amongst other
+of doing this, during which time control\-C (amongst other
Unix commands) can be used to kill this process before it
does any damage. See NOTES section for implementation details and
EXAMPLES section for typical use.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
print out the usage information then exit.
.TP
---long | -l
+\fB\-l\fR, \fB\-\-long\fR
the default action of this utility is to assume 32 bit logical block
addresses. With 512 byte block size this permits almost 2
terabytes (almost 2 ** 41 bytes) on a single disk. This option selects
@@ -125,78 +128,79 @@ Specifically this is the "longlba" flag in the MODE SENSE (10) command
and READ CAPACITY (16) rather than READ CAPACITY (10). When a disk
supports "protection information" then this option may also be useful.
.TP
---pfu=<n> | -P <n>
+\fB\-P\fR, \fB\-\-pfu\fR=\fIPFU\fR
sets the "Protection Field Usage" field in the parameter block associated
-with a FORMAT command to <n>. The default value is 0, values in the range
-0 to 7 may be given.
+with a FORMAT command to \fIPFU\fR. The default value is 0, values in the
+range 0 to 7 may be given.
.TP
---pinfo | -p
-instructs a '--format' to add an extra 8 bytes of protection information
-by setting the FMTPINFO bit in the FORMAT command cdb. Default action is
-not to format with protection information. Has no action
-unless '--format' is given.
+\fB\-p\fR, \fB\-\-pinfo\fR
+instructs a format operation to add an extra 8 bytes of protection
+information by setting the FMTPINFO bit in the FORMAT command cdb. Default
+action is not to format with protection information. Has no action
+unless \fI\-\-format\fR is given.
.TP
---resize | -r
+\fB\-r\fR, \fB\-\-resize\fR
rather than format the disk, it can be resized. This means changing the
number of blocks on the device reported by the READ CAPACITY command.
-This option should be used with the '--count=<new_blk_count>' option.
+This option should be used with the \fI\-\-count=COUNT\fR option.
The contents of all logical blocks on the media remain unchanged when
this option is used. This means that any resize operation can be
-reversed. This option cannot be used together with either "--format"
-or a "--size" whose argument is different to the existing block size.
+reversed. This option cannot be used together with either \fI\-\-format\fR
+or a \fI\-\-size=SIZE\fR whose argument is different to the existing block
+size.
.TP
---rto_req | -R
+\fB\-R\fR, \fB\-\-rto_req\fR
instructs a format to enable application client ownership of
the "logical block reference tag" field (i.e. the RTO_REQ bit in the
FORMAT cdb). The default action is to disable application client
-ownership of that field. Has no action unless both '--format'
-and '--pinfo' are given.
+ownership of that field. Has no action unless both \fI\-\-format\fR
+and \fI\-\-pinfo\fR are given.
.TP
---six | -6
+\fB\-6\fR, \fB\-\-six\fR
Use 6 byte variants of MODE SENSE and MODE SELECT. The default action
is to use the 10 byte variants. Some MO drives need this option set
when doing a format.
.TP
---size=<n> | -s <n>
-block size (i.e. number of bytes in each block) to format the device to.
-The default value is whatever is currently reported by the block descriptor
-in a MODE SENSE command. This option is only active when the "--format"
-option is also given. If the block size given by this option is different
-from the current value then a MODE SELECT command is used to change it
-prior to the FORMAT command being started (as recommended in the draft
-standard). Recent SCSI disks usually have 512 byte sectors by default
-and allow up to 16 bytes extra in a sector (i.e. 528 byte sectors).
-If the given size in unacceptable to the disk, most likely an "Invalid
-field in parameter list" message will appear in sense data (requires the
-use of '-v' to decode sense data).
+\fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR
+where \fISIZE\fR is the block size (i.e. number of bytes in each block) to
+format the device to. The default value is whatever is currently reported
+by the block descriptor in a MODE SENSE command. This option is only active
+when the \fI\-\-format\fR option is also given. If the block size given by
+this option is different from the current value then a MODE SELECT command
+is used to change it prior to the FORMAT command being started (as
+recommended in the draft standard). Recent SCSI disks usually have 512 byte
+sectors by default and allow up to 16 bytes extra in a sector (i.e. 528 byte
+sectors). If the given size in unacceptable to the disk, most likely
+an "Invalid field in parameter list" message will appear in sense
+data (requires the use of '\-v' to decode sense data).
.TP
---verbose | -v
-increase the level of verbosity, (i.e. debug output). "-vvv" gives
+\fB\-v\fR, \fB\-\-verbose\fR
+increase the level of verbosity, (i.e. debug output). "\-vvv" gives
the maximum debug output.
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
.TP
---wait | -w
-this option only has an effect when used together with the "--format"
+\fB\-w\fR, \fB\-\-wait\fR
+this option only has an effect when used together with the \fI\-\-format\fR
option. The default format action is to set the "IMMED" bit in the FORMAT
-UNIT command's (short) parameter header. If this option (i.e. "--wait") is
-given then the "IMMED" bit is not set. Then the FORMAT UNIT command waits
+UNIT command's (short) parameter header. If this option (i.e. \fI\-\-wait\fR)
+is given then the "IMMED" bit is not set. Then the FORMAT UNIT command waits
until the format operation completes before returning its response. This
can be several hours on large disks. This utility sets a four hour timeout
on such a FORMAT UNIT command.
.SH LISTS
-The SBC-3 draft (revision 6) defines PLIST, CLIST, DLIST and GLIST in
+The SBC\-3 draft (revision 6) defines PLIST, CLIST, DLIST and GLIST in
section 4.8 on "Medium defects". Briefly, the PLIST is the "primary"
list of manufacturer detected defects, the CLIST ("certification" list)
are those detected during the format operation, the DLIST is a list
of defects that can be given to the format operation. The GLIST
is the grown list which starts in the format process as CLIST+DLIST
and can "grow" later due to automatic reallocation (see the
-ARRE and AWRE bits in the read-write error recovery mode page (see
-sdparm)) and use of the REASSIGN SCSI command (see sg_reassign).
+ARRE and AWRE bits in the read\-write error recovery mode page (see
+sdparm)) and use of the SCSI REASSIGN BLOCKS command (see sg_reassign).
.PP
-The CMPLST bit (controlled by the '--cmplst=0|1' option) determines
+The CMPLST bit (controlled by the \fI\-\-cmplst=\fR0|1 option) determines
whether the existing GLIST, when the format operation is invoked,
is taken into account. The sg_format utility sets the FOV bit to zero
which causes the DPRY=0, so the PLIST is taken into account, and
@@ -206,7 +210,7 @@ The sg_format utility does not permit a user to provide a defect
list (i.e. DLIST). All protection information options are
defaulted to off.
.SH NOTES
-The SBC-2 draft standard (revision 16) says that the REQUEST SENSE command
+The SBC\-2 draft standard (revision 16) says that the REQUEST SENSE command
should be used for obtaining a progress indication when the format
command returns prior to the completion of the format operation.
However, tests on a selection of recent disks shows that TEST UNIT READY
@@ -214,26 +218,26 @@ commands yield progress indications (but not REQUEST SENSE commands). A
new option may be required to handle this when disks catch up to the current
draft.
.PP
-When the "--format" option is given then there is a 10 second window
-during which the user is invited to abort sg_format. This is just prior
-the FORMAT UNIT SCSI command being issued. If the "--wait" option is not
-given then the FORMAT UNIT SCSI command is issued with the IMMED bit set
+When the \fI\-\-format\fR option is given then there is a 10 second window
+during which the user is invited to abort sg_format. This is just prior the
+SCSI FORMAT UNIT command being issued. If the \fI\-\-wait\fR option is not
+given then the SCSI FORMAT UNIT command is issued with the IMMED bit set
which causes the SCSI command to return after it has started the format
-operation. The "--early" option will cause sg_format to exit at that
-point. Otherwise the given device is polled every 30 seconds with
+operation. The \fI\-\-early\fR option will cause sg_format to exit at that
+point. Otherwise the \fIDEVICE\fR is polled every 30 seconds with
TEST UNIT READY commands until it reports an "all clear" (i.e. the
format operation has completed). Normally these polling commands will
result in a progress indicator (expressed as a percentage) being output
to the screen. If the user gets bored watching the progress report then
-sg_format process can be terminated (e.g. with control-C) without
+sg_format process can be terminated (e.g. with control\-C) without
affecting the format operation which continues. However a bus or device
reset (or a power cycle) may well cause the device to become "format
corrupt".
.PP
-When the "--format" and "--wait" options are both given then this utility
-may take a long time to return. In this case care should be taken not to
-send any other SCSI commands to the disk as it may not respond leaving
-those commands queued behind the active format command. This may
+When the \fI\-\-format\fR and \fI\-\-wait\fR options are both given then
+this utility may take a long time to return. In this case care should be
+taken not to send any other SCSI commands to the disk as it may not respon
+leaving those commands queued behind the active format command. This may
cause a timeout in the OS driver (in a lot shorter period than 4 hours
applicable to the format command). This may result in the OS resetting
the disk leaving the format operation incomplete. This may leave the
@@ -252,15 +256,15 @@ potentially requiring a format. The solution to this situation is to
do a format again (and this time the new block size does not have to
be given) or change the block size back to the original size.
.PP
-The draft SBC-2 standard states that the block count can be set back
+The draft SBC\-2 standard states that the block count can be set back
to the manufacturer's maximum recommended value in a format or resize
operation. This can be done by placing an address of 0xffffffff (or the
64 bit equivalent) in the appropriate block descriptor field to a MODE
SELECT command. In signed (two's complement) arithmetic that value
-corresponds to '-1'. So a "--count" argument of '-1' causes the block count
+corresponds to '\-1'. So a \fI\-\-count=\fR-1 causes the block count
to be set back to the manufacturer's maximum recommended value. To see
exactly which SCSI commands are being executed and parameters passed
-add "-vvv" to the sg_format command line.
+add "\-vvv" to the sg_format command line.
.PP
Short stroking is a technique to trade off capacity for performance.
Disk performance is usually highest on the outer tracks (i.e. lower
@@ -277,7 +281,7 @@ scsiformat is another utility available for formatting SCSI disks
with linux. It dates from 1997 (most recent update) and may be useful for
disks whose firmware is of that vintage.
.PP
-The argument to "--count" is a number which may be followed by one of
+The \fICOUNT\fR value is a number which may be followed by one of
these multiplicative suffixes: c C *1; w W *2; b B *512; k K KiB *1,024;
KB *1,000; m M MiB *1,048,576; MB *1,000,000 . This pattern continues
for "G", "T" and "P". Also a suffix of the form "x<n>" multiplies the
@@ -296,33 +300,33 @@ were previously. The FORMAT command is executed in IMMED mode
and the device is polled every 30 seconds to print out a progress
indication:
.PP
- sg_format --format /dev/sdm
+ sg_format \-\-format /dev/sdm
.PP
Now the same format, but waiting (passively) until the format
operation is complete:
.PP
- sg_format --format --wait /dev/sdm
+ sg_format \-\-format \-\-wait /dev/sdm
.PP
Next is a format in which the block size is changed to 520 bytes
and the block count is set to the manufacturer's maximum
value (for that block size). Note, not all disks support changing
the block size:
.PP
- sg_format --format --size=520 /dev/sdm
+ sg_format \-\-format \-\-size=520 /dev/sdm
.PP
Now a resize operation so that only the first 0x10000 (65536)
blocks on a disk are accessible. The remaining blocks remain
unaltered.
.PP
- sg_format --resize --count=0x10000 /dev/sdm
+ sg_format \-\-resize \-\-count=0x10000 /dev/sdm
.PP
Now resize the disk back to its normal (maximum) block count:
.PP
- sg_format --resize --count=-1 /dev/sdm
+ sg_format \-\-resize \-\-count=\-1 /dev/sdm
.PP
.SH EXIT STATUS
The exit status of sg_format is 0 when it is successful. Otherwise see
-the sg3_utils(8) man page. Unless the '--wait' option is given, the
+the sg3_utils(8) man page. Unless the \fI\-\-wait\fR option is given, the
exit status may not reflect to success of otherwise of the format.
Using sg_turs and sg_readcap after the format operation may be wise.
.SH AUTHORS
@@ -330,7 +334,7 @@ Written by Grant Grundler, James Bottomley and Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2005-2006 Grant Grundler, James Bottomley and Douglas Gilbert
+Copyright \(co 2005\-2007 Grant Grundler, James Bottomley and Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_format.c b/sg_format.c
index a605aacb..6f89229f 100644
--- a/sg_format.c
+++ b/sg_format.c
@@ -6,7 +6,7 @@
**
** Copyright (C) 2003 Grant Grundler grundler at parisc-linux dot org
** Copyright (C) 2003 James Bottomley jejb at parisc-linux dot org
-** Copyright (C) 2005-2006 Douglas Gilbert dgilbert at interlog dot com
+** Copyright (C) 2005-2007 Douglas Gilbert dgilbert at interlog dot com
**
** 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
@@ -35,6 +35,8 @@
#include <string.h>
#include <getopt.h>
#include <unistd.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -51,12 +53,23 @@
#define FORMAT_TIMEOUT (4 * 3600) /* 4 hours ! */
#define POLL_DURATION_SECS 30
+
+#if defined(MSC_VER) || defined(__MINGW32__)
+#define HAVE_MS_SLEEP
+#endif
+
+#ifdef HAVE_MS_SLEEP
+#include <windows.h>
+#define sleep_for(seconds) Sleep( (seconds) * 1000)
+#else
+#define sleep_for(seconds) sleep(seconds)
+#endif
#define MAX_BUFF_SZ 252
static unsigned char dbuff[MAX_BUFF_SZ];
-static char * version_str = "1.11 20061012";
+static char * version_str = "1.13 20070125";
static struct option long_options[] = {
{"count", 1, 0, 'c'},
@@ -138,7 +151,7 @@ scsi_format(int fd, int fmtpinfo, int rto_req, int cmplst, int pf_usage,
verb = (verbose > 1) ? (verbose - 1) : 0;
for(;;) {
- sleep(POLL_DURATION_SECS);
+ sleep_for(POLL_DURATION_SECS);
progress = -1;
res = sg_ll_test_unit_ready_progress(fd, 0, &progress, 0,
verb);
@@ -178,7 +191,7 @@ print_read_cap(int fd, int do_16, int verbose)
printf(" Protection: prot_en=%d, rto_en=%d\n",
!!(resp_buff[12] & 0x1),
!!(resp_buff[12] & 0x2));
- printf(" Number of blocks=%llu\n",
+ printf(" Number of blocks=%" PRIu64 "\n",
llast_blk_addr + 1);
printf(" Block size=%u bytes\n", block_size);
return (int)block_size;
@@ -219,52 +232,54 @@ print_read_cap(int fd, int do_16, int verbose)
static void usage()
{
- printf("usage: sg_format [--cmplst=<n>] [--count=<block count>] "
- "[--early] [--format]\n"
- " [--help] [--long] [--pfu=<n>] [--pinfo] "
- "[--resize]\n"
- " [--rto_req] [--six] [--size=<block size>] "
- "[--verbose]\n"
- " [--version] [--wait] <scsi_disk>\n"
+ printf("usage: sg_format [--cmplst=0|1] [--count=COUNT] [--early] "
+ "[--format] [--help]\n"
+ " [--long] [--pfu=PFU] [--pinfo] [--resize] "
+ "[--rto_req] [--six]\n"
+ " [--size=SIZE] [--verbose] [--version] "
+ "[--wait] DEVICE\n"
" where:\n"
- " --cmplst=<n> | -C <n> for CMPLST bit in format cdb "
+ " --cmplst=0|1\n"
+ " -C 0|1 sets CMPLST bit in format cdb "
"(default: 1)\n"
- " --count=<block count> | -c <block count>\n"
- " best left alone during format (defaults "
- "to max allowable)\n"
- " --early | -e exit once format started (user can "
+ " --count=COUNT|-c COUNT number of blocks to "
+ "report after format or\n"
+ " resize. With format "
+ "defaults to same as current\n"
+ " --early|-e exit once format started (user can "
"monitor progress)\n"
- " --format | -F format unit (default report current count"
+ " --format|-F format unit (default: report current count"
" and size)\n"
- " --help | -h prints out this usage message\n"
- " --long | -l allow for 64 bit lbas (default: assume "
+ " --help|-h prints out this usage message\n"
+ " --long|-l allow for 64 bit lbas (default: assume "
"32 bit lbas)\n"
- " --pfu=<n> | -P <n> Protection Field Usage value "
+ " --pfu=PFU|-P PFU Protection Field Usage value "
"(default: 0)\n"
- " --pinfo | -p set the FMTPINFO bit to format with "
+ " --pinfo|-p set the FMTPINFO bit to format with "
"protection\n");
- printf( " information (defaults to no protection "
+ printf( " information (defaults to no protection "
"information)\n"
- " --resize | -r resize (rather than format) to '--count' "
+ " --resize|-r resize (rather than format) to COUNT "
"value\n"
- " --rto_req | -R set the RTO_REQ bit in format (only valid "
- "with '--pinfo')\n"
- " --six | -6 use 6 byte MODE SENSE/SELECT\n"
- " --size=<block size> | -s <block size>\n"
- " only needed to change block size"
- " (default to\n"
- " current device's block size)\n"
- " --verbose | -v verbosity (show commands + parameters "
- "sent)\n"
- " use multiple time for more verbosity\n"
- " --version | -V print version details and exit\n"
- " --wait | -w format command waits till complete (def: "
- "poll)\n\n"
+ " --rto_req|-R set the RTO_REQ bit in format (only "
+ "vaid with '--pinfo')\n"
+ " --six|-6 use 6 byte MODE SENSE/SELECT\n"
+ " --size=SIZE|-s SIZE bytes per block, defaults to "
+ "DEVICE's current\n"
+ " block size. Only needed to "
+ "change current block\n"
+ " size\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version details and exit\n"
+ " --wait|-w format command waits until format "
+ "operation completes\n"
+ " (default: set IMMED=1 and poll with "
+ "Test Unit Ready)\n\n"
"\tExample: sg_format --format /dev/sdc\n\n"
"This utility formats or resizes SCSI disks.\n");
- printf("WARNING: This utility will destroy all the data on the "
- "target device when\n\t '--format' is given. Check that you "
- "have the correct device.\n");
+ printf("WARNING: This utility will destroy all the data on "
+ "DEVICE when\n\t '--format' is given. Check that you "
+ "have the correct DEVICE.\n");
}
@@ -549,7 +564,8 @@ int main(int argc, char **argv)
prob = 1;
} else if (bd_len != 8)
prob = 1;
- printf(" Number of blocks=%llu [0x%llx]\n", ull, ull);
+ printf(" Number of blocks=%" PRIu64 " [0x%" PRIx64 "]\n",
+ ull, ull);
printf(" Block size=%d [0x%x]\n", bd_blk_len, bd_blk_len);
} else {
printf(" No block descriptors present\n");
@@ -680,11 +696,11 @@ int main(int argc, char **argv)
printf("\nA FORMAT will commence in 10 seconds\n");
printf(" ALL data on %s will be DESTROYED\n", device_name);
printf(" Press control-C to abort\n");
- sleep(5);
+ sleep_for(5);
printf("A FORMAT will commence in 5 seconds\n");
printf(" ALL data on %s will be DESTROYED\n", device_name);
printf(" Press control-C to abort\n");
- sleep(5);
+ sleep_for(5);
res = scsi_format(fd, pinfo, rto_req, cmplst, pfu, ! fwait,
early, verbose);
ret = res;
diff --git a/sg_get_config.8 b/sg_get_config.8
index 986534b7..6bff500c 100644
--- a/sg_get_config.8
+++ b/sg_get_config.8
@@ -1,101 +1,104 @@
-.TH SG_GET_CONFIG "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_GET_CONFIG "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_get_config \- invoke SCSI GET CONFIGURATION command on a (cd/dvd) device
+sg_get_config \- sends a SCSI GET CONFIGURATION command
.SH SYNOPSIS
.B sg_get_config
-[\fI--brief\fR] [\fI--current\fR] [\fI--help\fR] [\fI--hex\fR]
-[\fI--inner-hex\fR] [\fI--list\fR] [\fI--rt=<n>\fR] [\fI--starting=<n>\fR]
-[\fI--verbose\fR] [\fI--version\fR] \fI<device>\fR
+[\fI\-\-brief\fR] [\fI\-\-current\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR]
+[\fI\-\-inner\-hex\fR] [\fI\-\-list\fR] [\fI\-\-rt=RT\fR]
+[\fI\-\-starting=FC\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Sends a SCSI GET CONFIGURATION command to the given device and
-decodes the response. The response includes the features and profiles
-of the device. Typically these devices are CD and DVD players that
-may (but not necessarily) have media in them. These devices may well
-be connected via ATAPI, USB or IEEE 1394 transports. In such
-cases they are "SCSI" devices only in the sense that they use
-the "Multi-Media command" set (MMC). MMC is a specialized SCSI
-command set whose definition can be found at http://www.t10.org .
+Sends a SCSI GET CONFIGURATION command to \fIDEVICE\fR and decodes the
+response. The response includes the features and profiles of the device.
+Typically these devices are CD and DVD players that may (but not
+necessarily) have media in them. These devices may well be connected via
+ATAPI, USB or IEEE 1394 transports. In such cases they are "SCSI" devices
+only in the sense that they use the "Multi\-Media command" set (MMC).
+MMC is a specialized SCSI command set whose definition can be found
+at http://www.t10.org .
.PP
-This utility is based on the MMC-4 and MMC-5 draft standards. See
+This utility is based on the MMC\-4 and MMC\-5 draft standards. See
section 5 on "Features and Profile for Multi_Media devices" for more
information on specific feature parameters and profiles. The manufacturer's
product manual may also be useful.
.PP
Since modern DVD writers support many features and profiles, the decoded
output from this utility can be large. There are various ways to cut down
-the output. If the '--brief' option is used only the feature names are shown
-and the feature parameters are not decoded. Alternatively if only one
-feature is of interest then this combination of options is
-appropriate: "--rt=2 --starting=<feature_code>". Another possibility is to
-show only the features that are relevant to the media in the
-drive (i.e. "current") with the "--rt=1" option.
+the output. If the \fI\-\-brief\fR option is used only the feature names
+are shown and the feature parameters are not decoded. Alternatively if only
+one feature is of interest then this combination of options is
+appropriate: "\-\-rt=2 \-\-starting=\fIFC\fR". Another possibility is to show
+only the features that are relevant to the media in the drive (i.e. "current")
+with the "\-\-rt=1" option.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---brief | -b
+\fB\-b\fR, \fB\-\-brief\fR
show the feature names but don't decode the parameters of those features.
-When used with '--list' outputs known feature names but not known profile
-names.
+When used with \fI\-\-list\fR outputs known feature names but not known
+profile names.
.TP
---current | -c
-output features marked as current. This option is equivalent to '--rt=1'.
+\fB\-c\fR, \fB\-\-current\fR
+output features marked as current. This option is equivalent to '\-\-rt=1'.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---hex | -H
+\fB\-H\fR, \fB\-\-hex\fR
output the response in hex (don't decode response).
.TP
---inner-hex | -i
+\fB\-i\fR, \fB\-\-inner\-hex\fR
decode to the feature name level then output each feature's data in hex.
.TP
---list | -l
+\fB\-l\fR, \fB\-\-list\fR
list all known feature and profile names. Ignore the device name (if given).
Simply lists the feature names and profiles (followed by their hex values)
-that this utility knows about. If '--brief' is also given then only feature
-names are listed.
+that this utility knows about. If \fI\-\-brief\fR is also given then only
+feature names are listed.
.TP
---rt=<n> | -r <n>
-RT value given to GET CONFIGURATION command. Allowable values are 0,
-1, 2, or 3 . The command's action also depends on the value given
-to '--starting='. The default value is 0.
-When <n> is 0 then all features, regardless of currency, are returned (whose
-feature code is greater than or equal to the value given to '--starting=').
-When <n> is 1 then all current features are returned (whose
-feature code is greater than or equal to the value given to '--starting=').
-When <n> is 2 then the feature whose feature code is equal to the value
-given to '--starting=', if any, is returned.
-When <n> is 3 the response is reserved (probably yields an "illegal
-field in cdb" error).
+\fB\-r\fR, \fB\-\-rt\fR=\fIRT\fR
+where \fIRT\fR is the field of that name in the GET CONFIGURATION cdb.
+Allowable values are 0, 1, 2, or 3 . The command's action also depends on
+the value given to the \fI\-\-starting=FC\fR option. The default value is 0.
+When \fIRT\fR is 0 then all features, regardless of currency, are
+returned (whose feature code is greater than or equal to \fIFC\fR given
+to \fI\-\-starting=\fR). When \fIRT\fR is 1 then all current features are
+returned (whose feature code is greater than or equal to \fIFC\fR). When
+\fIRT\fR is 2 then the feature whose feature code is equal to \fIFC\fR,
+if any, is returned. When \fIRT\fR is 3 the response is reserved (probably
+yields an "illegal field in cdb" error).
.TP
---starting=<n> | -s <n>
-this option works closely with the --rt option. Its value is a feature
-code in the range 0 to 0xffff (inclusive). Its default value is 0. A value
-prefixed with "0x" is interpreted as hexadecimal.
+\fB\-s\fR, \fB\-\-starting\fR=\fIFC\fR
+where \fIFC\fR is the feature code value. This option works closely with
+the \fI\-\-rt=RT\fR option. The \fIFC\fR value is in the range 0 to
+65535 (0xffff) inclusive. Its default value is 0. A value prefixed
+with "0x" (or a trailing 'h') is interpreted as hexadecimal.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
+.SH NOTES
There are multiple versions of the MMC (draft) standards: MMC [1997],
-MMC-2 [2000], MMC-3 [2002], MMC-4 and MMC-5. The first three are now
+MMC\-2 [2000], MMC\-3 [2002], MMC\-4 and MMC\-5. The first three are now
ANSI INCITS standards with the year they became standards shown in
brackets. The draft immediately prior to standardization can
be found at http://www.t10.org . In the initial MMC standard there
was no GET CONFIGURATION command and the relevant information was
obtained from the "CD capabilities and mechanical status mode
page" (mode page 0x2a). It was later renamed the "MM capabilities and
-mechanical status mode page" and has been made obsolete in MMC-4 and
-MMC-5. The GET CONFIGURATION command was introduced in MMC-2 and has
+mechanical status mode page" and has been made obsolete in MMC\-4 and
+MMC\-5. The GET CONFIGURATION command was introduced in MMC\-2 and has
become a replacement for that mode page. New features such as support
for "BD" (blue ray) media type can only be found by using the
GET CONFIGURATION command. Hence older CD players may not support
the GET CONFIGURATION command in which case the "MM capabilities ..."
mode page can be checked with sdpar, sginfo or sg_modes.
.PP
-In the 2.4 series of Linux kernels the given device must be
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be
a SCSI generic (sg) device. In the 2.6 series block devices
can also be specified. For example "sg_get_config /dev/hdc"
will work in the 2.6 series kernels as long as /dev/hdc is
@@ -109,10 +112,10 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B sginfo, sg_modes, sg_inq, sg_prevent, sg_start (all in sg3_utils)
+.B sginfo, sg_modes, sg_inq, sg_prevent, sg_start (all in sg3_utils),
.B sdparm
diff --git a/sg_get_config.c b/sg_get_config.c
index c3f38687..17fec041 100644
--- a/sg_get_config.c
+++ b/sg_get_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@
*/
-static char * version_str = "0.28 20061015";
+static char * version_str = "0.30 20070125";
#define MX_ALLOC_LEN 8192
#define NAME_BUFF_SZ 64
@@ -73,31 +73,32 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr,
- "Usage: 'sg_get_config [--brief] [--current] [--help] [--hex] "
+ "Usage: sg_get_config [--brief] [--current] [--help] [--hex] "
"[--inner-hex]\n"
- " [--list] [--rt=<num>] [--starting=<num>] "
+ " [--list] [--rt=RT] [--starting=FC] "
"[--verbose]\n"
- " [--version] <device>'\n"
- " where --brief | -b only give feature names of <device> "
+ " [--version] DEVICE\n"
+ " where\n"
+ " --brief|-b only give feature names of DEVICE "
"(don't decode)\n"
- " --current | -c equivalent to '--rt=1' (show "
+ " --current|-c equivalent to '--rt=1' (show "
"current)\n"
- " --help | -h output usage message\n"
- " --hex | -H output response in hex\n"
- " --inner-hex | -i decode to feature name, then output "
+ " --help|-h print usage message then exit\n"
+ " --hex|-H output response in hex\n"
+ " --inner-hex|-i decode to feature name, then output "
"features in hex\n"
- " --list | -l list all known features + profiles "
- "(ignore <device>)\n"
- " --rt=<num> | -r <num> default value is 0\n"
- " 0 -> all feature descriptors (regardless "
+ " --list|-l list all known features + profiles "
+ "(ignore DEVICE)\n"
+ " --rt=RT|-r RT default value is 0\n"
+ " 0 -> all feature descriptors (regardless "
"of currency)\n"
- " 1 -> all current feature descriptors\n"
- " 2 -> only feature descriptor matching "
+ " 1 -> all current feature descriptors\n"
+ " 2 -> only feature descriptor matching "
"'starting'\n"
- " --starting=<num> | -s <num> starting from feature "
- "<num>\n"
- " --verbose | -v verbose\n"
- " --version | -V output version string\n\n"
+ " --starting=FC|-s FC starting from feature "
+ "code (FC) value\n"
+ " --verbose|-v verbose\n"
+ " --version|-V output version string\n\n"
"Get configuration information for MMC drive and/or media\n");
}
@@ -240,8 +241,8 @@ static void decode_feature(int feature, unsigned char * ucp, int len)
printf(" version=%d, persist=%d, current=%d [0x%x]\n",
((ucp[2] >> 2) & 0xf), !!(ucp[2] & 2), !!(ucp[2] & 1),
feature);
- printf(" available profiles [ordered from most to least "
- "advanced]:\n");
+ printf(" available profiles [more recent typically higher "
+ "in list]:\n");
for (k = 4; k < len; k += 4) {
profile = (ucp[k] << 8) + ucp[k + 1];
printf(" profile: %s , currentP=%d\n",
diff --git a/sg_ident.8 b/sg_ident.8
index 3cff9acc..7bae4eec 100644
--- a/sg_ident.8
+++ b/sg_ident.8
@@ -1,86 +1,86 @@
-.TH SG_IDENT "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_IDENT "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_ident \- report or set identifying information
+sg_ident \- sends a SCSI REPORT or SET IDENTIFYING INFORMATION command
.SH SYNOPSIS
.B sg_ident
-[\fI--ascii\fR] [\fI--clear\fR] [\fI--help\fR] [\fI--itype=<n>\fR]
-[\fI--raw\fR] [\fI--set\fR] [\fI--verbose\fR] [\fI--version\fR]
-\fI<scsi_device>\fR
+[\fI\-\-ascii\fR] [\fI\-\-clear\fR] [\fI\-\-help\fR] [\fI\-\-itype=IT\fR]
+[\fI\-\-raw\fR] [\fI\-\-set\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send a REPORT IDENTIFYING INFORMATION or SET IDENTIFYING INFORMATION
-SCSI command to the given device. Prior to SPC-4 (revison 7) these
+Send a SCSI REPORT IDENTIFYING INFORMATION or SET IDENTIFYING INFORMATION
+command to \fIDEVICE\fR. Prior to SPC\-4 (revison 7) these
commands were called REPORT DEVICE IDENTIFIER and SET DEVICE IDENTIFIER
respectively. SCSI devices that support these two commands allow users
to write (set) identifying information and report it back at some
later time. The information is persistent (i.e. stored on some
-non-volatile medium within the SCSI device that will survive a power
+non\-volatile medium within the SCSI device that will survive a power
outage).
.PP
Typically the space allocated for the information is limited:
-SPC-4 (revision 7) states that for information type 0, the minimum
+SPC\-4 (revision 7) states that for information type 0, the minimum
length is 64 bytes and the maximum is 512 bytes. For other information
types (1 to 126 inclusive) the maximum length is 256 bytes. Also
information types 1 to 126 (inclusive) should contain a null
-terminated UTF-8 string. The author has seen older disks that only
+terminated UTF\-8 string. The author has seen older disks that only
support 16 bytes.
.PP
The default action when no options are given is to invoke the
Report Identifying Information command with the information type defaulting
to zero. Error reports are sent to stderr. By default the information is
-shown in ASCII-HEX (up to 16 bytes per line) with an ASCII representation
+shown in ASCII\-HEX (up to 16 bytes per line) with an ASCII representation
to the right with dots replacing non printable characters.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---ascii | -A
+\fB\-A\fR, \fB\-\-ascii\fR
invokes the Report Identifying Information command and if anything is
-found interprets it as ASCII (or UTF-8 depending on the locale)
+found interprets it as ASCII (or UTF\-8 depending on the locale)
and prints the information to stdout.
.TP
---clear | -C
+\fB\-C\fR, \fB\-\-clear\fR
invokes the Set Identifying Information command with an information length
of zero. This has the effect of clearing the existing information.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---itype=<n> | -i <n>
-sets the information type. Defaults to zero. The maximum value is
-127 which is special and cannot be used with '--set' or '--clear'.
-The information type of 127 (if supported) causes the REPORT IDENTIFYING
-INFORMATION command to respond with a list of available information
-types and their maximum lengths in bytes. The odd numbered information
-types between 3 and 125 (inclusive) are not to be used (as they clash
-with the SCC-2 standard).
+\fB\-i\fR, \fB\-\-itype\fR=\fIIT\fR
+where \fIIT\fR is the information type. Defaults to zero. The maximum value
+is 127 which is special and cannot be used with \fI\-\-set\fR or
+\fI\-\-clear\fR. The information type of 127 (if supported) causes the REPORT
+IDENTIFYING INFORMATION command to respond with a list of available
+information types and their maximum lengths in bytes. The odd numbered
+information types between 3 and 125 (inclusive) are not to be used (as they
+clash with the SCC\-2 standard).
.TP
---raw | -r
+\fB\-r\fR, \fB\-\-raw\fR
invokes the Report Identifying information command and if anything
is found sends the information (which may be binary) to stdout. Nothing else
is sent to stdout however error reports, if any, are sent to stderr.
.TP
---set | -S
-first read stdin until an EOF is detected then invokes the Set Identifying
+\fB\-S\fR, \fB\-\-set\fR
+first reads stdin until an EOF is detected then invokes the Set Identifying
Information command to set what has been fetched from stdin as the
information. The amount of data read must be between 1 and 512 bytes
length (inclusive).
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
.PP
-This utility facilitates users writing their own information to
+This utility permits users to write their own identifying information to
their SCSI devices. There are several other types of descriptors (or
-designators) that the user cannot change. These include the SCSI
-INQUIRY command with its standard vendor and product identification
-strings and the product revision level; plus the large amount of
-information provided by the "Device Identification" VPD page (see
-sg_vpd).
-There is also the READ MEDIA SERIAL NUMBER command (see sg_rmsn).
-The MMC-4 command set for CDs and DVDs has a "media serial number"
-feature (0x109) [and a "logical unit serial number" feature]. These
-can be viewed with sg_get_config.
+designators) that the user cannot change. These include the SCSI INQUIRY
+command with its standard vendor and product identification strings and the
+product revision level; plus the large amount of information provided by
+the "Device Identification" VPD page (see sg_vpd). There is also the READ
+MEDIA SERIAL NUMBER command (see sg_rmsn). The MMC\-4 command set for CD
+and DVDs has a "media serial number" feature (0x109) [and a "logical unit
+serial number" feature]. These can be viewed with the sg_get_config utility.
.SH EXAMPLES
First, to see if there is an existing information whose format
is unknown (for information type 0), use no options:
@@ -91,18 +91,18 @@ is unknown (for information type 0), use no options:
.PP
If it is ASCII then it can printed as such:
.PP
- # sg_ident --ascii /dev/sdb
+ # sg_ident \-\-ascii /dev/sdb
.br
1234567890
.PP
The information can be copied to a file, cleared and then
-re-asserted with this sequence:
+re\-asserted with this sequence:
.PP
- # sg_ident --raw /dev/sdb > t
+ # sg_ident \-\-raw /dev/sdb > t
.br
- # sg_ident --clear /dev/sdb
+ # sg_ident \-\-clear /dev/sdb
.br
- # cat t | sg_ident --set /dev/sdb
+ # cat t | sg_ident \-\-set /dev/sdb
.SH EXIT STATUS
The exit status of sg_ident is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
@@ -111,7 +111,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2005-2006 Douglas Gilbert
+Copyright \(co 2005\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_ident.c b/sg_ident.c
index 2c1cf31b..57cf307a 100644
--- a/sg_ident.c
+++ b/sg_ident.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2006 Douglas Gilbert.
+ * Copyright (c) 2005-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@
* DEVICE IDENTIFIER and SET DEVICE IDENTIFIER prior to spc4r07.
*/
-static char * version_str = "1.04 20061013";
+static char * version_str = "1.06 20070127";
#define ME "sg_ident: "
@@ -94,25 +94,23 @@ static void decode_ii(const unsigned char * iip, int ii_len, int itype,
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_ident [--ascii] [--clear] [--help] [--itype] [--raw] "
+ "sg_ident [--ascii] [--clear] [--help] [--itype=IT] [--raw] "
"[--set]\n"
- " [--verbose] [--version] <scsi_device>\n"
- " where: --ascii|-A report identifying information as ASCII "
- "(or UTF8)\n"
- " string\n"
- " --clear|-C clear (set to zero length) identifying "
+ " [--verbose] [--version] DEVICE\n"
+ " where:\n"
+ " --ascii|-A report identifying information as ASCII "
+ "(or UTF8) string\n"
+ " --clear|-C clear (set to zero length) identifying "
"information\n"
- " --help|-h print out usage message\n"
- " --itype=<n>|-i <n> specify information type\n"
- " --raw|-r output identifying information to "
- "stdout or\n"
- " fetch from stdin (when '--set')\n"
- " --set|-S invoke set identifying information with "
- "data from\n"
- " stdin\n"
- " --verbose|-v increase verbosity of output\n"
- " --version|-V print version string and exit\n\n"
- "Performs a REPORT or SET IDENTIFYING INFORMATION SCSI command\n"
+ " --help|-h print out usage message\n"
+ " --itype=IT|-i IT specify information type\n"
+ " --raw|-r output identifying information to "
+ "stdout\n"
+ " --set|-S invoke set identifying information with "
+ "data from stdin\n"
+ " --verbose|-v increase verbosity of output\n"
+ " --version|-V print version string and exit\n\n"
+ "Performs a SCSI REPORT (or SET) IDENTIFYING INFORMATION command\n"
);
}
@@ -255,7 +253,7 @@ int main(int argc, char * argv[])
"command\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
fprintf(stderr, "bad field in Set identifying information "
- "cdb\n");
+ "cdb including unsupported service action\n");
else {
fprintf(stderr, "Set identifying information command "
"failed\n");
@@ -309,7 +307,8 @@ int main(int argc, char * argv[])
"not supported\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == ret)
fprintf(stderr, "bad field in Report identifying "
- "information cdb\n");
+ "information cdb including unsupported service "
+ "action\n");
else {
fprintf(stderr, "Report identifying information command "
"failed\n");
diff --git a/sg_inq.8 b/sg_inq.8
index 6e1b3b3a..205d9492 100644
--- a/sg_inq.8
+++ b/sg_inq.8
@@ -1,264 +1,322 @@
-.TH SG_INQ "8" "September 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_INQ "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_inq \- outputs data retrieved from the SCSI INQUIRY or
-ATA IDENTIFY (PACKET) DEVICE command
+sg_inq \- sends a SCSI INQUIRY or ATA IDENTIFY (PACKET) DEVICE command
+and outputs the response
.SH SYNOPSIS
.B sg_inq
-[\fI-a\fR] [\fI-A\fR] [\fI-b\fR] [\fI-c\fR] [\fI-cl\fR] [\fI-d\fR]
-[\fI-e\fR] [\fI-h\fR] [\fI-H\fR] [\fI-i\fR] [\fI-m\fR] [\fI-m\fR]
-[\fI-o=<opcode_page>\fR] [\fI-p=<vpd_page>\fR] [\fI-P\fR] [\fI-r\fR]
-[\fI-s\fR] [\fI-v\fR] [\fI-V\fR] [\fI-x\fR] [\fI-36\fR] [\fI-?\fR]
-\fI<device>\fR
+[\fI\-\-ata\fR] [\fI\-\-cmddt\fR] [\fI\-\-descriptors\fR] [\fI\-\-extended\fR]
+[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id\fR] [\fI\-\-len=LEN\fR]
+[\fI\-\-page=PG\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+\fIDEVICE\fR
+.PP
+.B sg_inq
+[\fI\-36\fR] [\fI\-a\fR] [\fI\-A\fR] [\fI\-b\fR] [\fI\-c\fR] [\fI\-cl\fR]
+[\fI\-d\fR] [\fI\-e\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-i\fR] [\fI\-l=LEN\fR]
+[\fI\-m\fR] [\fI\-M\fR] [\fI\-o=OPCODE_PG\fR] [\fI\-p=VPD_PG\fR] [\fI\-P\fR]
+[\fI\-r\fR] [\fI\-s\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-x\fR] [\fI\-36\fR]
+[\fI\-?\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-This utility by default sends an INQUIRY SCSI command to the given
+This utility by default sends a SCSI INQUIRY command to the given
device and then outputs the response. All SCSI devices are meant
to respond to a "standard" INQUIRY command with at least a 36 byte
response (in SCSI 2 and higher). An INQUIRY is termed as "standard"
-when both the EVPD and CmdDt bits are clear.
+when both the EVPD and CmdDt (obsolete) bits are clear.
+.PP
+This utility supports two command line syntaxes, the preferred one is
+shown first in the synopsis and explained in this section. A later
+section on the old command line syntax outlines the second group of
+options.
.PP
-An important "non-standard" INQUIRY page is the Device Identification
-Vital Product Data (VPD) page (page number: 0x83). Since SPC-3,
-support for this page has been flagged as mandatory. The '-i'
-option decodes this page.
+An important "non\-standard" INQUIRY page is the Device Identification
+Vital Product Data (VPD) page [0x83]. Since SPC\-3, support for this page
+has been flagged as mandatory. The \fI\-\-id\fR option decodes this page.
+To get fine grained decoding of this VPD page and others, including
+some vendor specific VPD pages, see the
+.B sg_vpd
+utility.
.PP
-If <device> exists and the SCSI INQUIRY fails (because the SG_IO
-ioctl is unknown) then an ATA IDENTIFY (PACKET) DEVICE is tried. If it
-succeeds then device identification strings are output. If the "-r" option
-is given then the 512 byte IDENTIFY response is output in binary. If
-the "-H" (or "-h") option is given then the 512 byte response is
-output in ASCII hex, grouped as 256 16 bit words, 8 words per line.
-If the "-A" option is given then the SCSI INQUIRY is not performed
-and the device is assumed to be ATA (or ATAPI). This allows ATAPI
-transport information to be found for ATAPI cd/dvd drives; since
-without this option such drives respond to a SCSI INQUIRY command.
+If the \fIDEVICE\fR exists and the SCSI INQUIRY fails (because the SG_IO ioctl
+is not supported) then an ATA IDENTIFY (PACKET) DEVICE is tried. If it
+succeeds then device identification strings are output. The \fI\-\-raw\fR
+and \fI\-\-hex\fR options can be used to manipulate the output. If the
+\fI\-\-ata\fR option is given then the SCSI INQUIRY is not performed
+and the \fIDEVICE\fR is assumed to be ATA (or ATAPI).
.PP
-The reference document used for interpreting an INQUIRY is T10/1713-D
-Revision 6 (SPC-4, 18 July 2006) found at http://www.t10.org .
+The reference document used for interpreting an INQUIRY is T10/1713\-D
+Revision 7a (SPC\-4, 7 October 2006) found at http://www.t10.org .
Obsolete items in the standard INQUIRY response are displayed in
brackets. The reference document for the ATA IDENTIFY (PACKET) DEVICE
-command is ATA8-ACS found at http://www.t13.org .
-.PP
-ATA or ATAPI devices that use a SCSI to ATA Translation layer (see
-SAT at www.t10.org) may support the ATA Information VPD page. This
-returns the IDENTIFY (PACKET) DEVICE response amongst other things.
-See the '-a' option.
-.TP
--a
-decodes the ATA Information Vital Product Data (VPD) page [0x89].
-If '-H' is given then the whole page as ASCII hex bytes; with '-HH'
-the IDENTIFY (PACKET) DEVICE response is output in ASCII hex bytes;
-and without either the IDENTIFY (PACKET) DEVICE response is output
-in 16 bit ASCII hex words. This page is defined in SAT (revision 5)
-at www.t10.org .
-.TP
--A
-Assume given <device> is an ATA or ATAPI device which can receive
-ATA passthrough commands from the host operating system. Skip
-the SCSI INQUIRY command and use either the ATA IDENTIFY DEVICE
-command (for nonpacket devices) or the ATA IDENTIFY PACKET DEVICE
-command. This option is not available in the FreeBSD port.
-.TP
--b
-decodes the Block Limits Vital Product Data (VPD) page [0xb0].
-This page is defined in SBC-2 (revision 16) at www.t10.org .
-.TP
--c
-set the Command Support Data (CmdDt) bit (defaults to clear(0)). Used
-in conjunction with the '-o=<opcode>' option to specify the SCSI command
-opcode to supply the support data for. The command support data is a mask of
-the same length as the command with bits set in positions that are
-modifiable. For example, '12 03 ff 00 ff 01' shows the device
-supports the EVPD and CmdDt bits [byte 1, bits 0 and 1] in an INQUIRY command.
-The CmdDt bit is now obsolete. It has been replaced by the REPORT SUPPORTED
-OPERATION CODES command which is accessed via the sg_opcodes utility.
-.TP
--cl
-lists the command data for all supported commands (followed by the command
-name) by looping through all 256 opcodes. This option uses the CmdDt bit
-which is now obsolete. See the sg_opcodes utility.
+command is ATA8\-ACS found at http://www.t13.org .
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
--d
-decodes depending on context. If '-e' option is given, or any option that
-implies '-e' (e.g. '-i' or '-p=80'), then this utility attempts to
-decode the indicated VPD page. Otherwise the version descriptors (if any)
-are listed following a standard INQUIRY response. There are up to 8 version
-descriptors in the response of a standard INQUIRY, If the version descriptor
-code is recognised then the corresponding string is output.
-Version descriptors are versions of standards and drafts that the device
-claims to comply with (e.g. SAM, SPC, SBC, SPI, FCP, SAS etc).
-.TP
--e
-enable (i.e. sets) the Vital Product Data (EVPD) bit (defaults to clear(0)).
-Used in conjunction with the '-p=<vpd_page>' option to specify the VPD page
-to fetch. If '-p' is not given then VPD page 0 (list supported VPD pages)
-is assumed. Support for VPD page 0 and page 0x83 (device identification)
-have been made mandatory in SPC-3 .
-.TP
--h
-outputs INQUIRY response in hex rather than trying to decode it. When
-used with '-i' outputs partially decoded device identification descriptors
-with the identifier itself output in hex. When selected, ATA IDENTIFY (PACKET)
-DEVICE responses are output in 16 bit words if '-h' is given; they are output in
-bytes when '-hh' (or '-HH') is given. The '-hh' option has a similar effect
-on the ATA information VPD page decoding (i.e. when the '-a' option is given).
-When used three times ('-hhh' or '-HHH'), the response is output in a form
-acceptable for 'hdparm --Istdin' to decode.
-.TP
--H
-same action as '-h'. For compatibility with many other sg3_utils programs
-in which '-H' is for hex output.
-.TP
--i
-decodes the Device Identification Vital Product Data (VPD) page [0x83].
-This page is made up of several "identification descriptors". If '-h' is
-given then each descriptor header is decoded and the identifier itself
-is output in hex. To see the whole VPD 0x83 page response in hex
-use '-p=83 -h'. Since SPC-3, support for the device identification VPD
-page is mandatory.
-.TP
--m
-decodes the Management network addresses Vital Product Data (VPD)
-page [0x85]. This page is made up of several "network service descriptors".
-If '-h' is given then each descriptor payload is output in hex.
-.TP
--M
-decodes the Mode page policy Vital Product Data (VPD) page [0x87].
-This page is made up of several "mode page policy descriptors".
-If '-h' is given then each descriptor payload is output in hex.
-.TP
--o=<opcode_page>
-used in conjunction with the '-e' or '-c' option. If neither given then
-the '-e' option assumed. When the '-e' option is also given (or assumed)
-then the argument to this option is the VPD page number. The argument
-is interpreted as hexadecimal and is expected to be in the range 0 to ff
-inclusive. Only VPD page 0 is decoded and lists supported VPD pages and
-their names (if known). To decode the mandatory device identification
-page (0x83) use the '-i' option.
-A now obsolete usage is when the '-c' option is given in which
-case the argument to this option is assumed to be a command opcode number.
-Recent SCSI draft standards have moved this facility (see sg_opcodes).
-Defaults to 0 so if '-e' is given without '-o=' then VPD page 0 is output.
-.TP
--p=<vpd_page>
-same action as '-o=<opcode_page>' option described above. Since the
-opcode value with the CmdDt is now obsolete, the main use of this
-option is to specify the VPD page number. The argument is interpreted as
-hexadecimal and is expected to be in the range 0 to ff inclusive.
-Defaults to 0 so if '-e' is given without '-p=' then VPD page 0 is output.
-.TP
--P
-decodes the Unit Path Report Vital Product Data (VPD) page [0xc0],
-which is specific to selected EMC devices. To see the whole VPD 0xc0
-page response in hex use '-p=c0 -h'.
-.TP
--r
-outputs the INQUIRY response in binary. If the SCSI INQUIRY has failed
-and an ATA IDENTIFY succeeds then the 512 bytes of the IDENTIFY response
-is output in binary. Overrides the various VPD decoding options. Standard
-output should be redirected to a file or some other program that can
-process binary data. Can be used twice (i.e. '-rr' (and '-HHH' has same
-effect)) and if used with the '-A' or '-a' option yields output with the
-same format as "cat /proc/ide/hd<x>/identify" so that it can then be
-piped to "hdparm --Istdin".
-.TP
--s
-decodes the SCSI Ports Vital Product Data (VPD) page [0x88]. The response
-contains information about the target (or rarely the initiator) ports
-associated with the addressed device server (i.e. the target). In practice
-this is a way to find all target port addresses of a dual ported disk.
-If '-h' is given then each target (and/or initiator) descriptor is output
-in hex. To see the whole VPD 0x88 page response in hex use '-p=88 -h'.
-.TP
--v
-verbose: print out cdb of issued commands prior to execution. '-vv'
-and '-vvv' are also accepted yielding greater verbosity. For ATA disks
-the identity response (256 16 bit words) is output when this option
-is given.
-.TP
--V
-print out version string
-.TP
--x
-decodes the Extended INQUIRY data Vital Product Data (VPD) [0x86] page.
-If '-h' is given then prints out VPD page in hex which is similar to
-using '-p=86 -h'.
-.TP
--36
-only requests 36 bytes of response data for an INQUIRY. Furthermore even
-if the device indicates in its response it can supply more data, a
-second (longer) INQUIRY is not performed. This is a paranoid setting.
+\fB\-a\fR, \fB\-\-ata\fR
+Assume given \fIDEVICE\fR is an ATA or ATAPI device which can receive ATA
+commands from the host operating system. Skip the SCSI INQUIRY command and
+use either the ATA IDENTIFY DEVICE command (for nonpacket devices) or the
+ATA IDENTIFY PACKET DEVICE command. This option is only available in Linux.
.TP
--?
-output usage message and exit. Ignore all other parameters.
-.PP
+\fB\-c\fR, \fB\-\-cmddt\fR
+set the Command Support Data (CmdDt) bit (defaults to clear(0)). Used in
+conjunction with the \fI\-\-page=PG\fR option where \fIPG\fR specifies the
+SCSI command opcode to query. When used twice (e.g. '\-cc') this utility
+forms a list by looping over all 256 opcodes (0 to 255 inclusive) only
+outputting a line for found commands. The CmdDt bit is now obsolete.
+It has been replaced by the REPORT SUPPORTED OPERATION CODES command,
+see the sg_opcodes utility.
+.TP
+\fB\-d\fR, \fB\-\-descriptors\fR
+decodes and prints the version descriptors found in a standard INQUIRY
+response. There are up to 8 of them. Version descriptors indicate which
+versions of standards and/or drafts the \fIDEVICE\fR complies with. The
+normal components of a standard INQUIRY are output (typically from
+the first 36 bytes of the response) followed by the version descriptors
+if any.
+.TP
+\fB\-e\fR, \fB\-x\fR, \fB\-\-extended\fR
+prints the extended INQUIRY VPD page [0x86].
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+print out the usage message then exit. When used twice, after the
+usage message, there is a list of available abbreviations than can be
+given to the \fI\-\-page=PG\fR option.
+.TP
+\fB\-H\fR, \fB\-\-hex\fR
+rather than decode a standard INQUIRY response, a VPD page or command
+support data; print out the response in hex to stdout. Error messages and
+warnings are typically output to stderr. When used twice with the ATA
+Information VPD page [0x89] decodes the start of the response then output
+the ATA IDENTIFY (PACKET) DEVICE response in hexadecimal bytes (not 16 bit
+words). When used three times with the ATA Information VPD page [0x89] or
+the \fI\-\-ata\fR option, this utility outputs the ATA IDENTIFY (PACKET)
+DEVICE response in hexadecimal words suitable for input
+to 'hdparm \-\-Istdin'. See note below.
+.TP
+\fB\-i\fR, \fB\-\-id\fR
+prints the device identification VPD page [0x83].
+.TP
+\fB\-l\fR, \fB\-\-len\fR=\fILEN\fR
+the number \fILEN\fR is the "allocation length" field in the INQUIRY cdb.
+This is the (maximum) length of the response to be sent by the device.
+The default value of \fILEN\fR is 0 which is interpreted as: first request
+is for 36 bytes and if necessary execute another INQUIRY if the "additional
+length" field in the response indicates that more than 36 bytes is available.
+If \fILEN\fR is greater than 0 then only one INQUIRY command is performed.
+See paragraph below about "36 byte INQUIRYs".
+.TP
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
+.TP
+\fB\-p\fR, \fB\-\-page\fR=\fIPG\fR
+the \fIPG\fR argument can be either a number of an abbreviation for a VPD
+page. To enumerate the available abbreviations for VPD pages use '\-hh' or
+a bad abbreviation (e.g, '\-\-page=xxx'). When the \fI\-\-cmddt\fR option is
+given (once) then \fIPG\fR is interpreted as an opcode number (so VPD page
+abbreviations make little sense).
+.TP
+\fB\-r\fR, \fB\-\-raw\fR
+output the response in binary to stdout. Error messages and warnings, if
+any, are sent to stderr.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+increase level of verbosity. Can be used multiple times.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+print out version string then exit.
+.SH NOTES
Some devices with weak SCSI command set implementations lock up when
they receive commands they don't understand (or even response lengths
that they don't expect). Such devices need to be treated carefully,
-hence the '-36' option. Without this option this utility will issue
+use the '\-\-len=36' option. Without this option this utility will issue
an initial standard INQUIRY requesting 36 bytes of response data. If
the device indicates it could have supplied more data then a second
INQUIRY is issued to fetch the longer response. That second command may
lock up faulty devices.
.PP
+ATA or ATAPI devices that use a SCSI to ATA Translation layer (see
+SAT at www.t10.org) may support the ATA Information VPD page. This
+returns the IDENTIFY (PACKET) DEVICE response amongst other things.
+The ATA Information VPD page can be fetched with '\-\-page=ai'.
+.PP
In the INQUIRY standard response there is a 'MultiP' flag which is set
when the device has 2 or more ports. Some vendors use the preceding
vendor specific ('VS') bit to indicate which port is being accessed by
-the INQUIRY command (0 -> relative port 1 (port "a"), 1 -> relative
+the INQUIRY command (0 \-> relative port 1 (port "a"), 1 \-> relative
port 2 (port "b")). When the 'MultiP' flag is set, the preceding vendor
-specific bit is shown in parentheses. SPC-3 compliant devices should
+specific bit is shown in parentheses. SPC\-3 compliant devices should
use the device identification VPD page (0x83) to show which port is
being used for access and the SCSI ports VPD page (0x88) to show all
available ports on the device.
.PP
-In the 2.4 series of Linux kernels the given device must be
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be
a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
and ATAPI DVDs) can also be specified. For example "sg_inq /dev/sda"
will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char"
device names may be used as well (e.g. "/dev/st0m").
.SH ATA DEVICES
-There are two major types of ATA devices: non-packet devices (e.g. ATA
+There are two major types of ATA devices: non\-packet devices (e.g. ATA
disks) and packet devices (ATAPI). The majority of ATAPI devices are
CD/DVD drives in which the ATAPI transport carries the MMC set (i.e.
a SCSI command set). Further, both types of ATA devices can be connected
to a host computer via a "SCSI" (or some other) transport. When an
-ATA disk is controlled via a SCSI (or non-ATA) transport then two
+ATA disk is controlled via a SCSI (or non\-ATA) transport then two
approaches are commonly used: tunnelling (e.g. STP in Serial Attached
-SCSI (SAS)) or by emulating a SCSI device (typically via a SCSI to
+SCSI (SAS)) or by emulating a SCSI device (e.g. with a SCSI to
ATA translation layer, see SAT at www.t10.org ). Even when the
physical transport to the host computer is ATA (especially in the
-case of SATA) the linux operating system may choose to put a SAT
-layer in the driver "stack" (e.g. libata).
+case of SATA) the operating system may choose to put a SAT
+layer in the driver "stack" (e.g. libata in Linux).
.PP
The main identifying command for any SCSI device is an INQUIRY. The
-corresponding command for an ATA non-packet device is IDENTIFY DEVICE
+corresponding command for an ATA non\-packet device is IDENTIFY DEVICE
while for an ATA packet device it is IDENTIFY PACKET DEVICE.
.PP
When this utility is invoked for an ATAPI device (e.g. a CD/DVD
drive with "sg_inq /dev/hdc") then a SCSI INQUIRY is sent to the
device and if it responds then the response to decoded and output and
this utility exits. To see the response for an ATA IDENTIFY PACKET
-DEVICE command add the '-A' option (e.g. "sg_inq -A /dev/hdc) and to
-see the response in hex add the "-H" option as
-well (e.g. "sg_inq -A -H /dev/hdc").
+DEVICE command add the \fI\-\-ata\fR option (e.g. "sg_inq \-\-ata /dev/hdc).
.PP
This utility doesn't decode the response to an ATA IDENTIFY (PACKET)
-DEVICE command, hdparm does a good job at that. The '-rr'
-option (or '-HHH') has been added for use with either the '-A' or '-a'
-option to produce a format acceptable to "hdparm --Istdin". See hdparm.
+DEVICE command, hdparm does a good job at that. The '\-HHH' option has
+been added for use with either the '\-\-ata' or '\-\-page=ai'
+option to produce a format acceptable to "hdparm \-\-Istdin".
+An example: 'sg_inq \-\-ata \-HHH /dev/hdc | hdparm \-\-Istdin'. See hdparm.
.SH EXIT STATUS
The exit status of sg_inq is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using \fI\-\-old\fR (or \fI\-O\fR) as the first option.
+.TP
+\fB\-36\fR
+only requests 36 bytes of response data for an INQUIRY. Furthermore even
+if the device indicates in its response it can supply more data, a
+second (longer) INQUIRY is not performed. This is a paranoid setting.
+Equivalent to '\-\-len=36' in the main description.
+.TP
+\fB\-a\fR
+fetch the ATA Information VPD page [0x89]. Equivalent to '\-\-page=ai' in
+the main description. This page is defined in SAT (see at www.t10.org).
+.TP
+\fB\-A\fR
+Assume given \fIDEVICE\fR is an ATA or ATAPI device.
+Equivalent to \fI\-\-ata\fR in the main description.
+.TP
+\fB\-b\fR
+decodes the Block Limits VPD page [0xb0]. Equivalent to '\-\-page=bl' in
+the main description. This page is defined in SBC\-2 (see www.t10.org).
+.TP
+\fB\-c\fR
+set the Command Support Data (CmdDt) bit (defaults to clear(0)). Used in
+ conjunction with the \fI\-o=OPCODE_PG\fR option to specify the SCSI command
+opcode to query. Equivalent to \fI\-\-cmddt\fR in the main description.
+.TP
+\fB\-cl\fR
+lists the command data for all supported commands (followed by the command
+name) by looping through all 256 opcodes. This option uses the CmdDt bit
+which is now obsolete. See the sg_opcodes utility.
+Equivalent to '\-\-cmddt \-\-cmddt' in the main description.
+.TP
+\fB\-d\fR
+decodes depending on context. If \fI\-e\fR option is given, or any option
+that implies \fI\-e\fR (e.g. '\-i' or '\-p=80'), then this utility attempts
+to decode the indicated VPD page. Otherwise the version descriptors (if any)
+are listed following a standard INQUIRY response. In the version descriptors
+sense, equivalent to \fI\-\-descriptors\fR in the main description.
+.TP
+\fB\-e\fR
+enable (i.e. sets) the Vital Product Data (EVPD) bit (defaults to clear(0)).
+Used in conjunction with the \fI\-p=VPD_PG\fR option to specify the VPD page
+to fetch. If \fI\-p=VPD_PG\fR is not given then VPD page 0 (list supported
+VPD pages) is assumed.
+.TP
+\fB\-h\fR
+outputs INQUIRY response in hex rather than trying to decode it.
+Equivalent to \fI\-\-hex\fR in the main description.
+.TP
+\fB\-H\fR
+same action as \fI\-h\fR.
+Equivalent to \fI\-\-hex\fR in the main description.
+.TP
+\fB\-i\fR
+decodes the Device Identification VPD page [0x83]. Equivalent to
+\fI\-\-id\fR in the main description. This page is made up of
+several "designation descriptors". If \fI\-h\fR is given then each
+descriptor header is decoded and the identifier itself is output in hex.
+To see the whole VPD 0x83 page response in hex use '\-p=83 \-h'.
+.TP
+\fB\-m\fR
+decodes the Management network addresses VPD page [0x85]. Equivalent
+to '\-\-page=mna' in the main description.
+.TP
+\fB\-M\fR
+decodes the Mode page policy VPD page [0x87]. Equivalent to '\-\-page=mpp'
+in the main description.
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-o\fR=\fIOPCODE_PG\fR
+used in conjunction with the \fI\-e\fR or \fI\-c\fR option. If neither given
+then the \fI\-e\fR option assumed. When the \fI\-e\fR option is also
+given (or assumed) then the argument to this option is the VPD page number.
+The argument is interpreted as hexadecimal and is expected to be in the range
+0 to ff inclusive. Only VPD page 0 is decoded and it lists supported VPD pages
+and their names (if known). To decode the mandatory device identification
+page (0x83) use the \fI\-i\fR option. A now obsolete usage is when the
+\fI\-c\fR option is given in which case the argument to this option is assumed
+to be a command opcode number. Recent SCSI draft standards have moved this
+facility to a separate command (see sg_opcodes). Defaults to 0 so if \fI\-e\fR
+is given without this option then VPD page 0 is output.
+.TP
+\fB\-p\fR=\fIVPD_PG\fR
+same action as \fI\-o=OPCODE_PG\fR option described in the previous entry.
+Since the opcode value with the CmdDt is now obsolete, the main use of this
+option is to specify the VPD page number. The argument is interpreted as
+hexadecimal and is expected to be in the range 0 to ff inclusive.
+Defaults to 0 so if \fI\-e\fR is given without this option then VPD page 0
+is output.
+.TP
+\fB\-P\fR
+decodes the Unit Path Report VPD page [0xc0] which is EMC specific.
+Equivalent to '\-\-page=upr' in the main description.
+.TP
+\fB\-r\fR
+outputs the response in binary to stdout. Equivalent to \fI\-\-raw\fR in
+the main description. Can be used twice (i.e. '\-rr' (and '\-HHH' has
+same effect)) and if used with the \fI\-A\fR or \fI\-a\fR option yields
+output with the same format as "cat /proc/ide/hd<x>/identify" so that it
+can then be piped to "hdparm \-\-Istdin".
+.TP
+\fB\-s\fR
+decodes the SCSI Ports VPD page [0x88].
+Equivalent to '\-\-page=sp' in the main description.
+.TP
+\fB\-v\fR
+increase level of verbosity. Can be used multiple times.
+.TP
+\fB\-V\fR
+print out version string then exit.
+.TP
+\fB\-x\fR
+decodes the Extended INQUIRY data VPD [0x86] page.
+Equivalent to '\-\-page=ei' in the main description.
+.TP
+\fB\-?\fR
+output usage message and exit. Ignore all other parameters.
.SH AUTHOR
Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2001-2006 Douglas Gilbert
+Copyright \(co 2001\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B sgdiag(scsirastools), sg_opcodes(sg3_utils), sg_modes(sg3_utils),
-.B sg_logs(sg3_utils), hdparm(hdparm), sg_vpd(sg_vpd)
+.B sg_opcodes sg_vpd(sg3_utils), hdparm(hdparm), sgdiag(scsirastools)
diff --git a/sg_inq.c b/sg_inq.c
index 56ca9dc4..98996c0c 100644
--- a/sg_inq.c
+++ b/sg_inq.c
@@ -4,6 +4,10 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
#ifdef SG3_UTILS_LINUX
#include <errno.h>
#include <sys/ioctl.h>
@@ -15,8 +19,8 @@
#include "sg_lib.h"
#include "sg_cmds_basic.h"
-/* A utility program for the Linux OS SCSI subsystem.
-* Copyright (C) 2000-2006 D. Gilbert
+/* A utility program originally written for the Linux OS SCSI subsystem.
+* Copyright (C) 2000-2007 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)
@@ -59,27 +63,34 @@
* information [MAINTENANCE IN, service action = 0xc]; see sg_opcodes.
*/
-static char * version_str = "0.65 20061007"; /* spc-4 rev 07 */
-
-
-#define SUPPORTED_VPDS_VPD 0x0
-#define UNIT_SERIAL_NUM_VPD 0x80
-#define DEV_ID_VPD 0x83
-#define SOFTW_INF_ID_VPD 0x84
-#define MAN_NET_ADDR_VPD 0x85
-#define X_INQ_VPD 0x86
-#define MODE_PG_POLICY_VPD 0x87
-#define SCSI_PORTS_VPD 0x88
-#define ATA_INFO_VPD 0x89
-#define BLOCK_LIMITS_VPD 0xb0
-#define UPR_EMC_VPD 0xc0
-#define RDAC_VERS_VPD 0xc2
-#define RDAC_VAC_VPD 0xc9
+static char * version_str = "0.70 20070125"; /* spc-4 rev 08 */
+
+
+#define VPD_SUPPORTED_VPDS 0x0
+#define VPD_UNIT_SERIAL_NUM 0x80
+#define VPD_DEVICE_ID 0x83
+#define VPD_SOFTW_INF_ID 0x84
+#define VPD_MAN_NET_ADDR 0x85
+#define VPD_EXT_INQ 0x86
+#define VPD_MODE_PG_POLICY 0x87
+#define VPD_SCSI_PORTS 0x88
+#define VPD_ATA_INFO 0x89
+#define VPD_BLOCK_LIMITS 0xb0
+#define VPD_UPR_EMC 0xc0
+#define VPD_RDAC_VERS 0xc2
+#define VPD_RDAC_VAC 0xc9
+
+/* values for selection one or more associations (2**vpd_assoc),
+ except _AS_IS */
+#define VPD_DI_SEL_LU 1
+#define VPD_DI_SEL_TPORT 2
+#define VPD_DI_SEL_TARGET 4
+#define VPD_DI_SEL_AS_IS 32
#define DEF_ALLOC_LEN 252
#define SAFE_STD_INQ_RESP_LEN 36
#define MX_ALLOC_LEN (0xc000 + 0x80)
-#define ATA_INFO_VPD_LEN 572
+#define VPD_ATA_INFO_LEN 572
static unsigned char rsp_buff[MX_ALLOC_LEN + 1];
@@ -96,17 +107,144 @@ static int try_ata_identify(int ata_fd, int do_hex, int do_raw,
int do_verbose);
#endif
+/* This structure is a duplicate of one of the same name in sg_vpd_vendor.c .
+ Take care that both have the same fields (and types). */
+struct svpd_values_name_t {
+ int value;
+ int subvalue;
+ int pdt; /* peripheral device type id, -1 is the default */
+ /* (all or not applicable) value */
+ int ro_vendor; /* read-only or vendor flag */
+ const char * acron;
+ const char * name;
+};
+
+static struct svpd_values_name_t vpd_pg[] = {
+ {VPD_ATA_INFO, 0, -1, 0, "ai", "ATA information (SAT)"},
+ {VPD_BLOCK_LIMITS, 0, 0, 0, "bl", "Block limits (SBC)"},
+ {VPD_DEVICE_ID, 0, -1, 0, "di", "Device identification"},
+#if 0
+ {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, 0, "di_asis", "Like 'di' "
+ "but designators ordered as found"},
+ {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, 0, "di_lu", "Device identification, "
+ "lu only"},
+ {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, 0, "di_port", "Device "
+ "identification, target port only"},
+ {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, 0, "di_target", "Device "
+ "identification, target device only"},
+#endif
+ {VPD_EXT_INQ, 0, -1, 0, "ei", "Extended inquiry data"},
+ {VPD_MAN_NET_ADDR, 0, -1, 0, "mna", "Management network addresses"},
+ {VPD_MODE_PG_POLICY, 0, -1, 0, "mpp", "Mode page policy"},
+ {VPD_SOFTW_INF_ID, 0, -1, 0, "sii", "Software interface identification"},
+ {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"},
+ {VPD_UPR_EMC, 0, -1, 0, "upr", "Unit path report (EMC)"},
+ {VPD_RDAC_VERS, 0, -1, 0, "rdac_vers", "RDAC software version (IBM)"},
+ {VPD_RDAC_VAC, 0, -1, 0, "rdac_vac", "RDAC volume access control (IBM)"},
+ {0, 0, 0, 0, NULL, NULL},
+};
+
+static struct option long_options[] = {
+#ifdef SG3_UTILS_LINUX
+ {"ata", 0, 0, 'a'},
+#endif
+ {"cmddt", 0, 0, 'c'},
+ {"descriptors", 0, 0, 'd'},
+ {"extended", 0, 0, 'x'},
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"id", 0, 0, 'i'},
+ {"len", 1, 0, 'l'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"page", 1, 0, 'p'},
+ {"raw", 0, 0, 'r'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+struct opts_t {
+ int do_ata;
+ int do_cmddt;
+ int do_descriptors;
+ int do_help;
+ int do_hex;
+ int do_raw;
+ int do_verbose;
+ int do_version;
+ int do_decode;
+ int do_vpd;
+ int resp_len;
+ int page_num;
+ int num_pages;
+ int num_opcodes;
+ int p_given;
+ const char * page_arg;
+ const char * device_name;
+ int opt_new;
+};
static void usage()
{
#ifdef SG3_UTILS_LINUX
fprintf(stderr,
+ "Usage: sg_inq [--ata] [--cmddt] [--descriptors] [--extended] "
+ "[--help] [--hex]\n"
+ " [--id] [--len=LEN] [--page=PG] [--raw] "
+ "[--verbose] [--version]\n"
+ " DEVICE\n"
+ " where:\n"
+ " --ata|-a treat DEVICE as (directly attached) ATA "
+ "device\n");
+#else
+ fprintf(stderr,
+ "Usage: sg_inq [--cmddt] [--descriptors] [--extended] [--help] "
+ "[--hex] [--id]\n"
+ " [--len=LEN] [--page=PG] [--raw] [--verbose] "
+ "[--version]\n"
+ " DEVICE\n"
+ " where:\n");
+#endif
+ fprintf(stderr,
+ " --cmddt|-c command support data mode (set opcode "
+ "with '--page=PG')\n"
+ " use twice for list of supported "
+ "commands; obsolete\n"
+ " --descriptors|-d fetch and decode version descriptors\n"
+ " --extended|-e|-x decode extended INQUIRY data VPD page "
+ "(0x86)\n"
+ " --help|-h print usage message then exit\n"
+ " --hex|-H output response in hex\n"
+ " --id|-i decode device identification VPD page "
+ "(0x83)\n"
+ " --len=LEN|-l LEN requested response length (def: 0 "
+ "-> fetch 36\n"
+ " bytes first, then fetch again as "
+ "indicated)\n"
+ " --page=PG|-p PG Vital Product Data (VPD) page number "
+ "or\n"
+ " abbreviation (opcode number if "
+ "'--cmddt' given)\n"
+ " --raw|-r output response in binary (to stdout)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string then exit\n\n"
+ "Performs a SCSI INQUIRY command.\n"
+ "If no options given then does a 'standard' INQUIRY.\n");
+}
+
+static void usage_old()
+{
+#ifdef SG3_UTILS_LINUX
+ fprintf(stderr,
"Usage: sg_inq [-a] [-A] [-b] [-c] [-cl] [-d] [-e] [-h] [-H] "
"[-i]\n"
- " [-l=<resp_len>] [-m] [-M] [-o=<opcode_page>] "
- "[-p=<vpd_page>]\n"
+ " [-l=LEN] [-m] [-M] [-o=OPCODE_PG] "
+ "[-p=VPD_PG]\n"
" [-P] [-r] [-s] [-v] [-V] [-x] [-36] [-?] "
- "<device>\n"
+ "DEVICE\n"
" where:\n"
" -a decode ATA information VPD page (0x89)\n"
" -A treat <device> as (directly attached) ATA device\n");
@@ -114,10 +252,10 @@ static void usage()
fprintf(stderr,
"Usage: sg_inq [-a] [-b] [-c] [-cl] [-d] [-e] [-h] [-H] "
"[-i]\n"
- " [-l=<resp_len>] [-m] [-M] [-o=<opcode_page>] "
- "[-p=<vpd_page>]\n"
+ " [-l=LEN] [-m] [-M] [-o=OPCODE_PG] "
+ "[-p=VPD_PG]\n"
" [-P] [-r] [-s] [-v] [-V] [-x] [-36] [-?] "
- "<device>\n"
+ "DEVICE\n"
" where:\n"
" -a decode ATA information VPD page (0x89)\n");
@@ -131,14 +269,17 @@ static void usage()
" -h output in hex (ASCII to the right)\n"
" -H output in hex (ASCII to the right) [same as '-h']\n"
" -i decode device identification VPD page (0x83)\n"
- " -l=<resp_len> requested response length (def: 36)\n"
+ " -l=LEN requested response length (def: 0 "
+ "-> fetch 36\n"
+ " bytes first, then fetch again as "
+ "indicated)\n"
" -m decode management network addresses VPD page "
"(0x85)\n"
" -M decode mode page policy VPD page (0x87)\n"
- " -o=<opcode_page> opcode or page code in hex (def: 0)\n"
- " -p=<vpd_page> vpd page code in hex (def: 0)\n"
+ " -o=OPCODE_PG opcode or page code in hex (def: 0)\n"
+ " -p=VPD_PG vpd page code in hex (def: 0)\n"
" -P decode Unit Path Report VPD page (0xc0) (EMC)\n"
- " -r output raw binary data ('-rr': output for hdparm)\n"
+ " -r output response in binary ('-rr': output for hdparm)\n"
" -s decode SCSI Ports VPD page (0x88)\n"
" -v verbose (output cdb and, if non-zero, resid)\n"
" -V output version string\n"
@@ -148,6 +289,300 @@ static void usage()
"If no options given then does a standard SCSI INQUIRY\n");
}
+static void usage_for(const struct opts_t * optsp)
+{
+ if (optsp->opt_new)
+ usage();
+ else
+ usage_old();
+}
+
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c, n;
+
+ while (1) {
+ int option_index = 0;
+
+#ifdef SG3_UTILS_LINUX
+ c = getopt_long(argc, argv, "acdehHil:NOp:rvVx", long_options,
+ &option_index);
+#else
+ c = getopt_long(argc, argv, "cdehHil:NOp:rvVx", long_options,
+ &option_index);
+#endif
+ if (c == -1)
+ break;
+
+ switch (c) {
+#ifdef SG3_UTILS_LINUX
+ case 'a':
+ ++optsp->do_ata;
+ break;
+#endif
+ case 'c':
+ ++optsp->do_cmddt;
+ break;
+ case 'd':
+ ++optsp->do_descriptors;
+ break;
+ case 'e':
+ case 'x':
+ ++optsp->do_decode;
+ optsp->page_num = VPD_EXT_INQ;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'i':
+ ++optsp->do_decode;
+ optsp->page_num = VPD_DEVICE_ID;
+ break;
+ case 'l':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 65532)) {
+ fprintf(stderr, "bad argument to '--len='\n");
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->resp_len = n;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'p':
+ optsp->page_arg = optarg;
+ ++optsp->p_given;
+ break;
+ case 'r':
+ ++optsp->do_raw;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
+{
+ int k, jmp_out, plen, num, n;
+ const char * cp;
+
+ for (k = 1; k < argc; ++k) {
+ cp = argv[k];
+ plen = strlen(cp);
+ if (plen <= 0)
+ continue;
+ if ('-' == *cp) {
+ for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
+ switch (*cp) {
+ case '3':
+ if ('6' == *(cp + 1)) {
+ optsp->resp_len = 36;
+ --plen;
+ ++cp;
+ } else
+ jmp_out = 1;
+ break;
+ case 'a':
+ optsp->page_num = VPD_ATA_INFO;
+ ++optsp->do_vpd;
+ ++optsp->num_pages;
+ break;
+#ifdef SG3_UTILS_LINUX
+ case 'A':
+ ++optsp->do_ata;
+ break;
+#endif
+ case 'b':
+ optsp->page_num = VPD_BLOCK_LIMITS;
+ ++optsp->do_vpd;
+ ++optsp->num_pages;
+ break;
+ case 'c':
+ ++optsp->do_cmddt;
+ if ('l' == *(cp + 1)) {
+ ++optsp->do_cmddt;
+ --plen;
+ ++cp;
+ }
+ break;
+ case 'd':
+ ++optsp->do_descriptors;
+ ++optsp->do_decode;
+ break;
+ case 'e':
+ ++optsp->do_vpd;
+ break;
+ case 'h':
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'i':
+ optsp->page_num = VPD_DEVICE_ID;
+ ++optsp->do_vpd;
+ ++optsp->num_pages;
+ break;
+ case 'm':
+ optsp->page_num = VPD_MAN_NET_ADDR;
+ ++optsp->do_vpd;
+ ++optsp->num_pages;
+ break;
+ case 'M':
+ optsp->page_num = VPD_MODE_PG_POLICY;
+ ++optsp->do_vpd;
+ ++optsp->num_pages;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case 'P':
+ optsp->page_num = VPD_UPR_EMC;
+ ++optsp->do_vpd;
+ ++optsp->num_pages;
+ break;
+ case 'r':
+ ++optsp->do_raw;
+ break;
+ case 's':
+ optsp->page_num = VPD_SCSI_PORTS;
+ ++optsp->do_vpd;
+ ++optsp->num_pages;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case 'x':
+ optsp->page_num = VPD_EXT_INQ;
+ ++optsp->do_vpd;
+ ++optsp->num_pages;
+ break;
+ case '?':
+ ++optsp->do_help;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+ else if (0 == strncmp("l=", cp, 2)) {
+ num = sscanf(cp + 2, "%d", &n);
+ if ((1 != num) || (n < 1)) {
+ fprintf(stderr, "Inappropriate value after 'l=' "
+ "option\n");
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ } else if (n > MX_ALLOC_LEN) {
+ fprintf(stderr, "value after 'l=' "
+ "option too large\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->resp_len = n;
+ } else if (0 == strncmp("o=", cp, 2)) {
+ optsp->page_arg = cp + 2;
+ ++optsp->num_opcodes;
+ } else if (0 == strncmp("p=", cp, 2)) {
+ optsp->page_arg = cp + 2;
+ ++optsp->p_given;
+ } else if (0 == strncmp("-old", cp, 4))
+ ;
+ else if (jmp_out) {
+ fprintf(stderr, "Unrecognized option: %s\n", cp);
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == optsp->device_name)
+ optsp->device_name = cp;
+ else {
+ fprintf(stderr, "too many arguments, got: %s, not expecting: "
+ "%s\n", optsp->device_name, cp);
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
+
+static const struct svpd_values_name_t *
+ sdp_find_vpd_by_acron(const char * ap)
+{
+ const struct svpd_values_name_t * vnp;
+
+ for (vnp = vpd_pg; vnp->acron; ++vnp) {
+ if (0 == strcmp(vnp->acron, ap))
+ return vnp;
+ }
+ return NULL;
+}
+
+static void enumerate_vpds()
+{
+ const struct svpd_values_name_t * vnp;
+
+ for (vnp = vpd_pg; vnp->acron; ++vnp) {
+ if (vnp->name && (0 == vnp->ro_vendor))
+ printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value,
+ vnp->name);
+ }
+}
static void dStrRaw(const char* str, int len)
{
@@ -164,18 +599,18 @@ struct vpd_name {
};
static struct vpd_name vpd_name_arr[] = {
- {SUPPORTED_VPDS_VPD, 0, "Supported VPD pages"},
- {UNIT_SERIAL_NUM_VPD, 0, "Unit serial number"},
+ {VPD_SUPPORTED_VPDS, 0, "Supported VPD pages"},
+ {VPD_UNIT_SERIAL_NUM, 0, "Unit serial number"},
{0x81, 0, "Implemented operating definitions (obsolete)"},
{0x82, 0, "ASCII implemented operating definition (obsolete)"},
- {DEV_ID_VPD, 0, "Device identification"},
- {SOFTW_INF_ID_VPD, 0, "Software interface identification"},
- {MAN_NET_ADDR_VPD, 0, "Management network addresses"},
- {X_INQ_VPD, 0, "Extended INQUIRY data"},
- {MODE_PG_POLICY_VPD, 0, "Mode page policy"},
- {SCSI_PORTS_VPD, 0, "SCSI ports"},
- {ATA_INFO_VPD, 0, "ATA information"},
- {BLOCK_LIMITS_VPD, 0, "Block limits (sbc2)"},
+ {VPD_DEVICE_ID, 0, "Device identification"},
+ {VPD_SOFTW_INF_ID, 0, "Software interface identification"},
+ {VPD_MAN_NET_ADDR, 0, "Management network addresses"},
+ {VPD_EXT_INQ, 0, "Extended INQUIRY data"},
+ {VPD_MODE_PG_POLICY, 0, "Mode page policy"},
+ {VPD_SCSI_PORTS, 0, "SCSI ports"},
+ {VPD_ATA_INFO, 0, "ATA information"},
+ {VPD_BLOCK_LIMITS, 0, "Block limits (sbc2)"},
{0xb0, 0x1, "Sequential access device capabilities (ssc3)"},
{0xb2, 0x1, "TapeAlert supported flags (ssc3)"},
{0xb0, 0x11, "OSD information (osd)"},
@@ -492,7 +927,7 @@ static void decode_dev_ids(const char * leadin, unsigned char * buff,
id_ext <<= 8;
id_ext |= ip[m];
}
- printf(" Identifier extension: 0x%llx\n", id_ext);
+ printf(" Identifier extension: 0x%" PRIx64 "\n", id_ext);
} else if ((8 != i_len) && (12 != i_len)) {
fprintf(stderr, " << can only decode 8, 12 and 16 "
"byte ids>>\n");
@@ -508,8 +943,8 @@ static void decode_dev_ids(const char * leadin, unsigned char * buff,
vsei <<= 8;
vsei |= ip[ci_off + 3 + m];
}
- printf(" Vendor Specific Extension Identifier: 0x%llx\n",
- vsei);
+ printf(" Vendor Specific Extension Identifier: 0x%" PRIx64
+ "\n", vsei);
if (12 == i_len) {
d_id = ((ip[8] << 24) | (ip[9] << 16) | (ip[10] << 8) |
ip[11]);
@@ -565,8 +1000,8 @@ static void decode_dev_ids(const char * leadin, unsigned char * buff,
vsei |= ip[3 + m];
}
printf(" NAA 5, IEEE Company_id: 0x%x\n", c_id);
- printf(" Vendor Specific Identifier: 0x%llx\n",
- vsei);
+ printf(" Vendor Specific Identifier: 0x%" PRIx64
+ "\n", vsei);
printf(" [0x");
for (m = 0; m < 8; ++m)
printf("%02x", (unsigned int)ip[m]);
@@ -586,7 +1021,7 @@ static void decode_dev_ids(const char * leadin, unsigned char * buff,
vsei |= ip[3 + m];
}
printf(" NAA 6, IEEE Company_id: 0x%x\n", c_id);
- printf(" Vendor Specific Identifier: 0x%llx\n",
+ printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n",
vsei);
vsei = 0;
for (m = 0; m < 8; ++m) {
@@ -595,7 +1030,7 @@ static void decode_dev_ids(const char * leadin, unsigned char * buff,
vsei |= ip[8 + m];
}
printf(" Vendor Specific Identifier Extension: "
- "0x%llx\n", vsei);
+ "0x%" PRIx64 "\n", vsei);
printf(" [0x");
for (m = 0; m < 16; ++m)
printf("%02x", (unsigned int)ip[m]);
@@ -673,7 +1108,7 @@ static void decode_transport_id(const char * leadin, unsigned char * ucp,
unsigned long long ull;
int bump;
- for (k = 0, bump; k < len; k += bump, ucp += bump) {
+ for (k = 0, bump = 24; k < len; k += bump, ucp += bump) {
if ((len < 24) || (0 != (len % 4)))
printf("%sTransport Id short or not multiple of 4 "
"[length=%d]:\n", leadin, len);
@@ -742,7 +1177,7 @@ static void decode_transport_id(const char * leadin, unsigned char * ucp,
ull <<= 8;
ull |= ucp[4 + j];
}
- printf("%s SAS address: 0x%llx\n", leadin, ull);
+ printf("%s SAS address: 0x%" PRIx64 "\n", leadin, ull);
if (0 != format_code)
printf("%s [Unexpected format code: %d]\n", leadin,
format_code);
@@ -787,8 +1222,9 @@ static void decode_x_inq_vpd(unsigned char * buff, int len, int do_hex)
printf(" GRP_SUP=%d PRIOR_SUP=%d HEADSUP=%d ORDSUP=%d SIMPSUP=%d\n",
!!(buff[5] & 0x10), !!(buff[5] & 0x8), !!(buff[5] & 0x4),
!!(buff[5] & 0x2), !!(buff[5] & 0x1));
- printf(" CORR_D_SUP=%d NV_SUP=%d V_SUP=%d\n", !!(buff[6] & 0x80),
- !!(buff[6] & 0x2), !!(buff[6] & 0x1));
+ printf(" CORR_D_SUP=%d NV_SUP=%d V_SUP=%d LUICLR=%d\n",
+ !!(buff[6] & 0x4), !!(buff[6] & 0x2), !!(buff[6] & 0x1),
+ !!(buff[7] & 0x1));
}
static void decode_softw_inf_id(unsigned char * buff, int len, int do_hex)
@@ -1094,32 +1530,45 @@ static int fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len,
sz = sizeof(b);
memset(b, 0xff, 4); /* guard against empty response */
/* first check if unit serial number VPD page is supported */
- res = sg_ll_inquiry(sg_fd, 0, 1, SUPPORTED_VPDS_VPD, b, sz, 0,
- verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_SUPPORTED_VPDS, b, sz, 0, verbose);
if (0 == res) {
- if ((SUPPORTED_VPDS_VPD != b[1]) || (0x0 != b[2]))
+ if ((VPD_SUPPORTED_VPDS != b[1]) || (0x0 != b[2])) {
+ if (verbose > 2)
+ fprintf(stderr, "fetch_unit_serial_num: bad supported VPDs "
+ "page\n");
return SG_LIB_CAT_MALFORMED;
+ }
len = b[3];
for (k = 0; k < len; ++k) {
- if (UNIT_SERIAL_NUM_VPD == b[k + 4])
+ if (VPD_UNIT_SERIAL_NUM == b[k + 4])
break;
}
if (k < len) {
- res = sg_ll_inquiry(sg_fd, 0, 1, UNIT_SERIAL_NUM_VPD,
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_UNIT_SERIAL_NUM,
b, sz, 0, verbose);
if (0 == res) {
len = b[3];
len = (len < (obuff_len - 1)) ? len : (obuff_len - 1);
- if ((UNIT_SERIAL_NUM_VPD == b[1]) && (len > 0)) {
+ if ((VPD_UNIT_SERIAL_NUM == b[1]) && (len > 0)) {
memcpy(obuff, b + 4, len);
obuff[len] = '\0';
return 0;
- } else
+ } else {
+ if (verbose > 2)
+ fprintf(stderr, "fetch_unit_serial_num: bad sn VPD "
+ "page\n");
return SG_LIB_CAT_MALFORMED;
+ }
}
- } else
+ } else {
+ if (verbose > 2)
+ fprintf(stderr, "fetch_unit_serial_num: no supported VPDs "
+ "page\n");
return SG_LIB_CAT_MALFORMED;
- }
+ }
+ } else if (verbose > 2)
+ fprintf(stderr, "fetch_unit_serial_num: fetch supported VPDs "
+ "failed\n");
return res;
}
@@ -1146,25 +1595,21 @@ static const char * get_ansi_version_str(int version, char * buff,
/* Returns 0 if successful */
-static int process_std_inq(int sg_fd, const char * file_name, int do_36,
- int resp_len, int do_vdescriptors, int do_hex,
- int do_raw, int do_verbose)
+static int process_std_inq(int sg_fd, const struct opts_t * optsp)
{
- int res, len, act_len, pqual, peri_type, ansi_version, k, j;
+ int res, len, rlen, act_len, pqual, peri_type, ansi_version, k, j;
const char * cp;
int vdesc_arr[8];
char buff[48];
+ int verb;
memset(vdesc_arr, 0, sizeof(vdesc_arr));
- if (resp_len > 0)
- res = sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff,
- resp_len, 0, do_verbose);
- else
- res = sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff,
- SAFE_STD_INQ_RESP_LEN, 0, do_verbose);
+ rlen = (optsp->resp_len > 0) ? optsp->resp_len : SAFE_STD_INQ_RESP_LEN;
+ verb = optsp->do_verbose;
+ res = sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, rlen, 0, verb);
if (0 == res) {
pqual = (rsp_buff[0] & 0xe0) >> 5;
- if (! do_raw) {
+ if (! optsp->do_raw) {
if (0 == pqual)
printf("standard INQUIRY:\n");
else if (1 == pqual)
@@ -1180,28 +1625,29 @@ static int process_std_inq(int sg_fd, const char * file_name, int do_36,
len = rsp_buff[4] + 5;
ansi_version = rsp_buff[2] & 0x7;
peri_type = rsp_buff[0] & 0x1f;
- if ((len > SAFE_STD_INQ_RESP_LEN) && (len < 256) && (! do_36) &&
- (0 == resp_len)) {
- if (sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, len, 1, do_verbose)) {
+ if ((len > SAFE_STD_INQ_RESP_LEN) && (len < 256) &&
+ (0 == optsp->resp_len)) {
+ rlen = len;
+ memset(rsp_buff, 0, rlen);
+ if (sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, rlen, 1, verb)) {
fprintf(stderr, "second INQUIRY (%d byte) failed\n", len);
return SG_LIB_CAT_OTHER;
}
if (len != (rsp_buff[4] + 5)) {
- fprintf(stderr,
- "strange, twin INQUIRYs yield different "
- "'additional length'\n");
+ fprintf(stderr, "strange, twin INQUIRYs yield different "
+ "'additional lengths'\n");
res = SG_LIB_CAT_MALFORMED;
+ len = rsp_buff[4] + 5;
}
}
- if (do_36) {
- act_len = len;
- len = SAFE_STD_INQ_RESP_LEN;
- } else
- act_len = len;
- if (do_hex)
- dStrHex((const char *)rsp_buff, len, 0);
- else if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
+ if (optsp->resp_len > 0)
+ act_len = rlen;
+ else
+ act_len = (rlen < len) ? rlen : len;
+ if (optsp->do_raw)
+ dStrRaw((const char *)rsp_buff, act_len);
+ else if (optsp->do_hex)
+ dStrHex((const char *)rsp_buff, act_len, 0);
else {
printf(" PQual=%d Device_type=%d RMB=%d version=0x%02x ",
pqual, peri_type, !!(rsp_buff[1] & 0x80),
@@ -1229,57 +1675,59 @@ static int process_std_inq(int sg_fd, const char * file_name, int do_36,
!!(rsp_buff[7] & 0x20), !!(rsp_buff[7] & 0x10),
!!(rsp_buff[7] & 0x08), !!(rsp_buff[7] & 0x04));
printf("CmdQue=%d\n", !!(rsp_buff[7] & 0x02));
- if (len > 56)
- printf(" Clocking=0x%x QAS=%d IUS=%d\n",
+ if (act_len > 56)
+ printf(" [SPI: Clocking=0x%x QAS=%d IUS=%d]\n",
(rsp_buff[56] & 0x0c) >> 2, !!(rsp_buff[56] & 0x2),
!!(rsp_buff[56] & 0x1));
- if (act_len == len)
+ if (act_len >= len)
printf(" length=%d (0x%x)", len, len);
else
- printf(" length=%d (0x%x), but only read 36 bytes",
- len, len);
+ printf(" length=%d (0x%x), but only fetched %d bytes",
+ len, len, act_len);
if ((ansi_version >= 2) && (len < SAFE_STD_INQ_RESP_LEN))
printf(" [for SCSI>=2, len>=36 is expected]");
cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
if (strlen(cp) > 0)
printf(" Peripheral device type: %s\n", cp);
- if (len <= 8)
+ if (act_len <= 8)
printf(" Inquiry response length=%d, no vendor, "
- "product or revision data\n", len);
+ "product or revision data\n", act_len);
else {
- if (len < SAFE_STD_INQ_RESP_LEN)
- rsp_buff[len] = '\0';
+ if (act_len < SAFE_STD_INQ_RESP_LEN)
+ rsp_buff[act_len] = '\0';
memcpy(xtra_buff, &rsp_buff[8], 8);
xtra_buff[8] = '\0';
printf(" Vendor identification: %s\n", xtra_buff);
- if (len <= 16)
+ if (act_len <= 16)
printf(" Product identification: <none>\n");
else {
memcpy(xtra_buff, &rsp_buff[16], 16);
xtra_buff[16] = '\0';
printf(" Product identification: %s\n", xtra_buff);
}
- if (len <= 32)
+ if (act_len <= 32)
printf(" Product revision level: <none>\n");
else {
memcpy(xtra_buff, &rsp_buff[32], 4);
xtra_buff[4] = '\0';
printf(" Product revision level: %s\n", xtra_buff);
}
- if (do_vdescriptors) {
- for (j = 0, k = 58; ((j < 8) && ((k + 1) < len));
+ if (optsp->do_descriptors) {
+ for (j = 0, k = 58; ((j < 8) && ((k + 1) < act_len));
k +=2, ++j)
vdesc_arr[j] = ((rsp_buff[k] << 8) +
rsp_buff[k + 1]);
}
}
}
- if (! (do_raw || do_hex || do_36 || resp_len)) {
- if (0 == fetch_unit_serial_num(sg_fd, xtra_buff,
- sizeof(xtra_buff), do_verbose))
- printf(" Unit serial number: %s\n", xtra_buff);
- if (do_vdescriptors) {
+ if (! (optsp->do_raw || optsp->do_hex)) {
+ if (0 == optsp->resp_len) {
+ if (0 == fetch_unit_serial_num(sg_fd, xtra_buff,
+ sizeof(xtra_buff), optsp->do_verbose))
+ printf(" Unit serial number: %s\n", xtra_buff);
+ }
+ if (optsp->do_descriptors) {
if (0 == vdesc_arr[0])
printf("\n No version descriptors available\n");
else {
@@ -1300,36 +1748,50 @@ static int process_std_inq(int sg_fd, const char * file_name, int do_36,
} else if (res < 0) { /* could be an ATA device */
#ifdef SG3_UTILS_LINUX
/* Try an ATA Identify Device command */
- res = try_ata_identify(sg_fd, do_hex, do_raw, do_verbose);
+ res = try_ata_identify(sg_fd, optsp->do_hex, optsp->do_raw,
+ optsp->do_verbose);
if (0 != res) {
fprintf(stderr, "Both SCSI INQUIRY and fetching ATA information "
- "failed on %s\n", file_name);
+ "failed on %s\n", optsp->device_name);
return SG_LIB_CAT_OTHER;
}
#else
- fprintf(stderr, "SCSI INQUIRY failed on %s\n", file_name);
+ fprintf(stderr, "SCSI INQUIRY failed on %s, res=%d\n",
+ optsp->device_name, res);
return res;
#endif
- } else { /* SCSI device not supporting 36 byte INQUIRY?? */
- printf("36 byte INQUIRY failed\n");
+ } else {
+ fprintf(stderr, " inquiry: failed requesting %d byte response: ",
+ rlen);
+ if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, "not supported (?)\n");
+ else if (SG_LIB_CAT_NOT_READY == res)
+ fprintf(stderr, "device not ready (?)\n");
+ else if (SG_LIB_CAT_ILLEGAL_REQ == res)
+ fprintf(stderr, "field in cdb illegal\n");
+ else if (SG_LIB_CAT_UNIT_ATTENTION == res)
+ fprintf(stderr, "unit attention (?)\n");
+ else if (SG_LIB_CAT_ABORTED_COMMAND == res)
+ fprintf(stderr, "aborted command\n");
+ else
+ fprintf(stderr, "res=%d\n", res);
return res;
}
return 0;
}
/* Returns 0 if successful */
-static int process_cmddt(int sg_fd, int do_cmdlst, int num_opcode,
- int do_hex, int do_raw, int do_verbose)
+static int process_cmddt(int sg_fd, const struct opts_t * optsp)
{
int k, j, num, len, peri_type, reserved_cmddt, support_num, res;
char op_name[128];
memset(rsp_buff, 0, DEF_ALLOC_LEN);
- if (do_cmdlst) {
+ if (optsp->do_cmddt > 1) {
printf("Supported command list:\n");
for (k = 0; k < 256; ++k) {
res = sg_ll_inquiry(sg_fd, 1, 0, k, rsp_buff, DEF_ALLOC_LEN,
- 1, do_verbose);
+ 1, optsp->do_verbose);
if (0 == res) {
peri_type = rsp_buff[0] & 0x1f;
support_num = rsp_buff[1] & 7;
@@ -1361,22 +1823,22 @@ static int process_cmddt(int sg_fd, int do_cmdlst, int num_opcode,
}
}
else {
- res = sg_ll_inquiry(sg_fd, 1, 0, num_opcode, rsp_buff,
- DEF_ALLOC_LEN, 1, do_verbose);
+ res = sg_ll_inquiry(sg_fd, 1, 0, optsp->page_num, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
peri_type = rsp_buff[0] & 0x1f;
- if (! do_raw) {
- printf("CmdDt INQUIRY, opcode=0x%.2x: [", num_opcode);
- sg_get_opcode_name((unsigned char)num_opcode, peri_type,
+ if (! optsp->do_raw) {
+ printf("CmdDt INQUIRY, opcode=0x%.2x: [", optsp->page_num);
+ sg_get_opcode_name((unsigned char)optsp->page_num, peri_type,
sizeof(op_name) - 1, op_name);
op_name[sizeof(op_name) - 1] = '\0';
printf("%s]\n", op_name);
}
len = rsp_buff[5] + 6;
reserved_cmddt = rsp_buff[4];
- if (do_hex)
+ if (optsp->do_hex)
dStrHex((const char *)rsp_buff, len, 0);
- else if (do_raw)
+ else if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else {
const char * desc_p;
@@ -1415,36 +1877,35 @@ static int process_cmddt(int sg_fd, int do_cmdlst, int num_opcode,
}
}
else {
- if (! do_raw) {
- printf("CmdDt INQUIRY, opcode=0x%.2x: [", num_opcode);
- sg_get_opcode_name((unsigned char)num_opcode, 0,
+ if (! optsp->do_raw) {
+ printf("CmdDt INQUIRY, opcode=0x%.2x: [", optsp->page_num);
+ sg_get_opcode_name((unsigned char)optsp->page_num, 0,
sizeof(op_name) - 1, op_name);
op_name[sizeof(op_name) - 1] = '\0';
printf("%s]\n", op_name);
}
fprintf(stderr, "CmdDt INQUIRY on opcode=0x%.2x: failed\n",
- num_opcode);
+ optsp->page_num);
}
}
return res;
}
/* Returns 0 if successful */
-static int process_evpd(int sg_fd, int num_opcode, int do_hex,
- int do_raw, int verbose)
+static int process_evpd(int sg_fd, const struct opts_t * optsp)
{
int res, len, num, k, peri_type, vpd;
const char * cp;
char buff[48];
memset(rsp_buff, 0, DEF_ALLOC_LEN);
- if (!do_raw)
- printf("VPD INQUIRY, page code=0x%.2x:\n", num_opcode);
- res = sg_ll_inquiry(sg_fd, 0, 1, num_opcode, rsp_buff, DEF_ALLOC_LEN,
- 1, verbose);
+ if (! optsp->do_raw)
+ printf("VPD INQUIRY, page code=0x%.2x:\n", optsp->page_num);
+ res = sg_ll_inquiry(sg_fd, 0, 1, optsp->page_num, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (num_opcode != rsp_buff[1]) {
+ if (optsp->page_num != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
@@ -1454,16 +1915,16 @@ static int process_evpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, num_opcode, rsp_buff, len, 1,
- verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, optsp->page_num, rsp_buff, len, 1,
+ optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else {
- if (do_hex)
+ if (optsp->do_hex)
dStrHex((const char *)rsp_buff, len, 0);
- else if (0 == num_opcode) { /* decode this mandatory page */
+ else if (0 == optsp->page_num) { /* decode this mandatory page */
peri_type = rsp_buff[0] & 0x1f;
printf(" [PQual=%d Peripheral device type: %s]\n",
(rsp_buff[0] & 0xe0) >> 5,
@@ -1482,35 +1943,45 @@ static int process_evpd(int sg_fd, int num_opcode, int do_hex,
dStrHex((const char *)rsp_buff, len, 0);
}
} else {
- fprintf(stderr,
- "VPD INQUIRY, page code=0x%.2x: failed\n", num_opcode);
+ if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, " inquiry: not supported (?)\n");
+ else if (SG_LIB_CAT_NOT_READY == res)
+ fprintf(stderr, " inquiry: device not ready (?)\n");
+ else if (SG_LIB_CAT_ILLEGAL_REQ == res)
+ fprintf(stderr, " inquiry: field in cdb illegal (page not "
+ "supported)\n");
+ else if (SG_LIB_CAT_UNIT_ATTENTION == res)
+ fprintf(stderr, " inquiry: unit attention (?)\n");
+ else if (SG_LIB_CAT_ABORTED_COMMAND == res)
+ fprintf(stderr, " inquiry: aborted command\n");
+ else
+ fprintf(stderr, " inquiry: failed, res=%d\n", res);
}
return res;
}
/* Returns 0 if successful */
-static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
- int do_raw, int verbose)
+static int decode_vpd(int sg_fd, const struct opts_t * optsp)
{
int len, pdt;
int res = 0;
- switch(num_opcode) {
- case UNIT_SERIAL_NUM_VPD:
- if (! do_raw)
+ switch (optsp->page_num) {
+ case VPD_UNIT_SERIAL_NUM:
+ if (! optsp->do_raw)
printf("VPD INQUIRY: Unit serial number page\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, UNIT_SERIAL_NUM_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_UNIT_SERIAL_NUM, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = rsp_buff[3] + 4;
- if (UNIT_SERIAL_NUM_VPD != rsp_buff[1]) {
+ if (VPD_UNIT_SERIAL_NUM != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
- else if (do_hex)
+ else if (optsp->do_hex)
dStrHex((const char *)rsp_buff, len, 0);
else {
char obuff[DEF_ALLOC_LEN];
@@ -1524,14 +1995,14 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
}
}
break;
- case DEV_ID_VPD:
- if (! do_raw)
+ case VPD_DEVICE_ID:
+ if (! optsp->do_raw)
printf("VPD INQUIRY: Device Identification page\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, DEV_ID_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (DEV_ID_VPD != rsp_buff[1]) {
+ if (VPD_DEVICE_ID != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
@@ -1541,42 +2012,42 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, DEV_ID_VPD, rsp_buff, len,
- 1, verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff, len,
+ 1, optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else
- decode_id_vpd(rsp_buff, len, do_hex);
+ decode_id_vpd(rsp_buff, len, optsp->do_hex);
}
break;
- case SOFTW_INF_ID_VPD:
- if (! do_raw)
+ case VPD_SOFTW_INF_ID:
+ if (! optsp->do_raw)
printf("VPD INQUIRY: Software interface identification page\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, SOFTW_INF_ID_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_SOFTW_INF_ID, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = rsp_buff[3] + 4;
- if (SOFTW_INF_ID_VPD != rsp_buff[1]) {
+ if (VPD_SOFTW_INF_ID != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else
- decode_softw_inf_id(rsp_buff, len, do_hex);
+ decode_softw_inf_id(rsp_buff, len, optsp->do_hex);
}
break;
- case MAN_NET_ADDR_VPD:
- if (!do_raw)
+ case VPD_MAN_NET_ADDR:
+ if (!optsp->do_raw)
printf("VPD INQUIRY: Management network addresses page\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, MAN_NET_ADDR_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_MAN_NET_ADDR, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (MAN_NET_ADDR_VPD != rsp_buff[1]) {
+ if (VPD_MAN_NET_ADDR != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
@@ -1586,24 +2057,24 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, MAN_NET_ADDR_VPD, rsp_buff,
- len, 1, verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_MAN_NET_ADDR, rsp_buff,
+ len, 1, optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else
- decode_net_man_vpd(rsp_buff, len, do_hex);
+ decode_net_man_vpd(rsp_buff, len, optsp->do_hex);
}
break;
- case MODE_PG_POLICY_VPD:
- if (!do_raw)
+ case VPD_MODE_PG_POLICY:
+ if (!optsp->do_raw)
printf("VPD INQUIRY: Mode page policy\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, MODE_PG_POLICY_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_MODE_PG_POLICY, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (MODE_PG_POLICY_VPD != rsp_buff[1]) {
+ if (VPD_MODE_PG_POLICY != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
@@ -1613,24 +2084,24 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, MODE_PG_POLICY_VPD, rsp_buff,
- len, 1, verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_MODE_PG_POLICY, rsp_buff,
+ len, 1, optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else
- decode_mode_policy_vpd(rsp_buff, len, do_hex);
+ decode_mode_policy_vpd(rsp_buff, len, optsp->do_hex);
}
break;
- case X_INQ_VPD:
- if (!do_raw)
+ case VPD_EXT_INQ:
+ if (!optsp->do_raw)
printf("VPD INQUIRY: extended INQUIRY data page\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, X_INQ_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_EXT_INQ, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (X_INQ_VPD != rsp_buff[1]) {
+ if (VPD_EXT_INQ != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
@@ -1640,24 +2111,24 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, X_INQ_VPD, rsp_buff, len,
- 1, verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_EXT_INQ, rsp_buff, len,
+ 1, optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else
- decode_x_inq_vpd(rsp_buff, len, do_hex);
+ decode_x_inq_vpd(rsp_buff, len, optsp->do_hex);
}
break;
- case ATA_INFO_VPD:
- if (!do_raw)
+ case VPD_ATA_INFO:
+ if (!optsp->do_raw)
printf("VPD INQUIRY: ATA information page\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, ATA_INFO_VPD, rsp_buff,
- ATA_INFO_VPD_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_ATA_INFO, rsp_buff,
+ VPD_ATA_INFO_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (ATA_INFO_VPD != rsp_buff[1]) {
+ if (VPD_ATA_INFO != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
@@ -1666,27 +2137,27 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
fprintf(stderr, "response length too long: %d > %d\n", len,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
- } else if (len > ATA_INFO_VPD_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, ATA_INFO_VPD, rsp_buff, len,
- 1, verbose))
+ } else if (len > VPD_ATA_INFO_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_ATA_INFO, rsp_buff, len,
+ 1, optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
/* format output for 'hdparm --Istdin' with '-rr' or '-HHH' */
- if ((2 == do_raw) || (3 == do_hex))
+ if ((2 == optsp->do_raw) || (3 == optsp->do_hex))
dWordHex((const unsigned short *)(rsp_buff + 60),
256, -2, sg_is_big_endian());
- else if (do_raw)
+ else if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else
- decode_ata_info_vpd(rsp_buff, len, do_hex);
+ decode_ata_info_vpd(rsp_buff, len, optsp->do_hex);
}
break;
case 0xb0: /* could be BLOCK LIMITS but need to know pdt to find out */
res = sg_ll_inquiry(sg_fd, 0, 1, 0xb0, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
pdt = rsp_buff[0] & 0x1f;
- if (! do_raw) {
+ if (! optsp->do_raw) {
switch (pdt) {
case 0: case 4: case 7:
printf("VPD INQUIRY: Block limits page (SBC)\n");
@@ -1715,24 +2186,24 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
if (sg_ll_inquiry(sg_fd, 0, 1, 0xb0, rsp_buff,
- len, 1, verbose))
+ len, 1, optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else
- decode_b0_vpd(rsp_buff, len, do_hex, pdt);
- } else if (! do_raw)
+ decode_b0_vpd(rsp_buff, len, optsp->do_hex, pdt);
+ } else if (! optsp->do_raw)
printf("VPD INQUIRY: page=0xb0\n");
break;
- case UPR_EMC_VPD: /* 0xc0 */
- if (!do_raw)
+ case VPD_UPR_EMC: /* 0xc0 */
+ if (!optsp->do_raw)
printf("VPD INQUIRY: Unit Path Report Page (EMC)\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, UPR_EMC_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_UPR_EMC, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = rsp_buff[3] + 4;
- if (UPR_EMC_VPD != rsp_buff[1]) {
+ if (VPD_UPR_EMC != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably not "
"supported\n");
return SG_LIB_CAT_MALFORMED;
@@ -1742,26 +2213,26 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, UPR_EMC_VPD, rsp_buff, len, 1,
- verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_UPR_EMC, rsp_buff, len, 1,
+ optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
- else if (do_hex)
+ else if (optsp->do_hex)
dStrHex((const char *)rsp_buff, len, 1);
else
decode_upr_vpd_c0_emc(rsp_buff, len);
}
break;
- case RDAC_VERS_VPD: /* 0xc2 */
- if (!do_raw)
+ case VPD_RDAC_VERS: /* 0xc2 */
+ if (!optsp->do_raw)
printf("VPD INQUIRY: Software Version (RDAC)\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, RDAC_VERS_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_RDAC_VERS, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = rsp_buff[3] + 4;
- if (RDAC_VERS_VPD != rsp_buff[1]) {
+ if (VPD_RDAC_VERS != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably not "
"supported\n");
return SG_LIB_CAT_MALFORMED;
@@ -1771,26 +2242,26 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, RDAC_VERS_VPD, rsp_buff, len, 1,
- verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_RDAC_VERS, rsp_buff, len, 1,
+ optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
- else if (do_hex)
+ else if (optsp->do_hex)
dStrHex((const char *)rsp_buff, len, 1);
else
decode_rdac_vpd_c2(rsp_buff, len);
}
break;
- case RDAC_VAC_VPD: /* 0xc9 */
- if (!do_raw)
+ case VPD_RDAC_VAC: /* 0xc9 */
+ if (!optsp->do_raw)
printf("VPD INQUIRY: Volume Access Control (RDAC)\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, RDAC_VAC_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_RDAC_VAC, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = rsp_buff[3] + 4;
- if (RDAC_VAC_VPD != rsp_buff[1]) {
+ if (VPD_RDAC_VAC != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably not "
"supported\n");
return SG_LIB_CAT_MALFORMED;
@@ -1800,26 +2271,26 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, RDAC_VAC_VPD, rsp_buff, len, 1,
- verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_RDAC_VAC, rsp_buff, len, 1,
+ optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
- else if (do_hex)
+ else if (optsp->do_hex)
dStrHex((const char *)rsp_buff, len, 1);
else
decode_rdac_vpd_c9(rsp_buff, len);
}
break;
- case SCSI_PORTS_VPD:
- if (!do_raw)
+ case VPD_SCSI_PORTS:
+ if (!optsp->do_raw)
printf("VPD INQUIRY: SCSI Ports page\n");
- res = sg_ll_inquiry(sg_fd, 0, 1, SCSI_PORTS_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, verbose);
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_SCSI_PORTS, rsp_buff,
+ DEF_ALLOC_LEN, 1, optsp->do_verbose);
if (0 == res) {
len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (SCSI_PORTS_VPD != rsp_buff[1]) {
+ if (VPD_SCSI_PORTS != rsp_buff[1]) {
fprintf(stderr, "invalid VPD response; probably a STANDARD "
"INQUIRY response\n");
return SG_LIB_CAT_MALFORMED;
@@ -1829,19 +2300,34 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
MX_ALLOC_LEN);
return SG_LIB_CAT_MALFORMED;
} else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, SCSI_PORTS_VPD, rsp_buff, len,
- 1, verbose))
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_SCSI_PORTS, rsp_buff, len,
+ 1, optsp->do_verbose))
return SG_LIB_CAT_OTHER;
}
- if (do_raw)
+ if (optsp->do_raw)
dStrRaw((const char *)rsp_buff, len);
else
- decode_scsi_ports_vpd(rsp_buff, len, do_hex);
+ decode_scsi_ports_vpd(rsp_buff, len, optsp->do_hex);
}
break;
default:
printf(" Only hex output supported\n");
- return process_evpd(sg_fd, num_opcode, do_hex, do_raw, verbose);
+ return process_evpd(sg_fd, optsp);
+ }
+ if (res) {
+ if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, " inquiry: not supported (?)\n");
+ else if (SG_LIB_CAT_NOT_READY == res)
+ fprintf(stderr, " inquiry: device not ready (?)\n");
+ else if (SG_LIB_CAT_ILLEGAL_REQ == res)
+ fprintf(stderr, " inquiry: field in cdb illegal (page not "
+ "supported)\n");
+ else if (SG_LIB_CAT_UNIT_ATTENTION == res)
+ fprintf(stderr, " inquiry: unit attention (?)\n");
+ else if (SG_LIB_CAT_ABORTED_COMMAND == res)
+ fprintf(stderr, " inquiry: aborted command\n");
+ else
+ fprintf(stderr, " inquiry: failed, res=%d\n", res);
}
return res;
}
@@ -1849,240 +2335,135 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
int main(int argc, char * argv[])
{
- int sg_fd, k, num, plen, jmp_out, res;
- const char * file_name = 0;
- const char * cp;
- unsigned int num_opcode = 0; /* SUPPORTED_VPDS_VPD == 0 */
- int num_opcode_given = 0;
- int p_switch_given = 0;
- int do_ata_device = 0;
- int do_decode = 0;
- int do_evpd = 0;
- int do_cmddt = 0;
- int do_cmdlst = 0;
- int do_hex = 0;
- int do_raw = 0;
- int do_resp_len = 0;
- int do_36 = 0;
- int do_vdescriptors = 0;
- int do_verbose = 0;
- int num_pages = 0;
+ int sg_fd, num, res, n;
+ unsigned int u;
int ret = 0;
+ const struct svpd_values_name_t * vnp;
+ struct opts_t opts;
-
- for (k = 1; k < argc; ++k) {
- cp = argv[k];
- plen = strlen(cp);
- if (plen <= 0)
- continue;
- if ('-' == *cp) {
- for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
- switch (*cp) {
- case '3':
- if ('6' == *(cp + 1)) {
- do_36 = 1;
- --plen;
- ++cp;
- } else
- jmp_out = 1;
- break;
- case 'a':
- num_opcode = ATA_INFO_VPD;
- do_evpd = 1;
- ++num_pages;
- break;
-#ifdef SG3_UTILS_LINUX
- case 'A':
- do_ata_device = 1;
- break;
-#endif
- case 'b':
- num_opcode = BLOCK_LIMITS_VPD;
- do_evpd = 1;
- ++num_pages;
- break;
- case 'c':
- do_cmddt = 1;
- if ('l' == *(cp + 1)) {
- do_cmdlst = 1;
- --plen;
- ++cp;
- }
- break;
- case 'd':
- do_decode = 1;
- break;
- case 'e':
- do_evpd = 1;
- break;
- case 'h':
- case 'H':
- ++do_hex;
- break;
- case 'i':
- num_opcode = DEV_ID_VPD;
- do_evpd = 1;
- ++num_pages;
- break;
- case 'm':
- num_opcode = MAN_NET_ADDR_VPD;
- do_evpd = 1;
- ++num_pages;
- break;
- case 'M':
- num_opcode = MODE_PG_POLICY_VPD;
- do_evpd = 1;
- ++num_pages;
- break;
- case 'P':
- num_opcode = UPR_EMC_VPD;
- do_evpd = 1;
- ++num_pages;
- break;
- case 'r':
- ++do_raw;
- break;
- case 's':
- num_opcode = SCSI_PORTS_VPD;
- do_evpd = 1;
- ++num_pages;
- break;
- case 'v':
- ++do_verbose;
- break;
- case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
- case 'x':
- num_opcode = X_INQ_VPD;
- do_evpd = 1;
- ++num_pages;
- break;
- case '?':
- usage();
- return 0;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
+ memset(&opts, 0, sizeof(opts));
+ opts.page_num = -1;
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ usage_for(&opts);
+ if (opts.do_help > 1) {
+ fprintf(stderr, "/n>>> Available VPD page abbreviations:\n");
+ enumerate_vpds();
+ }
+ return 0;
+ }
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
+ }
+ if (opts.page_arg) {
+ if (opts.page_num >= 0) {
+ fprintf(stderr, "Given '-p' option and another option that "
+ "implies a page\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (isalpha(*opts.page_arg)) {
+ vnp = sdp_find_vpd_by_acron(opts.page_arg);
+ if (NULL == vnp) {
+ if (opts.opt_new)
+ fprintf(stderr, "abbreviation %s given to '--page=' "
+ "not recognized\n", opts.page_arg);
+ else
+ fprintf(stderr, "abbreviation %s given to '-p=' "
+ "not recognized\n", opts.page_arg);
+ fprintf(stderr, ">>> Available abbreviations:\n");
+ enumerate_vpds();
+ return SG_LIB_SYNTAX_ERROR;
}
- if (plen <= 0)
- continue;
- else if (0 == strncmp("l=", cp, 2)) {
- num = sscanf(cp + 2, "%d", &do_resp_len);
- if ((1 != num) || (do_resp_len < 1)) {
- fprintf(stderr, "Inappropriate value after 'l=' "
- "option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- } else if (do_resp_len > MX_ALLOC_LEN) {
- fprintf(stderr, "value after 'l=' "
- "option too large\n");
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == strncmp("o=", cp, 2)) {
- num = sscanf(cp + 2, "%x", &num_opcode);
- if ((1 != num) || (num_opcode > 255)) {
- fprintf(stderr, "Inappropriate value after 'o=' "
- "option\n");
- usage();
+ if ((1 != opts.do_hex) && (0 == opts.do_raw))
+ ++opts.do_decode;
+ opts.page_num = vnp->value;
+ } else {
+ if (opts.opt_new) {
+ n = sg_get_num(opts.page_arg);
+ if ((n < 0) || (n > 255)) {
+ fprintf(stderr, "Bad argument to '--page=', "
+ "expecting 0 to 255 inclusive\n");
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- num_opcode_given = 1;
- ++num_pages;
- } else if (0 == strncmp("p=", cp, 2)) {
- num = sscanf(cp + 2, "%x", &num_opcode);
- if ((1 != num) || (num_opcode > 255)) {
- fprintf(stderr, "Inappropriate value after '-p' "
- "switch\n");
- usage();
+ if ((1 != opts.do_hex) && (0 == opts.do_raw))
+ ++opts.do_decode;
+ } else {
+ num = sscanf(opts.page_arg, "%x", &u);
+ if ((1 != num) || (u > 255)) {
+ fprintf(stderr, "Inappropriate value after '-o=' "
+ "or '-p=' option\n");
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- num_opcode_given = 1;
- p_switch_given = 1;
- ++num_pages;
- } else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n", cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
+ n = u;
}
- } else if (0 == file_name)
- file_name = cp;
- else {
- fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
+ opts.page_num = n;
}
}
- if (do_raw && do_hex) {
+ if ((0 == opts.do_cmddt) && (opts.page_num >= 0) && opts.p_given)
+ ++opts.do_vpd;
+
+ if (opts.do_raw && opts.do_hex) {
fprintf(stderr, "Can't do hex and raw at the same time\n");
- usage();
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- if (do_evpd && do_cmddt) {
- fprintf(stderr, "Can't have both '-e' and '-c' (or '-cl')\n");
- usage();
+ if (opts.do_vpd && opts.do_cmddt) {
+ if (opts.opt_new)
+ fprintf(stderr, "Can't use '--cmddt' with VPD pages\n");
+ else
+ fprintf(stderr, "Can't have both '-e' and '-c' (or '-cl')\n");
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- if (num_pages > 1) {
+ if (opts.num_pages > 1) {
fprintf(stderr, "Can only fetch one page (VPD or Cmd) at a time\n");
- usage();
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- if (do_decode) {
- if (num_pages)
- num_opcode_given = 0;
- else {
- do_vdescriptors = 1;
- if (do_36) {
- fprintf(stderr, "version descriptors need > 36 byte "
- "INQUIRY\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- if (do_cmddt || do_evpd) {
- fprintf(stderr, "version descriptors require standard"
- "INQUIRY\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
+ if (opts.do_descriptors) {
+ if ((opts.resp_len > 0) && (opts.resp_len < 60)) {
+ fprintf(stderr, "version descriptors need INQUIRY response "
+ "length >= 60 bytes\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_vpd || opts.do_cmddt) {
+ fprintf(stderr, "version descriptors require standard INQUIRY\n");
+ return SG_LIB_SYNTAX_ERROR;
}
}
- if (num_pages && do_ata_device) {
+ if (opts.num_pages && opts.do_ata) {
fprintf(stderr, "Can't use '-A' with an explicit decode VPD "
"page option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- if (0 == file_name) {
- fprintf(stderr, "No <device> argument given\n");
- usage();
return SG_LIB_SYNTAX_ERROR;
}
- if (num_pages && (! do_cmddt) && (! do_evpd)) {
- do_evpd = 1; /* '-o=' and '-p=' implies '-e' unless overridden */
- if (! (do_raw || p_switch_given))
- printf(" <<given page_code so assumed EVPD selected>>\n");
+ if (0 == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ usage_for(&opts);
+ return SG_LIB_SYNTAX_ERROR;
}
- if ((sg_fd = sg_cmds_open_device(file_name, 1 /* ro */, do_verbose)) < 0) {
+ if ((sg_fd = sg_cmds_open_device(opts.device_name, 1 /* ro */,
+ opts.do_verbose)) < 0) {
fprintf(stderr, "sg_inq: error opening file: %s: %s\n",
- file_name, safe_strerror(-sg_fd));
+ opts.device_name, safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- memset(rsp_buff, 0, MX_ALLOC_LEN + 1);
+ memset(rsp_buff, 0, sizeof(rsp_buff));
#ifdef SG3_UTILS_LINUX
- if (do_ata_device) {
- res = try_ata_identify(sg_fd, do_hex, do_raw, do_verbose);
+ if (opts.do_ata) {
+ res = try_ata_identify(sg_fd, opts.do_hex, opts.do_raw,
+ opts.do_verbose);
if (0 != res) {
fprintf(stderr, "fetching ATA information failed on %s\n",
- file_name);
+ opts.device_name);
ret = SG_LIB_CAT_OTHER;
} else
ret = 0;
@@ -2090,24 +2471,24 @@ int main(int argc, char * argv[])
}
#endif
- if ((! do_cmddt) && (! do_evpd)) {
+ if ((! opts.do_cmddt) && (! opts.do_vpd)) {
/* So it's a Standard INQUIRY, try ATA IDENTIFY if that fails */
- ret = process_std_inq(sg_fd, file_name, do_36, do_resp_len,
- do_vdescriptors, do_hex, do_raw, do_verbose);
+ ret = process_std_inq(sg_fd, &opts);
if (ret)
goto err_out;
- } else if (do_cmddt) {
- ret = process_cmddt(sg_fd, do_cmdlst, num_opcode, do_hex, do_raw,
- do_verbose);
+ } else if (opts.do_cmddt) {
+ if (opts.page_num < 0)
+ opts.page_num = 0;
+ ret = process_cmddt(sg_fd, &opts);
if (ret)
goto err_out;
- } else if (do_evpd) {
- if (num_opcode_given) {
- ret = process_evpd(sg_fd, num_opcode, do_hex, do_raw, do_verbose);
+ } else if (opts.do_vpd) {
+ if (opts.do_decode) {
+ ret = decode_vpd(sg_fd, &opts);
if (ret)
goto err_out;
} else {
- ret = decode_vpd(sg_fd, num_opcode, do_hex, do_raw, do_verbose);
+ ret = process_evpd(sg_fd, &opts);
if (ret)
goto err_out;
}
@@ -2310,6 +2691,7 @@ static struct version_descriptor version_descriptor_arr[] = {
{0x54, "SAM-2 T10/1157-D revision 23"},
{0x55, "SAM-2 T10/1157-D revision 24"},
{0x5c, "SAM-2 ANSI INCITS 366-2003"},
+ {0x5e, "SAM-2 ISO/IEC 14776-412"},
{0x60, "SAM-3 (no version claimed)"},
{0x62, "SAM-3 T10/1561-D revision 7"},
{0x75, "SAM-3 T10/1561-D revision 13"},
@@ -2407,6 +2789,7 @@ static struct version_descriptor version_descriptor_arr[] = {
{0x420, "MMC-5 (no version claimed)"},
{0x42f, "MMC-5 T10/1675-D revision 03"},
{0x431, "MMC-5 T10/1675-D revision 03b"},
+ {0x432, "MMC-5 T10/1675-D revision 04"},
{0x440, "OSD-2 (no version claimed)"},
{0x460, "SPC-4 (no version claimed)"},
{0x480, "SMC-3 (no version claimed)"},
@@ -2514,6 +2897,8 @@ static struct version_descriptor version_descriptor_arr[] = {
{0xd5c, "FC-AL ANSI INCITS 272-1996"},
{0xd60, "FC-AL-2 (no version claimed)"},
{0xd61, "FC-AL-2 T11/1133-D revision 7.0"},
+ {0xd63, "FC-AL-2 ANSI INCITS 332-1999 with AM1-2003 & AM2-2006"},
+ {0xd64, "FC-AL-2 ANSI INCITS 332-1999 with Amnd 2 AM2-2006"},
{0xd7c, "FC-AL-2 ANSI INCITS 332-1999"},
{0xd7d, "FC-AL-2 ANSI INCITS 332-1999 with Amnd 1 AM1:2002"},
{0xd80, "FC-PH-3 (no version claimed)"},
@@ -2530,6 +2915,11 @@ static struct version_descriptor version_descriptor_arr[] = {
{0xe20, "FC-LS (no version claimed)"},
{0xe40, "FC-SP (no version claimed)"},
{0xe42, "FC-SP T11/1570-D revision 1.6"},
+ {0xe60, "FC-PI-3 (no version claimed)"},
+ {0xe80, "FC-PI-4 (no version claimed)"},
+ {0xea0, "FC 10GFC (no version claimed)"},
+ {0xea2, "FC 10GFC ANSI INCITS 364-2003"},
+ {0xea3, "FC 10GFC ISO/IEC 14165-116"},
{0x12e0, "FC-DA (no version claimed)"},
{0x12e2, "FC-DA T11/1513-DT revision 3.1"},
{0x1300, "FC-Tape (no version claimed)"},
diff --git a/sg_io_linux.h b/sg_io_linux.h
index 8f97c951..30047c11 100644
--- a/sg_io_linux.h
+++ b/sg_io_linux.h
@@ -31,7 +31,7 @@
*/
/*
- * Version 1.01 [20060621]
+ * Version 1.02 [20070121]
*/
/*
@@ -43,6 +43,9 @@
#include "sg_lib.h"
#include "sg_linux_inc.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
/* The following are 'host_status' codes */
#ifndef DID_OK
@@ -180,4 +183,8 @@ extern int sg_err_category3(struct sg_io_hdr * hp);
version of SCSI standard status codes. Now CHECK_CONDITION
and friends (in <scsi/scsi.h>) are deprecated. */
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/sg_lib.c b/sg_lib.c
index a315153c..0dac2f4d 100644
--- a/sg_lib.c
+++ b/sg_lib.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2006 Douglas Gilbert.
+ * Copyright (c) 1999-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -65,10 +65,13 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
#include "sg_lib.h"
-static char * version_str = "1.26 20061015"; /* spc-4 rev 7a */
+static char * version_str = "1.32 20070129"; /* spc-4 rev 8 */
FILE * sg_warnings_strm = NULL; /* would like to default to stderr */
@@ -206,6 +209,7 @@ static const struct value_name_t normal_opcodes[] = {
{0x87, 0, "Access control out"},
{0x88, 0, "Read(16)"},
{0x8a, 0, "Write(16)"},
+ {0x8b, 0, "Orwrite(16)"},
{0x8c, 0, "Read attribute"},
{0x8d, 0, "Write attribute"},
{0x8e, 0, "Write and verify(16)"},
@@ -281,6 +285,7 @@ static const struct value_name_t maint_in_arr[] = {
{0xd, 0, "Report supported task management functions"},
{0xe, 0, "Report priority"},
{0xf, 0, "Report timestamp"},
+ {0x10, 0, "Maintenance in"},
};
#define MAINT_IN_SZ \
@@ -293,6 +298,7 @@ static const struct value_name_t maint_out_arr[] = {
{0xb, 0, "Change aliases"},
{0xe, 0, "Set priority"},
{0xf, 0, "Set timestamp"},
+ {0x10, 0, "Maintenance out"},
};
#define MAINT_OUT_SZ \
@@ -435,8 +441,8 @@ void sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff)
case 0x2: ccp = "Check Condition"; break;
case 0x4: ccp = "Condition Met"; break;
case 0x8: ccp = "Busy"; break;
- case 0x10: ccp = "Intermediate"; break;
- case 0x14: ccp = "Intermediate-Condition Met"; break;
+ case 0x10: ccp = "Intermediate (obsolete)"; break;
+ case 0x14: ccp = "Intermediate-Condition Met (obs)"; break;
case 0x18: ccp = "Reservation Conflict"; break;
case 0x22: ccp = "Command Terminated (obsolete)"; break;
case 0x28: ccp = "Task set Full"; break;
@@ -1520,7 +1526,7 @@ void sg_get_sense_str(const char * leadin,
--buff_len;
n = 0;
if (sb_len < 1) {
- snprintf(buff, n, "sense buffer empty\n");
+ snprintf(buff, buff_len, "sense buffer empty\n");
return;
}
if (leadin) {
@@ -2307,13 +2313,13 @@ long long sg_get_llnum(const char * buf)
return -1LL;
len = strlen(buf);
if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
- res = sscanf(buf + 2, "%llx", &unum);
+ res = sscanf(buf + 2, "%" SCNx64 "", &unum);
num = unum;
} else if ('H' == toupper(buf[len - 1])) {
- res = sscanf(buf, "%llx", &unum);
+ res = sscanf(buf, "%" SCNx64 "", &unum);
num = unum;
} else
- res = sscanf(buf, "%lld%c%c%c", &num, &c, &c2, &c3);
+ res = sscanf(buf, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3);
if (res < 1)
return -1LL;
else if (1 == res)
diff --git a/sg_lib.h b/sg_lib.h
index 87316967..c650c885 100644
--- a/sg_lib.h
+++ b/sg_lib.h
@@ -2,7 +2,7 @@
#define SG_LIB_H
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
*
*/
-/* Version 1.26 [20051015]
+/* Version 1.32 [20070129]
*
* On 5th October 2004 a FreeBSD license was added to this file.
* The intention is to keep this file and the related sg_lib.c file
@@ -51,14 +51,18 @@
#include <stdio.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef SAM_STAT_GOOD
/* The SCSI status codes as found in SAM-4 at www.t10.org */
#define SAM_STAT_GOOD 0x0
#define SAM_STAT_CHECK_CONDITION 0x2
#define SAM_STAT_CONDITION_MET 0x4
#define SAM_STAT_BUSY 0x8
-#define SAM_STAT_INTERMEDIATE 0x10
-#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
+#define SAM_STAT_INTERMEDIATE 0x10 /* obsolete in SAM-4 */
+#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14 /* obsolete in SAM-4 */
#define SAM_STAT_RESERVATION_CONFLICT 0x18
#define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */
#define SAM_STAT_TASK_SET_FULL 0x28
@@ -296,5 +300,8 @@ extern long long sg_get_llnum(const char * buf);
extern const char * sg_lib_version();
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/sg_logs.8 b/sg_logs.8
index 39f36a65..2e4abd45 100644
--- a/sg_logs.8
+++ b/sg_logs.8
@@ -1,143 +1,154 @@
-.TH SG_LOGS "8" "September 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_LOGS "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_logs \- access SCSI device log pages
+sg_logs \- access log pages with SCSI LOG SENSE command
.SH SYNOPSIS
.B sg_logs
-[\fI-a\fR] [\fI-A\fR] [\fI-c=<page_control>\fR] [\fI-h\fR] [\fI-H\fR]
-[\fI-l\fR] [\fI-L\fR] [\fI-m=<max_len>\fR]
-[\fI-p=<page_code>[,<subpage_code]\fR] [\fI-paramp=<parameter_pointer>\fR]
-[\fI-pcb\fR] [\fI-ppc\fR] [\fI-r\fR] [\fI-select\fR] [\fI-sp\fR] [\fI-t\fR]
-[\fI-T\fR] [\fI-v\fR] [\fI-V\fR] [\fI-?\fR] \fI<scsi_device>\fR
+[\fI\-\-all\fR] [\fI\-\-control=PC\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR]
+[\fI\-\-list\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-name\fR]
+[\fI\-\-page=PG[,SPG]\fR] [\fI\-\-paramp=PP\fR] [\fI\-\-pcb\fR]
+[\fI\-\-ppc\fR] [\fI\-\-raw\fR] [\fI\-\-reset\fR] [\fI\-\-select\fR]
+[\fI\-\-sp\fR] [\fI\-\-temperature\fR] [\fI\-\-transport\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.PP
+.B sg_logs
+[\fI\-a\fR] [\fI\-A\fR] [\fI\-c=PC\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-l\fR]
+[\fI\-L\fR] [\fI\-m=LEN\fR] [\fI\-n\fR] [\fI\-p=PG[,SPG]\fR]
+[\fI\-paramp=PP\fR] [\fI\-pcb\fR] [\fI\-ppc\fR] [\fI\-r\fR] [\fI\-select\fR]
+[\fI\-sp\fR] [\fI\-t\fR] [\fI\-T\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-This utility sends a LOG SENSE SCSI command to the given device and then
-outputs the response. The LOG SENSE command is used to fetch log pages.
-Known log pages are decoded and output in ASCII, or output in hex. When
-the '-r' and/or '-select' option is given then a LOG SELECT SCSI command
-is issued to reset parameters.
+This utility sends a SCSI LOG SENSE command to the \fIDEVICE\fR and then
+outputs the response. The LOG SENSE command is used to fetch log pages. Known
+log pages are decoded by default. When the \fI\-\-reset\fR and/or
+\fI\-\-select\fR option is given then a SCSI LOG SELECT command is issued to
+reset parameters.
.PP
-In SPC-4 revision 5 a subpage code was introduced to both the LOG
-SENSE and LOG SELECT command. At the same time a page code field was
-introduced to the to the LOG SELECT command. The log subpage code
-can range from 0 to ff (255) inclusive. The subpage code value 'ff'
-can be thought of as a wildcard.
+In SPC\-4 revision 5 a subpage code was introduced to both the LOG SENSE and
+LOG SELECT command. At the same time a page code field was introduced to the
+to the LOG SELECT command. The log subpage code can range from 0 to 255 (0xff)
+inclusive. The subpage code value 255 can be thought of as a wildcard.
.PP
-Options with arguments or with two or more letters can have an extra '-'
-prepended. For example: both '-pcb' and '--pcb' are acceptable.
-.TP
--a
-outputs all the log pages supported by the device. This requires
-a two stage process: first the supported log pages log page is
-fetched, then for each entry in the response, the corresponding
-log page is fetched and displayed.
-.TP
--A
-outputs all the log pages and subpages supported by the device. This
-requires a two stage process: first the supported log pages and subpages
-log page is fetched, then for each entry in the response, the corresponding
-log page is fetched and displayed.
-.TP
--c=page_control
-accepts 0, 1, 2 or 3 as an argument. 0 for current threshold values,
-1 for current cumulative values, 2 for default threshold values and 3
-for default cumulative values. The default is 1 (i.e. current threshold
+This utility supports two command line syntaxes, the preferred one is shown
+first in the synopsis and explained in this section. A later section on the
+old command line syntax outlines the second group of options.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-a\fR, \fB\-\-all\fR
+outputs all the log pages supported by the device. This requires a two stage
+process: first the "supported log pages" log page is fetched, then for each
+entry in the response, the corresponding log page is fetched and displayed.
+When used twice (e.g. '-aa') all log pages and subpages are fetched.
+.TP
+\fB\-c\fR, \fB\-\-control\fR=\fIPC\fR
+accepts 0, 1, 2 or 3 for the \fIPC\fR argument. 0 for current threshold
+values, 1 for current cumulative values, 2 for default threshold values and
+3 for default cumulative values. The default is 1 (i.e. current threshold
values).
.TP
--h
-suppresses decoding of known log sense pages and prints out the
-response in hex instead.
+\fB\-h\fR, \fB\-\-help\fR
+print out the usage message then exit.
.TP
--H
-same action as '-h'.
+\fB\-H\fR, \fB\-\-hex\fR
+The default action is to decode known mode page numbers (and subpage numbers)
+into text. When this option is used once, the response is output in
+hexadecimal.
.TP
--l
-lists the names of all logs sense pages supported by this device.
-This is done bt reading the "supported log pages" log page. See the
-list of common log page codes below.
+\fB\-l\fR, \fB\-\-list\fR
+lists the names of all logs sense pages supported by this device. This is
+done by reading the "supported log pages" log page. When used
+twice (e.g. '-ll') lists the names of all logs sense pages and subpages
+supported by this device. There is a list of common log page codes below.
.TP
--L
-lists the names of all logs sense pages and subpages supported by this
-device. See the list of common log page codes below.
+\fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR
+sets the "allocation length" field in the LOG SENSE cdb. The is the maximum
+length in bytes that the response will be. Without this option (or \fILEN\fR
+equal to 0) this utility first fetches the 4 byte response then does a second
+access with the length indicated in the first (4 byte) response. Responses
+can be quite large (e.g. the background scan results log page) and this
+option can be used to limit the amount of information returned.
.TP
--m=<max_len>
-request only <max_len> bytes of response data. Default is 0 which is
-interpreted as all that is available. <max_len> is decimal unless it
-has a lleading '0x' or trailing 'h'. Useful for seeing earlier
-parameters in large logs.
+\fB\-n\fR, \fB\-\-name\fR
+decode some log pages into 'name=value' entries, one per line. The name
+contains no space and may be abbreviated and the value is decimal unless
+prefixed by '0x'. Nesting is indicated by leading spaces. This form
+is meant to be relatively easy to parse.
.TP
--p=<page_code>
-log page code to access. Should be a hexadecimal number between 0 and 3f
-inclusive. Commonly accessed log pages are listed below.
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
.TP
--p=<page_code>,<subpage_code>
-log page code and subpage code to access. The page code should be a
-hexadecimal number between 0 and 3f inclusive. The subpage code should be
-a hexadecimal number between 0 and ff inclusive. The subpage code of 'ff'
-can be thought of as a wildcard.
+\fB\-p\fR, \fB\-\-page\fR=\fIPG[,SPG]\fR
+log page code to access. \fIPG\fR is expected to be a decimal number between
+0 and 63 inclusive. A hexadecimal number can be specified by a leading "0x"
+or a trailing "h". Common log page codes are listed below. Optionally
+\fISPG\fR, a subpage code, can be given. \fISPG\fR is expected to be a
+decimal number between 0 and 255 inclusive.
.TP
--paramp=<parameter_pointer>
-parameter pointer value (in hex) to place in command. Should be a number
-between 0 and ffff inclusive.
+\fB\-P\fR, \fB\-\-paramp\fR=\fIPP\fR
+\fIPP\fR is the parameter pointer value to place in a field of that name in
+the LOG SENSE cdb. A decimal number in the range 0 to 65535 (0xffff) is
+expected. When a value greater than 0 is given the \fI\-\-ppc\fR option
+should be selected. The default value is 0.
.TP
--pcb
+\fB\-q\fR, \fB\-\-pcb\fR
show Parameter Control Byte settings (only relevant when log parameters
being output in ASCII).
.TP
--ppc
-sets the Parameter Pointer Control (PPC) bit. Default is 0 (i.e. cleared).
+\fB\-Q\fR, \fB\-\-ppc\fR
+sets the Parameter Pointer Control (PPC) bit in the LOG SENSE cdb. Default
+is 0 (i.e. cleared).
.TP
--r
-use LOG SELECT SCSI command (PCR bit set) to reset the all log pages (or
-the given page). [SPC-4 (rev 6) doesn't say that a given log (sub)page can
+\fB\-r\fR, \fB\-\-raw\fR
+output the response in binary to stdout. Error messages and warnings are
+output to stderr.
+.TP
+\fB\-R\fR, \fB\-\-reset\fR
+use SCSI LOG SELECT command (PCR bit set) to reset the all log pages (or
+the given page). [SPC\-4 (rev 6) doesn't say that a given log (sub)page can
be reset yet.] Exactly what is reset depends on the accompanying SP
-bit (i.e. '-sp' option which defaults to 0) and the PC ("page control")
-value (i.e. argument to '-c=' which defaults to 1). Supplying this option
-implies the '-select' option as well.
-This option seems to clear error counter log pages but leaves pages like
-self-test results, start-stop cycle counter and temperature log pages
-unaffected. This option may be required to clear log pages if a counter
-reaches its maximum value since the log page in which the counter is found
-will remain "stuck" until something is done.
-.TP
--select
+bit (i.e. \fI\-\-sp\fR option which defaults to 0) and the
+\fIPC\fR ("page control") value (which defaults to 1). Supplying this option
+implies the \fI\-\-select\fR option as well. This option seems to clear error
+counter log pages but leaves pages like self\-test results, start\-stop cycle
+counter and temperature log pages unaffected. This option may be required to
+clear log pages if a counter reaches its maximum value since the log page in
+which the counter is found will remain "stuck" until something is done.
+.TP
+\fB\-S\fR, \fB\-\-select\fR
use a LOG SELECT command. The default action (i.e. when neither this option
-not '-r' is given) is to do a LOG SENSE command. When this option is given,
-the SP bit (i.e. '-sp' option which defaults to 0), the PC ("page control")
-value (i.e. argument to '-c=' which defaults to 1) and the PCR
-bit (i.e. '-r' option which defaults to 0) are placed in the command
-block ("cdb") sent to the device. At some stage the log page and subpage
-option may also be active [but SPC-4 (rev 6) doesn't say that].
-.TP
--sp
-sets the Saving Parameters (SP) bit. Default is 0 (i.e. cleared). When
-set this instructs the device to store the current log page
-parameters (as indicated by the DS and TSD parameter codes) in some
-non-volatile location. Hence the log parameters will be preserved
-across power cycles. This option is typically not needed, especially
-if the GLTSD flag is clear in the control mode page as this instructs
-the device to periodically save all saveable log parameters to
-non-volatile locations.
-.TP
--t
+nor \fI\-\-reset\fR is given) is to do a LOG SENSE command. When this option
+is given, the SP bit (i.e. \fI\-\-sp\fR option which defaults to 0), the
+\fIPC\fR ("page control") value (which defaults to 1) and the PCR bit (i.e.
+\fI\-\-reset\fR option which defaults to 0) are placed in the LOG SELECT
+cdb. At some stage the log page and subpage options may also be active [but
+SPC\-4 (rev 6) doesn't say that].
+.TP
+\fB\-s\fR, \fB\-\-sp\fR
+sets the Saving Parameters (SP) bit. Default is 0 (i.e. cleared). When set
+this instructs the device to store the current log page parameters (as
+indicated by the DS and TSD parameter codes) in some non\-volatile location.
+Hence the log parameters will be preserved across power cycles. This option
+is typically not needed, especially if the GLTSD flag is clear in the
+control mode page as this instructs the device to periodically save all
+saveable log parameters to non\-volatile locations.
+.TP
+\fB\-t\fR, \fB\-\-temperature\fR
outputs the temperature. First looks in the temperature log page and if
-that is not available tries the Informational Exceptions page which may also
-have the current temperature (especially in older disks).
+that is not available tries the Informational Exceptions log page which
+may also have the current temperature (especially on older disks).
.TP
--T
+\fB\-T\fR, \fB\-\-transport\fR
outputs the transport ('Protocol specific port') log page. Equivalent
-to setting '-p=18'.
-.TP
--v
-verbose: show SCSI command blocks prior to execution. '-vv'
-and '-vvv' are also accepted yielding greater verbosity.
+to setting '\-\-page=18h'.
.TP
--V
-print out version string
+\fB\-v\fR, \fB\-\-verbose\fR
+increase level of verbosity.
.TP
--?
-output usage message. Ignore all other parameters.
-.PP
+\fB\-V\fR, \fB\-\-version\fR
+print out version string then exit.
+.SH NOTES
Various log pages hold information error rates, device temperature,
start stop cycles since device produced and the results of the last
20 self tests. Self tests can be initiated by the sg_senddiag utility.
@@ -145,8 +156,9 @@ The smartmontools package provides much of the information found with
sg_logs in a form suitable for monitoring the health of SCSI disks and
tape drives.
.PP
-Here is a list of log pages that are decoded by this utility. [The "0x"
-prefix amy be dropped when using them as an argument to the '-p=' option]:
+Here is a list of log pages that are decoded by this utility. [The code
+values can be given to '\-\-page=' as is, with a trailing "h" instead of
+the leading "0x", or as their decimal equivalents.]:
.PP
0x0 Supported log pages
.br
@@ -162,25 +174,25 @@ prefix amy be dropped when using them as an argument to the '-p=' option]:
.br
0x5 Verify error counter
.br
-0x6 Non-medium error
+0x6 Non\-medium error
.br
0x7 Last n error events
.br
-0x8 Format status (sbc-2)
+0x8 Format status (sbc\-2)
.br
0xb Last n deferred errors or asynchronous events
.br
-0xc Sequential access device (ssc-2)
+0xc Sequential access device (ssc\-2)
.br
0xd Temperature
.br
-0xe Start-stop cycle counter
+0xe Start\-stop cycle counter
.br
-0x10 Self-test results
+0x10 Self\-test results
.br
-0x15 Background scan results (sbc-3)
+0x15 Background scan results (sbc\-3)
.br
-0x17 Non-volatile cache (sbc-3)
+0x17 Non\-volatile cache (sbc\-3)
.br
0x18 Protocol specific port (SAS transport)
.br
@@ -190,21 +202,114 @@ prefix amy be dropped when using them as an argument to the '-p=' option]:
.br
0x3e Seagate factory (vendor, disk)
.PP
-In the 2.4 series of Linux kernels the given device must be
-a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example "sg_logs -a /dev/sda"
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI
+generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks
+and DVD drives) can also be specified. For example "sg_logs \-a /dev/sda"
will work in the 2.6 series kernels.
.SH EXIT STATUS
-The exit status of sg_logs is 0 when it is successful. Otherwise see
+The exit status of sg_modes is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using '\-\-old' (or '\-O) as the first option.
+.PP
+Options with arguments or with two or more letters can have an extra '\-'
+prepended. For example: both '\-pcb' and '\-\-pcb' are acceptable.
+.TP
+\fB\-a\fR
+outputs all the log pages supported by the device.
+Equivalent to \fI\-\-all\fR in the main description.
+.TP
+\fB\-A\fR
+outputs all the log pages and subpages supported by the device.
+Equivalent to '\-\-all \-\-all' in the main description.
+.TP
+\fB\-c\fR=\fIPC\fR
+Equivalent to \fI\-\-control=PC\fR in the main description.
+.TP
+\fB\-h\fR
+suppresses decoding of known log sense pages and prints out the
+response in hex instead.
+.TP
+\fB\-H\fR
+same action as '\-h' in this section and equivalent to \fI\-\-hex\fR in
+the main description.
+.TP
+\fB\-l\fR
+lists the names of all logs sense pages supported by this device.
+Equivalent to \fI\-\-list\fR in the main description.
+.TP
+\fB\-L\fR
+lists the names of all logs sense pages and subpages supported by this
+device. Equivalent to '\-\-list \-\-list' in the main description.
+.TP
+\fB\-m\fR=\fILEN\fR
+request only \fILEN\fR bytes of response data. Default is 0 which is
+interpreted as all that is available. \fILEN\fR is decimal unless it has
+a leading '0x' or trailing 'h'. Equivalent to \fI\-\-maxlen=LEN\fR in
+the main description.
+.TP
+\fB\-n\fR
+Equivalent to \fI\-\-name\fR in the main description.
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-p\fR=\fIPG[,SPG]\fR
+\fIPG\fR is the log page code to access. Should be a hexadecimal number
+between 0 and 3f inclusive. If given \fISPG\fR is the log subpage code.
+\fISPG\fR should be a hexadecimal number between 0 and ff inclusive. The
+subpage code of 'ff' can be thought of as a wildcard.
+.TP
+\fB\-paramp\fR=\fIPP\fR
+\fIPP\fR is the parameter pointer value (in hex) to place in command.
+Should be a number between 0 and ffff inclusive.
+.TP
+\fB\-pcb\fR
+show Parameter Control Byte settings (only relevant when log parameters
+being output in ASCII).
+.TP
+\fB\-ppc\fR
+sets the Parameter Pointer Control (PPC) bit. Default is 0 (i.e. cleared).
+.TP
+\fB\-r\fR
+use SCSI LOG SELECT command (PCR bit set) to reset the all log pages (or
+the given page). Equivalent to \fI\-\-reset\fR in the main description.
+.TP
+\fB\-select\fR
+use a LOG SELECT command. Equivalent to \fI\-\-select\fR in the main
+description.
+.TP
+\fB\-sp\fR
+sets the Saving Parameters (SP) bit. Default is 0 (i.e. cleared).
+Equivalent to \fI\-\-sp\fR in the main description.
+.TP
+\fB\-t\fR
+outputs the temperature. Equivalent to \fI\-\-temperature in the main
+description.
+.TP
+\fB\-T\fR
+outputs the transport ('Protocol specific port') log page. Equivalent
+to \fI\-\-transport\fR in the main description.
+.TP
+\fB\-v\fR
+increase level of verbosity.
+.TP
+\fB\-V\fR
+print out version string then exit.
+.TP
+\fB\-?\fR
+output usage message then exit.
.SH AUTHOR
Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2002-2006 Douglas Gilbert
+Copyright \(co 2002\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B smartctl(smartmontools: see net), sg_senddiag(sg3_utils)
+.B smartctl(smartmontools), sg_senddiag(sg3_utils)
diff --git a/sg_logs.c b/sg_logs.c
index abaa2ad9..88c93168 100644
--- a/sg_logs.c
+++ b/sg_logs.c
@@ -4,12 +4,15 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
-/* A utility program for the Linux OS SCSI generic ("sg") device driver.
-* Copyright (C) 2000-2006 D. Gilbert
+/* A utility program originally written for the Linux OS SCSI subsystem.
+* Copyright (C) 2000-2007 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)
@@ -19,36 +22,556 @@
*/
-static char * version_str = "0.65 20061012"; /* SPC-4 revision 7a */
+static char * version_str = "0.69 20070129"; /* SPC-4 revision 8 */
-#define ME "sg_logs: "
-
-#define MX_ALLOC_LEN (0xfffe)
+#define MX_ALLOC_LEN (0xfffc)
#define SHORT_RESP_LEN 128
-#define PG_CODE_ALL 0x0
-#define SUBPG_CODE_ALL 0xff
+
+#define ALL_PAGE_LPAGE 0x0
+#define BUFF_OVER_UNDER_LPAGE 0x1
+#define WRITE_ERR_LPAGE 0x2
+#define READ_ERR_LPAGE 0x3
+#define READ_REV_ERR_LPAGE 0x4
+#define VERIFY_ERR_LPAGE 0x5
+#define NON_MEDIUM_LPAGE 0x6
+#define LAST_N_ERR_LPAGE 0x7
+#define LAST_N_DEFERRED_LPAGE 0xb
+#define TEMPERATURE_LPAGE 0xd
+#define START_STOP_LPAGE 0xe
+#define APP_CLIENT_LPAGE 0xf
+#define SELF_TEST_LPAGE 0x10
+#define PORT_SPECIFIC_LPAGE 0x18
+#define GSP_LPAGE 0x19
+#define IE_LPAGE 0x2f
+#define NOT_SUBPG_LOG 0x0
+#define ALL_SUBPG_LOG 0xff
#define PCB_STR_LEN 128
+static unsigned char rsp_buff[MX_ALLOC_LEN];
+
+static struct option long_options[] = {
+ {"all", 0, 0, 'a'},
+ {"control", 1, 0, 'c'},
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"list", 0, 0, 'l'},
+ {"maxlen", 1, 0, 'm'},
+ {"name", 0, 0, 'n'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"page", 1, 0, 'p'},
+ {"paramp", 1, 0, 'P'},
+ {"pcb", 0, 0, 'q'},
+ {"ppc", 0, 0, 'Q'},
+ {"raw", 0, 0, 'r'},
+ {"reset", 0, 0, 'R'},
+ {"sp", 0, 0, 's'},
+ {"select", 0, 0, 'S'},
+ {"temperature", 0, 0, 't'},
+ {"transport", 0, 0, 'T'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+struct opts_t {
+ int do_all;
+ int do_help;
+ int do_hex;
+ int do_list;
+ int do_name;
+ int do_pcb;
+ int do_ppc;
+ int do_raw;
+ int do_pcreset;
+ int do_select;
+ int do_sp;
+ int do_temperature;
+ int do_transport;
+ int do_verbose;
+ int do_version;
+ int page_control;
+ int maxlen;
+ int pg_code;
+ int subpg_code;
+ int paramp;
+ const char * device_name;
+ int opt_new;
+};
+
+static void usage()
+{
+ printf("Usage: sg_logs [--all] [--control=PC] [--help] [--hex] "
+ "[--list] [--maxlen=LEN]\n"
+ " [--name] [--page=PG[,SPG]] [--paramp=PP] [--pcb] "
+ "[--ppc]\n"
+ " [--raw] [--reset] [--select] [--sp] "
+ "[--temperature]\n"
+ " [--transport] [--verbose] [--version] DEVICE\n"
+ " where:\n"
+ " --all|-a fetch and decode all log pages\n"
+ " use twice to fetch and decode all log pages "
+ "and subpages\n"
+ " --control=PC|-c PC page control(PC) (default: 1)\n"
+ " 0: current threshhold, 1: current "
+ "cumulative\n"
+ " 2: default threshhold, 3: default "
+ "cumulative\n"
+ " --help|-h print usage message then exit\n"
+ " --hex|-H output response in hex (default: decode if "
+ "known)\n"
+ " --list|-l list supported log page names (equivalent to "
+ "'-p 0')\n"
+ " use twice to list supported log page and "
+ "subpage names\n"
+ " --maxlen=LEN|-m LEN max response length (def: 0 "
+ "-> everything)\n"
+ " --name|-n decode some pages into multiple name=value "
+ "lines\n"
+ " --page=PG|-p PG page code (in decimal)\n"
+ " --page=PG,SPG|-p PG,SPG\n"
+ " page code plus subpage code (both default "
+ "to 0)\n"
+ " --paramp=PP|-P PP parameter pointer (decimal) (def: 0)\n"
+ " --pcb|-q show parameter control bytes in decoded "
+ "output\n");
+ printf(" --ppc|-Q set the Parameter Pointer Control (PPC) bit "
+ "(def: 0)\n"
+ " --raw|-r output response in binary to stdout\n"
+ " --reset|-R reset log parameters (takes PC and SP into "
+ "account)\n"
+ " (uses PCR bit in LOG SELECT)\n"
+ " --select|-S perform LOG SELECT using SP and PC values\n"
+ " --sp|-s set the Saving Parameters (SP) bit (def: 0)\n"
+ " --temperature|-t decode temperature (log page 0xd or "
+ "0x2f)\n"
+ " --transport|-T decode transport (protocol specific port "
+ "0x18) log page\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V output version string then exit\n\n"
+ "Performs a SCSI LOG SENSE (or LOG SELECT) command\n");
+}
+
+static void usage_old()
+{
+ printf("Usage: sg_logs [-a] [-A] [-c=PC] [-h] [-H] [-l] [-L] "
+ "[-m=LEN] [-n]\n"
+ " [-p=PG[,SPG]] [-paramp=PP] [-pcb] [-ppc] "
+ "[-r] [-select]\n"
+ " [-sp] [-t] [-T] [-v] [-V] [-?] DEVICE\n"
+ " where:\n"
+ " -a fetch and decode all log pages\n"
+ " -A fetch and decode all log pages and subpages\n"
+ " -c=PC page control(PC) (default: 1)\n"
+ " 0: current threshhold, 1: current cumulative\n"
+ " 2: default threshhold, 3: default cumulative\n"
+ " -h output in hex (default: decode if known)\n"
+ " -H output in hex (same as '-h')\n"
+ " -l list supported log page names (equivalent to "
+ "'-p=0')\n"
+ " -L list supported log page and subpages names "
+ "(equivalent to\n"
+ " '-p=0,ff')\n"
+ " -m=LEN max response length (decimal) (def: 0 "
+ "-> everything)\n"
+ " -n decode some pages into multiple name=value "
+ "lines\n"
+ " -p=PG page code in hex (def: 0)\n"
+ " -p=PG,SPG both in hex, (defs: 0,0)\n"
+ " -paramp=PP (in hex) (def: 0)\n"
+ " -pcb show parameter control bytes in decoded "
+ "output\n");
+ printf(" -ppc set the Parameter Pointer Control (PPC) bit "
+ "(def: 0)\n"
+ " -r reset log parameters (takes PC and SP into "
+ "account)\n"
+ " (uses PCR bit in LOG SELECT)\n"
+ " -select perform LOG SELECT using SP and PC values\n"
+ " -sp set the Saving Parameters (SP) bit (def: 0)\n"
+ " -t outputs temperature log page (0xd)\n"
+ " -T outputs transport (protocol specific port) log "
+ "page (0x18)\n"
+ " -v increase verbosity\n"
+ " -V output version string\n"
+ " -? output this usage message\n\n"
+ "Performs a SCSI LOG SENSE (or LOG SELECT) command\n");
+}
+
+static void usage_for(const struct opts_t * optsp)
+{
+ if (optsp->opt_new)
+ usage();
+ else
+ usage_old();
+}
+
+/* Trying to decode multipliers as sg_get_num() [as sg_libs does] would
+ * only confuse things here, so use this local trimmed version */
+static int get_num(const char * buf)
+{
+ int res, len, num;
+ unsigned int unum;
+ const char * commap;
+
+ if ((NULL == buf) || ('\0' == buf[0]))
+ return -1;
+ len = strlen(buf);
+ commap = strchr(buf + 1, ',');
+ if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
+ res = sscanf(buf + 2, "%x", &unum);
+ num = unum;
+ } else if (commap && ('H' == toupper(*(commap - 1)))) {
+ res = sscanf(buf, "%x", &unum);
+ num = unum;
+ } else if ((NULL == commap) && ('H' == toupper(buf[len - 1]))) {
+ res = sscanf(buf, "%x", &unum);
+ num = unum;
+ } else
+ res = sscanf(buf, "%d", &num);
+ if (1 == res)
+ return num;
+ else
+ return -1;
+}
+
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c, n, nn;
+ char * cp;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "aAc:hHlLm:nNOp:P:qQrRsStTvV",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'a':
+ ++optsp->do_all;
+ break;
+ case 'A':
+ optsp->do_all += 2;
+ break;
+ case 'c':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 3)) {
+ fprintf(stderr, "bad argument to '--control='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->page_control = n;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'l':
+ ++optsp->do_list;
+ break;
+ case 'L':
+ optsp->do_list += 2;
+ break;
+ case 'm':
+ n = sg_get_num(optarg);
+ if (n < 0) {
+ fprintf(stderr, "bad argument to '--maxlen='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->maxlen = n;
+ break;
+ case 'n':
+ ++optsp->do_name;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'p':
+ cp = strchr(optarg, ',');
+ n = get_num(optarg);
+ if ((n < 0) || (n > 63)) {
+ fprintf(stderr, "Bad argument to '--page='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (cp) {
+ nn = get_num(cp + 1);
+ if ((nn < 0) || (nn > 255)) {
+ fprintf(stderr, "Bad second value in argument to "
+ "'--page='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else
+ nn = 0;
+ optsp->pg_code = n;
+ optsp->subpg_code = nn;
+ break;
+ case 'P':
+ n = sg_get_num(optarg);
+ if (n < 0) {
+ fprintf(stderr, "bad argument to '--paramp='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->paramp = n;
+ break;
+ case 'q':
+ ++optsp->do_pcb;
+ break;
+ case 'Q':
+ ++optsp->do_ppc;
+ break;
+ case 'r':
+ ++optsp->do_raw;
+ break;
+ case 'R':
+ ++optsp->do_pcreset;
+ ++optsp->do_select;
+ break;
+ case 's':
+ ++optsp->do_sp;
+ break;
+ case 'S':
+ ++optsp->do_select;
+ break;
+ case 't':
+ ++optsp->do_temperature;
+ break;
+ case 'T':
+ ++optsp->do_transport;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
+{
+ int k, jmp_out, plen, num, n;
+ unsigned int u, uu;
+ const char * cp;
+
+ for (k = 1; k < argc; ++k) {
+ cp = argv[k];
+ plen = strlen(cp);
+ if (plen <= 0)
+ continue;
+ if ('-' == *cp) {
+ for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
+ switch (*cp) {
+ case 'a':
+ ++optsp->do_all;
+ break;
+ case 'A':
+ optsp->do_all += 2;
+ break;
+ case 'h':
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'l':
+ ++optsp->do_list;
+ break;
+ case 'L':
+ optsp->do_list += 2;
+ break;
+ case 'n':
+ ++optsp->do_name;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case 'r':
+ optsp->do_pcreset = 1;
+ optsp->do_select = 1;
+ break;
+ case 't':
+ ++optsp->do_temperature;
+ break;
+ case 'T':
+ ++optsp->do_transport;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case '?':
+ ++optsp->do_help;
+ break;
+ case '-':
+ ++cp;
+ jmp_out = 1;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+ if (0 == strncmp("c=", cp, 2)) {
+ num = sscanf(cp + 2, "%x", &u);
+ if ((1 != num) || (u > 3)) {
+ printf("Bad page control after '-c=' option [0..3]\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->page_control = u;
+ } else if (0 == strncmp("m=", cp, 2)) {
+ num = sscanf(cp + 2, "%d", &n);
+ if ((1 != num) || (n < 0) || (n > MX_ALLOC_LEN)) {
+ printf("Bad maximum response length after '-m=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->maxlen = n;
+ } else if (0 == strncmp("p=", cp, 2)) {
+ if (NULL == strchr(cp + 2, ',')) {
+ num = sscanf(cp + 2, "%x", &u);
+ if ((1 != num) || (u > 63)) {
+ fprintf(stderr, "Bad page code value after '-p=' "
+ "option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->pg_code = u;
+ } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) {
+ if (uu > 255) {
+ fprintf(stderr, "Bad sub page code value after '-p=' "
+ "option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->pg_code = u;
+ optsp->subpg_code = uu;
+ } else {
+ fprintf(stderr, "Bad page code, subpage code sequence "
+ "after '-p=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == strncmp("paramp=", cp, 7)) {
+ num = sscanf(cp + 7, "%x", &u);
+ if ((1 != num) || (u > 0xffff)) {
+ printf("Bad parameter pointer after '-paramp=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->paramp = u;
+ } else if (0 == strncmp("pcb", cp, 3))
+ optsp->do_pcb = 1;
+ else if (0 == strncmp("ppc", cp, 3))
+ optsp->do_ppc = 1;
+ else if (0 == strncmp("select", cp, 6))
+ optsp->do_select = 1;
+ else if (0 == strncmp("sp", cp, 2))
+ optsp->do_sp = 1;
+ else if (0 == strncmp("old", cp, 3))
+ ;
+ else if (jmp_out) {
+ fprintf(stderr, "Unrecognized option: %s\n", cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == optsp->device_name)
+ optsp->device_name = cp;
+ else {
+ fprintf(stderr, "too many arguments, got: %s, not expecting: "
+ "%s\n", optsp->device_name, cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
+
+static void dStrRaw(const char* str, int len)
+{
+ int k;
+
+ for (k = 0 ; k < len; ++k)
+ printf("%c", str[k]);
+}
/* Call LOG SENSE twice: the first time ask for 4 byte response to determine
actual length of response; then a second time requesting the
min(actual_len, mx_resp_len) bytes. If the calculated length for the
- second fetch is odd then it is incremented (perhaps should be made modulo 4
- in the future for SAS). Returns 0 if ok, SG_LIB_CAT_INVALID_OP for
+ second fetch is odd then it is incremented (perhaps should be made modulo
+ 4 in the future for SAS). Returns 0 if ok, SG_LIB_CAT_INVALID_OP for
log_sense not supported, SG_LIB_CAT_ILLEGAL_REQ for bad field in log sense
command, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_UNIT_ATTENTION,
SG_LIB_CAT_ABORTED_COMMAND and -1 for other errors. */
-static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code,
- int subpg_code, int paramp, unsigned char * resp,
- int mx_resp_len, int noisy, int verbose)
+static int do_logs(int sg_fd, unsigned char * resp, int mx_resp_len,
+ int noisy, const struct opts_t * optsp)
{
int actual_len;
int res;
memset(resp, 0, mx_resp_len);
- if ((res = sg_ll_log_sense(sg_fd, ppc, sp, pc, pg_code, subpg_code,
- paramp, resp, 4, noisy, verbose))) {
+ if ((res = sg_ll_log_sense(sg_fd, optsp->do_ppc, optsp->do_sp,
+ optsp->page_control, optsp->pg_code,
+ optsp->subpg_code, optsp->paramp,
+ resp, 4, noisy, optsp->do_verbose))) {
switch (res) {
case SG_LIB_CAT_NOT_READY:
case SG_LIB_CAT_INVALID_OP:
@@ -61,7 +584,7 @@ static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code,
}
}
actual_len = (resp[2] << 8) + resp[3] + 4;
- if (verbose > 1) {
+ if ((0 == optsp->do_raw) && (optsp->do_verbose > 1)) {
fprintf(stderr, " Log sense (find length) response:\n");
dStrHex((const char *)resp, 4, 1);
fprintf(stderr, " hence calculated response length=%d\n",
@@ -72,8 +595,10 @@ static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code,
actual_len += 1;
if (actual_len > mx_resp_len)
actual_len = mx_resp_len;
- if ((res = sg_ll_log_sense(sg_fd, ppc, sp, pc, pg_code, subpg_code,
- paramp, resp, actual_len, noisy, verbose))) {
+ if ((res = sg_ll_log_sense(sg_fd, optsp->do_ppc, optsp->do_sp,
+ optsp->page_control, optsp->pg_code,
+ optsp->subpg_code, optsp->paramp,
+ resp, actual_len, noisy, optsp->do_verbose))) {
switch (res) {
case SG_LIB_CAT_NOT_READY:
case SG_LIB_CAT_INVALID_OP:
@@ -85,58 +610,13 @@ static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code,
return -1;
}
}
- if (verbose > 1) {
+ if ((0 == optsp->do_raw) && (optsp->do_verbose > 1)) {
fprintf(stderr, " Log sense response:\n");
dStrHex((const char *)resp, actual_len, 1);
}
return 0;
}
-static void usage()
-{
- printf("Usage: sg_logs [-a] [-A] [-c=<page_control] [-h] [-H] [-l] "
- "[-L]\n"
- " [-m=<max_len>] [-p=<page_number>[,"
- "<subpage_code>]]\n"
- " [-paramp=<parameter_pointer>] [-pcb] [-ppc] "
- "[-r] [-select]\n"
- " [-sp] [-t] [-T] [-v] [-V] [-?] <scsi_device>\n"
- " where:\n"
- " -a fetch and decode all log pages\n"
- " -A fetch and decode all log pages and subpages\n"
- " -c=<page_control> page control(PC) (default: 1)\n"
- " 0: current threshhold, 1: current cumulative\n"
- " 2: default threshhold, 3: default cumulative\n"
- " -h output in hex (default: decode if known)\n"
- " -H output in hex (same as '-h')\n"
- " -l list supported log page names (equivalent to "
- "'-p=0')\n"
- " -L list supported log page and subpages names "
- "(equivalent to\n"
- " '-p=0,ff')\n"
- " -m=<max_len> max response length (decimal) (def: 0 "
- "-> everything)\n"
- " -p=<page_code> page code (in hex)\n"
- " -p=<page_code>,<subpage_code> both in hex, (defs: 0)\n"
- " -paramp=<parameter_pointer> (in hex) (def: 0)\n"
- " -pcb show parameter control bytes (ignored if -h "
- "given)\n");
- printf(" -ppc set the Parameter Pointer Control (PPC) bit "
- "(def: 0)\n"
- " -r reset log parameters (takes PC and SP into "
- "account)\n"
- " (uses PCR bit in LOG SELECT)\n"
- " -select perform LOG SELECT using SP and PC values\n"
- " -sp set the Saving Parameters (SP) bit (def: 0)\n"
- " -t outputs temperature log page (0xd)\n"
- " -T outputs transport (protocol specific port) log "
- "page (0x18)\n"
- " -v verbose: output cdbs prior to execution\n"
- " -V output version string\n"
- " -? output this usage message\n\n"
- "Performs a SCSI LOG SENSE (or LOG SELECT) command\n");
-}
-
static void show_page_name(int pg_code, int subpg_code,
struct sg_simple_inquiry_resp * inq_dat)
{
@@ -145,42 +625,48 @@ static void show_page_name(int pg_code, int subpg_code,
memset(b, 0, sizeof(b));
/* first process log pages that do not depend on peripheral type */
- if (0 == subpg_code)
+ if (NOT_SUBPG_LOG == subpg_code)
snprintf(b, sizeof(b) - 1, " 0x%02x ", pg_code);
else
snprintf(b, sizeof(b) - 1, " 0x%02x,0x%02x ", pg_code,
subpg_code);
done = 1;
- if ((0 == subpg_code) || (0xff == subpg_code)) {
+ if ((NOT_SUBPG_LOG == subpg_code) || (ALL_SUBPG_LOG == subpg_code)) {
switch (pg_code) {
- case 0x0: printf("%sSupported log pages", b); break;
- case 0x1: printf("%sBuffer over-run/under-run", b); break;
- case 0x2: printf("%sError counters (write)", b); break;
- case 0x3: printf("%sError counters (read)", b); break;
- case 0x4: printf("%sError counters (read reverse)", b); break;
- case 0x5: printf("%sError counters (verify)", b); break;
- case 0x6: printf("%sNon-medium errors", b); break;
- case 0x7: printf("%sLast n error events", b); break;
- case 0xb: printf("%sLast n deferred errors or "
+ case ALL_PAGE_LPAGE: printf("%sSupported log pages", b); break;
+ case BUFF_OVER_UNDER_LPAGE:
+ printf("%sBuffer over-run/under-run", b);
+ break;
+ case WRITE_ERR_LPAGE: printf("%sError counters (write)", b); break;
+ case READ_ERR_LPAGE: printf("%sError counters (read)", b); break;
+ case READ_REV_ERR_LPAGE:
+ printf("%sError counters (read reverse)", b);
+ break;
+ case VERIFY_ERR_LPAGE: printf("%sError counters (verify)", b); break;
+ case NON_MEDIUM_LPAGE: printf("%sNon-medium errors", b); break;
+ case LAST_N_ERR_LPAGE: printf("%sLast n error events", b); break;
+ case LAST_N_DEFERRED_LPAGE: printf("%sLast n deferred errors or "
"asynchronous events", b); break;
- case 0xd: printf("%sTemperature", b); break;
- case 0xe: printf("%sStart-stop cycle counter", b); break;
- case 0xf: printf("%sApplication client", b); break;
- case 0x10: printf("%sSelf-test results", b); break;
- case 0x18: printf("%sProtocol specific port", b); break;
- case 0x19: printf("%sGeneral statistics and performance", b); break;
- case 0x2f: printf("%sInformational exceptions (SMART)", b); break;
+ case TEMPERATURE_LPAGE: printf("%sTemperature", b); break;
+ case START_STOP_LPAGE: printf("%sStart-stop cycle counter", b); break;
+ case APP_CLIENT_LPAGE: printf("%sApplication client", b); break;
+ case SELF_TEST_LPAGE: printf("%sSelf-test results", b); break;
+ case PORT_SPECIFIC_LPAGE: printf("%sProtocol specific port", b); break;
+ case GSP_LPAGE:
+ printf("%sGeneral statistics and performance", b);
+ break;
+ case IE_LPAGE: printf("%sInformational exceptions (SMART)", b); break;
default : done = 0; break;
}
if (done) {
- if (0xff == subpg_code)
+ if (ALL_SUBPG_LOG == subpg_code)
printf(" and subpages\n");
else
printf("\n");
return;
}
}
- if ((0x19 == pg_code) && (subpg_code > 0) && (subpg_code < 32)) {
+ if ((GSP_LPAGE == pg_code) && (subpg_code > 0) && (subpg_code < 32)) {
printf("%sGroup statistics and performance (%d)\n", b, subpg_code);
return;
}
@@ -364,7 +850,7 @@ static void show_buffer_under_overrun_page(unsigned char * resp, int len,
ull <<= 8;
ull |= xp[j];
}
- printf(" = %llu", ull);
+ printf(" = %" PRIu64 "", ull);
}
if (show_pcb) {
pcb = ucp[2];
@@ -387,16 +873,16 @@ static void show_error_counter_page(unsigned char * resp, int len,
char pcb_str[PCB_STR_LEN];
switch(resp[0] & 0x3f) {
- case 2:
+ case WRITE_ERR_LPAGE:
printf("Write error counter page\n");
break;
- case 3:
+ case READ_ERR_LPAGE:
printf("Read error counter page\n");
break;
- case 4:
+ case READ_REV_ERR_LPAGE:
printf("Read Reverse error counter page\n");
break;
- case 5:
+ case VERIFY_ERR_LPAGE:
printf("Verify error counter page\n");
break;
default:
@@ -433,7 +919,7 @@ static void show_error_counter_page(unsigned char * resp, int len,
ull <<= 8;
ull |= xp[j];
}
- printf(" = %llu", ull);
+ printf(" = %" PRIu64 "", ull);
if (show_pcb) {
get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
printf("\n <%s>\n", pcb_str);
@@ -482,7 +968,7 @@ static void show_non_medium_error_page(unsigned char * resp, int len,
ull <<= 8;
ull |= xp[j];
}
- printf(" = %llu", ull);
+ printf(" = %" PRIu64 "", ull);
if (show_pcb) {
get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
printf("\n <%s>\n", pcb_str);
@@ -616,7 +1102,7 @@ static void show_self_test_page(unsigned char * resp, int len, int show_pcb)
ull <<= 8; ull |= ucp[13]; ull <<= 8; ull |= ucp[14];
ull <<= 8; ull |= ucp[15];
if ((0xffffffffffffffffULL != ull) && (res > 0) && ( res < 0xf))
- printf(" address of first error = 0x%llx\n", ull);
+ printf(" address of first error = 0x%" PRIx64 "\n", ull);
if (ucp[16] & 0xf)
printf(" sense key = 0x%x, asc = 0x%x, asq = 0x%x",
ucp[16] & 0xf, ucp[17], ucp[18]);
@@ -628,7 +1114,7 @@ static void show_self_test_page(unsigned char * resp, int len, int show_pcb)
}
}
-static void show_Temperature_page(unsigned char * resp, int len,
+static void show_temperature_page(unsigned char * resp, int len,
int show_pcb, int hdr, int show_unknown)
{
int k, num, extra, pc, pcb;
@@ -926,7 +1412,6 @@ static void show_sas_phy_event_info(int peis, unsigned long val,
case 0x61:
printf(" Received SMP frame count: %lu\n", val);
break;
- /* case 0x63: */
case 0x63:
printf(" Received SMP frame error count: %lu\n", val);
break;
@@ -935,11 +1420,10 @@ static void show_sas_phy_event_info(int peis, unsigned long val,
}
}
-static int show_protocol_specific_page(unsigned char * resp, int len,
- int show_pcb)
+static void show_sas_rel_target_port(unsigned char * ucp, int param_len,
+ const struct opts_t * optsp)
{
- int k, j, m, num, param_len, nphys, pcb, t, sz, spld_len;
- unsigned char * ucp;
+ int j, m, n, nphys, pcb, t, sz, spld_len;
unsigned char * vcp;
unsigned long long ull;
unsigned long ul;
@@ -947,35 +1431,59 @@ static int show_protocol_specific_page(unsigned char * resp, int len,
char s[64];
sz = sizeof(s);
- num = len - 4;
- for (k = 0, ucp = resp + 4; k < num; ) {
- pcb = ucp[2];
- param_len = ucp[3] + 4;
- /* each phy has a 48 byte descriptor but since param_len is
- an 8 bit quantity then only the first 5 phys (of, for example,
- a 8 phy wide link) can be represented */
- if (6 != (0xf & ucp[4]))
- return 0; /* only decode SAS log page [sas2r05a] */
- if (0 == k)
- printf("SAS Protocol Specific page\n");
- printf("relative target port id = %d\n", (ucp[0] << 8) | ucp[1]);
- nphys = ucp[7];
+ pcb = ucp[2];
+ t = (ucp[0] << 8) | ucp[1];
+ if (optsp->do_name)
+ printf("rel_target_port=%d\n", t);
+ else
+ printf("relative target port id = %d\n", t);
+ nphys = ucp[7];
+ if (optsp->do_name)
+ printf(" num_phys=%d\n", nphys);
+ else {
printf(" number of phys = %d", nphys);
- if (show_pcb) {
+ if ((optsp->do_pcb) && (0 == optsp->do_name)) {
get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
printf("\n <%s>\n", pcb_str);
} else
printf("\n");
+ }
- for (j = 0, vcp = ucp + 8; j < (param_len - 8);
- vcp += spld_len, j += spld_len) {
+ for (j = 0, vcp = ucp + 8; j < (param_len - 8);
+ vcp += spld_len, j += spld_len) {
+ if (optsp->do_name)
+ printf(" phy_id=%d\n", vcp[1]);
+ else
printf(" phy identifier = %d\n", vcp[1]);
- spld_len = vcp[3];
- if (spld_len < 44)
- spld_len = 48;
- else
- spld_len += 4;
- t = ((0x70 & vcp[4]) >> 4);
+ spld_len = vcp[3];
+ if (spld_len < 44)
+ spld_len = 48;
+ else
+ spld_len += 4;
+ t = ((0x70 & vcp[4]) >> 4);
+ if (optsp->do_name) {
+ printf(" att_dev_type=%d\n", t);
+ printf(" att_iport_mask=0x%x\n", vcp[6]);
+ printf(" att_phy_id=%d\n", vcp[24]);
+ for (n = 0, ull = vcp[16]; n < 8; ++n) {
+ ull <<= 8; ull |= vcp[16 + n];
+ }
+ printf(" att_sas_addr=0x%" PRIx64 "\n", ull);
+ printf(" att_tport_mask=0x%x\n", vcp[7]);
+ ul = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
+ printf(" inv_dwords=%ld\n", ul);
+ ul = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43];
+ printf(" loss_dword_sync=%ld\n", ul);
+ printf(" neg_log_lrate=%d\n", 0xf & vcp[5]);
+ ul = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
+ printf(" phy_reset_probs=%ld\n", ul);
+ ul = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39];
+ printf(" running_disparity=%ld\n", ul);
+ for (n = 0, ull = vcp[8]; n < 8; ++n) {
+ ull <<= 8; ull |= vcp[8 + n];
+ }
+ printf(" sas_addr=0x%" PRIx64 "\n", ull);
+ } else {
switch (t) {
case 0: snprintf(s, sz, "no device attached"); break;
case 1: snprintf(s, sz, "end device"); break;
@@ -1002,21 +1510,19 @@ static int show_protocol_specific_page(unsigned char * resp, int len,
case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
default: snprintf(s, sz, "reserved [%d]", t); break;
}
- printf(" negotiated physical link rate: %s\n", s);
+ printf(" negotiated logical link rate: %s\n", s);/* sas2r07 */
printf(" attached initiator port: ssp=%d stp=%d smp=%d\n",
!! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
printf(" attached target port: ssp=%d stp=%d smp=%d\n",
!! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
- ull = vcp[8]; ull <<= 8; ull |= vcp[9]; ull <<= 8; ull |= vcp[10];
- ull <<= 8; ull |= vcp[11]; ull <<= 8; ull |= vcp[12];
- ull <<= 8; ull |= vcp[13]; ull <<= 8; ull |= vcp[14];
- ull <<= 8; ull |= vcp[15];
- printf(" SAS address = 0x%llx\n", ull);
- ull = vcp[16]; ull <<= 8; ull |= vcp[17]; ull <<= 8; ull |= vcp[18];
- ull <<= 8; ull |= vcp[19]; ull <<= 8; ull |= vcp[20];
- ull <<= 8; ull |= vcp[21]; ull <<= 8; ull |= vcp[22];
- ull <<= 8; ull |= vcp[23];
- printf(" attached SAS address = 0x%llx\n", ull);
+ for (n = 0, ull = vcp[8]; n < 8; ++n) {
+ ull <<= 8; ull |= vcp[8 + n];
+ }
+ printf(" SAS address = 0x%" PRIx64 "\n", ull);
+ for (n = 0, ull = vcp[16]; n < 8; ++n) {
+ ull <<= 8; ull |= vcp[16 + n];
+ }
+ printf(" attached SAS address = 0x%" PRIx64 "\n", ull);
printf(" attached phy identifier = %d\n", vcp[24]);
ul = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
printf(" Invalid DWORD count = %ld\n", ul);
@@ -1026,25 +1532,50 @@ static int show_protocol_specific_page(unsigned char * resp, int len,
printf(" Loss of DWORD synchronization = %ld\n", ul);
ul = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
printf(" Phy reset problem = %ld\n", ul);
- if (spld_len > 51) {
- int num_ped, peis;
- unsigned char * xcp;
- unsigned long pvdt;
-
- num_ped = vcp[51];
- if (num_ped > 0)
- printf(" Phy event descriptors:\n");
- xcp = vcp + 52;
- for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
- peis = xcp[3];
- ul = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) |
- xcp[7];
- pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) |
- xcp[11];
- show_sas_phy_event_info(peis, ul, pvdt);
- }
+ }
+ if (spld_len > 51) {
+ int num_ped, peis;
+ unsigned char * xcp;
+ unsigned long pvdt;
+
+ num_ped = vcp[51];
+ if (num_ped > 0) {
+ if (optsp->do_name) {
+ printf(" phy_event_desc_num=%d\n", num_ped);
+ return; /* don't decode at this stage */
+ } else
+ printf(" Phy event descriptors:\n");
+ }
+ xcp = vcp + 52;
+ for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
+ peis = xcp[3];
+ ul = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) |
+ xcp[7];
+ pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) |
+ xcp[11];
+ show_sas_phy_event_info(peis, ul, pvdt);
}
}
+ }
+}
+
+static int show_protocol_specific_page(unsigned char * resp, int len,
+ const struct opts_t * optsp)
+{
+ int k, num, param_len;
+ unsigned char * ucp;
+
+ num = len - 4;
+ for (k = 0, ucp = resp + 4; k < num; ) {
+ param_len = ucp[3] + 4;
+ /* each phy has a 48 byte descriptor but since param_len is
+ an 8 bit quantity then only the first 5 phys (of, for example,
+ a 8 phy wide link) can be represented */
+ if (6 != (0xf & ucp[4]))
+ return 0; /* only decode SAS log page [sas2r05a] */
+ if ((0 == k) && (0 == optsp->do_name))
+ printf("SAS Protocol Specific page\n");
+ show_sas_rel_target_port(ucp, param_len, optsp);
k += param_len;
ucp += param_len;
}
@@ -1103,7 +1634,7 @@ static void show_format_status_page(unsigned char * resp, int len,
if (all_ff)
printf(" <not available>");
else
- printf(" = %llu", ull);
+ printf(" = %" PRIu64 "", ull);
if (show_pcb) {
get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
printf("\n <%s>\n", pcb_str);
@@ -1252,8 +1783,13 @@ static void show_background_scan_results_page(unsigned char * resp, int len,
printf("unknown [0x%x] background scan status value\n", j);
printf(" Number of background scans performed: %d\n",
(ucp[10] << 8) + ucp[11]);
+#ifdef SG3_UTILS_MINGW
+ printf(" Background medium scan progress: %g%%\n",
+ (double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0);
+#else
printf(" Background medium scan progress: %.2f%%\n",
(double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0);
+#endif
break;
default:
printf(" Medium scan parameter # %d\n", pc);
@@ -1332,51 +1868,52 @@ static void show_sequential_access_page(unsigned char * resp, int len,
gbytes = ull / 1000000000;
switch (pc) {
case 0:
- printf(" Data bytes received with WRITE commands: %llu GB",
- gbytes);
+ printf(" Data bytes received with WRITE commands: %" PRIu64
+ " GB", gbytes);
if (verbose)
- printf(" [%llu bytes]", ull);
+ printf(" [%" PRIu64 " bytes]", ull);
printf("\n");
break;
case 1:
- printf(" Data bytes written to media by WRITE commands: %llu "
- "GB", gbytes);
+ printf(" Data bytes written to media by WRITE commands: %" PRIu64
+ " GB", gbytes);
if (verbose)
- printf(" [%llu bytes]", ull);
+ printf(" [%" PRIu64 " bytes]", ull);
printf("\n");
break;
case 2:
- printf(" Data bytes read from media by READ commands: %llu "
- "GB", gbytes);
+ printf(" Data bytes read from media by READ commands: %" PRIu64
+ " GB", gbytes);
if (verbose)
- printf(" [%llu bytes]", ull);
+ printf(" [%" PRIu64 " bytes]", ull);
printf("\n");
break;
case 3:
- printf(" Data bytes transferred by READ commands: %llu "
- "GB", gbytes);
+ printf(" Data bytes transferred by READ commands: %" PRIu64
+ " GB", gbytes);
if (verbose)
- printf(" [%llu bytes]", ull);
+ printf(" [%" PRIu64 " bytes]", ull);
printf("\n");
break;
case 4:
- printf(" Native capacity from BOP to EOD: %llu MB\n", ull);
+ printf(" Native capacity from BOP to EOD: %" PRIu64 " MB\n",
+ ull);
break;
case 5:
printf(" Native capacity from BOP to EW of current partition: "
- "%llu MB\n", ull);
+ "%" PRIu64 " MB\n", ull);
break;
case 6:
printf(" Minimum native capacity from EW to EOP of current "
- "partition: %llu MB\n", ull);
+ "partition: %" PRIu64 " MB\n", ull);
break;
case 7:
- printf(" Native capacity from BOP to current position: %llu "
- "MB\n", ull);
+ printf(" Native capacity from BOP to current position: %"
+ PRIu64 " MB\n", ull);
break;
case 8:
- printf(" Maximum native capacity in device object buffer: %llu "
- "MB\n", ull);
+ printf(" Maximum native capacity in device object buffer: %"
+ PRIu64 " MB\n", ull);
break;
case 0x100:
if (ull > 0)
@@ -1384,14 +1921,14 @@ static void show_sequential_access_page(unsigned char * resp, int len,
else
printf(" Cleaning action not required (or completed)\n");
if (verbose)
- printf(" cleaning value: %llu\n", ull);
+ printf(" cleaning value: %" PRIu64 "\n", ull);
break;
default:
if (pc >= 0x8000)
- printf(" Vendor specific parameter [0x%x] value: %llu\n",
- pc, ull);
+ printf(" Vendor specific parameter [0x%x] value: %" PRIu64
+ "\n", pc, ull);
else
- printf(" Reserved parameter [0x%x] value: %llu\n",
+ printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n",
pc, ull);
break;
}
@@ -1436,51 +1973,53 @@ static void show_device_stats_page(unsigned char * resp, int len,
}
switch (pc) {
case 0:
- printf(" Lifetime media loads: %llu\n", ull);
+ printf(" Lifetime media loads: %" PRIu64 "\n", ull);
break;
case 1:
- printf(" Lifetime cleaning operations: %llu\n", ull);
+ printf(" Lifetime cleaning operations: %" PRIu64 "\n", ull);
break;
case 2:
- printf(" Lifetime power on hours: %llu\n", ull);
+ printf(" Lifetime power on hours: %" PRIu64 "\n", ull);
break;
case 3:
- printf(" Lifetime media motion (head) hours: %llu\n", ull);
+ printf(" Lifetime media motion (head) hours: %" PRIu64 "\n",
+ ull);
break;
case 4:
- printf(" Lifetime metres of tape processed: %llu\n", ull);
+ printf(" Lifetime metres of tape processed: %" PRIu64 "\n",
+ ull);
break;
case 5:
printf(" Lifetime media motion (head) hours when "
- "incompatible media last loaded: %llu\n", ull);
+ "incompatible media last loaded: %" PRIu64 "\n", ull);
break;
case 6:
- printf(" Lifetime power on hours when "
- "last temperature condition occurred: %llu\n", ull);
+ printf(" Lifetime power on hours when last temperature "
+ "condition occurred: %" PRIu64 "\n", ull);
break;
case 7:
printf(" Lifetime power on hours when last power "
- "consumption condition occurred: %llu\n", ull);
+ "consumption condition occurred: %" PRIu64 "\n", ull);
break;
case 8:
printf(" Media motion (head) hours since last successful "
- "cleaning operation: %llu\n", ull);
+ "cleaning operation: %" PRIu64 "\n", ull);
break;
case 9:
printf(" Media motion (head) hours since 2nd to last "
- "successful cleaning: %llu\n", ull);
+ "successful cleaning: %" PRIu64 "\n", ull);
break;
case 0xa:
printf(" Media motion (head) hours since 3rd to last "
- "successful cleaning: %llu\n", ull);
+ "successful cleaning: %" PRIu64 "\n", ull);
break;
case 0xb:
printf(" Lifetime power on hours when last operator "
"initiated forced reset\n and/or emergency "
- "eject occurred: %llu\n", ull);
+ "eject occurred: %" PRIu64 "\n", ull);
break;
default:
- printf(" Reserved parameter [0x%x] value: %llu\n",
+ printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n",
pc, ull);
break;
}
@@ -1545,7 +2084,7 @@ static void show_seagate_cache_page(unsigned char * resp, int len,
ull <<= 8;
ull |= xp[j];
}
- printf(" = %llu", ull);
+ printf(" = %" PRIu64 "", ull);
if (show_pcb) {
get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
printf("\n <%s>\n", pcb_str);
@@ -1598,7 +2137,7 @@ static void show_seagate_factory_page(unsigned char * resp, int len,
if (0 == pc)
printf(" = %.2f", ((double)ull) / 60.0 );
else
- printf(" = %llu", ull);
+ printf(" = %" PRIu64 "", ull);
}
if (show_pcb) {
get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
@@ -1610,9 +2149,9 @@ static void show_seagate_factory_page(unsigned char * resp, int len,
}
}
-static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
+static void show_ascii_page(unsigned char * resp, int len,
struct sg_simple_inquiry_resp * inq_dat,
- int verbose)
+ const struct opts_t * optsp)
{
int k, num, done, pg_code, subpg_code, spf;
@@ -1626,7 +2165,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
pg_code = resp[0] & 0x3f;
subpg_code = spf ? resp[1] : 0;
- if ((0 != pg_code ) && (0xff == subpg_code)) {
+ if ((ALL_PAGE_LPAGE != pg_code ) && (ALL_SUBPG_LOG == subpg_code)) {
printf("Supported subpages for log page=0x%x\n", pg_code);
for (k = 0; k < num; k += 2)
show_page_name((int)resp[4 + k], (int)resp[4 + k + 1],
@@ -1634,7 +2173,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
return;
}
switch (pg_code) {
- case 0:
+ case ALL_PAGE_LPAGE:
if (spf) {
printf("Supported log pages and subpages:\n");
for (k = 0; k < num; k += 2)
@@ -1646,27 +2185,27 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
show_page_name((int)resp[4 + k], 0, inq_dat);
}
break;
- case 0x1:
- show_buffer_under_overrun_page(resp, len, show_pcb);
+ case BUFF_OVER_UNDER_LPAGE:
+ show_buffer_under_overrun_page(resp, len, optsp->do_pcb);
break;
- case 0x2:
- case 0x3:
- case 0x4:
- case 0x5:
- show_error_counter_page(resp, len, show_pcb);
+ case WRITE_ERR_LPAGE:
+ case READ_ERR_LPAGE:
+ case READ_REV_ERR_LPAGE:
+ case VERIFY_ERR_LPAGE:
+ show_error_counter_page(resp, len, optsp->do_pcb);
break;
- case 0x6:
- show_non_medium_error_page(resp, len, show_pcb);
+ case NON_MEDIUM_LPAGE:
+ show_non_medium_error_page(resp, len, optsp->do_pcb);
break;
- case 0x7:
- show_last_n_error_page(resp, len, show_pcb);
+ case LAST_N_ERR_LPAGE:
+ show_last_n_error_page(resp, len, optsp->do_pcb);
break;
case 0x8:
{
switch (inq_dat->peripheral_type) {
case 0: case 4: case 7: case 0xe:
/* disk (direct access) type devices */
- show_format_status_page(resp, len, show_pcb);
+ show_format_status_page(resp, len, optsp->do_pcb);
break;
default:
done = 0;
@@ -1674,15 +2213,16 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
}
}
break;
- case 0xb:
- show_last_n_deferred_error_page(resp, len, show_pcb);
+ case LAST_N_DEFERRED_LPAGE:
+ show_last_n_deferred_error_page(resp, len, optsp->do_pcb);
break;
case 0xc:
{
switch (inq_dat->peripheral_type) {
case 1: case 2: case 8:
/* tape, (printer) and medium changer type devices */
- show_sequential_access_page(resp, len, show_pcb, verbose);
+ show_sequential_access_page(resp, len, optsp->do_pcb,
+ optsp->do_verbose);
break;
default:
done = 0;
@@ -1690,21 +2230,21 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
}
}
break;
- case 0xd:
- show_Temperature_page(resp, len, show_pcb, 1, 1);
+ case TEMPERATURE_LPAGE:
+ show_temperature_page(resp, len, optsp->do_pcb, 1, 1);
break;
- case 0xe:
- show_Start_Stop_page(resp, len, show_pcb, verbose);
+ case START_STOP_LPAGE:
+ show_Start_Stop_page(resp, len, optsp->do_pcb, optsp->do_verbose);
break;
- case 0x10:
- show_self_test_page(resp, len, show_pcb);
+ case SELF_TEST_LPAGE:
+ show_self_test_page(resp, len, optsp->do_pcb);
break;
case 0x14:
{
switch (inq_dat->peripheral_type) {
case 1: case 8: case 0x12:
/* tape, medium changer and adc type devices */
- show_device_stats_page(resp, len, show_pcb);
+ show_device_stats_page(resp, len, optsp->do_pcb);
break;
default:
done = 0;
@@ -1717,8 +2257,8 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
switch (inq_dat->peripheral_type) {
case 0: case 4: case 7: case 0xe:
/* disk (direct access) type devices */
- show_background_scan_results_page(resp, len, show_pcb,
- verbose);
+ show_background_scan_results_page(resp, len, optsp->do_pcb,
+ optsp->do_verbose);
break;
default:
done = 0;
@@ -1731,7 +2271,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
switch (inq_dat->peripheral_type) {
case 0: case 4: case 7: case 0xe:
/* disk (direct access) type devices */
- show_non_volatile_cache_page(resp, len, show_pcb);
+ show_non_volatile_cache_page(resp, len, optsp->do_pcb);
break;
default:
done = 0;
@@ -1739,18 +2279,18 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
}
}
break;
- case 0x18:
- done = show_protocol_specific_page(resp, len, show_pcb);
+ case PORT_SPECIFIC_LPAGE:
+ done = show_protocol_specific_page(resp, len, optsp);
break;
- case 0x2f:
- show_IE_page(resp, len, show_pcb, 1);
+ case IE_LPAGE:
+ show_IE_page(resp, len, optsp->do_pcb, 1);
break;
case 0x37:
{
switch (inq_dat->peripheral_type) {
case 0: case 4: case 7: case 0xe:
/* disk (direct access) type devices */
- show_seagate_cache_page(resp, len, show_pcb);
+ show_seagate_cache_page(resp, len, optsp->do_pcb);
break;
default:
done = 0;
@@ -1763,7 +2303,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
switch (inq_dat->peripheral_type) {
case 0: case 4: case 7: case 0xe:
/* disk (direct access) type devices */
- show_seagate_factory_page(resp, len, show_pcb);
+ show_seagate_factory_page(resp, len, optsp->do_pcb);
break;
case 1: case 2: case 8:
/* streaming or medium changer devices */
@@ -1793,20 +2333,36 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
}
static int fetchTemperature(int sg_fd, unsigned char * resp, int max_len,
- int verbose)
+ struct opts_t * optsp)
{
+ int len;
int res = 0;
- res = do_logs(sg_fd, 0, 0, 1, 0xd, 0, 0, resp, max_len, 0, verbose);
- if (0 == res)
- show_Temperature_page(resp, (resp[2] << 8) + resp[3] + 4, 0, 0, 0);
- else if (SG_LIB_CAT_NOT_READY == res)
+ optsp->pg_code = TEMPERATURE_LPAGE;
+ optsp->subpg_code = NOT_SUBPG_LOG;
+ res = do_logs(sg_fd, resp, max_len, 0, optsp);
+ if (0 == res) {
+ len = (resp[2] << 8) + resp[3] + 4;
+ if (optsp->do_raw)
+ dStrRaw((const char *)resp, len);
+ else if (optsp->do_hex)
+ dStrHex((const char *)resp, len, 1);
+ else
+ show_temperature_page(resp, len, optsp->do_pcb, 0, 0);
+ }else if (SG_LIB_CAT_NOT_READY == res)
fprintf(stderr, "Device not ready\n");
else {
- res = do_logs(sg_fd, 0, 0, 1, 0x2f, 0, 0, resp, max_len, 0, verbose);
- if (0 == res)
- show_IE_page(resp, (resp[2] << 8) + resp[3] + 4, 0, 0);
- else
+ optsp->pg_code = IE_LPAGE;
+ res = do_logs(sg_fd, resp, max_len, 0, optsp);
+ if (0 == res) {
+ len = (resp[2] << 8) + resp[3] + 4;
+ if (optsp->do_raw)
+ dStrRaw((const char *)resp, len);
+ else if (optsp->do_hex)
+ dStrHex((const char *)resp, len, 1);
+ else
+ show_IE_page(resp, len, 0, 0);
+ } else
fprintf(stderr, "Unable to find temperature in either log page "
"(temperature or IE)\n");
}
@@ -1814,199 +2370,80 @@ static int fetchTemperature(int sg_fd, unsigned char * resp, int max_len,
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
}
-static unsigned char rsp_buff[MX_ALLOC_LEN];
int main(int argc, char * argv[])
{
- int sg_fd, k, num, pg_len, res, plen, jmp_out, resp_len;
- const char * file_name = 0;
- const char * cp;
- unsigned int u, uu;
- int pg_code = 0;
- int subpg_code = 0;
- int subpg_code_set = 0;
- int pc = 1; /* N.B. some disks only give data for current cumulative */
- int paramp = 0;
- int do_list = 0;
- int do_pcb = 0;
- int do_ppc = 0;
- int do_select = 0;
- int do_sp = 0;
- int do_hex = 0;
- int do_all = 0;
- int do_temp = 0;
- int do_pcreset = 0;
- int do_verbose = 0;
- int max_len = 0;
+ int sg_fd, k, pg_len, res, resp_len;
int ret = 0;
struct sg_simple_inquiry_resp inq_out;
+ struct opts_t opts;
+ memset(&opts, 0, sizeof(opts));
memset(rsp_buff, 0, sizeof(rsp_buff));
- for (k = 1; k < argc; ++k) {
- cp = argv[k];
- plen = strlen(cp);
- if (plen <= 0)
- continue;
- if ('-' == *cp) {
- for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
- switch (*cp) {
- case 'a':
- do_all = 1;
- break;
- case 'A':
- do_all = 2;
- break;
- case 'h':
- case 'H':
- do_hex = 1;
- break;
- case 'l':
- do_list = 1;
- break;
- case 'L':
- do_list = 2;
- break;
- case 'r':
- do_pcreset = 1;
- do_select = 1;
- break;
- case 't':
- do_temp = 1;
- break;
- case 'T':
- pg_code = 0x18;
- break;
- case 'v':
- ++do_verbose;
- break;
- case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
- case '?':
- usage();
- return SG_LIB_SYNTAX_ERROR;
- case '-':
- ++cp;
- jmp_out = 1;
- break;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
- }
- if (plen <= 0)
- continue;
- if (0 == strncmp("c=", cp, 2)) {
- num = sscanf(cp + 2, "%x", &u);
- if ((1 != num) || (u > 3)) {
- printf("Bad page control after '-c=' option [0..3]\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- pc = u;
- } else if (0 == strncmp("m=", cp, 2)) {
- num = sscanf(cp + 2, "%d", &max_len);
- if ((1 != num) || (max_len < 0) || (max_len > MX_ALLOC_LEN)) {
- printf("Bad maximum response length after '-m=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == strncmp("p=", cp, 2)) {
- if (NULL == strchr(cp + 2, ',')) {
- num = sscanf(cp + 2, "%x", &u);
- if ((1 != num) || (u > 63)) {
- fprintf(stderr, "Bad page code value after '-p=' "
- "option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- pg_code = u;
- } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) {
- if (uu > 255) {
- fprintf(stderr, "Bad sub page code value after '-p=' "
- "option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- pg_code = u;
- subpg_code = uu;
- subpg_code_set = 1;
- } else {
- fprintf(stderr, "Bad page code, subpage code sequence "
- "after '-p=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == strncmp("paramp=", cp, 7)) {
- num = sscanf(cp + 7, "%x", &u);
- if ((1 != num) || (u > 0xffff)) {
- printf("Bad parameter pointer after '-paramp=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- paramp = u;
- } else if (0 == strncmp("pcb", cp, 3))
- do_pcb = 1;
- else if (0 == strncmp("ppc", cp, 3))
- do_ppc = 1;
- else if (0 == strncmp("select", cp, 6))
- do_select = 1;
- else if (0 == strncmp("sp", cp, 2))
- do_sp = 1;
- else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n", cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == file_name)
- file_name = cp;
- else {
- fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
+ /* N.B. some disks only give data for current cumulative */
+ opts.page_control = 1;
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ usage_for(&opts);
+ return 0;
+ }
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
}
-
- if (0 == file_name) {
- fprintf(stderr, "No <scsi_device> argument given. Try '-?' for "
- "usage.\n");
+
+ if (NULL == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- if ((sg_fd = sg_cmds_open_device(file_name, 0 /* rw */,
- do_verbose)) < 0) {
- if ((sg_fd = sg_cmds_open_device(file_name, 1 /* r0 */,
- do_verbose)) < 0) {
- fprintf(stderr, ME "error opening file: %s: %s \n", file_name,
- safe_strerror(-sg_fd));
+ if ((sg_fd = sg_cmds_open_device(opts.device_name, 0 /* rw */,
+ opts.do_verbose)) < 0) {
+ if ((sg_fd = sg_cmds_open_device(opts.device_name, 1 /* r0 */,
+ opts.do_verbose)) < 0) {
+ fprintf(stderr, "error opening file: %s: %s \n",
+ opts.device_name, safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
}
- if (do_list || do_all) {
- pg_code = PG_CODE_ALL;
- if ((do_list > 1) || (do_all > 1))
- subpg_code = SUBPG_CODE_ALL;
+ if (opts.do_list || opts.do_all) {
+ opts.pg_code = ALL_PAGE_LPAGE;
+ if ((opts.do_list > 1) || (opts.do_all > 1))
+ opts.subpg_code = ALL_SUBPG_LOG;
+ }
+ if (opts.do_transport) {
+ if ((opts.pg_code > 0) || (opts.subpg_code > 0) ||
+ opts.do_temperature) {
+ fprintf(stderr, "'-T' should not be mixed with options "
+ "implying other pages\n");
+ return SG_LIB_FILE_ERROR;
+ }
+ opts.pg_code = PORT_SPECIFIC_LPAGE;
}
pg_len = 0;
- if (sg_simple_inquiry(sg_fd, &inq_out, 1, do_verbose)) {
- fprintf(stderr, ME "%s doesn't respond to a SCSI INQUIRY\n",
- file_name);
- sg_cmds_close_device(sg_fd);
- return SG_LIB_CAT_OTHER;
+ if (0 == opts.do_raw) {
+ if (sg_simple_inquiry(sg_fd, &inq_out, 1, opts.do_verbose)) {
+ fprintf(stderr, "%s doesn't respond to a SCSI INQUIRY\n",
+ opts.device_name);
+ sg_cmds_close_device(sg_fd);
+ return SG_LIB_CAT_OTHER;
+ } else if ((0 == opts.do_hex) && (0 == opts.do_name))
+ printf(" %.8s %.16s %.4s\n", inq_out.vendor,
+ inq_out.product, inq_out.revision);
} else
- printf(" %.8s %.16s %.4s\n", inq_out.vendor, inq_out.product,
- inq_out.revision);
+ memset(&inq_out, 0, sizeof(inq_out));
- if (1 == do_temp)
- return fetchTemperature(sg_fd, rsp_buff, SHORT_RESP_LEN, do_verbose);
+ if (1 == opts.do_temperature)
+ return fetchTemperature(sg_fd, rsp_buff, SHORT_RESP_LEN, &opts);
- if (do_select) {
- k = sg_ll_log_select(sg_fd, !!(do_pcreset), do_sp, pc, pg_code,
- subpg_code, NULL, 0, 1, do_verbose);
+ if (opts.do_select) {
+ k = sg_ll_log_select(sg_fd, !!(opts.do_pcreset), opts.do_sp,
+ opts.page_control, opts.pg_code, opts.subpg_code,
+ NULL, 0, 1, opts.do_verbose);
if (k) {
if (SG_LIB_CAT_NOT_READY == k)
fprintf(stderr, "log_select: device not ready\n");
@@ -2019,9 +2456,8 @@ int main(int argc, char * argv[])
}
return (k >= 0) ? k : SG_LIB_CAT_OTHER;
}
- resp_len = (max_len > 0) ? max_len : MX_ALLOC_LEN;
- res = do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, subpg_code, paramp,
- rsp_buff, resp_len, 1, do_verbose);
+ resp_len = (opts.maxlen > 0) ? opts.maxlen : MX_ALLOC_LEN;
+ res = do_logs(sg_fd, rsp_buff, resp_len, 1, &opts);
if (0 == res) {
pg_len = (rsp_buff[2] << 8) + rsp_buff[3];
if ((pg_len + 4) > resp_len) {
@@ -2040,24 +2476,27 @@ int main(int argc, char * argv[])
fprintf(stderr, "log_sense: unit attention\n");
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
fprintf(stderr, "log_sense: aborted command\n");
- if ((pg_len > 1) && (0 == do_all)) {
- if (do_hex) {
- if (rsp_buff[0] & 0x40)
- printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, "
- "page_len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1],
- !!(rsp_buff[0] & 0x80), pg_len);
+ if (0 == opts.do_all) {
+ if (opts.do_raw)
+ dStrRaw((const char *)rsp_buff, pg_len + 4);
+ else if (pg_len > 1) {
+ if (opts.do_hex) {
+ if (rsp_buff[0] & 0x40)
+ printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, "
+ "page_len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1],
+ !!(rsp_buff[0] & 0x80), pg_len);
+ else
+ printf("Log page code=0x%x, DS=%d, SPF=0, page_len=0x%x\n",
+ rsp_buff[0] & 0x3f, !!(rsp_buff[0] & 0x80), pg_len);
+ dStrHex((const char *)rsp_buff, pg_len + 4, 1);
+ }
else
- printf("Log page code=0x%x, DS=%d, SPF=0, page_len=0x%x\n",
- rsp_buff[0] & 0x3f, !!(rsp_buff[0] & 0x80), pg_len);
- dStrHex((const char *)rsp_buff, pg_len + 4, 1);
+ show_ascii_page(rsp_buff, pg_len + 4, &inq_out, &opts);
}
- else
- show_ascii_page(rsp_buff, pg_len + 4, do_pcb, &inq_out,
- do_verbose);
}
ret = res;
- if (do_all && (pg_len > 1)) {
+ if (opts.do_all && (pg_len > 1)) {
int my_len = pg_len;
int spf;
unsigned char parr[1024];
@@ -2071,14 +2510,13 @@ int main(int argc, char * argv[])
memcpy(parr, rsp_buff + 4, my_len);
for (k = 0; k < my_len; ++k) {
printf("\n");
- pg_code = parr[k] & 0x3f;
+ opts.pg_code = parr[k] & 0x3f;
if (spf)
- subpg_code = parr[++k];
+ opts.subpg_code = parr[++k];
else
- subpg_code = 0;
+ opts.subpg_code = NOT_SUBPG_LOG;
- res = do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, subpg_code,
- paramp, rsp_buff, resp_len, 1, do_verbose);
+ res = do_logs(sg_fd, rsp_buff, resp_len, 1, &opts);
if (0 == res) {
pg_len = (rsp_buff[2] << 8) + rsp_buff[3];
if ((pg_len + 4) > resp_len) {
@@ -2086,7 +2524,7 @@ int main(int argc, char * argv[])
"output\n", resp_len);
pg_len = resp_len - 4;
}
- if (do_hex) {
+ if (opts.do_hex) {
if (rsp_buff[0] & 0x40)
printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, page_"
"len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1],
@@ -2098,16 +2536,15 @@ int main(int argc, char * argv[])
dStrHex((const char *)rsp_buff, pg_len + 4, 1);
}
else
- show_ascii_page(rsp_buff, pg_len + 4, do_pcb, &inq_out,
- do_verbose);
+ show_ascii_page(rsp_buff, pg_len + 4, &inq_out, &opts);
} else if (SG_LIB_CAT_INVALID_OP == res)
fprintf(stderr, "log_sense: page=0x%x,0x%x not supported\n",
- pg_code, subpg_code);
+ opts.pg_code, opts.subpg_code);
else if (SG_LIB_CAT_NOT_READY == res)
fprintf(stderr, "log_sense: device not ready\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
fprintf(stderr, "log_sense: field in cdb illegal "
- "[page=0x%x,0x%x]\n", pg_code, subpg_code);
+ "[page=0x%x,0x%x]\n", opts.pg_code, opts.subpg_code);
else if (SG_LIB_CAT_UNIT_ATTENTION == res)
fprintf(stderr, "log_sense: unit attention\n");
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
diff --git a/sg_luns.8 b/sg_luns.8
index 4236b8d7..230b4d52 100644
--- a/sg_luns.8
+++ b/sg_luns.8
@@ -1,46 +1,48 @@
-.TH SG_LUNS "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_LUNS "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_luns \- send the scsi command report luns
+sg_luns \- send the SCSI REPORT LUNS command
.SH SYNOPSIS
.B sg_luns
-[\fI--decode\fR] [\fI--help\fR] [\fI--hex\fR] [\fI--raw\fR]
-[\fI--select=<n>\fR] [\fI--verbose\fR] [\fI--version\fR]
-\fI<scsi_device>\fR
+[\fI\-\-decode\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-raw\fR]
+[\fI\-\-select=SR\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send REPORT LUNS command to a SCSI device and output the response.
-In the SPC-3 SCSI standard support for this command is mandatory.
+Send the SCSI REPORT LUNS command to the \fIDEVICE\fR and outputs the
+response. In the SPC\-3 SCSI standard support for this command is mandatory.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---decode | -d
+\fB\-d\fR, \fB\-\-decode\fR
decode logical unit numbers into their hierarchical parts. Interprets
-luns as described in SAM-3 when the HiSup bit is set in a
+luns as described in SAM\-3 when the HiSup bit is set in a
standard INQUIRY's response.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---hex | -H
+\fB\-H\fR, \fB\-\-hex\fR
output response to this command in ASCII hex.
.TP
---raw | -r
+\fB\-r\fR, \fB\-\-raw\fR
output response in binary (to stdout).
.TP
---select=<n> | -s <n>
-this option sets the 'select report' field in the SCSI REPORT LUNS command.
-The default value is 0. When 0 is given (or this option is not specified)
-then the given device should yield a list of luns addressable via
-this "I_T nexus" that use the following lun addressing methods: logical
+\fB\-s\fR, \fB\-\-select\fR=\fISR\fR
+this option sets the 'select report' field (\fISR\fR) in the SCSI REPORT
+LUNS command. The default value is 0. When 0 is given (or this option is
+not specified) then the \fIDEVICE\fR should yield a list of luns addressable
+via this "I_T nexus" that use the following lun addressing methods: logical
unit addressing, peripheral device addressing and flat space addressing.
-When 1 is given the given device should yield a list of only "well known"
-logical units addressable via this "I_T" nexus. When 2 is given the given
-device should yield all luns addressable via this "I_T" nexus. Currently
-SPC-3 (rev 21) doesn't specify any other values.
+When 1 is given the \fIDEVICE\fR should yield a list of only "well known"
+logical units addressable via this "I_T" nexus. When 2 is given the
+\fIDEVICE\fR should yield all luns addressable via this "I_T" nexus.
+Currently SPC\-3 (rev 23) doesn't specify any other values.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
.SH EXIT STATUS
The exit status of sg_luns is 0 when it is successful. Otherwise see
@@ -50,7 +52,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_luns.c b/sg_luns.c
index f3a41964..dfcf36c5 100644
--- a/sg_luns.c
+++ b/sg_luns.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -43,7 +45,7 @@
* This program issues the SCSI command REPORT LUNS to the given SCSI device.
*/
-static char * version_str = "1.08 20061015";
+static char * version_str = "1.10 20070128";
#define REPORT_LUNS_BUFF_LEN 1024
@@ -64,14 +66,14 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_luns [--decode] [--help] [--hex] [--raw] [--select=<n>]\n"
- " [--verbose] [--version] <scsi_device>\n"
+ "sg_luns [--decode] [--help] [--hex] [--raw] [--select=SR]\n"
+ " [--verbose] [--version] DEVICE\n"
" where:\n"
- " --decode|-d decode all luns into parts\n"
+ " --decode|-d decode all luns into component parts\n"
" --help|-h print out usage message\n"
" --hex|-H output in hexadecimal\n"
" --raw|-r output in binary\n"
- " --select=<n>|-s <n> select report <n> (def: 0)\n"
+ " --select=SR|-s SR select report SR (def: 0)\n"
" 0 -> luns apart from 'well "
"known' lus\n"
" 1 -> only 'well known' "
@@ -79,7 +81,7 @@ static void usage()
" 2 -> all luns\n"
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
- "Performs a REPORT LUNS SCSI command\n"
+ "Performs a SCSI REPORT LUNS command\n"
);
}
@@ -181,8 +183,8 @@ static void decode_lun(const char * leadin, unsigned char * lunp)
ull |= lunp[1 + j];
}
printf("%sExtended logical unit addressing: length=%d, "
- "e. a. method=%d, value=0x%llx\n", l_leadin, len,
- e_a_method, ull);
+ "e. a. method=%d, value=0x%" PRIx64 "\n",
+ l_leadin, len, e_a_method, ull);
}
}
break;
diff --git a/sg_map.8 b/sg_map.8
index 38a36ab9..c3aad5ec 100644
--- a/sg_map.8
+++ b/sg_map.8
@@ -1,10 +1,10 @@
-.TH SG_MAP "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_MAP "8" "December 2006" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_map \- displays mapping between linux sg and other SCSI devices
.SH SYNOPSIS
.B sg_map
-[\fI-a\fR] [\fI-h\fR] [\fI-i\fR] [\fI-n\fR] [\fI-scd\fR] [\fI-sd\fR]
-[\fI-sr\fR] [\fI-st\fR] [\fI-V\fR] [\fI-x\fR]
+[\fI\-a\fR] [\fI-h\fR] [\fI\-i\fR] [\fI\-n\fR] [\fI\-scd\fR] [\fI\-sd\fR]
+[\fI\-sr\fR] [\fI\-st\fR] [\fI\-V\fR] [\fI\-x\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -14,46 +14,47 @@ sg devices and finds the corresponding SCSI disk, cdrom or tape
device name (if any). Scanners are an example of SCSI devices
that have no alternate SCSI device name apart from their sg device
name.
+.SH OPTIONS
.TP
--a
+\fB\-a\fR
assume the sg devices have alphabetical device names and loop
through /dev/sga, /dev/sgb, etc. Default is numeric scan.
Note that sg device nodes with an alphabetical index have been
deprecated since the linux kernel 2.2 series.
.TP
--h
+\fB\-h\fR
print usage message then exit.
.TP
--i
+\fB\-i\fR
in addition do a standard INQUIRY and output vendor, product and revision
strings for devices that are found.
.TP
--n
+\fB\-n\fR
assume the sg devices have numeric device names and loop
through /dev/sg0, /dev/sg1, etc. Default is numeric scan
.TP
--scd
+\fB\-scd\fR
display mappings to SCSI cdrom device names of the form
/dev/scd0, /dev/scd1 etc
.TP
--sd
+\fB\-sd\fR
display mappings to SCSI disk device names
.TP
--sr
+\fB\-sr\fR
display mappings to SCSI cdrom device names of the form
/dev/sr0, /dev/sr1 etc
.TP
--st
+\fB\-st\fR
display mappings to SCSI tape device names
.TP
--V
+\fB\-V\fR
print out version string then exit (without further ado).
.TP
--x
+\fB\-x\fR
after each active sg device name is displayed there are
five digits: <host_number> <bus> <scsi_id> <lun> <scsi_type>
-.PP
-If no options starting with "-s" are given then the mapping to
+.SH NOTES
+If no options starting with "\-s" are given then the mapping to
all SCSI disk, cdrom and tape device names is shown.
.PP
If the device file system (devfs) is present a line noting
@@ -80,7 +81,7 @@ be /dev/sdb this is not necessarily so. Facilities associated
with udev may assign major 8, minor 16 some other device node
name. This version of sg_map has been extended to cope with
sparse disk device node names of the form "/dev/sd<str>"
-where <str> can be one of [a-z,aa-zz,aaa-zzz]. See the sg_map26
+where <str> can be one of [a\-z,aa\-zz,aaa\-zzz]. See the sg_map26
utility for a more precise way (i.e. less directory scanning)
for mapping between sg device names and higher level names;
including finding user defined names.
@@ -113,7 +114,7 @@ My system has a SCSI disk, a cd writer and a dvd player:
.PP
In order to find which sg device name corresponds to the disk:
.br
- $ sg_map -sd
+ $ sg_map \-sd
.br
# Note: the devfs pseudo file system is present
.br
@@ -123,9 +124,9 @@ In order to find which sg device name corresponds to the disk:
.br
/dev/sg2
.PP
-The "-x" option gives the following output:
+The "\-x" option gives the following output:
.br
- sg_map -x
+ sg_map \-x
.br
# Note: the devfs pseudo file system is present
.br
@@ -158,7 +159,7 @@ Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000-2006 Douglas Gilbert
+Copyright \(co 2000\-2006 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_map.c b/sg_map.c
index 6602257d..e2c43298 100644
--- a/sg_map.c
+++ b/sg_map.c
@@ -1,4 +1,6 @@
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -16,7 +18,7 @@
#include "sg_io_linux.h"
/* Utility program for the Linux OS SCSI generic ("sg") device driver.
-* Copyright (C) 2000-2006 D. Gilbert
+* Copyright (C) 2000-2007 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)
@@ -36,7 +38,7 @@
*/
-static char * version_str = "1.07 20060907";
+static char * version_str = "1.08 20070125";
static const char * devfs_id = "/dev/.devfsd";
@@ -95,20 +97,21 @@ static void scan_dev_type(const char * leadin, int max_dev, int do_numeric,
static void usage()
{
- printf("Usage: 'sg_map [-a] [-h] [-i] [-n] [-sd] [-scd or -sr] [-st] "
- "[-V] [-x]'\n");
- printf(" where: -a do alphabetic scan (ie sga, sgb, sgc)\n");
- printf(" -h or -? show this usage message then exit\n");
- printf(" -i also show device INQUIRY strings\n");
- printf(" -n do numeric scan (i.e. sg0, sg1, sg2) "
+ printf("Usage: sg_map [-a] [-h] [-i] [-n] [-sd] [-scd or -sr] [-st] "
+ "[-V] [-x]\n");
+ printf(" where:\n");
+ printf(" -a do alphabetic scan (ie sga, sgb, sgc)\n");
+ printf(" -h or -? show this usage message then exit\n");
+ printf(" -i also show device INQUIRY strings\n");
+ printf(" -n do numeric scan (i.e. sg0, sg1, sg2) "
"(default)\n");
- printf(" -sd show mapping to disks\n");
- printf(" -scd show mapping to cdroms (look for /dev/scd<n>\n");
- printf(" -sr show mapping to cdroms (look for /dev/sr<n>\n");
- printf(" -st show mapping to tapes (st and osst devices)\n");
- printf(" -V print version string then exit\n");
- printf(" -x also show bus,chan,id,lun and type\n");
- printf(" If no '-s*' arguments given then show all mappings\n");
+ printf(" -sd show mapping to disks\n");
+ printf(" -scd show mapping to cdroms (look for /dev/scd<n>\n");
+ printf(" -sr show mapping to cdroms (look for /dev/sr<n>\n");
+ printf(" -st show mapping to tapes (st and osst devices)\n");
+ printf(" -V print version string then exit\n");
+ printf(" -x also show bus,chan,id,lun and type\n");
+ printf(" If no '-s*' arguments given then show all mappings\n");
}
static int scandir_select(const struct dirent * s)
diff --git a/sg_map26.8 b/sg_map26.8
index 8ef5c405..2dc2d103 100644
--- a/sg_map26.8
+++ b/sg_map26.8
@@ -1,11 +1,12 @@
-.TH SG_MAP26 "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_MAP26 "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_map26 \- maps a special file to a SCSI generic (sg) device (or vv)
+sg_map26 \- maps a special file to a SCSI generic (sg) device (or
+vice versa)
.SH SYNOPSIS
.B sg_map26
-[\fI--dev_dir=<dir>\fR] [\fI--given_is=<n>\fR] [\fI--help\fR]
-[\fI--result=<n>\fR] [\fI--symlink\fR] [\fI--verbose\fR] [\fI--version\fR]
-\fI<device>\fR
+[\fI\-\-dev_dir=DIR\fR] [\fI\-\-given_is=\fR0|1] [\fI\-\-help\fR]
+[\fI\-\-result=\fR0|1|2|3] [\fI\-\-symlink\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -16,7 +17,7 @@ or '/sys/block/sda/dev'.
.PP
Rather than map to or from a sg device, the sysfs file name
matching a given device special file (or vice versa) can be
-requested. This is done with '--result=2' and '--result=3'.
+requested. This is done with '\-\-result=2' and '\-\-result=3'.
This feature works on ATA devices (e.g. 'dev/hdc') as well
as SCSI devices.
.PP
@@ -25,7 +26,7 @@ a SCSI generic (sg) node and the higher level SCSI device name; or
vice versa. For example '/dev/sg0' may "map" to '/dev/sda'.
Mappings may not exist, if a relevant module is not loaded, for
example. Also there are SCSI devices that can only be accessed via a sg
-node (e.g. SAF-TE and some SES devices).
+node (e.g. SAF\-TE and some SES devices).
.PP
In this utility, "matching" refers to different representations of
the same device accessed via the same driver. For example, '/dev/hdc'
@@ -33,29 +34,31 @@ and '/sys/block/hdc' usually refer to the same device and thus would
be considered matching. A related example is that '/dev/cdrom'
and '/dev/hdc' are also considered matching if '/dev/cdrom' is a
symlink to '/dev/hdc'.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---dev_dir=<dir> | -d <dir>
-The <dir> argument is the directory to search for resultant device
-special files in (or symlinks to same). Only active
-when '--result=0' (the default) or '--result=2'. If this option is not
-given and <device> is a device special file then the directory part
-of <device> is assumed. If this option is not given and <device> is a
-sysfs name, then if necessary '/dev' is assumed as the directory.
+\fB\-d\fR, \fB\-\-dev_dir\fR=\fIDIR\fR
+where \fIDIR\fR is the directory to search for resultant device special
+files in (or symlinks to same). Only active when '\-\-result=0' (the
+default) or '\-\-result=2'. If this option is not given and \fIDEVICE\fR is
+a device special file then the directory part of \fIDEVICE\fR is assumed.
+If this option is not given and \fIDEVICE\fR is a sysfs name, then if
+necessary '/dev' is assumed as the directory.
.TP
---given_is=0|1 | -g 0|1
-specifies the given <device> is either a device special file (when the
+\fB\-g\fR, \fB\-\-given_is\fR=0 | 1
+specifies the \fIDEVICE\fR is either a device special file (when the
argument is 0), or a sysfs 'dev' file (when the argument is 1). The parent
directory of a sysfs 'dev' file is also accepted (e.g.
either '/sys/block/sda/dev' or '/sys/block/sda' are accepted). Usually
there is no need to give this option since this utility first checks for
special files (or symlinks to special files) and if not, assumes it
has been given a sysfs 'dev' file (or its parent). Generates an error
-if given and disagrees with variety of <device>.
+if given and disagrees with variety of \fIDEVICE\fR.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---result=0|1|2|3 | -r 0|1|2|3
+\fB\-r\fR, \fB\-\-result\fR=0 | 1 | 2 | 3
specifies what variety of file (or files) that this utility tries to find.
The default is a "mapped" device special file, when the argument is 0.
When the argument is 1, this utility tries to find the "mapped" sysfs node
@@ -63,17 +66,17 @@ name. When the argument is 2, this utility tries to find the "matching"
device special file. When the argument is 3, this utility tries to find
the "matching" sysfs node name.
.TP
---symlink | -s
-when a device special file is being sought (i.e. when '--result=0' (the
-default) or '--result=2') then also look for symlinks to that device
+\fB\-s\fR, \fB\-\-symlink\fR
+when a device special file is being sought (i.e. when '\-\-result=0' (the
+default) or '\-\-result=2') then also look for symlinks to that device
special file in the same directory.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
+.SH NOTES
This utility is designed for the linux 2.6 kernel series. It uses
special file major and minor numbers (and whether the special is
block or character) together with sysfs to do its mapping or
@@ -102,15 +105,15 @@ Assume sg2 maps to sdb while dvd, cdrom and hdc are all matching.
.br
/dev/sg2
.PP
- # sg_map26 --result=0 /dev/sdb
+ # sg_map26 \-\-result=0 /dev/sdb
.br
/dev/sg2
.PP
- # sg_map26 --result=3 /dev/sdb
+ # sg_map26 \-\-result=3 /dev/sdb
.br
/sys/block/sda
.PP
- # sg_map26 --result=1 /dev/sdb
+ # sg_map26 \-\-result=1 /dev/sdb
.br
/sys/class/scsi_generic/sg0
.PP
@@ -120,15 +123,15 @@ Now look at '/dev/hdc' and friends
.br
<error: a hd device does not map to a sg device>
.PP
- # sg_map26 --result=3 /dev/hdc
+ # sg_map26 \-\-result=3 /dev/hdc
.br
/sys/block/hdc
.PP
- # sg_map26 --result=2 /dev/hdc
+ # sg_map26 \-\-result=2 /dev/hdc
.br
/dev/hdc
.PP
- # sg_map26 --result=2 --symlink /dev/hdc
+ # sg_map26 \-\-result=2 \-\-symlink /dev/hdc
.br
/dev/cdrom
.br
@@ -136,7 +139,7 @@ Now look at '/dev/hdc' and friends
.br
/dev/hdc
.PP
- # sg_map26 --result=2 --symlink /sys/block/hdc
+ # sg_map26 \-\-result=2 \-\-symlink /sys/block/hdc
.br
/dev/cdrom
.br
@@ -151,7 +154,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2005-2006 Douglas Gilbert
+Copyright \(co 2005\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_map26.c b/sg_map26.c
index 6f81d828..5f92ca36 100644
--- a/sg_map26.c
+++ b/sg_map26.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2006 Douglas Gilbert.
+ * Copyright (c) 2005-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,7 +37,9 @@
/* #define _XOPEN_SOURCE 500 */
/* needed to see DT_REG and friends when compiled with: c99 pedantic */
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -56,7 +58,7 @@
#include "sg_lib.h"
-static char * version_str = "1.03 20061003";
+static char * version_str = "1.05 20070127";
#define ME "sg_map26: "
@@ -137,30 +139,31 @@ static const char * nt_names[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_map26 [--dev_dir=<dir>] [--given_is=<n>] [--help] "
- "[--result=<n>]\n"
- " [--symlink] [--verbose] [--version] "
- "<device>\n"
+ "sg_map26 [--dev_dir=DIR] [--given_is=0|1] [--help] "
+ "[--result=0|1|2|3]\n"
+ " [--symlink] [--verbose] [--version] "
+ "DEVICE\n"
" where:\n"
- " --dev_dir=<dir>|-d <dir> search in <dir> for "
+ " --dev_dir=DIR|-d DIR search in DIR for "
"resulting special\n"
- " (def: directory of <device> "
+ " (def: directory of DEVICE "
"or '/dev')\n"
- " --given_is=<n>|-g <n> variety of given "
- "<device>\n"
- " 0->block or char special "
+ " --given_is=0|1|-g 0|1 variety of given "
+ "DEVICE\n"
+ " 0->block or char special "
"(or symlink to)\n"
- " 1->sysfs device, 'dev' or "
+ " 1->sysfs device, 'dev' or "
"parent\n"
" --help|-h print out usage message\n"
- " --result=<n>|-r <n> variety of file(s) to "
+ " --result=0|1|2|3|-r 0|1|2|3 variety of file(s) to "
"find\n"
- " 0->mapped block or char "
+ " 0->mapped block or char "
"special(def)\n"
- " 1->mapped sysfs parent\n"
- " 2->matching block or char "
- "special\n"
- " 3->matching sysfs parent\n"
+ " 1->mapped sysfs path\n"
+ " 2->matching block or "
+ "char special\n"
+ " 3->matching sysfs "
+ "path\n"
" --symlink|-s symlinks to special included in "
"result\n"
" --verbose|-v set device identifier\n"
diff --git a/sg_modes.8 b/sg_modes.8
index cc631a8b..0b6b7033 100644
--- a/sg_modes.8
+++ b/sg_modes.8
@@ -1,156 +1,258 @@
-.TH SG_MODES "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_MODES "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_modes \- reads SCSI MODE SENSE pages
+sg_modes \- reads mode pages with SCSI MODE SENSE command
.SH SYNOPSIS
.B sg_modes
-[\fI-a\fR] [\fI-A\fR] [\fI-c=<page_control>\fR] [\fI-d\fR] [\fI-D\fR]
-[\fI-e\fR] [\fI-f\fR] [\fI-h\fR] [\fI-H\fR] [\fI-l\fR] [\fI-L\fR]
-[\fI-p=<page_code>\fR] [\fI-p=<page_code>,<sub_page_code>\fR]
-[\fI-r\fR] [\fI-subp=<sub_page_code>\fR] [\fI-v\fR] [\fI-V\fR] [\fI-6\fR]
-[\fI-?\fR] [\fI<scsi_device>\fR]
+[\fI\-\-all\fR] [\fI\-\-control=PC\fR] [\fI\-\-dbd\fR] [\fI\-\-dbout\fR]
+[\fI\-\-examine\fR] [\fI\-\-flexible\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR]
+[\fI\-\-list\fR] [\fI\-\-llbaa\fR] [\fI\-\-page=PG[,SPG]\fR]
+[\fI\-\-raw\fR] [\fI\-R\fR] [\fI\-\-six\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] [\fIDEVICE\fR]
+.PP
+.B sg_modes
+[\fI\-6\fR] [\fI\-a\fR] [\fI\-A\fR] [\fI\-c=PC\fR] [\fI\-d\fR] [\fI\-D\fR]
+[\fI\-e\fR] [\fI\-f\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-l\fR] [\fI\-L\fR]
+[\fI\-p=PG[,SPG]\fR] [\fI\-r\fR] [\fI\-subp=SPG\fR] [\fI\-v\fR] [\fI\-V\fR]
+[\fI\-?\fR] [\fIDEVICE\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
-This utility sends a MODE SENSE SCSI command (the 10 byte variant
-by default) to the given device and then outputs the response. There
-is no facility to change the page or descriptor data with this utility.
-If no page is given (and '-l' is not selected) then '-a' is assumed.
-.TP
--a
-output all the mode pages supported by the given device.
-.TP
--A
-output all the mode pages and subpages supported by the device.
-.TP
--c=page_control
-up to four different versions of each page are held by the device:
-the current values [0] (i.e. those active at the moment), the changeable
-values [1] (bit mask showing which sections could be changed with a MODE
-SELECT), default values [2] (the manufacturer's settings) and saved
-values [3] (the values that will be re-instated the next time the device
-is power cycled). If this option is not given then current values [0]
-are assumed.
-.TP
--d
-disable block descriptors. By default, block descriptors (usually one or
-none) are returned in a MODE SENSE response. This option sets the "disable
-block descriptors" (DBD) bit in the cdb which instructs the device not
-to return any block descriptors in its response. Older devices may not
-support this setting and should return an "illegal request" status;
-alternatively they may ignore it.
-.TP
--D
+This utility sends a MODE SENSE SCSI command to the \fIDEVICE\fR and
+outputs the response. There is a 6 byte and 10 byte (cdb) variant of
+the MODE SENSE command, this utility defaults to the 10 byte variant.
+.PP
+This utility decodes mode page headers and block descriptors but outputs
+the contents of each mode page in hex. It also has no facility to change
+the mode page contents or block descriptor data. Mode page contents are
+decoded and can be changed by the
+.B sdparm
+utility.
+.PP
+This utility supports two command line syntaxes, the preferred one is
+shown first in the synopsis and explained in this section. A later
+section on the old command line syntax outlines the second group of
+options.
+.PP
+If no page is given (and \fI\-\-list\fR is not selected) then \fI\-\-all\fR
+is assumed. The \fI\-\-all\fR option requests all mode pages (but not
+subpages) in a single response.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-a\fR, \fB\-\-all\fR
+output all the mode pages reported by the \fIDEVICE\fR. This is what the
+page code 63 (0x3f) is defined to do. When used once, mode subpages are
+not fetched. When used twice (e.g. '\-aa'), all mode pages and subpages
+are requested which is equivalent to '\-\-page=63,255'.
+.TP
+\fB\-c\fR, \fB\-\-control\fR=\fIPC\fR
+\fIPC\fR is the page control value. Up to four different versions of each
+page are held by the device: the current values [0] (i.e. those active at
+the moment), the changeable values [1] (bit mask showing which fields could
+be changed with a MODE SELECT), default values [2] (the manufacturer's
+settings). Finally there are the saved values [3] which are the values that
+will be re\-instated the next time the device is power cycled. If this option
+is not given then current values [0] are assumed.
+.TP
+\fB\-d\fR, \fB\-\-dbd\fR
+disable block descriptors. By default, block descriptors (usually
+one (for disks) or none) are returned in a MODE SENSE response. This option
+sets the "disable block descriptors" (DBD) bit in the cdb which instructs
+the device not to return any block descriptors in its response. Older
+devices may not support this setting and may return an "illegal request"
+sense key; alternatively they may ignore it. Oddly the Reduced Block Command
+set (RBC) requires this bit set.
+.TP
+\fB\-D\fR, \fB\-\-dbout\fR
disable outputting block descriptors. Irrespective of whether block
descriptors are present in the response or not, they are not output.
.TP
--e
+\fB\-e\fR, \fB\-\-examine\fR
examine each mode page in the range 0 through to 62 (inclusive).
-If some response is given print out the mode page name or number (in hex)
-if the name is not known.
-.TP
--f
-Be "flexible". Some devices, bridges and/or drivers attempt crude
-switches between mode sense 6 and 10 byte commands without correcting
-the response. This will cause the response to be mis-interpreted (usually
-with an error saying the response is malformed). With this option, the
-length of the response is checked, and if it looks wrong, the response
-is then decoded as if the other mode sense (cdb length) was sent.
-.TP
--h
-The default action is to decode known mode page numbers (and subpage
-numbers) into text. With this option mode page numbers (and subpage
-numbers) are output in hexadecimal.
+If some response is given then print out the mode page name or
+number (in hex) if the name is not known.
+.TP
+\fB\-f\fR, \fB\-\-flexible\fR
+Some devices, bridges and/or drivers attempt crude translations between
+MODE SENSE 6 and 10 byte commands without correcting the response. This
+will cause the response to be mis\-interpreted (usually with an error saying
+the response is malformed). With this option, the length of the response
+is checked, and if it looks wrong, the response is then decoded as if the
+other mode sense (cdb length) was sent.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+print out the usage message then exit.
.TP
--H
-same action as the '-h' option.
+\fB\-H\fR, \fB\-\-hex\fR
+The default action is to decode known mode page numbers (and subpage
+numbers) into text. When this option is used once, the response is output
+in hexadecimal. When this option is used twice, mode page numbers and
+page control values are output in hex.
.TP
--l
+\fB\-l\fR, \fB\-\-list\fR
lists all common page and subpage codes and their names that are found in
-the command set that matches the peripheral type of the given device.
-If no device and no page_code is given then the common page and
-subpage codes and their names for the disk command set are listed.
-If no device is given and a page_code is given then the common page and
-subpage codes and their names for the command set whose peripheral device
-type matches the value given to page_code are listed. For
-example 'sg_mode -l -p=1' lists the command mode pages and subpages for tape
-devices. Additionally if a sub_page_code is given then it is interpreted as
-a transport identifier and command transport specific mode page codes and
-their names are listed following the main mode page list.
+the command set that matches the peripheral type of the given \fIDEVICE\fR.
+If no \fIDEVICE\fR and no \fI\-\-page=PG\fR is given then the common page and
+subpage codes and their names are listed for SBC (e.g. a disk). If no
+\fIDEVICE\fR is given and a \fI\-\-page=PG\fR is given then the
+common page and subpage codes and their names are listed for the command set
+whose peripheral device type matches the value given to \fIPG\fR. For
+example 'sg_mode \-\-list \-\-page=1' lists the command mode pages and
+subpages for tape devices. Additionally if a sub_page_code is given then it
+is interpreted as a transport identifier and command transport specific mode
+page codes and their names are listed following the main mode page list.
Other options are ignored.
.TP
--L
+\fB\-L\fR, \fB\-\-llbaa\fR
set the Long LBA Accepted (LLBAA) bit in the MODE SENSE (10) cdb. This
-bit is not defined in the MODE SENSE (6) cdb so setting the '-L'
-and '-6' options is reported as an error. When set the given device
+bit is not defined in the MODE SENSE (6) cdb so setting the '\-L'
+and '\-\-six' options is reported as an error. When set the \fIDEVICE\fR
may respond with 16 byte block descriptors as indicated by
-the 'LongLBA' field in the response. In almost all cases setting
-this option is not needed.
+the 'LongLBA' field in the response. In most cases setting this option
+is not needed.
.TP
--p=<page_code>
-page code to fetch. Should be a hexadecimal number between 0 and 3f
-inclusive (0 to 63 decimal). The default value is 0.
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
.TP
--p=<page_code>,<sub_page_code>
-page code and subpage code values to fetch. The page code should be a
-hexadecimal number between 0 and 3f inclusive. The subpage code should
-be a hexadecimal number between 0 and ff inclusive. The default value
-of both is 0.
+\fB\-p\fR, \fB\-\-page\fR=\fIPG\fR
+page code to fetch. The \fIPG\fR is assumed to be a decimal value unless
+prefixed by '0x' or has a trailing 'h'. It should be a value between 0
+and 63 (inclusive). When not given and a default is required then
+a value of 63 (0x3f), which fetches all mode pages, is used.
.TP
--r
-output the selected mode page to stdout a byte per line. Each line contains
-two hexadecimal digits (e.g. "0a"). Useful as input (after editing) to
-the sg_wr_mode utility.
+\fB\-p\fR, \fB\-\-page\fR=\fIPG,SPG\fR
+page code and subpage code values to fetch. Both arguments are assumed
+to be decimal unless flagged as hexadecimal. The page code should be
+between 0 and 63 inclusive. The subpage code should be between 0 and 255
+inclusive. The default value for the subpage code is 0.
.TP
--subp=<sub_page_code>
-sub page code to fetch. Should be a hexadecimal number between 0 and
-0xff inclusive. The default value is 0.
+\fB\-r\fR, \fB\-\-raw\fR
+output the response in binary to stdout. Error messages and warnings, if
+any, are sent to stderr. When this option is used twice (e.g. '\-rr')
+then has the same action as '\-R'
.TP
--v
-verbose: output cdbs in hex before executing them. '-vv'
-and '-vvv' are also accepted yielding greater verbosity.
+\fB\-R\fR
+output the selected mode page to stdout a byte per line. Each line contains
+two hexadecimal digits (e.g. "3e"). Useful as input (after editing) to
+the sg_wr_mode utility.
.TP
--V
-print out version string
+\fB\-6\fR, \fB\-\-six\fR
+by default this utility sends a 10 byte MODE SENSE command to
+the \fIDEVICE\fR. However some SCSI devices only support 6 byte MODE SENSE
+commands (e.g. SCSI\-2 tape drives). This parameter forces the use
+of 6 byte MODE SENSE commands.
.TP
--6
-by default this utility sends out a 10 byte MODE SENSE command. However
-some SCSI devices only support 6 byte MODE SENSE commands (e.g. SCSI-2
-tape drives). This parameter forces the use of 6 byte MODE SENSE commands.
+\fB\-v\fR, \fB\-\-verbose\fR
+increase level of verbosity. Can be used multiple times.
.TP
--?
-output usage message. Ignore all other parameters.
-.PP
+\fB\-V\fR, \fB\-\-version\fR
+print out version string then exit.
+.SH NOTES
If the normal sg_modes utility fails with "illegal command
-operation code" then try the "-6" parameter.
-.PP
-Mode pages cannot be modified with this utility. Mode pages (and subpages)
-can be modified with the sg_wr_mode and sginfo utilities in the sg3_utils
-package. See the sdparm utility and those other utilities that are
-listed in the "SEE ALSO" section below.
+operation code" then try the '\-\-six' (or '\-6') option.
.PP
This utility performs a SCSI INQUIRY command to determine the peripheral
-type of the device (e.g. 0 -> Direct Access Device (disk)) prior to
+type of the device (e.g. 0 \-> Direct Access Device (disk)) prior to
sending a MODE SENSE command. This helps in decoding the block
descriptor and mode pages.
.PP
-In the 2.4 series of Linux kernels the given device must be
-a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example "sg_modes -a /dev/sda"
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI
+generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks
+and DVD drives) can also be specified. For example "sg_modes \-a /dev/sda"
will work in the 2.6 series kernels.
.SH EXIT STATUS
The exit status of sg_modes is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using '\-\-old' (or '\-O) as the first option.
+.TP
+\fB\-6\fR
+by default this utility sends a 10 byte MODE SENSE command to
+the \fIDEVICE\fR. This parameter forces the use of 6 byte MODE SENSE commands.
+See \fI\-\-six\fR in the main description.
+.TP
+\fB\-a\fR
+see \fI\-\-all\fR in the main description.
+.TP
+\fB\-A\fR
+output all the mode pages and subpages supported by the \fIDEVICE\fR. Same
+as '\-\-all \-\-all' in the new syntax.
+.TP
+\fB\-c\fR=\fIPC\fR
+\fIPC\fR is the page control value. See \fB\-\-control\fR=\fIPC\fR in
+the main description.
+.TP
+\fB\-d\fR
+see \fB\-\-dbd\fR in the main description.
+.TP
+\fB\-D\fR
+see \fB\-\-dbout\fR in the main description.
+.TP
+\fB\-e\fR
+see \fB\-\-examine\fR in the main description.
+.TP
+\fB\-f\fR
+see \fB\-\-flexible\fR in the main description.
+.TP
+\fB\-h\fR
+The default action is to decode known mode page numbers (and subpage
+numbers) into text. With this option mode page numbers (and subpage
+numbers) are output in hexadecimal.
+.TP
+\fB\-H\fR
+same action as the '\-h' option.
+.TP
+\fB\-l\fR
+see \fB\-\-list\fR in the main description.
+.TP
+\fB\-L\fR
+see \fB\-\-llbaa\fR in the main description.
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-p\fR=\fIPG\fR
+\fIPG\fR is page code to fetch. Should be a hexadecimal number between 0
+and 3f inclusive (0 to 63 decimal). The default value when required is
+3f (fetch all mode pages).
+.TP
+\fB\-p\fR=\fIPG,SPG\fR
+page code and subpage code values to fetch. The page code should be a
+hexadecimal number between 0 and 3f inclusive. The subpage code should
+be a hexadecimal number between 0 and ff inclusive. The default value
+for the subpage code is 0.
+.TP
+\fB\-r\fR
+output the selected mode page to stdout a byte per line. Each line contains
+two hexadecimal digits (e.g. "3e"). Useful as input (after editing) to
+the sg_wr_mode utility.
+.TP
+\fB\-subp\fR=\fISPG\fR
+sub page code to fetch. Should be a hexadecimal number between 0 and
+0xff inclusive. The default value is 0.
+.TP
+\fB\-v\fR
+increase verbosity of output.
+.TP
+\fB\-V\fR
+print out version string then exit.
+.TP
+\fB\-?\fR
+output usage message then exit. Ignore all other parameters.
.SH AUTHOR
Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000-2006 Douglas Gilbert
+Copyright \(co 2000\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B sdparm(net), sg_wr_mode(sg3_utils), sginfo(sg3_utils),
+.B sdparm(sdparm), sg_wr_mode(sg3_utils), sginfo(sg3_utils),
.B sgmode(scsirastools), scsiinfo(net), scu(net),
.B seatools(seagate)
.PP
diff --git a/sg_modes.c b/sg_modes.c
index a2854afd..e663a9f9 100644
--- a/sg_modes.c
+++ b/sg_modes.c
@@ -4,12 +4,13 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <getopt.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
-/* A utility program for the Linux OS SCSI generic ("sg") device driver.
-* Copyright (C) 2000-2006 D. Gilbert
+/*
+* Copyright (C) 2000-2007 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)
@@ -18,12 +19,11 @@
This program outputs information provided by a SCSI MODE SENSE command.
Does 10 byte MODE SENSE commands by default, Trent Piepho added a "-6"
switch for force 6 byte mode sense commands.
+ This utility cannot modify mode pages. See the sdparm utility for that.
*/
-static char * version_str = "1.20 20061012";
-
-#define ME "sg_modes: "
+static char * version_str = "1.23 20070127";
#define MX_ALLOC_LEN (1024 * 4)
#define PG_CODE_ALL 0x3f
@@ -36,6 +36,455 @@ static char * version_str = "1.20 20061012";
#define EBUFF_SZ 256
+static struct option long_options[] = {
+ {"all", 0, 0, 'a'},
+ {"control", 1, 0, 'c'},
+ {"dbd", 0, 0, 'd'},
+ {"dbout", 0, 0, 'D'},
+ {"examine", 0, 0, 'e'},
+ {"flexible", 0, 0, 'f'},
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"list", 0, 0, 'l'},
+ {"llbaa", 0, 0, 'L'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"page", 1, 0, 'p'},
+ {"raw", 0, 0, 'r'},
+ {"six", 0, 0, '6'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+struct opts_t {
+ int do_all;
+ int do_dbd;
+ int do_dbout;
+ int do_examine;
+ int do_flexible;
+ int do_help;
+ int do_hex;
+ int do_list;
+ int do_llbaa;
+ int do_raw;
+ int do_six;
+ int do_verbose;
+ int do_version;
+ int page_control;
+ int pg_code;
+ int subpg_code;
+ int subpg_code_set;
+ const char * device_name;
+ int opt_new;
+};
+
+static void usage()
+{
+ printf("Usage: sg_modes [--all] [--control=PC] [--dbd] [--dbout] "
+ "[--examine]\n"
+ " [--flexible] [--help] [--hex] [--list] "
+ "[--llbaa]\n"
+ " [--page=PG[,SPG]] [--raw] [-R] [--six] "
+ "[--verbose] [--version]\n"
+ " [DEVICE]\n"
+ " where:\n"
+ " --all|-a get all mode pages supported by device\n"
+ " use twice to get all mode pages and subpages\n"
+ " --control=PC|-c PC page control (default: 0)\n"
+ " 0: current, 1: changeable,\n"
+ " 2: (manufacturer's) defaults, "
+ "3: saved\n"
+ " --dbd|-d disable block descriptors (DBD field in cdb)\n"
+ " --dbout|-D disable block descriptor output\n"
+ " --examine|-e examine pages # 0 through to 0x3e, note if "
+ "found\n"
+ " --flexible|-f be flexible, cope with MODE SENSE 6/10 "
+ "response mixup\n");
+ printf(" --help|-h print usage message then exit\n"
+ " --hex|-H output full response in hex\n"
+ " use twice to output page number and header "
+ "in hex\n"
+ " --list|-l list common page codes for device peripheral "
+ "type,\n"
+ " if no device given then assume disk type\n"
+ " --llbaa|-L set Long LBA Accepted (LLBAA field in mode "
+ "sense (10) cdb)\n"
+ " --page=PG|-p PG page code to fetch (def: 63)\n"
+ " --page=PG,SPG|-p PG,SPG\n"
+ " page code and subpage code to fetch "
+ "(defs: 63,0)\n"
+ " --raw|-r output response in binary to stdout\n"
+ " -R mode page response to stdout, a byte per "
+ "line in ASCII\n"
+ " hex (same result as '--raw --raw')\n"
+ " --six|-6 use MODE SENSE(6), by default uses MODE "
+ "SENSE(10)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V output version string then exit\n\n"
+ "Performs a SCSI MODE SENSE (10 or 6) command\n");
+}
+
+static void usage_old()
+{
+ printf("Usage: sg_modes [-a] [-A] [-c=PC] [-d] [-D] [-e] [-f] [-h] "
+ "[-H] [-l] [-L]\n"
+ " [-p=PG[,SPG]] [-r] [-subp=SPG] [-v] [-V] "
+ "[-6] [DEVICE]\n"
+ " where:\n"
+ " -a get all mode pages supported by device\n"
+ " -A get all mode pages and subpages supported by device\n"
+ " -c=PC page control (def: 0 [current],"
+ " 1 [changeable],\n"
+ " 2 [default], 3 [saved])\n"
+ " -d disable block descriptors (DBD field in cdb)\n"
+ " -D disable block descriptor output\n"
+ " -e examine pages # 0 through to 0x3e, note if found\n"
+ " -f be flexible, cope with MODE SENSE 6/10 response "
+ "mixup\n");
+ printf(" -h output page number and header in hex\n"
+ " -H output page number and header in hex (same as '-h')\n"
+ " -l list common page codes for device peripheral type,\n"
+ " if no device given then assume disk type\n"
+ " -L set Long LBA Accepted (LLBAA field in mode sense "
+ "10 cdb)\n"
+ " -p=PG page code in hex (def: 3f)\n"
+ " -p=PG,SPG both in hex, (defs: 3f,0)\n"
+ " -r mode page output to stdout, a byte per line in "
+ "ASCII hex\n"
+ " -subp=SPG sub page code in hex (def: 0)\n"
+ " -v verbose\n"
+ " -V output version string\n"
+ " -6 Use MODE SENSE(6), by default uses MODE SENSE(10)\n"
+ " -? output this usage message\n\n"
+ "Performs a SCSI MODE SENSE (10 or 6) command\n");
+}
+
+static void usage_for(const struct opts_t * optsp)
+{
+ if (optsp->opt_new)
+ usage();
+ else
+ usage_old();
+}
+
+/* Trying to decode multipliers as sg_get_num() [as sg_libs does] would
+ * only confuse things here, so use this local trimmed version */
+static int get_num(const char * buf)
+{
+ int res, len, num;
+ unsigned int unum;
+ const char * commap;
+
+ if ((NULL == buf) || ('\0' == buf[0]))
+ return -1;
+ len = strlen(buf);
+ commap = strchr(buf + 1, ',');
+ if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
+ res = sscanf(buf + 2, "%x", &unum);
+ num = unum;
+ } else if (commap && ('H' == toupper(*(commap - 1)))) {
+ res = sscanf(buf, "%x", &unum);
+ num = unum;
+ } else if ((NULL == commap) && ('H' == toupper(buf[len - 1]))) {
+ res = sscanf(buf, "%x", &unum);
+ num = unum;
+ } else
+ res = sscanf(buf, "%d", &num);
+ if (1 == res)
+ return num;
+ else
+ return -1;
+}
+
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c, n, nn;
+ char * cp;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "6aAc:dDefhHlLNOp:rRsvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case '6':
+ ++optsp->do_six;
+ break;
+ case 'a':
+ ++optsp->do_all;
+ break;
+ case 'A':
+ optsp->do_all += 2;
+ break;
+ case 'c':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 3)) {
+ fprintf(stderr, "bad argument to '--control='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->page_control = n;
+ break;
+ case 'd':
+ ++optsp->do_dbd;
+ break;
+ case 'D':
+ ++optsp->do_dbout;
+ break;
+ case 'e':
+ ++optsp->do_examine;
+ break;
+ case 'f':
+ ++optsp->do_flexible;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'l':
+ ++optsp->do_list;
+ break;
+ case 'L':
+ ++optsp->do_llbaa;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'p':
+ cp = strchr(optarg, ',');
+ n = get_num(optarg);
+ if ((n < 0) || (n > 63)) {
+ fprintf(stderr, "Bad argument to '--page='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (cp) {
+ nn = get_num(cp + 1);
+ if ((nn < 0) || (nn > 255)) {
+ fprintf(stderr, "Bad second value in argument to "
+ "'--page='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->subpg_code = nn;
+ optsp->subpg_code_set = 1;
+ } else
+ nn = 0;
+ optsp->pg_code = n;
+ break;
+ case 'r':
+ ++optsp->do_raw;
+ break;
+ case 'R':
+ optsp->do_raw += 2;
+ break;
+ case 's':
+ ++optsp->do_six;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
+{
+ int k, jmp_out, plen, num;
+ unsigned int u, uu;
+ const char * cp;
+
+ for (k = 1; k < argc; ++k) {
+ cp = argv[k];
+ plen = strlen(cp);
+ if (plen <= 0)
+ continue;
+ if ('-' == *cp) {
+ for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
+ switch (*cp) {
+ case '6':
+ ++optsp->do_six;
+ break;
+ case 'a':
+ ++optsp->do_all;
+ break;
+ case 'A':
+ optsp->do_all += 2;
+ break;
+ case 'd':
+ ++optsp->do_dbd;
+ break;
+ case 'D':
+ ++optsp->do_dbout;
+ break;
+ case 'e':
+ ++optsp->do_examine;
+ break;
+ case 'f':
+ ++optsp->do_flexible;
+ break;
+ case 'h':
+ case 'H':
+ optsp->do_hex += 2;
+ break;
+ case 'l':
+ ++optsp->do_list;
+ break;
+ case 'L':
+ ++optsp->do_llbaa;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case 'r':
+ optsp->do_raw += 2;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case '?':
+ ++optsp->do_help;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+ if (0 == strncmp("c=", cp, 2)) {
+ num = sscanf(cp + 2, "%x", &u);
+ if ((1 != num) || (u > 3)) {
+ fprintf(stderr, "Bad page control after 'c=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->page_control = u;
+ } else if (0 == strncmp("p=", cp, 2)) {
+ if (NULL == strchr(cp + 2, ',')) {
+ num = sscanf(cp + 2, "%x", &u);
+ if ((1 != num) || (u > 63)) {
+ fprintf(stderr, "Bad page code value after 'p=' "
+ "option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->pg_code = u;
+ } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) {
+ if (uu > 255) {
+ fprintf(stderr, "Bad sub page code value after 'p=' "
+ "option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->pg_code = u;
+ optsp->subpg_code = uu;
+ optsp->subpg_code_set = 1;
+ } else {
+ fprintf(stderr, "Bad page code, subpage code sequence "
+ "after 'p=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == strncmp("subp=", cp, 5)) {
+ num = sscanf(cp + 5, "%x", &u);
+ if ((1 != num) || (u > 255)) {
+ fprintf(stderr, "Bad sub page code after 'subp=' "
+ "option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->subpg_code = u;
+ optsp->subpg_code_set = 1;
+ if (-1 == optsp->pg_code)
+ optsp->pg_code = 0;
+ } else if (0 == strncmp("-old", cp, 4))
+ ;
+ else if (jmp_out) {
+ fprintf(stderr, "Unrecognized option: %s\n", cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == optsp->device_name)
+ optsp->device_name = cp;
+ else {
+ fprintf(stderr, "too many arguments, got: %s, not expecting: "
+ "%s\n", optsp->device_name, cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
+
+static void dStrRaw(const char* str, int len)
+{
+ int k;
+
+ for (k = 0 ; k < len; ++k)
+ printf("%c", str[k]);
+}
+
+
static const char * transport_proto_arr[] =
{
"Fibre Channel (FCP-2)",
@@ -394,17 +843,18 @@ static void list_page_codes(int scsi_ptype, int inq_byte6, int t_proto)
}
}
-static int examine_pages(int sg_fd, int do_mode6, int inq_pdt, int inq_byte6,
- int verbose)
+static int examine_pages(int sg_fd, int inq_pdt, int inq_byte6,
+ const struct opts_t * optsp)
{
- int k, res, header;
- unsigned char rbuf[4];
+ int k, res, header, mresp_len, len;
+ unsigned char rbuf[256];
const char * cp;
+ mresp_len = (optsp->do_raw || optsp->do_hex) ? sizeof(rbuf) : 4;
for (header = 0, k = 0; k < 0x3f; ++k) {
- if (do_mode6) {
- res = sg_ll_mode_sense6(sg_fd, 0, 0, k, 0,
- rbuf, sizeof(rbuf), 0, verbose);
+ if (optsp->do_six) {
+ res = sg_ll_mode_sense6(sg_fd, 0, 0, k, 0, rbuf, mresp_len,
+ 0, optsp->do_verbose);
if (SG_LIB_CAT_INVALID_OP == res) {
fprintf(stderr, ">>>>>> try again without the '-6' "
"switch for a 10 byte MODE SENSE command\n");
@@ -414,8 +864,8 @@ static int examine_pages(int sg_fd, int do_mode6, int inq_pdt, int inq_byte6,
return res;
}
} else {
- res = sg_ll_mode_sense10(sg_fd, 0, 0, 0, k,
- 0, rbuf, sizeof(rbuf), 1, verbose);
+ res = sg_ll_mode_sense10(sg_fd, 0, 0, 0, k, 0, rbuf, mresp_len,
+ 1, optsp->do_verbose);
if (SG_LIB_CAT_INVALID_OP == res) {
fprintf(stderr, ">>>>>> try again with a '-6' "
"switch for a 6 byte MODE SENSE command\n");
@@ -426,6 +876,14 @@ static int examine_pages(int sg_fd, int do_mode6, int inq_pdt, int inq_byte6,
}
}
if (0 == res) {
+ len = optsp->do_six ? (rbuf[0] + 1) :
+ ((rbuf[0] << 8) + rbuf[1] + 2);
+ if (len > mresp_len)
+ len = mresp_len;
+ if (optsp->do_raw) {
+ dStrRaw((const char *)rbuf, len);
+ continue;
+ }
if (0 == header) {
printf("Discovered mode pages:\n");
header = 1;
@@ -435,6 +893,8 @@ static int examine_pages(int sg_fd, int do_mode6, int inq_pdt, int inq_byte6,
printf(" %s\n", cp);
else
printf(" [0x%x]\n", k);
+ if (optsp->do_hex)
+ dStrHex((const char *)rbuf, len, 1);
}
}
return res;
@@ -447,227 +907,66 @@ static const char * pg_control_str_arr[] = {
"saved",
};
-static void usage()
-{
- printf("Usage: sg_modes [-a] [-A] [-c=<page_control] [-d] [-D] [-f] "
- "[-e] [-h] [-H]\n\t\t"
- " [-l] [-L] [-p=<page_number>[,<sub_page_code>]] [-r]"
- "\n\t\t [-subp=<sub_page_code>] [-v] [-V] [-6] [<scsi_device>]\n"
- " where:\n"
- " -a get all mode pages supported by device\n"
- " -A get all mode pages and subpages supported by device\n"
- " -c=<page_control> page control (def: 0 [current],"
- " 1 [changeable],\n"
- " 2 [default], "
- "3 [saved])\n"
- " -d disable block descriptors (DBD field in cdb)\n"
- " -e examine pages # 0 through to 0x3e, note if found\n"
- " -D disable block descriptor output\n"
- " -f be flexible, cope with MODE SENSE 6/10 response "
- "mixup\n");
- printf(" -h output page number and header in hex\n"
- " -H output page number and header in hex (same as '-h')\n"
- " -l list common page codes for device peripheral type,\n"
- " if no device given then assume disk type\n"
- " -L set Long LBA Accepted (LLBAA field in mode sense "
- "10 cdb)\n"
- " -p=<page_code> page code in hex (def: 0)\n"
- " -p=<page_code>,<sub_page_code> both in hex, (defs: 0)\n"
- " -r mode page output to stdout, a byte per line in "
- "ASCII hex\n"
- " -subp=<sub_page_code> sub page code (in hex, def: 0)\n"
- " -v verbose\n"
- " -V output version string\n"
- " -6 Use MODE SENSE(6), by default uses MODE SENSE(10)\n"
- " -? output this usage message\n\n"
- "Performs a SCSI MODE SENSE (6 or 10) command\n");
-}
-
int main(int argc, char * argv[])
{
int sg_fd, k, num, len, res, md_len, bd_len, longlba, page_num, spf;
- const char * file_name = 0;
char ebuff[EBUFF_SZ];
const char * descp;
- const char * cp;
unsigned char rsp_buff[MX_ALLOC_LEN];
int rsp_buff_size = MX_ALLOC_LEN;
- unsigned int u, uu;
- int pg_code = -1;
- int sub_pg_code = 0;
- int sub_pg_code_set = 0;
- int pc = 0;
- int do_all = 0;
- int do_all_sub = 0;
- int do_dbd = 0;
- int no_desc_out = 0;
- int do_examine = 0;
- int flexible = 0;
- int do_hex = 0;
- int do_llbaa = 0;
- int do_mode6 = 0; /* Use MODE SENSE(6) instead of MODE SENSE(10) */
- int do_list = 0;
- int do_raw = 0;
- int do_verbose = 0;
int ret = 0;
int density_code_off, t_proto, inq_pdt, inq_byte6, resp_mode6;
- int num_ua_pages, plen, jmp_out;
+ int num_ua_pages;
unsigned char * ucp;
unsigned char uc;
struct sg_simple_inquiry_resp inq_out;
char pdt_name[64];
+ struct opts_t opts;
- for (k = 1; k < argc; ++k) {
- cp = argv[k];
- plen = strlen(cp);
- if (plen <= 0)
- continue;
- if ('-' == *cp) {
- for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
- switch (*cp) {
- case '6':
- do_mode6 = 1;
- break;
- case 'a':
- do_all = 1;
- break;
- case 'A':
- do_all = 1;
- do_all_sub = 1;
- break;
- case 'd':
- do_dbd = 1;
- break;
- case 'D':
- no_desc_out = 1;
- break;
- case 'e':
- do_examine = 1;
- break;
- case 'f':
- flexible = 1;
- break;
- case 'h':
- case 'H':
- do_hex = 1;
- break;
- case 'l':
- do_list = 1;
- break;
- case 'L':
- do_llbaa = 1;
- break;
- case 'r':
- do_raw = 1;
- break;
- case 'v':
- ++do_verbose;
- break;
- case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
- case '?':
- usage();
- return 0;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
- }
- if (plen <= 0)
- continue;
- if (0 == strncmp("c=", cp, 2)) {
- num = sscanf(cp + 2, "%x", &u);
- if ((1 != num) || (u > 3)) {
- fprintf(stderr, "Bad page control after 'c=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- pc = u;
- } else if (0 == strncmp("p=", cp, 2)) {
- if (NULL == strchr(cp + 2, ',')) {
- num = sscanf(cp + 2, "%x", &u);
- if ((1 != num) || (u > 63)) {
- fprintf(stderr, "Bad page code value after 'p=' "
- "option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- pg_code = u;
- } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) {
- if (uu > 255) {
- fprintf(stderr, "Bad sub page code value after 'p=' "
- "option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- pg_code = u;
- sub_pg_code = uu;
- sub_pg_code_set = 1;
- } else {
- fprintf(stderr, "Bad page code, subpage code sequence "
- "after 'p=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == strncmp("subp=", cp, 5)) {
- num = sscanf(cp + 5, "%x", &u);
- if ((1 != num) || (u > 255)) {
- fprintf(stderr, "Bad sub page code after 'subp=' "
- "option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- sub_pg_code = u;
- sub_pg_code_set = 1;
- if (-1 == pg_code)
- pg_code = 0;
- } else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n", cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == file_name)
- file_name = cp;
- else {
- fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
+ memset(&opts, 0, sizeof(opts));
+ opts.pg_code = -1;
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ usage_for(&opts);
+ return 0;
}
-
- if (0 == file_name) {
- if (do_list) {
- if ((pg_code < 0) || (pg_code > 0x1f)) {
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
+ }
+
+ if (NULL == opts.device_name) {
+ if (opts.do_list) {
+ if ((opts.pg_code < 0) || (opts.pg_code > 0x3f)) {
printf(" Assume peripheral device type: disk\n");
list_page_codes(0, 0, -1);
} else {
printf(" peripheral device type: %s\n",
- sg_get_pdt_str(pg_code, sizeof(pdt_name), pdt_name));
- if (sub_pg_code_set)
- list_page_codes(pg_code, 0, sub_pg_code);
+ sg_get_pdt_str(opts.pg_code, sizeof(pdt_name),
+ pdt_name));
+ if (opts.subpg_code_set)
+ list_page_codes(opts.pg_code, 0, opts.subpg_code);
else
- list_page_codes(pg_code, 0, -1);
+ list_page_codes(opts.pg_code, 0, -1);
}
return 0;
}
- fprintf(stderr, "No <scsi_device> argument given\n");
- usage();
+ fprintf(stderr, "No DEVICE argument given\n");
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- if (do_examine && (pg_code >= 0)) {
+ if (opts.do_examine && (opts.pg_code >= 0)) {
fprintf(stderr, "can't give '-e' and a page number\n");
return SG_LIB_SYNTAX_ERROR;
}
/* The 6 bytes command only allows up to 252 bytes of response data */
- if (do_mode6) {
- if (do_llbaa) {
+ if (opts.do_six) {
+ if (opts.do_llbaa) {
fprintf(stderr, "LLBAA not defined for MODE SENSE 6, try "
"without '-L'\n");
return SG_LIB_SYNTAX_ERROR;
@@ -675,83 +974,88 @@ int main(int argc, char * argv[])
rsp_buff_size = 252;
}
/* If no pages or list selected than treat as 'a' */
- if (! ((pg_code >= 0) || do_all || do_list || do_examine))
- do_all = 1;
+ if (! ((opts.pg_code >= 0) || opts.do_all || opts.do_list ||
+ opts.do_examine))
+ opts.do_all = 1;
- if ((sg_fd = sg_cmds_open_device(file_name, 1 /* ro */, do_verbose)) < 0) {
- fprintf(stderr, ME "error opening file: %s: %s\n", file_name,
- safe_strerror(-sg_fd));
+ if ((sg_fd = sg_cmds_open_device(opts.device_name, 1 /* ro */,
+ opts.do_verbose)) < 0) {
+ fprintf(stderr, "error opening file: %s: %s\n",
+ opts.device_name, safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- if (sg_simple_inquiry(sg_fd, &inq_out, 1, do_verbose)) {
- fprintf(stderr, ME "%s doesn't respond to a SCSI INQUIRY\n",
- file_name);
+ if (sg_simple_inquiry(sg_fd, &inq_out, 1, opts.do_verbose)) {
+ fprintf(stderr, "%s doesn't respond to a SCSI INQUIRY\n",
+ opts.device_name);
sg_cmds_close_device(sg_fd);
return SG_LIB_CAT_OTHER;
}
inq_pdt = inq_out.peripheral_type;
inq_byte6 = inq_out.byte_6;
- if (0 == do_raw)
+ if (0 == opts.do_raw)
printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
inq_out.vendor, inq_out.product, inq_out.revision,
sg_get_pdt_str(inq_pdt, sizeof(pdt_name), pdt_name), inq_pdt);
- if (do_list) {
- if (sub_pg_code_set)
- list_page_codes(inq_pdt, inq_byte6, sub_pg_code);
+ if (opts.do_list) {
+ if (opts.subpg_code_set)
+ list_page_codes(inq_pdt, inq_byte6, opts.subpg_code);
else
list_page_codes(inq_pdt, inq_byte6, -1);
return 0;
}
- if (do_examine) {
- ret = examine_pages(sg_fd, do_mode6, inq_pdt, inq_byte6, do_verbose);
+ if (opts.do_examine) {
+ ret = examine_pages(sg_fd, inq_pdt, inq_byte6, &opts);
goto finish;
}
- if (PG_CODE_ALL == pg_code)
- do_all = 1;
- else if (do_all)
- pg_code = PG_CODE_ALL;
- if (do_all && do_all_sub)
- sub_pg_code = SPG_CODE_ALL;
-
- if (do_raw) {
- if (do_all) {
- fprintf(stderr, "'-r' requires a given (sub)page (not all)\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- if (do_hex) {
- fprintf(stderr, "'-r' and '-h' clash");
- usage();
+ if (PG_CODE_ALL == opts.pg_code) {
+ if (0 == opts.do_all)
+ ++opts.do_all;
+ } else if (opts.do_all)
+ opts.pg_code = PG_CODE_ALL;
+ if (opts.do_all > 1)
+ opts.subpg_code = SPG_CODE_ALL;
+
+ if (opts.do_raw > 1) {
+ if (opts.do_all) {
+ if (opts.opt_new)
+ fprintf(stderr, "'-R' requires a specific (sub)page, not "
+ "all\n");
+ else
+ fprintf(stderr, "'-r' requires a specific (sub)page, not "
+ "all\n");
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
}
memset(rsp_buff, 0, sizeof(rsp_buff));
- if (do_mode6) {
- res = sg_ll_mode_sense6(sg_fd, do_dbd, pc, pg_code, sub_pg_code,
- rsp_buff, rsp_buff_size, 1, do_verbose);
+ if (opts.do_six) {
+ res = sg_ll_mode_sense6(sg_fd, opts.do_dbd, opts.page_control,
+ opts.pg_code, opts.subpg_code, rsp_buff,
+ rsp_buff_size, 1, opts.do_verbose);
if (SG_LIB_CAT_INVALID_OP == res)
fprintf(stderr, ">>>>>> try again without the '-6' "
"switch for a 10 byte MODE SENSE command\n");
} else {
- res = sg_ll_mode_sense10(sg_fd, do_llbaa, do_dbd, pc, pg_code,
- sub_pg_code, rsp_buff, rsp_buff_size, 1,
- do_verbose);
+ res = sg_ll_mode_sense10(sg_fd, opts.do_llbaa, opts.do_dbd,
+ opts.page_control, opts.pg_code,
+ opts.subpg_code, rsp_buff, rsp_buff_size,
+ 1, opts.do_verbose);
if (SG_LIB_CAT_INVALID_OP == res)
fprintf(stderr, ">>>>>> try again with a '-6' "
"switch for a 6 byte MODE SENSE command\n");
}
if (SG_LIB_CAT_ILLEGAL_REQ == res) {
- if (sub_pg_code > 0)
+ if (opts.subpg_code > 0)
fprintf(stderr, "invalid field in cdb (perhaps subpages "
"not supported)\n");
- else if (pc > 0)
+ else if (opts.page_control > 0)
fprintf(stderr, "invalid field in cdb (perhaps "
"page control (PC) not supported)\n");
else
fprintf(stderr, "invalid field in cdb (perhaps "
- "page 0x%x not supported)\n", pg_code);
+ "page 0x%x not supported)\n", opts.pg_code);
} else if (SG_LIB_CAT_NOT_READY == res)
fprintf(stderr, "device not ready\n");
else if (SG_LIB_CAT_UNIT_ATTENTION == res)
@@ -763,12 +1067,12 @@ int main(int argc, char * argv[])
int medium_type, specific, headerlen;
ret = 0;
- resp_mode6 = do_mode6;
- if (flexible) {
+ resp_mode6 = opts.do_six;
+ if (opts.do_flexible) {
num = rsp_buff[0];
- if (do_mode6 && (num < 3))
+ if (opts.do_six && (num < 3))
resp_mode6 = 0;
- if ((0 == do_mode6) && (num > 5)) {
+ if ((0 == opts.do_six) && (num > 5)) {
if ((num > 11) && (0 == (num % 2)) && (0 == rsp_buff[4]) &&
(0 == rsp_buff[5]) && (0 == rsp_buff[6])) {
rsp_buff[1] = num;
@@ -779,14 +1083,14 @@ int main(int argc, char * argv[])
resp_mode6 = 1;
}
}
- if (! do_raw) {
- if (resp_mode6 == do_mode6)
- printf("Mode parameter header from %s byte MODE SENSE:\n",
- (do_mode6 ? "6" : "10"));
+ if ((! opts.do_raw) && (1 != opts.do_hex)) {
+ if (resp_mode6 == opts.do_six)
+ printf("Mode parameter header from MODE SENSE(%s):\n",
+ (opts.do_six ? "6" : "10"));
else
- printf(" >>> Mode parameter header from %s byte MODE "
- "SENSE,\n decoded as %s byte response:\n",
- (do_mode6 ? "6" : "10"), (resp_mode6 ? "6" : "10"));
+ printf(" >>> Mode parameter header from MODE SENSE(%s),\n"
+ " decoded as %s byte response:\n",
+ (opts.do_six ? "6" : "10"), (resp_mode6 ? "6" : "10"));
}
if (resp_mode6) {
headerlen = 4;
@@ -803,18 +1107,26 @@ int main(int argc, char * argv[])
specific = rsp_buff[3];
longlba = rsp_buff[4] & 1;
}
- if (do_raw) {
- ucp = rsp_buff + bd_len + headerlen;
- md_len -= bd_len + headerlen;
- spf = ((ucp[0] & 0x40) ? 1 : 0);
- len = (spf ? ((ucp[2] << 8) + ucp[3] + 4) : (ucp[1] + 2));
- len = (len < md_len) ? len : md_len;
- for (k = 0; k < len; ++k)
- printf("%02x\n", ucp[k]);
+ if (opts.do_raw) {
+ if (1 == opts.do_raw)
+ dStrRaw((const char *)rsp_buff, md_len);
+ else {
+ ucp = rsp_buff + bd_len + headerlen;
+ md_len -= bd_len + headerlen;
+ spf = ((ucp[0] & 0x40) ? 1 : 0);
+ len = (spf ? ((ucp[2] << 8) + ucp[3] + 4) : (ucp[1] + 2));
+ len = (len < md_len) ? len : md_len;
+ for (k = 0; k < len; ++k)
+ printf("%02x\n", ucp[k]);
+ }
sg_cmds_close_device(sg_fd);
return 0;
}
- if (do_hex)
+ if (1 == opts.do_hex) {
+ dStrHex((const char *)rsp_buff, md_len, 1);
+ sg_cmds_close_device(sg_fd);
+ return 0;
+ } else if (opts.do_hex > 1)
dStrHex((const char *)rsp_buff, headerlen, 1);
if (0 == inq_pdt)
printf(" Mode data length=%d, medium type=0x%.2x, WP=%d,"
@@ -831,7 +1143,7 @@ int main(int argc, char * argv[])
if (bd_len + headerlen > rsp_buff_size)
bd_len = rsp_buff_size - headerlen;
}
- if (! no_desc_out) {
+ if (! opts.do_dbout) {
printf(" Block descriptor length=%d\n", bd_len);
if (bd_len > 0) {
len = 8;
@@ -852,7 +1164,8 @@ int main(int argc, char * argv[])
ucp = rsp_buff + headerlen;
while (num > 0) {
- printf(" Density code=0x%x\n", *(ucp + density_code_off));
+ printf(" Density code=0x%x\n",
+ *(ucp + density_code_off));
dStrHex((const char *)ucp, len, 1);
ucp += len;
num -= len;
@@ -864,7 +1177,8 @@ int main(int argc, char * argv[])
md_len -= bd_len + headerlen; /* length of mode page(s) */
num_ua_pages = 0;
for (k = 0; md_len > 0; ++k) { /* got mode page(s) */
- if ((k > 0) && (! do_all) && (SPG_CODE_ALL != sub_pg_code)) {
+ if ((k > 0) && (! opts.do_all) &&
+ (SPG_CODE_ALL != opts.subpg_code)) {
fprintf(stderr, "Unexpectedly received extra mode page "
"responses, ignore\n");
break;
@@ -883,13 +1197,13 @@ int main(int argc, char * argv[])
break;
}
}
- if (do_hex) {
+ if (opts.do_hex) {
if (spf)
- printf(">> page_code=0x%x, subpage_code=0x%x, "
- "page_control=%d\n", page_num, ucp[1], pc);
+ printf(">> page_code=0x%x, subpage_code=0x%x, page_cont"
+ "rol=%d\n", page_num, ucp[1], opts.page_control);
else
printf(">> page_code=0x%x, page_control=%d\n", page_num,
- pc);
+ opts.page_control);
} else {
descp = NULL;
if ((0x18 == page_num) || (0x19 == page_num)) {
@@ -908,10 +1222,10 @@ int main(int argc, char * argv[])
}
if (descp)
printf(">> %s, page_control: %s\n", descp,
- pg_control_str_arr[pc]);
+ pg_control_str_arr[opts.page_control]);
else
printf(">> page_code: %s, page_control: %s\n", ebuff,
- pg_control_str_arr[pc]);
+ pg_control_str_arr[opts.page_control]);
}
num = (len > md_len) ? md_len : len;
if ((k > 0) && (num > 256)) {
@@ -924,6 +1238,7 @@ int main(int argc, char * argv[])
md_len -= len;
}
}
+
finish:
sg_cmds_close_device(sg_fd);
return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
diff --git a/sg_opcodes.8 b/sg_opcodes.8
index d55f70f4..2b67515c 100644
--- a/sg_opcodes.8
+++ b/sg_opcodes.8
@@ -1,96 +1,172 @@
-.TH SG_OPCODES "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_OPCODES "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_opcodes \- reports information on supported SCSI commands or
-supported task management functions
+task management functions
.SH SYNOPSIS
.B sg_opcodes
-[\fI-a\fR] [\fI-o=<opcode>\fR [\fI-s=<service_action>\fR ] ] [\fI-u\fR]
-[\fI-u\fR] [\fI-v\fR] [\fI-V\fR] [\fI-?\fR] \fI<scsi_device>\fR
+[\fI\-\-alpha\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-opcode=OP\fR]
+[\fI\-\-raw\fR] [\fI\-\-rctd\fR] [\fI\-\-sa=SA\fR] [\fI\-\-tmf\fR]
+[\fI\-\-unsorted\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.PP
+.B sg_opcodes
+[\fI\-a\fR] [\fI\-o=OP\fR] [\fI\-R\fR] [\fI\-s=SA\fR] [\fI\-t\fR] [\fI\-u\fR]
+[\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-This utility sends a REPORT SUPPORTED OPERATION CODES or a
-REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS SCSI command to the
-given device and then outputs the response. The default action is
-to report supported operation codes. In this mode it will either
-list all supported commands or give detailed information on a specific
-command identified by the "-o" option (perhaps with additional
-information from the "-s" option).
+This utility sends a SCSI REPORT SUPPORTED OPERATION CODES or a REPORT
+SUPPORTED TASK MANAGEMENT FUNCTIONS command to the \fIDEVICE\fR and then
+outputs the response. The default action is to report supported operation
+codes. In this mode it will either list all supported commands or give
+detailed information on a specific command identified by the
+\fI\-\-opcode=OP\fR option (perhaps with additional information from the
+\fI\-\-sa=SA\fR option).
.PP
-The name of a SCSI command depends on its peripheral device type (e.g.
-a disk) which is obtained from a standard SCSI INQUIRY command. Further
-the REPORT SUPPORTED OPERATION CODES and REPORT SUPPORTED TASK
-MANAGEMENT FUNCTIONS commands are not supported in the MMC command set
-for CD and DVD devices. This utility does an INQUIRY to obtain the
-peripheral device type and prints out the vendor, product and revision
-strings.
+The name of a SCSI command depends on its peripheral device type (e.g. a
+disk). The REPORT SUPPORTED OPERATION CODES and REPORT SUPPORTED TASK
+MANAGEMENT FUNCTIONS commands are not supported in the MMC command set for
+CD and DVD devices. This utility does an INQUIRY to obtain the peripheral
+device type and prints out the vendor, product and revision strings.
.PP
-A similar facility to query supported operation codes used to be available
+A similar facility to query supported operation codes previously was available
via the CmdDt bit in the SCSI INQUIRY command (see sg_inq(8)). However that
facility was made obsolete and replaced by the REPORT SUPPORTED OPERATION
-CODES SCSI command in SPC-3 (revision 4) in February 2002.
+CODES command in SPC\-3 (revision 4) during February 2002.
+.PP
+This utility supports two command line syntaxes, the preferred one is
+shown first in the synopsis and explained in this section. A later section
+on the old command line syntax outlines the second group of options.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
--a
+\fB\-a\fR, \fB\-\-alpha\fR
when all supported commands are being listed there is no requirement for
-the device server (i.e. the target) to sort the list of commands. When
+the device server (i.e. the \fIDEVICE\fR) to sort the list of commands. When
this option is given the list of supported commands is sorted by
-name (alphabetically). When this option and the '-u' option are
+name (alphabetically). When this option and the \fB\-\-unsorted\fR option are
both _not_ given then the list of supported commands is sorted
numerically (first by operation code and then by service action).
.TP
--o=<opcode>
-the given device will be queried for the given operation code ("opcode")
-which is the first byte of a SCSI command. Argument
-is hexadecimal and expected to be in the range 0 to ff inclusive.
-When this option is not given then all available SCSI commands supported
-by the target are listed.
+\fB\-h\fR, \fB\-\-help\fR
+outputs the usage message summarizing command line options
+then exits. Ignores \fIDEVICE\fR if given.
.TP
--s=<service_action>
-the given device will be queried for a command with the given service
-action ("service_action"). Used in conjunction with the '-o=<opcode>'
-option. If '-s' is not given, '-o' is given and the command in question
-does have a service action then a value of 0 will be assumed.
-The "<service_action>" argument is hexadecimal and expected to be in the
-range 0 to ffff inclusive.
+\fB\-H\fR, \fB\-\-hex\fR
+outputs the response in ASCII hexadecimal to stdout.
.TP
--t
-list supported task management functions. When this option is chosen
-the '-a', '-o' and '-u' options are ignored.
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
.TP
--u
-when all supported commands are being listed there is no requirement for
-the device server (i.e. the target) to sort the list of commands. When
-this option is given the list of supported commands is in the order
-given by the target. When this option is not given the supported commands
-are sorted numerically (first by operation code and then by service action).
+\fB\-o\fR, \fB\-\-opcode\fR=\fIOP\fR
+the \fIDEVICE\fR will be queried for the given operation code ( i.e. the
+\fIOP\fR value) which is the first byte of a SCSI command. \fIOP\fR is
+decimal unless prefixed by "0x" or it has a trailing "h". \fIOP\fR should
+be in the range 0 to 255 (0xff) inclusive. When this option is not given
+then all available SCSI commands supported by the \fIDEVICE\fR are listed.
.TP
--v
-verbose: print out cdb of issued commands prior to execution. '-vv'
-and '-vvv' are also accepted yielding greater verbosity.
+\fB\-r\fR, \fB\-\-raw\fR
+output the response in binary to stdout. Error messages and warnings, if
+any, are sent to stderr.
.TP
--V
-print out version string
+\fB\-R\fR, \fB\-\-rctd\fR
+set report command timeout descriptor (RCTD) bit in the cdb. The response
+may or may not contain command timeout descriptors. If available they are
+output. If supported there are two values: a nominal command timeout
+and a recommended command timeout. Both have units of seconds. A value
+of zero means that no timeout is indicated and this is shown in
+the corresponding decoded output as "-".
.TP
--?
-output usage message. Ignore all other parameters.
-.PP
-As of SPC-4 revision 1 the recognized task management functions are:
+\fB\-s\fR, \fB\-\-sa\fR=\fISA\fR
+the \fIDEVICE\fR will be queried for a command with the given service
+action (i.e. the \fISA\fR value). Used in conjunction with the
+\fI\-\-opcode=OP\fR option. If this option is not given, \fI\-\-opcode=OP\fR
+is given and the command in question does have a service action then a value
+of 0 will be assumed. \fISA\fR is decimal and expected to be in the range 0
+to 65535 (0xffff) inclusive.
+.TP
+\fB\-t\fR, \fB\-\-tmf\fR
+list supported task management functions. This is done with the SCSI REPORT
+SUPPORTED TASK MANAGEMENT FUNCTIONS command. When this option is chosen
+the \fI\-\-alpha\fR, \fI\-\-opcode=OP\fR, \fI\-\-rctd\fR, \fI\-\-sa=SA\fR
+and \fI\-\-unsorted\fR options are ignored.
+.TP
+\fB\-u\fR, \fB\-\-unsorted\fR
+when all supported commands are being listed there is no requirement for
+the device server (i.e. the \fIDEVICE\fR) to sort the list of commands. When
+this option is given the list of supported commands is in the order given by
+the \fIDEVICE\fR. When this option is not given the supported commands
+are sorted numerically (first by operation code and then by service action).
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+increase level of verbosity. Can be used multiple times.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+print out version string then exit.
+.SH NOTES
+As of SPC\-4 revision 7a the recognized task management functions are:
abort set, abort task set, clear ACA, clear task set, I_T nexus reset,
logical unit reset, query task, target reset and wakeup.
.PP
-In the 2.4 series of Linux kernels the given device must be
-a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example "sg_opcodes /dev/sda"
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI
+generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks
+and DVD drives) can also be specified. For example "sg_opcodes /dev/sda"
will work in the 2.6 series kernels.
.SH EXIT STATUS
The exit status of sg_opcodes is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using '\-\-old' (or '\-O) as the first option.
+.TP
+\fB\-a\fR
+sort command alphabetically. Equivalent to \fI\-\-alpha\fR in main
+description.
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-o\fR=\fIOP\fR
+the \fIDEVICE\fR will be queried for the given operation code (i.e.
+\fIOP\fR) which is the first byte of a SCSI command. \fIOP\fR is
+hexadecimal and expected to be in the range 0 to ff inclusive.
+When this option is not given then all available SCSI commands supported
+by the \fIDEVICE\fR are listed.
+.TP
+\fB\-R\fR
+set the report command timeout descriptor (RCTD) bit in cdb. Equivalent
+to \fI\-\-rctd\fR in main description.
+.TP
+\fB\-s\fR=\fISA\fR
+the \fIDEVICE\fR will be queried for a command with the given service
+action (i.e. \fISA\fR). Used in conjunction with the \fI\-o=OP\fR
+option. If this option is not given, \fI\-o=OP\fR is given and the command
+in question does have a service action then a value of 0 will be assumed.
+\fISA\fR is hexadecimal and expected to be in the range 0 to ffff inclusive.
+.TP
+\fB\-t\fR
+list supported task management functions. Equivalent to \fI\-\-tmf\fR in
+the main description.
+.TP
+\fB\-u\fR
+output all supported commands in the order given by \fIDEVICE\fR.
+Equivalent to \fI\-\-unsorted\fR in main description.
+.TP
+\fB\-v\fR
+increase level of verbosity. Can be used multiple times.
+.TP
+\fB\-V\fR
+print out version string then exit.
+.TP
+\fB\-?\fR
+output usage message. Ignore all other parameters.
.SH AUTHOR
Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_opcodes.c b/sg_opcodes.c
index fc2d0e57..017fb38c 100644
--- a/sg_opcodes.c
+++ b/sg_opcodes.c
@@ -1,32 +1,59 @@
+/* A utility program originally written for the Linux OS SCSI subsystem.
+ * Copyright (C) 2004-2007 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)
+ * any later version.
+
+ This program outputs information provided by a SCSI REPORT SUPPORTED
+ OPERATION CODES [0xa3/0xc] and REPORT SUPPORTED TASK MANAGEMENT
+ FUNCTIONS [0xa3/0xd] commands.
+ */
+
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <getopt.h>
+
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
-#include "sg_io_linux.h"
-/* A utility program for the Linux OS SCSI subsystem.
-* Copyright (C) 2004-2006 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)
-* any later version.
+static char * version_str = "0.29 20070127";
- This program outputs information provided by a SCSI "Report supported
- operation codes" command [0xa3/0xc].
+// #define USE_LINUX_SG_IO_IF 1
-*/
+/* Notes:
+ * - this file has both Linux specific pass through code using the
+ * SG_IO ioctl and a more generic sg_pt mechanism that is portable
+ * to other OSes. The code is conditionally compiled depending
+ * on the USE_LINUX_SG_IO_IF define and whether the Makefile
+ * indicates the OS is linux.
+ * N.B. Various Makefiles are set assuming this is not defined.
+ *
+ * - since support for the SCSI REPORT SUPPORTED OPERATION CODES and
+ * REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS is uncommon, dummy
+ * response code is provided. Uncomment the '#define TEST_CODE'
+ * line for test mode.
+ */
-static char * version_str = "0.26 20061015";
+#if defined(USE_LINUX_SG_IO_IF) && defined(SG3_UTILS_LINUX)
+ #define USE_SG_IO
+#endif
+#ifdef USE_SG_IO
+ #include <sys/ioctl.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+ #include "sg_io_linux.h"
+ #define EBUFF_SZ 256
+ static char ebuff[EBUFF_SZ];
+#else
+ #include "sg_pt.h"
+#endif
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
#define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
@@ -40,21 +67,29 @@ static char * version_str = "0.26 20061015";
#define NAME_BUFF_SZ 64
-#define EBUFF_SZ 256
static int peri_type = 0; /* ugly but not easy to pass to alpha compare */
+static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode,
+ int rq_servact, void * resp, int mx_resp_len, int noisy,
+ int verbose);
+static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
+ int verbose);
+
/* <<<<<<<<<<<<<<< start of test code */
-/* #define TEST_CODE */
+// #define TEST_CODE
#ifdef TEST_CODE
#warning "<<<< TEST_CODE response compiled in >>>>"
#define DUMMY_CMDS 17
+#define DUMMY_CMD_LEN 8
+#define DUMMY_TO_CMDS 4
+#define DUMMY_TO_CMD_LEN 20
struct cmd_descript_t {
- unsigned char d[8];
+ unsigned char d[DUMMY_CMD_LEN];
};
struct dummy_resp_t {
@@ -62,190 +97,355 @@ struct dummy_resp_t {
struct cmd_descript_t descript[DUMMY_CMDS];
};
-static struct dummy_resp_t dummy_resp = { {0, 0, 0, 8 * DUMMY_CMDS},
- {{{0, 0, 0, 0, 0, 0, 0, 6}},
- {{0xa3, 0, 0, 0xc, 0, 1, 0, 12}},
- {{0x12, 0, 0, 0, 0, 0, 0, 6}},
- {{0x1d, 0, 0, 0, 0, 0, 0, 6}},
- {{0x25, 0, 0, 0, 0, 0, 0, 10}},
- {{0x28, 0, 0, 0, 0, 0, 0, 10}},
- {{0x2a, 0, 0, 0, 0, 0, 0, 10}},
- {{0x1a, 0, 0, 0, 0, 0, 0, 6}},
- {{0x15, 0, 0, 0, 0, 0, 0, 6}},
- {{0xa3, 0, 0, 0x5, 0, 1, 0, 12}},
- {{0x5a, 0, 0, 0, 0, 0, 0, 10}},
- {{0x55, 0, 0, 0, 0, 0, 0, 10}},
- {{2, 0, 0, 0, 0, 0, 0, 6}},
- {{3, 0, 0, 0, 0, 0, 0, 6}},
- {{4, 0, 0, 0, 0, 0, 0, 6}},
- {{0xa0, 0, 0, 0, 0, 0, 0, 12}},
- {{0x7f, 0, 0, 0x1, 0, 1, 0, 32}},
+static struct dummy_resp_t dummy_resp = {
+ {0, 0, 0, DUMMY_CMD_LEN * DUMMY_CMDS},
+ {{{0, 0, 0, 0, 0, 0, 0, 6}}, /* tur */
+ {{0xa3, 0, 0, 0xc, 0, 1, 0, 12}}, /* rsoc */
+ {{0x12, 0, 0, 0, 0, 0, 0, 6}}, /* inq */
+ {{0x1d, 0, 0, 0, 0, 0, 0, 6}}, /* sd */
+ {{0x25, 0, 0, 0, 0, 0, 0, 10}}, /* rc */
+ {{0x28, 0, 0, 0, 0, 0, 0, 10}}, /* r(10) */
+ {{0x2a, 0, 0, 0, 0, 0, 0, 10}}, /* w(10) */
+ {{0x1a, 0, 0, 0, 0, 0, 0, 6}}, /* ms(6) */
+ {{0x15, 0, 0, 0, 0, 0, 0, 6}}, /* msel(6) */
+ {{0xa3, 0, 0, 0x5, 0, 1, 0, 12}}, /* rii */
+ {{0x5a, 0, 0, 0, 0, 0, 0, 10}}, /* ms(10) */
+ {{0x55, 0, 0, 0, 0, 0, 0, 10}}, /* msel(10) */
+ {{2, 0, 0, 0, 0, 0, 0, 6}}, /* ?? */
+ {{3, 0, 0, 0, 0, 0, 0, 6}}, /* rs */
+ {{4, 0, 0, 0, 0, 0, 0, 6}}, /* f */
+ {{0xa0, 0, 0, 0, 0, 0, 0, 12}}, /* rl */
+ {{0x7f, 0, 0, 0x3, 0, 1, 0, 32}}, /* vl:xdr(32) */
+}};
+
+struct cmd_descript_to_t {
+ unsigned char d[DUMMY_TO_CMD_LEN];
+};
+
+struct dummy_resp_to_t {
+ unsigned char cdl[4];
+ struct cmd_descript_to_t descript[DUMMY_TO_CMDS];
+};
+
+static struct dummy_resp_to_t dummy_to_resp =
+ {{0, 0, 0, DUMMY_TO_CMD_LEN * DUMMY_TO_CMDS},
+ {{{0, 0, 0, 0, 0, 0x2, 0, 6,
+ 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}}, /* tur */
+ {{0xa3, 0, 0, 0xc, 0, 0x3, 0, 12,
+ 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6}}, /* rsoc */
+ {{4, 0, 0, 0, 0, 0x2, 0, 6,
+ 0, 0xa, 0, 0, 0, 0, 0x8, 0, 0, 0, 0x10, 0}}, /* f */
+ {{0x7f, 0, 0, 0x3, 0, 0x3, 0, 32,
+ 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7}}, /* vl:xdr(32) */
}};
static unsigned char dummy_1_cmd[] = {
0, 3, 0, 6, 0x12, 0x3, 0xff, 0x0, 0xff, 0x1
};
+static unsigned char dummy_1_to_cmd[] = {
+ 0, 0x83, 0, 6, 0x12, 0x3, 0xff, 0x0, 0xff, 0x1,
+ 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, /* inq */
+};
+
static unsigned char dummy_rsmft_r0 = 0xff;
static unsigned char dummy_rsmft_r1 = 0x1;
#endif
/* <<<<<<<<<<<<<<< end of test code */
+static struct option long_options[] = {
+ {"alpha", 0, 0, 'a'},
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"new", 0, 0, 'N'},
+ {"opcode", 1, 0, 'o'},
+ {"old", 0, 0, 'O'},
+ {"raw", 0, 0, 'r'},
+ {"rctd", 0, 0, 'R'},
+ {"sa", 1, 0, 's'},
+ {"tmf", 0, 0, 't'},
+ {"unsorted", 0, 0, 'u'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
-/* Report Supported Operation Codes */
-/* Returns 0 when successful */
-static int do_rsoc(int sg_fd, int rep_opts, int rq_opcode, int rq_servact,
- void * resp, int mx_resp_len, int noisy, int verbose)
+struct opts_t {
+ int do_alpha;
+ int do_help;
+ int do_hex;
+ int do_opcode;
+ int do_raw;
+ int do_rctd;
+ int do_servact;
+ int do_verbose;
+ int do_version;
+ int do_unsorted;
+ int do_taskman;
+ const char * device_name;
+ int opt_new;
+};
+
+static void usage()
{
- int res, k;
- unsigned char rsocCmdBlk[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
+ fprintf(stderr,
+ "Usage: sg_opcodes [--alpha] [--help] [--hex] [--opcode=OP] "
+ "[--raw] [--rctd]\n"
+ " [--sa=SA] [--tmf] [--unsorted] [--verbose] "
+ "[--version]\n"
+ " DEVICE\n"
+ " where:\n"
+ " --alpha|-a output list of operation codes sorted "
+ "alphabetically\n"
+ " --help|-h print usage message then exit\n"
+ " --hex|-H output response in hex\n"
+ " --opcode=OP|-o OP first byte of command to query\n"
+ " (decimal, prefix with '0x' for hex)\n"
+ " --raw|-r output response in binary to stdout\n"
+ " --rctd|-R set RCTD (return command timeout "
+ "descriptor) bit\n"
+ " --sa=SA|-s SA service action in addition to opcode\n"
+ " (decimal, prefix with '0x' for hex)\n"
+ " --tmf|-t output list of supported task management "
+ "functions\n"
+ " --unsorted|-u output list of operation codes as is "
+ "(unsorted)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print vesrion string then exit\n\n"
+ "Performs a SCSI REPORT SUPPORTED OPERATION CODES or REPORT "
+ "SUPPORTED\nTASK MANAGEMENT FUNCTIONS command\n");
+}
- if (rep_opts)
- rsocCmdBlk[2] = (rep_opts & 0x7);
- if (rq_opcode > 0)
- rsocCmdBlk[3] = (rq_opcode & 0xff);
- if (rq_servact > 0) {
- rsocCmdBlk[4] = (unsigned char)((rq_servact >> 8) & 0xff);
- rsocCmdBlk[5] = (unsigned char)(rq_servact & 0xff);
+static void usage_old()
+{
+ fprintf(stderr,
+ "Usage: sg_opcodes [-a] [-H] [-o=OP] [-r] [-R] [-s=SA]"
+ " [-t] [-u]\n"
+ " [-v] [-V] DEVICE\n"
+ " where:\n"
+ " -a output list of operation codes sorted "
+ "alphabetically\n"
+ " -H print response in hex\n"
+ " -o=OP first byte of command to query (in hex)\n"
+ " -r output response in binary to stdout\n"
+ " -R set RCTD (return command timeout "
+ "descriptor) bit\n"
+ " -s=SA in addition to opcode (in hex)\n"
+ " -t output list of supported task management functions\n"
+ " -u output list of operation codes as is (unsorted)\n"
+ " -v verbose\n"
+ " -V output version string\n"
+ " -? output this usage message\n\n"
+ "Performs a SCSI REPORT SUPPORTED OPERATION CODES (or REPORT "
+ "TASK MANAGEMENT\nFUNCTIONS) command\n");
+}
- }
- rsocCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
- rsocCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
- rsocCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
- rsocCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c, n;
- if (verbose) {
- fprintf(stderr, " Report Supported Operation Codes cmd: ");
- for (k = 0; k < RSOC_CMD_LEN; ++k)
- fprintf(stderr, "%02x ", rsocCmdBlk[k]);
- fprintf(stderr, "\n");
- }
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(rsocCmdBlk);
- io_hdr.mx_sb_len = sizeof(sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = mx_resp_len;
- io_hdr.dxferp = resp;
- io_hdr.cmdp = rsocCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
+ while (1) {
+ int option_index = 0;
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("SG_IO (rsoc) error");
- return -1;
- }
- if (verbose > 2)
- fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
- res = sg_err_category3(&io_hdr);
- switch (res) {
- case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Report supported operation codes", &io_hdr,
- verbose > 1);
- /* fall through */
- case SG_LIB_CAT_CLEAN:
- return 0;
- default:
- if (noisy | verbose) {
- char ebuff[EBUFF_SZ];
+ c = getopt_long(argc, argv, "ahHNo:OrRs:tuvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
- if (0 == rep_opts)
- snprintf(ebuff, EBUFF_SZ, "RSOC error, rep_opts=0 (all) ");
- else if (1 == rep_opts)
- snprintf(ebuff, EBUFF_SZ, "RSOC error, rq_opcode=0x%x ",
- rq_opcode);
- else
- snprintf(ebuff, EBUFF_SZ, "RSOC error, rq_opcode=0x%x, "
- "rq_sa=0x%x ", rq_opcode, rq_servact);
- sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
+ switch (c) {
+ case 'a':
+ optsp->do_alpha = 1;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'o':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 255)) {
+ fprintf(stderr, "bad argument to '--opcode'\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_opcode = n;
+ break;
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'r':
+ ++optsp->do_raw;
+ break;
+ case 'R':
+ ++optsp->do_rctd;
+ break;
+ case 's':
+ n = sg_get_num(optarg);
+ if (n < 0) {
+ fprintf(stderr, "bad argument to '--sa'\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_servact = n;
+ break;
+ case 't':
+ ++optsp->do_taskman;
+ break;
+ case 'u':
+ ++optsp->do_unsorted;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
}
- return res;
}
+ return 0;
}
-/* Report Supported Task Management Function */
-/* Returns 0 when successful */
-static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
- int verbose)
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
{
- int res, k;
- unsigned char rstmfCmdBlk[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
-
- rstmfCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
- rstmfCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
- rstmfCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
- rstmfCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+ int k, jmp_out, plen, n, num;
+ const char * cp;
- if (verbose) {
- fprintf(stderr, " Report Supported Task Management Functions cmd: ");
- for (k = 0; k < RSTMF_CMD_LEN; ++k)
- fprintf(stderr, "%02x ", rstmfCmdBlk[k]);
- fprintf(stderr, "\n");
+ for (k = 1; k < argc; ++k) {
+ cp = argv[k];
+ plen = strlen(cp);
+ if (plen <= 0)
+ continue;
+ if ('-' == *cp) {
+ for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
+ switch (*cp) {
+ case 'a':
+ ++optsp->do_alpha;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case 'R':
+ ++optsp->do_rctd;
+ break;
+ case 't':
+ ++optsp->do_taskman;
+ break;
+ case 'u':
+ ++optsp->do_unsorted;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+ if (0 == strncmp("o=", cp, 2)) {
+ num = sscanf(cp + 2, "%x", (unsigned int *)&n);
+ if ((1 != num) || (n > 255)) {
+ fprintf(stderr, "Bad number after 'o=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_opcode = n;
+ } else if (0 == strncmp("s=", cp, 2)) {
+ num = sscanf(cp + 2, "%x", (unsigned int *)&n);
+ if (1 != num) {
+ fprintf(stderr, "Bad number after 's=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_servact = n;
+ } else if (0 == strncmp("-old", cp, 4))
+ ;
+ else if (jmp_out) {
+ fprintf(stderr, "Unrecognized option: %s\n", cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (NULL == optsp->device_name)
+ optsp->device_name = cp;
+ else {
+ fprintf(stderr, "too many arguments, got: %s, not expecting: "
+ "%s\n", optsp->device_name, cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
}
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(rstmfCmdBlk);
- io_hdr.mx_sb_len = sizeof(sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = mx_resp_len;
- io_hdr.dxferp = resp;
- io_hdr.cmdp = rstmfCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
+ return 0;
+}
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("SG_IO (rstmf) error");
- return -1;
- }
- if (verbose > 2)
- fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
- res = sg_err_category3(&io_hdr);
- switch (res) {
- case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Report supported task management fns", &io_hdr,
- verbose > 1);
- /* fall through */
- case SG_LIB_CAT_CLEAN:
- return 0;
- default:
- if (noisy | verbose) {
- char ebuff[EBUFF_SZ];
- snprintf(ebuff, EBUFF_SZ, "RSTMF error ");
- sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
- }
- return res;
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
}
+ return res;
}
-static void usage()
+static void dStrRaw(const char* str, int len)
{
- fprintf(stderr,
- "Usage: sg_opcodes [-a] [-o=<opcode> [-s=<service_action>] ]"
- " [-t] [-u] [-v]\n"
- " [-V] <scsi_device>\n"
- " where:\n"
- " -a output list of operation codes sorted "
- "alphabetically\n"
- " -o=<opcode> first byte of command to query (in hex)\n"
- " -s=<service_action> in addition to opcode (in hex)\n"
- " -t output list of supported task management functions\n"
- " -u output list of operation codes as is (unsorted)\n"
- " -v verbose\n"
- " -V output version string\n"
- " -? output this usage message\n\n"
- "Performs a REPORT SUPPORTED OPERATION CODES (or supported task "
- "management\nfunctions) SCSI command\n");
+ int k;
+
+ for (k = 0 ; k < len; ++k)
+ printf("%c", str[k]);
}
/* returns -1 when left < right, 0 when left == right, else returns 1 */
-int opcode_num_compare(const void * left, const void * right)
+static int opcode_num_compare(const void * left, const void * right)
{
const unsigned char * ll = *(unsigned char **)left;
const unsigned char * rr = *(unsigned char **)right;
@@ -275,7 +475,7 @@ int opcode_num_compare(const void * left, const void * right)
}
/* returns -1 when left < right, 0 when left == right, else returns 1 */
-int opcode_alpha_compare(const void * left, const void * right)
+static int opcode_alpha_compare(const void * left, const void * right)
{
const unsigned char * ll = *(unsigned char **)left;
const unsigned char * rr = *(unsigned char **)right;
@@ -304,10 +504,11 @@ int opcode_alpha_compare(const void * left, const void * right)
return strncmp(l_name_buff, r_name_buff, NAME_BUFF_SZ);
}
-void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
- int alpha)
+static void list_all_codes(unsigned char * rsoc_buff, int rsoc_len,
+ int unsorted, int alpha, int rctd)
{
- int k, cd_len, serv_act;
+ int k, j, cd_len, serv_act, len;
+ unsigned long to;
unsigned char * ucp;
char name_buff[NAME_BUFF_SZ];
char sa_buff[8];
@@ -324,12 +525,19 @@ void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
printf("sg_opcodes: no commands to display\n");
return;
}
- printf("\nOpcode Service CDB Name\n");
- printf( "(hex) action(h) size \n");
- printf("-----------------------------------------------\n");
+ if (rctd) {
+ printf("\nOpcode Service CDB Nominal Recommended Name\n");
+ printf( "(hex) action(h) size timeout timeout(sec) \n");
+ printf("-----------------------------------------------------------"
+ "-----\n");
+ } else {
+ printf("\nOpcode Service CDB Name\n");
+ printf( "(hex) action(h) size \n");
+ printf("-----------------------------------------------\n");
+ }
/* N.B. SPC-4 does _not_ requiring any ordering of response */
if (! unsorted) {
- sort_arr = malloc(cd_len * sizeof(unsigned char *));
+ sort_arr = (unsigned char **)malloc(cd_len * sizeof(unsigned char *));
if (NULL == sort_arr) {
printf("sg_opcodes: no memory to sort operation codes, "
"try '-u'\n");
@@ -337,13 +545,16 @@ void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
}
memset(sort_arr, 0, cd_len * sizeof(unsigned char *));
ucp = rsoc_buff + 4;
- for (k = 0; k < cd_len; k += 8, ucp += 8)
- sort_arr[(k / 8)] = ucp;
- qsort(sort_arr, (cd_len / 8), sizeof(unsigned char *),
+ for (k = 0, j = 0; k < cd_len; ++j, k += len, ucp += len) {
+ sort_arr[j] = ucp;
+ len = (ucp[5] & 0x2) ? 20 : 8;
+ }
+ qsort(sort_arr, j, sizeof(unsigned char *),
(alpha ? opcode_alpha_compare : opcode_num_compare));
}
- for (k = 0; k < cd_len; k += 8) {
- ucp = unsorted ? (rsoc_buff + 4 + k) : sort_arr[(k / 8)];
+ for (k = 0, j = 0; k < cd_len; ++j, k += len) {
+ ucp = unsorted ? (rsoc_buff + 4 + k) : sort_arr[j];
+ len = (ucp[5] & 0x2) ? 20 : 8;
if (ucp[5] & 1) {
serv_act = ((ucp[2] << 8) | ucp[3]);
sg_get_opcode_sa_name(ucp[0], serv_act, peri_type,
@@ -354,161 +565,252 @@ void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
NAME_BUFF_SZ, name_buff);
memset(sa_buff, ' ', sizeof(sa_buff));
}
- printf(" %.2x %.4s %3d %s\n",
- ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]), name_buff);
+ if (rctd) {
+ if (ucp[5] & 0x2) {
+ printf(" %.2x %.4s %3d", ucp[0], sa_buff,
+ ((ucp[6] << 8) | ucp[7]));
+ to = (ucp[12] << 24) + (ucp[13] << 16) + (ucp[14] << 8) +
+ ucp[15];
+ if (0 == to)
+ printf(" -");
+ else
+ printf(" %8lu", to);
+ to = (ucp[16] << 24) + (ucp[17] << 16) + (ucp[18] << 8) +
+ ucp[19];
+ if (0 == to)
+ printf(" -");
+ else
+ printf(" %8lu", to);
+ printf(" %s\n", name_buff);
+ } else
+ printf(" %.2x %.4s %3d "
+ "%s\n", ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]),
+ name_buff);
+ } else
+ printf(" %.2x %.4s %3d %s\n",
+ ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]), name_buff);
+ }
+}
+
+static void decode_cmd_to_descriptor(unsigned char * dp, int max_b_len,
+ char * b)
+{
+ int len;
+ unsigned long to;
+
+ if ((max_b_len < 2) || (NULL == dp))
+ return;
+ b[max_b_len - 1] = '\0';
+ --max_b_len;
+ len = (dp[0] << 8) + dp[1];
+ if (10 != len) {
+ snprintf(b, max_b_len, "command timeout descriptor length %d "
+ "(expect 10)", len);
+ return;
+ }
+ to = (dp[4] << 24) + (dp[5] << 16) + (dp[6] << 8) + dp[7];
+ if (0 == to)
+ snprintf(b, max_b_len, "no nominal timeout, ");
+ else
+ snprintf(b, max_b_len, "nominal timeout: %lu secs, ", to);
+ len = strlen(b);
+ max_b_len -= len;
+ b += len;
+ to = (dp[8] << 24) + (dp[9] << 16) + (dp[10] << 8) + dp[11];
+ if (0 == to)
+ snprintf(b, max_b_len, "no recommended timeout");
+ else
+ snprintf(b, max_b_len, "recommended timeout: %lu secs", to);
+ return;
+}
+
+static void list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts,
+ int do_opcode, int do_servact)
+{
+ int k;
+ char name_buff[NAME_BUFF_SZ];
+ unsigned char * ucp;
+ const char * cp;
+ int v = 0;
+
+
+ printf("\n Opcode=0x%.2x", do_opcode);
+ if (rep_opts > 1)
+ printf(" Service_action=0x%.4x", do_servact);
+ printf("\n");
+ sg_get_opcode_sa_name(((do_opcode > 0) ? do_opcode : 0),
+ ((do_servact > 0) ? do_servact : 0),
+ peri_type, NAME_BUFF_SZ, name_buff);
+ printf(" Command_name: %s\n", name_buff);
+ switch((int)(rsoc_buff[1] & 7)) {
+ case 0:
+ cp = "not currently available";
+ break;
+ case 1:
+ cp = "NOT supported";
+ break;
+ case 3:
+ cp = "supported (conforming to SCSI standard)";
+ v = 1;
+ break;
+ case 5:
+ cp = "supported (in a vendor specific manner)";
+ v = 1;
+ break;
+ default:
+ snprintf(name_buff, NAME_BUFF_SZ, "support reserved [0x%x]",
+ rsoc_buff[1] & 7);
+ cp = name_buff;
+ break;
+ }
+ printf(" Command %s\n", cp);
+ if (v) {
+ printf(" Usage data: ");
+ ucp = rsoc_buff + 4;
+ for (k = 0; k < cd_len; ++k)
+ printf("%.2x ", ucp[k]);
+ printf("\n");
+ }
+ if (0x80 & rsoc_buff[1]) { /* CTDP */
+ ucp = rsoc_buff + 4 + cd_len;
+ decode_cmd_to_descriptor(ucp, NAME_BUFF_SZ, name_buff);
+ printf(" %s\n", name_buff);
}
}
int main(int argc, char * argv[])
{
- int sg_fd, k, num, cd_len, plen, jmp_out, res;
- const char * file_name = 0;
- char ebuff[EBUFF_SZ];
+ int sg_fd, cd_len, res, len;
unsigned char rsoc_buff[MX_ALLOC_LEN];
- unsigned char * ucp;
- char name_buff[NAME_BUFF_SZ];
- int do_alpha = 0;
- int do_opcode = -1;
- int do_servact = -1;
- int do_verbose = 0;
- int do_unsorted = 0;
- int do_taskman = 0;
int rep_opts = 0;
const char * cp;
char buff[48];
struct sg_simple_inquiry_resp inq_resp;
const char * op_name;
+ struct opts_t opts;
- for (k = 1; k < argc; ++k) {
- cp = argv[k];
- plen = strlen(cp);
- if (plen <= 0)
- continue;
- if ('-' == *cp) {
- for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
- switch (*cp) {
- case 'a':
- do_alpha = 1;
- break;
- case 't':
- do_taskman = 1;
- break;
- case 'u':
- do_unsorted = 1;
- break;
- case 'v':
- ++do_verbose;
- break;
- case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
- case 'h':
- case '?':
- usage();
- return 0;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
- }
- if (plen <= 0)
- continue;
- if (0 == strncmp("o=", cp, 2)) {
- num = sscanf(cp + 2, "%x", (unsigned int *)&do_opcode);
- if ((1 != num) || (do_opcode > 255)) {
- fprintf(stderr, "Bad number after 'o=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == strncmp("s=", cp, 2)) {
- num = sscanf(cp + 2, "%x", (unsigned int *)&do_servact);
- if (1 != num) {
- fprintf(stderr, "Bad number after 's=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n", cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == file_name)
- file_name = cp;
- else {
- fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
+ memset(&opts, 0, sizeof(opts));
+ opts.do_opcode = -1;
+ opts.do_servact = -1;
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ if (opts.opt_new)
usage();
- return SG_LIB_SYNTAX_ERROR;
- }
+ else
+ usage_old();
+ return 0;
+ }
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
}
- if (0 == file_name) {
- fprintf(stderr, "No <scsi_device> argument given\n");
- usage();
+ if (NULL == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- if ((-1 != do_servact) && (-1 == do_opcode)) {
+ if ((-1 != opts.do_servact) && (-1 == opts.do_opcode)) {
fprintf(stderr, "When '-s' is chosen, so must '-o' be chosen\n");
- usage();
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- if (do_unsorted && do_alpha)
+ if (opts.do_unsorted && opts.do_alpha)
fprintf(stderr, "warning: unsorted ('-u') and alpha ('-a') options "
"chosen, ignoring alpha\n");
- if (do_taskman && ((-1 != do_opcode) || do_alpha || do_unsorted)) {
+ if (opts.do_taskman && ((-1 != opts.do_opcode) || opts.do_alpha ||
+ opts.do_unsorted)) {
fprintf(stderr, "warning: task management functions ('-t') chosen "
"so alpha ('-a'),\n unsorted ('-u') and opcode "
"('-o') options ignored\n");
}
- op_name = do_taskman ? "Report supported task management functions" :
+ op_name = opts.do_taskman ? "Report supported task management functions" :
"Report supported operation codes";
- if ((sg_fd = open(file_name, O_RDONLY | O_NONBLOCK)) < 0) {
- snprintf(ebuff, EBUFF_SZ, "sg_opcodes: error opening file: %s (ro)",
- file_name);
+#ifdef USE_SG_IO
+ if ((sg_fd = open(opts.device_name, O_RDONLY | O_NONBLOCK)) < 0) {
+ snprintf(ebuff, EBUFF_SZ, "sg_opcodes: error opening file (ro): %s",
+ opts.device_name);
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
- if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, do_verbose)) {
- printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product,
- inq_resp.revision);
+#else
+ if ((sg_fd = scsi_pt_open_device(opts.device_name, 1 /* RO */,
+ opts.do_verbose)) < 0) {
+ fprintf(stderr, "sg_opcodes: error opening file (ro): %s: %s\n",
+ opts.device_name, safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+#endif
+ if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, opts.do_verbose)) {
peri_type = inq_resp.peripheral_type;
- cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
- if (strlen(cp) > 0)
- printf(" Peripheral device type: %s\n", cp);
- else
- printf(" Peripheral device type: 0x%x\n", peri_type);
+ if (0 == opts.do_raw) {
+ printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product,
+ inq_resp.revision);
+ cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
+ if (strlen(cp) > 0)
+ printf(" Peripheral device type: %s\n", cp);
+ else
+ printf(" Peripheral device type: 0x%x\n", peri_type);
+ }
} else {
- printf("sg_opcodes: %s doesn't respond to a SCSI INQUIRY\n", file_name);
+ fprintf(stderr, "sg_opcodes: %s doesn't respond to a SCSI "
+ "INQUIRY\n", opts.device_name);
return SG_LIB_CAT_OTHER;
}
+#ifdef USE_SG_IO
close(sg_fd);
+#else
+ res = sg_cmds_close_device(sg_fd);
+ if (res < 0) {
+ fprintf(stderr, "close error: %s\n", safe_strerror(-res));
+ return SG_LIB_FILE_ERROR;
+ }
+#endif
+
#ifndef TEST_CODE
if (5 == peri_type) {
- printf("'%s' command not supported\nfor CD/DVD devices\n", op_name);
+ printf("'%s' command not supported\nfor CD/DVD devices\n",
+ op_name);
return SG_LIB_CAT_OTHER;
}
#endif
- if ((sg_fd = open(file_name, O_RDWR | O_NONBLOCK)) < 0) {
+#ifdef USE_SG_IO
+ if ((sg_fd = open(opts.device_name, O_RDWR | O_NONBLOCK)) < 0) {
snprintf(ebuff, EBUFF_SZ, "sg_opcodes: error opening file: %s (rw)",
- file_name);
+ opts.device_name);
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
- if (do_opcode >= 0)
- rep_opts = ((do_servact >= 0) ? 2 : 1);
+#else
+ if ((sg_fd = scsi_pt_open_device(opts.device_name, 0 /* RW */,
+ opts.do_verbose)) < 0) {
+ fprintf(stderr, "sg_opcodes: error opening file (rw): %s: %s\n",
+ opts.device_name, safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+#endif
+ if (opts.do_opcode >= 0)
+ rep_opts = ((opts.do_servact >= 0) ? 2 : 1);
memset(rsoc_buff, 0, sizeof(rsoc_buff));
#ifndef TEST_CODE
- if (do_taskman)
+ if (opts.do_taskman)
res = do_rstmf(sg_fd, rsoc_buff, sizeof(rsoc_buff), 0,
- do_verbose);
+ opts.do_verbose);
else
- res = do_rsoc(sg_fd, rep_opts, do_opcode, do_servact, rsoc_buff,
- sizeof(rsoc_buff), 0, do_verbose);
+ res = do_rsoc(sg_fd, opts.do_rctd, rep_opts, opts.do_opcode,
+ opts.do_servact, rsoc_buff, sizeof(rsoc_buff), 0,
+ opts.do_verbose);
switch (res) {
case 0:
case SG_LIB_CAT_RECOVERED:
@@ -526,21 +828,46 @@ int main(int argc, char * argv[])
fprintf(stderr, "%s: operation not supported\n", op_name);
goto err_out;
case SG_LIB_CAT_ILLEGAL_REQ:
- fprintf(stderr, "%s: bad field in cdb\n", op_name);
+ fprintf(stderr, "bad field in cdb including %s not supported\n",
+ op_name);
goto err_out;
default:
fprintf(stderr, "%s failed\n", op_name);
goto err_out;
}
#else
- if (do_taskman) {
+ if (opts.do_taskman) {
rsoc_buff[0] = dummy_rsmft_r0;
rsoc_buff[1] = dummy_rsmft_r1;
- } else
- memcpy(rsoc_buff, (unsigned char *)&dummy_resp, sizeof(dummy_resp));
+ } else if (opts.do_rctd) {
+ if (0 == rep_opts) {
+#if 1
+ memcpy(rsoc_buff, (unsigned char *)&dummy_to_resp,
+ sizeof(dummy_to_resp));
+#else
+ memcpy(rsoc_buff, (unsigned char *)&dummy_resp,
+ sizeof(dummy_resp));
+#endif
+ } else
+ memcpy(rsoc_buff, dummy_1_to_cmd, sizeof(dummy_1_to_cmd));
+ } else {
+ if (0 == rep_opts)
+ memcpy(rsoc_buff, (unsigned char *)&dummy_resp,
+ sizeof(dummy_resp));
+ else
+ memcpy(rsoc_buff, dummy_1_cmd, sizeof(dummy_1_cmd));
+ }
#endif
- if (do_taskman) {
+ if (opts.do_taskman) {
+ if (opts.do_raw) {
+ dStrRaw((const char *)rsoc_buff, 4);
+ goto err_out;
+ }
printf("\nTask Management Functions supported by device:\n");
+ if (opts.do_hex) {
+ dStrHex((const char *)rsoc_buff, 4, 1);
+ goto err_out;
+ }
if (rsoc_buff[0] & 0x80)
printf(" Abort task\n");
if (rsoc_buff[0] & 0x40)
@@ -559,47 +886,316 @@ int main(int argc, char * argv[])
printf(" Wakeup\n");
if (rsoc_buff[1] & 0x1)
printf(" I_T nexus reset\n");
- } else if (0 == rep_opts) /* list all supported operation codes */
- list_all_codes(rsoc_buff, sizeof(rsoc_buff), do_unsorted, do_alpha);
- else { /* asked about specific command */
- const char * cp;
- int v = 0;
-
-#ifdef TEST_CODE
- memcpy(rsoc_buff, dummy_1_cmd, sizeof(dummy_1_cmd));
-#endif
- printf("\n Opcode=0x%.2x", do_opcode);
- if (rep_opts > 1)
- printf(" Service_action=0x%.4x", do_servact);
- printf("\n");
- sg_get_opcode_sa_name(((do_opcode > 0) ? do_opcode : 0),
- ((do_servact > 0) ? do_servact : 0),
- peri_type, NAME_BUFF_SZ, name_buff);
- printf(" Command_name: %s\n", name_buff);
- switch((int)(rsoc_buff[1] & 7)) {
- case 0: cp = "not currently available"; break;
- case 1: cp = "NOT supported"; break;
- case 3: cp = "supported (conforming to SCSI standard)"; v = 1; break;
- case 5: cp = "supported (in a vendor specific manner)"; v = 1; break;
- default:
- snprintf(name_buff, NAME_BUFF_SZ, "support reserved [0x%x]",
- rsoc_buff[1] & 7);
- cp = name_buff;
- break;
+ } else if (0 == rep_opts) { /* list all supported operation codes */
+ len = ((rsoc_buff[0] << 24) | (rsoc_buff[1] << 16) |
+ (rsoc_buff[2] << 8) | rsoc_buff[3]) + 4;
+ if (len > (int)sizeof(rsoc_buff))
+ len = sizeof(rsoc_buff);
+ if (opts.do_raw) {
+ dStrRaw((const char *)rsoc_buff, len);
+ goto err_out;
+ }
+ if (opts.do_hex) {
+ dStrHex((const char *)rsoc_buff, len, 1);
+ goto err_out;
+ }
+ list_all_codes(rsoc_buff, sizeof(rsoc_buff), opts.do_unsorted,
+ opts.do_alpha, opts.do_rctd);
+ } else { /* asked about specific command */
+ cd_len = ((rsoc_buff[2] << 8) | rsoc_buff[3]);
+ len = cd_len + 4;
+ if (len > (int)sizeof(rsoc_buff))
+ len = sizeof(rsoc_buff);
+ if (opts.do_raw) {
+ dStrRaw((const char *)rsoc_buff, len);
+ goto err_out;
}
- printf(" Command %s\n", cp);
- if (v) {
- printf(" Usage data: ");
- cd_len = ((rsoc_buff[2] << 8) | rsoc_buff[3]);
- ucp = rsoc_buff + 4;
- for (k = 0; k < cd_len; ++k)
- printf("%.2x ", ucp[k]);
- printf("\n");
+ if (opts.do_hex) {
+ dStrHex((const char *)rsoc_buff, len, 1);
+ goto err_out;
}
+ list_one(rsoc_buff, cd_len, rep_opts, opts.do_opcode,
+ opts.do_servact);
}
res = 0;
err_out:
+#ifdef USE_SG_IO
close(sg_fd);
+#else
+ sg_cmds_close_device(sg_fd);
+#endif
return res;
}
+
+
+#ifdef USE_SG_IO
+/* Report Supported Operation Codes */
+/* Returns 0 when successful */
+static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode,
+ int rq_servact, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int res, k;
+ unsigned char rsocCmdBlk[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ if (rctd)
+ rsocCmdBlk[2] |= 0x80;
+ if (rep_opts)
+ rsocCmdBlk[2] |= (rep_opts & 0x7);
+ if (rq_opcode > 0)
+ rsocCmdBlk[3] = (rq_opcode & 0xff);
+ if (rq_servact > 0) {
+ rsocCmdBlk[4] = (unsigned char)((rq_servact >> 8) & 0xff);
+ rsocCmdBlk[5] = (unsigned char)(rq_servact & 0xff);
+
+ }
+ rsocCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
+ rsocCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rsocCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rsocCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+
+ if (verbose) {
+ fprintf(stderr, " Report Supported Operation Codes cmd: ");
+ for (k = 0; k < RSOC_CMD_LEN; ++k)
+ fprintf(stderr, "%02x ", rsocCmdBlk[k]);
+ fprintf(stderr, "\n");
+ }
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(rsocCmdBlk);
+ io_hdr.mx_sb_len = sizeof(sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = rsocCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ perror("SG_IO (rsoc) error");
+ return -1;
+ }
+ if (verbose > 2)
+ fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
+ res = sg_err_category3(&io_hdr);
+ switch (res) {
+ case SG_LIB_CAT_RECOVERED:
+ sg_chk_n_print3("Report supported operation codes", &io_hdr,
+ verbose > 1);
+ /* fall through */
+ case SG_LIB_CAT_CLEAN:
+ return 0;
+ default:
+ if (noisy | verbose) {
+ char ebuff[EBUFF_SZ];
+
+ if (0 == rep_opts)
+ snprintf(ebuff, EBUFF_SZ, "RSOC error, rep_opts=0 (all) ");
+ else if (1 == rep_opts)
+ snprintf(ebuff, EBUFF_SZ, "RSOC error, rq_opcode=0x%x ",
+ rq_opcode);
+ else
+ snprintf(ebuff, EBUFF_SZ, "RSOC error, rq_opcode=0x%x, "
+ "rq_sa=0x%x ", rq_opcode, rq_servact);
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
+ }
+ return res;
+ }
+}
+
+/* Report Supported Task Management Function */
+/* Returns 0 when successful */
+static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int res, k;
+ unsigned char rstmfCmdBlk[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ rstmfCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
+ rstmfCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rstmfCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rstmfCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+
+ if (verbose) {
+ fprintf(stderr, " Report Supported Task Management Functions "
+ "cmd: ");
+ for (k = 0; k < RSTMF_CMD_LEN; ++k)
+ fprintf(stderr, "%02x ", rstmfCmdBlk[k]);
+ fprintf(stderr, "\n");
+ }
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(rstmfCmdBlk);
+ io_hdr.mx_sb_len = sizeof(sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = rstmfCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ perror("SG_IO (rstmf) error");
+ return -1;
+ }
+ if (verbose > 2)
+ fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
+ res = sg_err_category3(&io_hdr);
+ switch (res) {
+ case SG_LIB_CAT_RECOVERED:
+ sg_chk_n_print3("Report supported task management fns", &io_hdr,
+ verbose > 1);
+ /* fall through */
+ case SG_LIB_CAT_CLEAN:
+ return 0;
+ default:
+ if (noisy | verbose) {
+ char ebuff[EBUFF_SZ];
+ snprintf(ebuff, EBUFF_SZ, "RSTMF error ");
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
+ }
+ return res;
+ }
+}
+
+#else /* use generic pass through code instead */
+
+static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode,
+ int rq_servact, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int k, ret, res, sense_cat;
+ unsigned char rsocCmdBlk[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ void * ptvp;
+
+ if (rctd)
+ rsocCmdBlk[2] |= 0x80;
+ if (rep_opts)
+ rsocCmdBlk[2] |= (rep_opts & 0x7);
+ if (rq_opcode > 0)
+ rsocCmdBlk[3] = (rq_opcode & 0xff);
+ if (rq_servact > 0) {
+ rsocCmdBlk[4] = (unsigned char)((rq_servact >> 8) & 0xff);
+ rsocCmdBlk[5] = (unsigned char)(rq_servact & 0xff);
+
+ }
+ rsocCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
+ rsocCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rsocCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rsocCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+
+ if (verbose) {
+ fprintf(stderr, " Report Supported Operation Codes cmd: ");
+ for (k = 0; k < RSOC_CMD_LEN; ++k)
+ fprintf(stderr, "%02x ", rsocCmdBlk[k]);
+ fprintf(stderr, "\n");
+ }
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ fprintf(sg_warnings_strm, "Report Supported Operation Codes: out "
+ "of memory\n");
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, rsocCmdBlk, sizeof(rsocCmdBlk));
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
+ res = do_scsi_pt(ptvp, sg_fd, DEF_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, "Report Supported Operation Codes", res,
+ mx_resp_len, sense_b, noisy, verbose,
+ &sense_cat);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_NOT_READY:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ case SG_LIB_CAT_INVALID_OP:
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ ret = sense_cat;
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ } else
+ ret = 0;
+
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int k, ret, res, sense_cat;
+ unsigned char rstmfCmdBlk[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ void * ptvp;
+
+ rstmfCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
+ rstmfCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rstmfCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rstmfCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+
+ if (verbose) {
+ fprintf(stderr, " Report Supported Task Management Functions "
+ "cmd: ");
+ for (k = 0; k < RSTMF_CMD_LEN; ++k)
+ fprintf(stderr, "%02x ", rstmfCmdBlk[k]);
+ fprintf(stderr, "\n");
+ }
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ fprintf(sg_warnings_strm, "Report Supported Task Management "
+ "Functions: out of memory\n");
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, rstmfCmdBlk, sizeof(rstmfCmdBlk));
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
+ res = do_scsi_pt(ptvp, sg_fd, DEF_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, "Report Supported Task management "
+ "functions", res, mx_resp_len, sense_b, noisy,
+ verbose, &sense_cat);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_NOT_READY:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ case SG_LIB_CAT_INVALID_OP:
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ ret = sense_cat;
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ } else
+ ret = 0;
+
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+#endif
diff --git a/sg_persist.8 b/sg_persist.8
index 912d6ef1..5d132e07 100644
--- a/sg_persist.8
+++ b/sg_persist.8
@@ -1,312 +1,316 @@
-.TH SG_PERSIST "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_PERSIST "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_persist \- use the Persistent Reserve In and Out SCSI commands
+sg_persist \- sends a SCSI PERSISTENT RESERVE (IN or OUT) command
to manipulate registrations and reservations
.SH SYNOPSIS
.B sg_persist
-[\fI<options>\fR] [\fI<scsi_device>\fR]
+[\fIOPTIONS\fR] [\fIDEVICE\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
This utility allows Persistent reservations and registrations to be
queried and changed. Persistent reservations and registrations are
-queried by sub-commands (called "service actions" in SPC-4) of the Persistent
-Reserve In (PRIN) SCSI command. Persistent reservations and
-registrations are changed by sub-commands of the Persistent Reserve
-Out (PROUT) SCSI command.
+queried by sub\-commands (called "service actions" in SPC\-4) of the
+SCSI PERSISTENT RESERVE IN (PRIN) command. Persistent reservations and
+registrations are changed by sub\-commands of the SCSI PERSISTENT RESERVE
+OUT (PROUT) command.
.PP
There is a two stage process to obtain a persistent reservation. First an
application (an I_T nexus in standard's jargon) must register a reservation
key. If that is accepted (and it should be unless some other I_T nexus has
-registered that key) then the application can try and reserve
-the device. The reserve operation must specify the reservation
-key and a "type" (see the '--prout-type=' option).
+registered that key) then the application can try and reserve the device.
+The reserve operation must specify the reservation key and a "type" (see
+the \fI\-\-prout\-type=TYPE\fR option).
.PP
It is relatively safe to query the state of Persistent reservations and
registrations. With no options this utility defaults to the READ KEYS
-sub-command of the PRIN command. Other PRIN sub-commands are
+sub\-command of the PRIN command. Other PRIN sub\-commands are
READ RESERVATION, REPORT CAPABILITIES and READ FULL STATUS.
.PP
Before trying to change Persistent reservations and registrations users
should be aware of what they are doing! The relevant sections of the
-SCSI Primary Commands document (SPC-4 most recent draft revision 5a
+SCSI Primary Commands document (SPC\-4 most recent draft revision 5a
dated 14th June 2006) are sections 5.6 (general information), 6.11 (for
PRIN) and 6.12 (for PROUT). To safeguard against accidental use,
-the '--out' option must be given when a PROUT sub-command (e.g. '--register')
-is used.
+the \fI\-\-out\fR option must be given when a PROUT sub\-command (e.g.
+\fI\-\-register\fR) is used.
.PP
-The older SCSI Reserve and Release commands (both 6 and 10 byte variants)
-are not supported by this utility. In SPC-3, Reserve and Release are
-deprecated, replaced by Persistent Reservations. Reserve and Release
-have been removed from SPC-4 and Annex B is provided showing how to
+The older SCSI RESERVE and RELEASE commands (both 6 and 10 byte variants)
+are not supported by this utility. In SPC\-3, RESERVE and RELEASE are
+deprecated, replaced by Persistent Reservations. RESERVE and RELEASE
+have been removed from SPC\-4 and Annex B is provided showing how to
convert to persistent reservation commands. See a utility
-called 'scsires' for support of the SCSI Reserve and Release commands.
+called 'scsires' for support of the SCSI RESERVE and RELEASE commands.
.PP
-The <scsi_device> is required by all variants of this utility apart
-from '--help' ('-h'). The <scsi_device> can be given either as an
+The \fIDEVICE\fR is required by all variants of this utility apart
+from \fI\-\-help\fR. The \fIDEVICE\fR can be given either as an
argument (typically but not necessarily the last one) or via
-the '--device=<scsi_device>' (or '-d <scsi_device') option.
+the \fI\-\-device=DEVICE\fR option.
.PP
-SPC-4 does not use the term "sub-command". It uses the term "service action"
+SPC\-4 does not use the term "sub\-command". It uses the term "service action"
for this and for part of a field's name in the parameter block associated
with the PROUT command (i.e. "service action reservation key"). To lessen
-the potential confusion the term "sub-command" has been introduced.
+the potential confusion the term "sub\-command" has been introduced.
.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---clear | -C
-Clear is a sub-command of the PROUT command. It releases the
+\fB\-C\fR, \fB\-\-clear\fR
+Clear is a sub\-command of the PROUT command. It releases the
persistent reservation (if any) and clears all registrations from the
device. It is required to supply a reservation key that is registered
-for this I_T_L nexus (identified by --param-rk).
+for this I_T_L nexus (identified by \fI\-\-param\-rk=RK\fR).
.TP
---device=<scsi_device> | -d <scsi_device>
-This utility needs to have a scsi_device to be specified. This can either
-be as an argument to '--device' or '-d' or just the first non-option
-argument.
+\fB\-d\fR, \fB\-\-device\fR=\fIDEVICE\fR
+\fIDEVICE\fR to send SCSI commands to. The \fIDEVICE\fR can either be
+provided via this option or via a freestanding argument. For example,
+these two: 'sg_persist \-\-device=/dev/sg2' and 'sg_persist /dev/sg2'
+are equivalent.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output a usage message.
.TP
---hex | -H
-the response to a valid PRIN sub-command will be output in hexadecimal.
-Normally if the PRIN sub-command is recognised then the response
-will be decoded as per SPC-4.
+\fB\-H\fR, \fB\-\-hex\fR
+the response to a valid PRIN sub\-command will be output in hexadecimal.
+Normally if the PRIN sub\-command is recognised then the response
+will be decoded as per SPC\-4.
.TP
---in | -i
-specify that a Persistent Reserve In SCSI command is required. This
+\fB\-i\fR, \fB\-\-in\fR
+specify that a SCSI PERSISTENT RESERVE IN command is required. This
is the default.
.TP
---out | -o
-specify that a Persistent Reserve Out SCSI command is required.
-.TP
---no-inquiry | -n
-the default action is to do a standard INQUIRY SCSI command and output
+\fB\-n\fR, \fB\-\-no\-inquiry\fR
+the default action is to do a standard SCSI INQUIRY command and output
make, product and revision strings plus the peripheral device type
prior to executing a PR In or Out command. With this option the
INQUIRY command is skipped.
.TP
---param-alltgpt | -Y
+\fB\-o\fR, \fB\-\-out\fR
+specify that a SCSI PERSISTENT RESERVE OUT command is required.
+.TP
+\fB\-Y\fR, \fB\-\-param\-alltgpt\fR
set the 'all target ports' (ALL_TG_PT) flag in the parameter block of the
PROUT command. Only relevant for 'register' and 'register and ignore existing
-key' sub-commands.
+key' sub\-commands.
.TP
---param-aptpl | -Z
+\fB\-Z\fR, \fB\-\-param\-aptpl\fR
set the 'activate persist through power loss' (APTPL) flag in the parameter
block of the PROUT command. Relevant for 'register', 'register and ignore
-existing key' and 'register and move' sub-commands.
+existing key' and 'register and move' sub\-commands.
.TP
---param-rk=<h> | -K <h>
+\fB\-K\fR, \fB\-\-param\-rk\fR=\fIRK\fR
specify the reservation key found in the parameter block of the PROUT
-command. Argument is assumed to be hex (up to 8 bytes long). Default value
-is 0. This option is needed by most PROUT sub-commands.
+command. \fIRK\fR is assumed to be hex (up to 8 bytes long). Default value
+is 0. This option is needed by most PROUT sub\-commands.
.TP
---param-sark=<h> | -S <h>
+\fB\-S\fR, \fB\-\-param\-sark\fR=\fISARK\fR
specify the service action reservation key found in the parameter block
-of the PROUT command. Argument is assumed to be hex (up to 8 bytes long).
-Default value is 0. This option is needed by some PROUT sub-commands.
+of the PROUT command. \fISARK\fR is assumed to be hex (up to 8 bytes long).
+Default value is 0. This option is needed by some PROUT sub\-commands.
.TP
---preempt | -P
-Preempt is a sub-command of the PROUT command. Preempts
-the existing persistent reservation (identified by '--param-sark') with
+\fB\-P\fR, \fB\-\-preempt\fR
+Preempt is a sub\-command of the PROUT command. Preempts the existing
+persistent reservation (identified by \fI\-\-param\-sark=SARK\fR) with
the registration key that is registered for this I_T_L nexus (identified
-by '--param-rk'). The associated '--prout-type<h>' option needs to match
-the type of the reservation.
+by \fI\-\-param\-rk=RK\fR). The associated \fI\-\-prout\-type=TYPE\fR option
+needs to match the type of the reservation.
.TP
---preempt-abort | -A
-Preempt and Abort is a sub-command of the PROUT command. Preempts
-the existing persistent reservation (identified by '--param-sark') with
-the registration key that is registered for this I_T_L nexus (identified
-by '--param-rk'). The associated '--prout-type<h>' option needs to match
-the type of the reservation. ACA and other pending tasks are aborted.
+\fB\-A\fR, \fB\-\-preempt\-abort\fR
+Preempt and Abort is a sub\-command of the PROUT command. Preempts
+the existing persistent reservation (identified by \fI\-\-param\-sark=SARK\fR)
+with the registration key that is registered for this I_T_L nexus (identified
+by \fI\-\-param\-rk=RK\fR). The associated \fI\-\-prout\-type=TYPE\fR option
+needs to match the type of the reservation. ACA and other pending tasks are
+aborted.
.TP
---prout-type=<h> | -T <h>
+\fB\-T\fR, \fB\-\-prout\-type\fR=\fITYPE\fR
specify the PROUT command's 'type' argument. Required by
-the 'register-move', 'reserve', 'release' and 'preempt (and abort)'
-sub-commands. Valid arguments: 1-> write exclusive, 3->
-exclusive access, 5-> write exclusive - registrants only, 6->
-exclusive access - registrants only, 7-> write exclusive - all registrants,
-8-> exclusive access - all registrants. Default value is 0 (which is
+the 'register\-move', 'reserve', 'release' and 'preempt (and abort)'
+sub\-commands. Valid \fITYPE\fR values: 1\-> write exclusive, 3\->
+exclusive access, 5\-> write exclusive \- registrants only, 6\->
+exclusive access \- registrants only, 7\-> write exclusive \- all registrants,
+8\-> exclusive access \- all registrants. Default value is 0 (which is
an invalid type). Each "persistent reservation type" is explained in more
detail in a subsection of that name in the read reservation section of
-the PRIN command (section 6.11.3.4 of SPC-4 revision 5a).
+the PRIN command (section 6.11.3.4 of SPC\-4 revision 5a).
.TP
---read-full-status | -s
-Read Full Status is a sub-command of the PRIN command. For each registration
+\fB\-s\fR, \fB\-\-read\-full\-status\fR
+Read Full Status is a sub\-command of the PRIN command. For each registration
with the given SCSI device, it lists the reservation key and associated
information. TransportIDs, if supplied in the response, are decoded.
.TP
---read-keys | -k
-Read Keys is a sub-command of the PRIN command. Lists all the reservation
+\fB\-k\fR, \fB\-\-read\-keys\fR
+Read Keys is a sub\-command of the PRIN command. Lists all the reservation
keys registered (i.e. registrations) with the given SCSI device. This is
-the default sub-command for the PRIN SCSI command.
+the default sub\-command for the SCSI PRIN command.
.TP
---read-reservation | -r
-Read Reservation is a sub-command of the PRIN command. List information
-about the current holder of the reservation on the given device. If there
+\fB\-r\fR, \fB\-\-read\-reservation\fR
+Read Reservation is a sub\-command of the PRIN command. List information
+about the current holder of the reservation on the \fIDEVICE\fR. If there
is no current reservation this will be noted. Information about the current
holder of the reservation includes its reservation key, scope and type.
.TP
---read-status | -s
-same as 'read-full-status'.
+\fB\-s\fR, \fB\-\-read\-status\fR
+same as \fI\-\-read\-full\-status\fR.
.TP
---register | -G
-Register is a sub-command of the PROUT command. It has 3 different
+\fB\-G\fR, \fB\-\-register\fR
+Register is a sub\-command of the PROUT command. It has 3 different
actions depending on associated parameters. a) add a new registration
-with '--param-rk=0' and '--param-sark=<new_rk>'; b) Change an existing
-registration with '--param-rk=<old_rk>'
-and '--param-sark=<new_rk>'; or c) Delete an existing registration
-with '--param-rk=<old_rk>' and '--param-sark=0'.
+with '\-\-param\-rk=0' and '\-\-param\-sark=<new_rk>'; b) Change an existing
+registration with '\-\-param\-rk=<old_rk>'
+and '\-\-param\-sark=<new_rk>'; or c) Delete an existing registration
+with '\-\-param\-rk=<old_rk>' and '\-\-param\-sark=0'.
.TP
---register-ignore | -I
-Register and Ignore Existing Key is a sub-command of the PROUT command.
-Similar to '--register' except that when changing a reservation key the
-old key is not specified. The '--prout-sark=<new_rk>' option should also
-be given.
+\fB\-I\fR, \fB\-\-register\-ignore\fR
+Register and Ignore Existing Key is a sub\-command of the PROUT command.
+Similar to \fI\-\-register\fR except that when changing a reservation key
+the old key is not specified. The '\-\-prout-sark=<new_rk>' option should
+also be given.
.TP
---register-move | -M
+\fB\-M\fR, \fB\-\-register\-move\fR
register (another initiator) and move (the reservation held by the current
-initiator to that other initiator) is a sub-command of the PROUT command.
+initiator to that other initiator) is a sub\-command of the PROUT command.
It requires the transportID of the other initiator. [The standard uses the
term I_T nexus but the point to stress is that there are two initiators
-(the one sending this command and another one) but only one target.]
-The '--param-type=<h>' and '--param-rk=<h>' options need to match that of
-the existing reservation while '--param-sark=<h>' option specifies the
-reservation key of the new (i.e. destination) registration.
+(the one sending this command and another one) but only one logical unit.]
+The \fI\-\-prout\-type=TYPE\fR and \fI\-\-param\-rk=RK\fR options need to
+match that of the existing reservation while \fI\-\-param\-sark=SARK\fR
+option specifies the reservation key of the new (i.e. destination)
+registration.
.TP
---relative-target-port=<h> | -Q <h>
-relative target port number that reservation is to be moved to by
-PROUT 'register and move' sub-command. <h> is assumed to be hex in the
-range 0 to ffff inclusive. Defaults to 0 .
+\fB\-Q\fR, \fB\-\-relative\-target\-port\fR=\fIRTPI\fR
+relative target port identifier that reservation is to be moved to by
+PROUT 'register and move' sub\-command. \fIRTPI\fR is assumed to be hex
+in the range 0 to ffff inclusive. Defaults to 0 .
.TP
---release | -L
-Release is a sub-command of the PROUT command. It releases the
-current persistent reservation. The '--prout-type=<h>'
-and '--prout-rk=<h>' options, matching the reservation, must also be
+\fB\-L\fR, \fB\-\-release\fR
+Release is a sub\-command of the PROUT command. It releases the
+current persistent reservation. The \fI\-\-prout\-type=TYPE\fR
+and \fI\-\-param\-rk=RK\fR options, matching the reservation, must also be
specified.
.TP
---report-capabilities | -c
-Report Capabilities is a sub-command of the PRIN command. It lists
+\fB\-c\fR, \fB\-\-report/-capabilities\fR
+Report Capabilities is a sub\-command of the PRIN command. It lists
information about the aspects of persistent reservations that the
-given device supports.
+\fIDEVICE\fR supports.
.TP
---reserve | -R
-Reserve is a sub-command of the PROUT command. It creates a new
-persistent reservation (if permitted). The '--prout-type=<h>'
-and '--prout-rk=<h>' options must also be specified.
+\fB\-R\fR, \fB\-\-reserve\fR
+Reserve is a sub\-command of the PROUT command. It creates a new
+persistent reservation (if permitted). The \fI\-\-prout\-type=TYPE\fR
+and \fI\-\-param\-rk=RK\fR options must also be specified.
.TP
---transport-id=<h>,<h>... | -X <h>,<h>...
-a transportID is required for the PROUT 'register and move' sub-command
+\fB\-X\fR, \fB\-\-transport\-id\fR=\fIH,H...\fR
+a transportID is required for the PROUT 'register and move' sub\-command
and is optional for the PROUT 'register' and 'register and ignore
-existing key' sub-commands. The latter two sub-commands can take multiple
+existing key' sub\-commands. The latter two sub\-commands can take multiple
transportIDs in a list but only one is supported on the command line.
-The argument is a comma separated list of hex numbers representing
+\fIH,H...\fR is a comma separated list of hex numbers representing
the bytes of the transportID. The list of hex numbers will be padded
-out with zeroes to 24 bytes which is the minimum length of a
+out with zeros to 24 bytes which is the minimum length of a
transportID. A transportID longer than 24 bytes (e.g. for iSCSI) is
-padded with zeroes so its length is a multiple of 4.
+padded with zeros so its length is a multiple of 4.
.TP
---transport-id=- | -X -
-a transportID is required for the PROUT 'register and move' sub-command
+\fB\-X\fR, \fB\-\-transport\-id=\-\fR
+a transportID is required for the PROUT 'register and move' sub\-command
and is optional for the PROUT 'register' and 'register and ignore
-existing key' sub-commands. The latter two sub-commands can take multiple
-transportIDs in a list. The argument is '-' which indicates
+existing key' sub\-commands. The latter two sub\-commands can take multiple
+transportIDs in a list. The argument is '\-' which indicates
stdin should be read for the transportID(s). Empty lines are ignored.
Everything from and including a "#" on a line is ignored.
Leading spaces and tabs are ignored. All numbers
are assumed to be hexadecimal and can be separated by space, comma or
tab. There can be one transportID per line. TranportIDs will be padded
-out with zeroes to 24 bytes which is the minimum length of a
+out with zeros to 24 bytes which is the minimum length of a
transportID. A transportID longer than 24 bytes (e.g. for iSCSI) is
-padded with zeroes so its length is a multiple of 4.
+padded with zeros so its length is a multiple of 4.
.TP
---unreg | -U
-optional when the PROUT register and move sub-command is invoked. If given
+\fB\-U\fR, \fB\-\-unreg\fR
+optional when the PROUT register and move sub\-command is invoked. If given
it will unregister the current initiator (I_T nexus) after the other initiator
has been registered and the reservation moved to it. When not given the
initiator (I_T nexus) that sent the PROUT command remains registered.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
print out cdb of issued commands prior to execution. If used twice
prints out the parameter block associated with the PROUT command prior
to its execution as well. If used thrice decodes given transportID(s)
as well. To see the response to a PRIN command in low level form use
-the '--hex' option.
+the \fI\-\-hex\fR option.
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print out version string. Ignore all other parameters.
.TP
--?
+\fB\-?\fR
output usage message. Ignore all other parameters.
.SH NOTES
-In the 2.4 series of Linux kernels the given device must be
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be
a SCSI generic (sg) device. In the 2.6 series any SCSI device
name (e.g. /dev/sdc, /dev/st1m or /dev/sg3) can be specified.
-For example "sg_persist --read-keys /dev/sda"
+For example "sg_persist \-\-read\-keys /dev/sda"
will work in the 2.6 series kernels.
.PP
The only scope for PROUT commands supported in the current draft of
-SPC-4 is "LU_SCOPE". Hence there seems to be no point in offering an
+SPC\-4 is "LU_SCOPE". Hence there seems to be no point in offering an
option to set scope to another value.
.PP
-Most errors with the PROUT sub-commands (e.g. missing or
-mismatched '--prout-type=<h>' option) will result in a RESERVATION
+Most errors with the PROUT sub\-commands (e.g. missing or
+mismatched \fI\-\-prout\-type=TYPE\fR) will result in a RESERVATION
CONFLICT status. This can be a bit confusing when you know there is
only one (active) initiator: the "conflict" is with the SPC standard, not
another initiator.
.SH EXAMPLES
.PP
-Due to defaults the simplest example executes the 'read keys' sub-command
+Due to defaults the simplest example executes the 'read keys' sub\-command
of the PRIN command:
.PP
sg_persist /dev/sda
.PP
-This is the same as the following (long-winded) command:
+This is the same as the following (long\-winded) command:
.PP
- sg_persist --in --read-keys --device=/dev/sda
+ sg_persist \-\-in \-\-read\-keys \-\-device=/dev/sda
.PP
-To read the current reservation either the '--read-reservation' form or
-the shorter '-r' can be used:
+To read the current reservation either the '\-\-read\-reservation' form or
+the shorter '\-r' can be used:
.PP
- sg_persist -r /dev/sda
+ sg_persist \-r /dev/sda
.PP
To
.B register
the new reservation key 0x123abc the following could be used:
.PP
- sg_persist --out --register --param-sark=123abc /dev/sda
+ sg_persist \-\-out \-\-register \-\-param\-sark=123abc /dev/sda
.PP
Given the above registration succeeds, to
.B reserve
-the given device (with type 'write exclusive') the following
+the \fIDEVICE\fR (with type 'write exclusive') the following
could be used:
.PP
- sg_persist --out --reserve --param-rk=123abc
+ sg_persist \-\-out \-\-reserve \-\-param\-rk=123abc
.br
- --prout-type=1 /dev/sda
+ \-\-prout\-type=1 /dev/sda
.PP
To
.B release
the reservation the following can be given (note that
-the --param-rk and --prout-type arguments must match those of the
+the \-\-param\-rk and \-\-prout\-type arguments must match those of the
reservation):
.PP
- sg_persist --out --release --param-rk=123abc
+ sg_persist \-\-out \-\-release \-\-param\-rk=123abc
.br
- --prout-type=1 /dev/sda
+ \-\-prout\-type=1 /dev/sda
.PP
Finally to
.B unregister
a reservation key (and not effect other
-registrations which is what '--clear' would do) the command
+registrations which is what '\-\-clear' would do) the command
is a little surprising:
.PP
- sg_persist --out --register --param-rk=123abc /dev/sda
+ sg_persist \-\-out \-\-register \-\-param\-rk=123abc /dev/sda
.PP
Now have a close look at the difference between the register and
unregister examples above.
.PP
An example file that is suitably formatted to pass transportIDs via
-the '-transport-id=-' option can be found in the examples sub-directory
+the '\-\-transport\-id=\-' option can be found in the examples sub\-directory
of the sg3_utils package. That file is called 'transport_ids.txt'.
.SH EXIT STATUS
The exit status of sg_persist is 0 when it is successful. Otherwise see
@@ -316,7 +320,7 @@ Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_persist.c b/sg_persist.c
index f7795f0e..3e00cb95 100644
--- a/sg_persist.c
+++ b/sg_persist.c
@@ -5,13 +5,16 @@
#include <string.h>
#include <ctype.h>
#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
/* A utility program for the Linux OS SCSI subsystem.
-* Copyright (C) 2004-2006 D. Gilbert
+* Copyright (C) 2004-2007 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)
@@ -21,7 +24,7 @@
*/
-static char * version_str = "0.27 20061015";
+static char * version_str = "0.31 20070129";
#define PRIN_RKEY_SA 0x0
@@ -45,8 +48,8 @@ static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"hex", 0, 0, 'H'},
{"in", 0, 0, 'i'},
- {"out", 0, 0, 'o'},
{"no-inquiry", 0, 0, 'n'},
+ {"out", 0, 0, 'o'},
{"param-alltgpt", 0, 0, 'Y'},
{"param-aptpl", 0, 0, 'Z'},
{"param-rk", 1, 0, 'K'},
@@ -104,50 +107,51 @@ static const int num_prout_sa_strs = sizeof(prout_sa_strs) /
static void usage()
{
fprintf(stderr,
- "Usage: 'sg_persist [<options>] [<scsi_device>]\n\n"
- " where Persistent Reserve (PR) <options> include:\n"
- " --clear|-C PR Out: Clear\n"
- " --device=<scsi_device> device to query or change\n"
- " -d <scsi_device> device to query or change "
- "('-d' optional)\n"
- " --help|-h output this usage message\n"
- " --hex|-H output response in hex\n"
- " --in|-i request PR In command (default)\n"
- " --out|-o request PR Out command\n"
- " --no-inquiry|-n skip INQUIRY (default: do "
+ "Usage: sg_persist [OPTIONS] [DEVICE]\n"
+ " where OPTIONS include:\n"
+ " --clear|-C PR Out: Clear\n"
+ " --device=DEVICE|-d DEVICE query or change DEVICE\n"
+ " --help|-h output this usage message\n"
+ " --hex|-H output response in hex\n"
+ " --in|-i request PR In command (default)\n"
+ " --no-inquiry|-n skip INQUIRY (default: do "
"INQUIRY)\n"
- " --param-alltgpt|-Y PR Out parameter 'ALL_TG_PT'\n"
- " --param-aptpl|-Z PR Out parameter 'APTPL'\n"
- " --param-rk=<h>|-K <h> PR Out parameter reservation key\n"
- " (argument in hex)\n"
- " --param-sark=<h>|-S <h> PR Out parameter service action\n"
- " reservation key (argument in hex)\n"
- " --preempt|-P PR Out: Preempt\n"
- " --preempt-abort|-A PR Out: Preempt and Abort\n"
- " --prout-type=<h>|-T <n> PR Out command type\n"
- " --read-full-status|-s PR In: Read Full Status\n"
- " --read-keys|-k PR In: Read Keys\n"
- " --read-reservation|-r PR In: Read Reservation\n"
- " --read-status|-s PR In: Read Full Status\n"
- " --register|-G PR Out: Register\n"
- " --register-ignore|-I PR Out: Register and Ignore\n"
- " --register-move|-M PR Out: Register and Move\n"
- " --relative-target-port=<h>|-Q <h> PR Out parameter for "
- "'-M'\n"
- " --release|-L PR Out: Release\n"
- " --report-capabilities|-c PR In: Report Capabilities\n"
- " --reserve|-R PR Out: Reserve\n"
- " --transport-id=<h>,<h>...|-X <h>,<h>... TransportID "
+ " --out|-o request PR Out command\n"
+ " --param-alltgpt|-Y PR Out parameter 'ALL_TG_PT'\n"
+ " --param-aptpl|-Z PR Out parameter 'APTPL'\n"
+ " --param-rk=RK|-K RK PR Out parameter reservation key\n"
+ " (RK in hex)\n"
+ " --param-sark=SARK|-S SARK PR Out parameter service "
+ "action\n"
+ " reservation key (SARK in "
+ "hex)\n"
+ " --preempt|-P PR Out: Preempt\n"
+ " --preempt-abort|-A PR Out: Preempt and Abort\n"
+ " --prout-type=TYPE|-T TYPE PR Out command type\n"
+ " --read-full-status|-s PR In: Read Full Status\n"
+ " --read-keys|-k PR In: Read Keys\n"
+ " --read-reservation|-r PR In: Read Reservation\n"
+ " --read-status|-s PR In: Read Full Status\n"
+ " --register|-G PR Out: Register\n"
+ " --register-ignore|-I PR Out: Register and Ignore\n"
+ " --register-move|-M PR Out: Register and Move\n"
+ " --relative-target-port=RTPI|-Q RTPI relative target port "
+ "identifier\n"
+ " for '--register-move'\n"
+ " --release|-L PR Out: Release\n"
+ " --report-capabilities|-c PR In: Report Capabilities\n"
+ " --reserve|-R PR Out: Reserve\n"
+ " --transport-id=H,H...|-X H,H... TransportID "
"hex number(s),\n"
- " comma separated list\n"
- " --transport-id=-|-X - read TransportID from stdin\n"
- " --unreg|-U optional with PR Out Register "
+ " comma separated list\n"
+ " --transport-id=-|-X - read TransportID from stdin\n"
+ " --unreg|-U optional with PR Out Register "
"and Move\n"
- " --verbose|-v output additional debug "
+ " --verbose|-v output additional debug "
"information\n"
- " --version|-V output version string\n"
- " -? output this usage message\n\n"
- "Performs a PERSISTENT RESERVE (IN or OUT) SCSI command\n");
+ " --version|-V output version string\n"
+ " -? output this usage message\n\n"
+ "Performs a SCSI PERSISTENT RESERVE (IN or OUT) command\n");
}
static const char * pr_type_strs[] = {
@@ -171,7 +175,7 @@ static void decode_transport_id(const char * leadin, unsigned char * ucp,
unsigned long long ull;
int bump;
- for (k = 0, bump; k < len; k += bump, ucp += bump) {
+ for (k = 0, bump = 24; k < len; k += bump, ucp += bump) {
if ((len < 24) || (0 != (len % 4)))
printf("%sTransport Id short or not multiple of 4 "
"[length=%d]:\n", leadin, len);
@@ -240,7 +244,7 @@ static void decode_transport_id(const char * leadin, unsigned char * ucp,
ull <<= 8;
ull |= ucp[4 + j];
}
- printf("%s SAS address: 0x%llx\n", leadin, ull);
+ printf("%s SAS address: 0x%" PRIx64 "\n", leadin, ull);
if (0 != format_code)
printf("%s [Unexpected format code: %d]\n", leadin,
format_code);
@@ -281,16 +285,16 @@ static int prin_work(int sg_fd, int prin_sa, int do_verbose, int do_hex)
sizeof(pr_buff), 1, do_verbose);
if (res) {
if (SG_LIB_CAT_INVALID_OP == res)
- fprintf(stderr, "Persistent reserve in, command not "
- "supported\n");
+ fprintf(stderr, "PR in: command not supported\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "Persistent reserve in: bad field in cdb\n");
+ fprintf(stderr, "PR in: bad field in cdb including "
+ "unsupported service action\n");
else if (SG_LIB_CAT_UNIT_ATTENTION == res)
- fprintf(stderr, "Persistent reserve in: unit attention\n");
+ fprintf(stderr, "PR in: unit attention\n");
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
- fprintf(stderr, "Persistent reserve in: aborted command\n");
+ fprintf(stderr, "PR in: aborted command\n");
else
- fprintf(stderr, "Persistent reserve in, command failed\n");
+ fprintf(stderr, "PR in: command failed\n");
return 1;
}
if (PRIN_RCAP_SA == prin_sa) {
@@ -365,7 +369,7 @@ static int prin_work(int sg_fd, int prin_sa, int do_verbose, int do_hex)
ull <<= 8;
ull |= ucp[j];
}
- printf(" 0x%llx\n", ull);
+ printf(" 0x%" PRIx64 "\n", ull);
}
} else
printf("there are NO registered reservation keys\n");
@@ -381,7 +385,7 @@ static int prin_work(int sg_fd, int prin_sa, int do_verbose, int do_hex)
ull <<= 8;
ull |= ucp[j];
}
- printf(" Key=0x%llx\n", ull);
+ printf(" Key=0x%" PRIx64 "\n", ull);
j = ((ucp[13] >> 4) & 0xf);
if (0 == j)
printf(" scope: LU_SCOPE, ");
@@ -404,7 +408,7 @@ static int prin_work(int sg_fd, int prin_sa, int do_verbose, int do_hex)
ull <<= 8;
ull |= ucp[j];
}
- printf(" Key=0x%llx\n", ull);
+ printf(" Key=0x%" PRIx64 "\n", ull);
if (ucp[12] & 0x2)
printf(" All target ports bit set\n");
else {
@@ -468,15 +472,16 @@ static int prout_work(int sg_fd, int prout_sa, unsigned int prout_type,
pr_buff, len, 1, do_verbose);
if (res) {
if (SG_LIB_CAT_INVALID_OP == res)
- fprintf(stderr, "Persistent reserve out, command not supported\n");
+ fprintf(stderr, "PR out:, command not supported\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "Persistent reserve out, bad field in cdb\n");
+ fprintf(stderr, "PR out: bad field in cdb including "
+ "unsupported service action\n");
else if (SG_LIB_CAT_UNIT_ATTENTION == res)
- fprintf(stderr, "Persistent reserve out, unit attention\n");
+ fprintf(stderr, "PR out: unit attention\n");
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
- fprintf(stderr, "Persistent reserve out, aborted command\n");
+ fprintf(stderr, "PR out: aborted command\n");
else
- fprintf(stderr, "Persistent reserve out, command failed\n");
+ fprintf(stderr, "PR out: command failed\n");
return 1;
} else if (do_verbose) {
char buff[64];
@@ -485,8 +490,7 @@ static int prout_work(int sg_fd, int prout_sa, unsigned int prout_type,
strncpy(buff, prout_sa_strs[prout_sa], sizeof(buff));
else
snprintf(buff, sizeof(buff), "service action=0x%x", prout_sa);
- fprintf(stderr, "Persistent Reserve Out command (%s) "
- "successful\n", buff);
+ fprintf(stderr, "PR out: command (%s) successful\n", buff);
}
return 0;
}
@@ -530,18 +534,19 @@ static int prout_rmove_work(int sg_fd, unsigned int prout_type,
do_verbose);
if (res) {
if (SG_LIB_CAT_INVALID_OP == res)
- fprintf(stderr, "Persistent reserve out command not supported\n");
+ fprintf(stderr, "PR out: command not supported\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "Persistent reserve out, bad field in cdb\n");
+ fprintf(stderr, "PR out: bad field in cdb including "
+ "unsupported service action\n");
else if (SG_LIB_CAT_UNIT_ATTENTION == res)
- fprintf(stderr, "Persistent reserve out, unit attention\n");
+ fprintf(stderr, "PR out: unit attention\n");
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
- fprintf(stderr, "Persistent reserve out, aborted command\n");
+ fprintf(stderr, "PR out: aborted command\n");
else
- fprintf(stderr, "Persistent reserve out command failed\n");
+ fprintf(stderr, "PR out: command failed\n");
return 1;
} else if (do_verbose)
- fprintf(stderr, "Persistent Reserve Out 'register and move' "
+ fprintf(stderr, "PR out: 'register and move' "
"command successful\n");
return 0;
}
@@ -757,7 +762,7 @@ int main(int argc, char * argv[])
++num_prin_sa;
break;
case 'K':
- if (1 != sscanf(optarg, "%llx", &param_rk)) {
+ if (1 != sscanf(optarg, "%" SCNx64 "", &param_rk)) {
fprintf(stderr, "bad argument to '--param-rk'\n");
return SG_LIB_SYNTAX_ERROR;
}
@@ -806,7 +811,7 @@ int main(int argc, char * argv[])
++num_prin_sa;
break;
case 'S':
- if (1 != sscanf(optarg, "%llx", &param_sark)) {
+ if (1 != sscanf(optarg, "%" SCNx64 "", &param_sark)) {
fprintf(stderr, "bad argument to '--param-sark'\n");
return SG_LIB_SYNTAX_ERROR;
}
diff --git a/sg_prevent.8 b/sg_prevent.8
index d6a75d08..d87c9412 100644
--- a/sg_prevent.8
+++ b/sg_prevent.8
@@ -1,49 +1,48 @@
-.TH SG_PREVENT "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_PREVENT "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_prevent \- invoke SCSI PREVENT ALLOW MEDIUM REMOVAL command on a device
+sg_prevent \- sends a SCSI PREVENT ALLOW MEDIUM REMOVAL command
.SH SYNOPSIS
.B sg_prevent
-[\fI--allow\fR] [\fI--help\fR] [\fI--prevent=<n>\fR] [\fI--verbose\fR]
-[\fI--version\fR] \fI<scsi_device>\fR
+[\fI\-\-allow\fR] [\fI\-\-help\fR] [\fI\-\-prevent=PC\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Sends a SCSI PREVENT ALLOW MEDIUM REMOVAL command to the given SCSI
-device. The default action of this utility is to disallow the user and the
-SCSI START STOP UNIT command (see sg_start) removing or ejecting
-the medium from a drive. Drives that hold removable disks, tape
-cartridges or cd/dvd media typically implement this command. The definition
-of the "prevent" codes for this command differ between disks and
-tapes (covered by SBC-3 and SSC-3) and cd/dvd drives (covered by MMC-5).
-The "prevent codes" described here are from MMC-5.
+Sends a SCSI PREVENT ALLOW MEDIUM REMOVAL command to \fIDEVICE\fR.
+The default action of this utility is to prevent the removing or
+ejecting of the medium from a drive. This is done by ignoring the
+SCSI START STOP UNIT command (see sg_start) and ignoring the eject
+button on the drive when the user presses it. Drives that hold removable
+disks, tape cartridges or cd/dvd media typically implement this command.
+The definition of the "prevent" codes for this command differ between
+disks and tapes (covered by SBC\-3 and SSC\-3) and cd/dvd drives (covered
+by MMC\-5). The "prevent codes" described here are from MMC\-5.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---allow | -a
-allow medium removal. This is equivalent to setting the argument
-to '--prevent' to 2. Cannot be used with '--prevent' option (i.e. use
-no options (hence prevent removal), this option or '--prevent').
+\fB\-a\fR, \fB\-\-allow\fR
+allow medium removal. This is equivalent to setting to '\-\-prevent=2'.
+Cannot be used with \fI\-\-prevent=PC\fR option (i.e. either use
+no options (hence prevent removal), this option or \fI\-\-prevent=PC\fR).
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---prevent=<n> | -p <n>
-prevent codes: 0 allows removal, 1 prevents removal (default), 2 allows
-persistent removal while 3 prevents persistent removal. "Persistent" in this
-context means that the initiator (port) that successfully uses code 3 blocks
-other initiators (ports) from allowing removal. A "persistent prevent" state
-can be cleared by owner allowing persistent removal (code 2) or a power
-cycle (or anything that resets the device (lun)) or some special
-commands (e.g. various service actions of Persistent Reserve Out, see SPC-3).
+\fB\-p\fR, \fB\-\-prevent\fR=\fIPC\fR
+where \fIPC\fR is a prevent code value. Defined values are: 0 allows removal,
+1 prevents removal (default), 2 allows persistent removal while 3 prevents
+persistent removal. "Persistent" in this context means that the
+initiator (port) that successfully uses code 3 blocks other initiators (ports)
+from allowing removal. A "persistent prevent" state can be cleared by the
+owner allowing persistent removal (code 2) or a power cycle (or anything that
+resets the device (lun)) or some special commands (e.g. various service
+actions of Persistent Reserve Out, see SPC\-3).
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
-In some cases removable media can be ejected by an application (see
-sg_start and its '-loej' option). Often a user with physical access
-to the drive can attempt to eject the media by pressing a button on
-the drive.
.SH EXIT STATUS
The exit status of sg_prevent is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
@@ -52,7 +51,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_prevent.c b/sg_prevent.c
index c3e6de66..ef0ee58e 100644
--- a/sg_prevent.c
+++ b/sg_prevent.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,11 +32,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include <getopt.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -46,7 +42,7 @@
* given SCSI device.
*/
-static char * version_str = "1.05 20061012";
+static char * version_str = "1.06 20070129";
#define ME "sg_prevent: "
@@ -63,20 +59,20 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_prevent [--allow] [--help] [--prevent=<n>] [--verbose] "
+ "sg_prevent [--allow] [--help] [--prevent=PC] [--verbose] "
"[--version]\n"
- " <scsi_device>\n"
+ " DEVICE\n"
" where:\n"
" --allow|-a allow media removal\n"
- " --help|-h print out usage message\n"
- " --prevent=<n>|-p <n> prevention level (def: 1 -> "
+ " --help|-h print usage message then exit\n"
+ " --prevent=PC|-p PC prevent code value (def: 1 -> "
"prevent)\n"
" 0 -> allow, 1 -> prevent\n"
" 2 -> persistent allow, 3 -> "
"persistent prevent\n"
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
- "Performs a PREVENT ALLOW MEDIUM REMOVAL SCSI command\n"
+ "Performs a SCSI PREVENT ALLOW MEDIUM REMOVAL command\n"
);
}
diff --git a/sg_pt.h b/sg_pt.h
index a5f82a70..9a5cab67 100644
--- a/sg_pt.h
+++ b/sg_pt.h
@@ -2,7 +2,7 @@
#define SG_PT_H
/*
- * Copyright (c) 2005-2006 Douglas Gilbert.
+ * Copyright (c) 2005-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,10 @@
*
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Returns >= 0 if successful. If error in Unix returns negated errno. */
extern int scsi_pt_open_device(const char * device_name, int read_only,
int verbose);
@@ -101,5 +105,8 @@ extern int get_scsi_pt_duration_ms(const void * scsi_pt_obj);
processing is complete in order to clean up resources. */
extern void destruct_scsi_pt_obj(void * scsi_pt_obj);
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/sg_pt_freebsd.c b/sg_pt_freebsd.c
index a0645e6a..f8f59b90 100644
--- a/sg_pt_freebsd.c
+++ b/sg_pt_freebsd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2006 Douglas Gilbert.
+ * Copyright (c) 2005-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
*
*/
-/* version 1.03 2006/1/9 */
+/* version 1.05 2007/1/21 */
#include <stdio.h>
#include <stdlib.h>
@@ -53,7 +53,6 @@
#define FREEBSD_MAXDEV 64
#define FREEBSD_FDOFFSET 16;
-#define MAX_NUM_DEV 26
struct freebsd_dev_channel {
@@ -64,7 +63,7 @@ struct freebsd_dev_channel {
// Private table of open devices: guaranteed zero on startup since
// part of static data.
-struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV];
+static struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV];
#define DEF_TIMEOUT 60000 /* 60,000 milliseconds (60 seconds) */
@@ -109,17 +108,18 @@ int scsi_pt_open_device(const char * device_name,
if (verbose)
fprintf(sg_warnings_strm, "too many open file descriptors "
"(%d)\n", FREEBSD_MAXDEV);
- errno=EMFILE;
+ errno = EMFILE;
return -1;
}
- fdchan = calloc(1,sizeof(struct freebsd_dev_channel));
+ fdchan = (struct freebsd_dev_channel *)
+ calloc(1,sizeof(struct freebsd_dev_channel));
if (fdchan == NULL) {
// errno already set by call to malloc()
return -1;
}
- if (! (fdchan->devname = calloc(1, DEV_IDLEN+1)))
+ if (! (fdchan->devname = (char *)calloc(1, DEV_IDLEN+1)))
return -1;
if (cam_get_device(device_name, fdchan->devname, DEV_IDLEN,
@@ -172,7 +172,8 @@ void * construct_scsi_pt_obj()
{
struct sg_pt_freebsd_scsi * ptp;
- ptp = malloc(sizeof(struct sg_pt_freebsd_scsi));
+ ptp = (struct sg_pt_freebsd_scsi *)
+ malloc(sizeof(struct sg_pt_freebsd_scsi));
if (ptp) {
memset(ptp, 0, sizeof(struct sg_pt_freebsd_scsi));
ptp->dxfer_dir = CAM_DIR_NONE;
@@ -182,7 +183,7 @@ void * construct_scsi_pt_obj()
void destruct_scsi_pt_obj(void * vp)
{
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
if (ptp) {
if (ptp->ccb)
@@ -193,7 +194,7 @@ void destruct_scsi_pt_obj(void * vp)
void set_scsi_pt_cdb(void * vp, const unsigned char * cdb, int cdb_len)
{
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
if (ptp->cdb)
++ptp->in_err;
@@ -204,7 +205,7 @@ void set_scsi_pt_cdb(void * vp, const unsigned char * cdb, int cdb_len)
void set_scsi_pt_sense(void * vp, unsigned char * sense,
int max_sense_len)
{
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
if (ptp->sense)
++ptp->in_err;
@@ -216,7 +217,7 @@ void set_scsi_pt_sense(void * vp, unsigned char * sense,
void set_scsi_pt_data_in(void * vp, /* from device */
unsigned char * dxferp, int dxfer_len)
{
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
if (ptp->dxferp)
++ptp->in_err;
@@ -230,7 +231,7 @@ void set_scsi_pt_data_in(void * vp, /* from device */
void set_scsi_pt_data_out(void * vp, /* to device */
const unsigned char * dxferp, int dxfer_len)
{
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
if (ptp->dxferp)
++ptp->in_err;
@@ -248,7 +249,7 @@ void set_scsi_pt_packet_id(void * vp __attribute__ ((unused)),
void set_scsi_pt_tag(void * vp, int tag __attribute__ ((unused)))
{
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
++ptp->in_err;
}
@@ -256,7 +257,7 @@ void set_scsi_pt_tag(void * vp, int tag __attribute__ ((unused)))
void set_scsi_pt_task_management(void * vp,
int tmf_code __attribute__ ((unused)))
{
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
++ptp->in_err;
}
@@ -264,7 +265,7 @@ void set_scsi_pt_task_management(void * vp,
void set_scsi_pt_task_attr(void * vp, int attrib __attribute__ ((unused)),
int priority __attribute__ ((unused)))
{
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
++ptp->in_err;
}
@@ -272,7 +273,7 @@ void set_scsi_pt_task_attr(void * vp, int attrib __attribute__ ((unused)),
int do_scsi_pt(void * vp, int device_fd, int time_secs, int verbose)
{
int fd = device_fd - FREEBSD_FDOFFSET;
- struct sg_pt_freebsd_scsi * ptp = vp;
+ struct sg_pt_freebsd_scsi * ptp = (struct sg_pt_freebsd_scsi *)vp;
struct freebsd_dev_channel *fdchan;
union ccb *ccb;
int len, timout_ms;
@@ -369,7 +370,8 @@ int do_scsi_pt(void * vp, int device_fd, int time_secs, int verbose)
int get_scsi_pt_result_category(const void * vp)
{
- const struct sg_pt_freebsd_scsi * ptp = vp;
+ const struct sg_pt_freebsd_scsi * ptp =
+ (const struct sg_pt_freebsd_scsi *)vp;
if (ptp->os_err)
return SCSI_PT_RESULT_OS_ERR;
@@ -386,21 +388,24 @@ int get_scsi_pt_result_category(const void * vp)
int get_scsi_pt_resid(const void * vp)
{
- const struct sg_pt_freebsd_scsi * ptp = vp;
+ const struct sg_pt_freebsd_scsi * ptp =
+ (const struct sg_pt_freebsd_scsi *)vp;
return ptp->resid;
}
int get_scsi_pt_status_response(const void * vp)
{
- const struct sg_pt_freebsd_scsi * ptp = vp;
+ const struct sg_pt_freebsd_scsi * ptp =
+ (const struct sg_pt_freebsd_scsi *)vp;
return ptp->scsi_status;
}
int get_scsi_pt_sense_len(const void * vp)
{
- const struct sg_pt_freebsd_scsi * ptp = vp;
+ const struct sg_pt_freebsd_scsi * ptp =
+ (const struct sg_pt_freebsd_scsi *)vp;
int len;
len = ptp->sense_len - ptp->sense_resid;
@@ -416,14 +421,16 @@ int get_scsi_pt_duration_ms(const void * vp __attribute__ ((unused)))
int get_scsi_pt_transport_err(const void * vp)
{
- const struct sg_pt_freebsd_scsi * ptp = vp;
+ const struct sg_pt_freebsd_scsi * ptp =
+ (const struct sg_pt_freebsd_scsi *)vp;
return ptp->transport_err;
}
int get_scsi_pt_os_err(const void * vp)
{
- const struct sg_pt_freebsd_scsi * ptp = vp;
+ const struct sg_pt_freebsd_scsi * ptp =
+ (const struct sg_pt_freebsd_scsi *)vp;
return ptp->os_err;
}
@@ -431,7 +438,8 @@ int get_scsi_pt_os_err(const void * vp)
char * get_scsi_pt_transport_err_str(const void * vp, int max_b_len, char * b)
{
- struct sg_pt_freebsd_scsi * ptp = (void *)vp;
+ const struct sg_pt_freebsd_scsi * ptp =
+ (const struct sg_pt_freebsd_scsi *)vp;
if (0 == ptp->transport_err) {
strncpy(b, "no transport error available", max_b_len);
@@ -456,7 +464,8 @@ char * get_scsi_pt_transport_err_str(const void * vp, int max_b_len, char * b)
char * get_scsi_pt_os_err_str(const void * vp,
int max_b_len, char * b)
{
- const struct sg_pt_freebsd_scsi * ptp = vp;
+ const struct sg_pt_freebsd_scsi * ptp =
+ (const struct sg_pt_freebsd_scsi *)vp;
const char * cp;
cp = safe_strerror(ptp->os_err);
diff --git a/sg_pt_linux.c b/sg_pt_linux.c
index 4d51d7dc..ff56879b 100644
--- a/sg_pt_linux.c
+++ b/sg_pt_linux.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2006 Douglas Gilbert.
+ * Copyright (c) 2005-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
*
*/
-/* version 1.01 2006/1/9 */
+/* version 1.02 2007/1/21 */
#include <stdio.h>
#include <stdlib.h>
@@ -90,7 +90,8 @@ void * construct_scsi_pt_obj()
{
struct sg_pt_linux_scsi * ptp;
- ptp = malloc(sizeof(struct sg_pt_linux_scsi));
+ ptp = (struct sg_pt_linux_scsi *)
+ malloc(sizeof(struct sg_pt_linux_scsi));
if (ptp) {
memset(ptp, 0, sizeof(struct sg_pt_linux_scsi));
ptp->io_hdr.interface_id = 'S';
@@ -101,7 +102,7 @@ void * construct_scsi_pt_obj()
void destruct_scsi_pt_obj(void * vp)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
if (ptp)
free(ptp);
@@ -109,7 +110,7 @@ void destruct_scsi_pt_obj(void * vp)
void set_scsi_pt_cdb(void * vp, const unsigned char * cdb, int cdb_len)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
if (ptp->io_hdr.cmdp)
++ptp->in_err;
@@ -120,7 +121,7 @@ void set_scsi_pt_cdb(void * vp, const unsigned char * cdb, int cdb_len)
void set_scsi_pt_sense(void * vp, unsigned char * sense,
int max_sense_len)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
if (ptp->io_hdr.sbp)
++ptp->in_err;
@@ -132,7 +133,7 @@ void set_scsi_pt_sense(void * vp, unsigned char * sense,
void set_scsi_pt_data_in(void * vp, /* from device */
unsigned char * dxferp, int dxfer_len)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
if (ptp->io_hdr.dxferp)
++ptp->in_err;
@@ -146,7 +147,7 @@ void set_scsi_pt_data_in(void * vp, /* from device */
void set_scsi_pt_data_out(void * vp, /* to device */
const unsigned char * dxferp, int dxfer_len)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
if (ptp->io_hdr.dxferp)
++ptp->in_err;
@@ -159,14 +160,14 @@ void set_scsi_pt_data_out(void * vp, /* to device */
void set_scsi_pt_packet_id(void * vp, int pack_id)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
ptp->io_hdr.pack_id = pack_id;
}
void set_scsi_pt_tag(void * vp, int tag)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
++ptp->in_err;
tag = tag; /* dummy to silence compiler */
@@ -174,7 +175,7 @@ void set_scsi_pt_tag(void * vp, int tag)
void set_scsi_pt_task_management(void * vp, int tmf_code)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
++ptp->in_err;
tmf_code = tmf_code; /* dummy to silence compiler */
@@ -182,7 +183,7 @@ void set_scsi_pt_task_management(void * vp, int tmf_code)
void set_scsi_pt_task_attr(void * vp, int attribute, int priority)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
++ptp->in_err;
attribute = attribute; /* dummy to silence compiler */
@@ -191,7 +192,7 @@ void set_scsi_pt_task_attr(void * vp, int attribute, int priority)
int do_scsi_pt(void * vp, int fd, int time_secs, int verbose)
{
- struct sg_pt_linux_scsi * ptp = vp;
+ struct sg_pt_linux_scsi * ptp = (struct sg_pt_linux_scsi *)vp;
if (NULL == sg_warnings_strm)
sg_warnings_strm = stderr;
@@ -242,7 +243,7 @@ int do_scsi_pt(void * vp, int fd, int time_secs, int verbose)
int get_scsi_pt_result_category(const void * vp)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK;
int scsi_st = ptp->io_hdr.status & 0x7e;
@@ -264,42 +265,42 @@ int get_scsi_pt_result_category(const void * vp)
int get_scsi_pt_resid(const void * vp)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
return ptp->io_hdr.resid;
}
int get_scsi_pt_status_response(const void * vp)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
return ptp->io_hdr.status;
}
int get_scsi_pt_sense_len(const void * vp)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
return ptp->io_hdr.sb_len_wr;
}
int get_scsi_pt_duration_ms(const void * vp)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
return ptp->io_hdr.duration;
}
int get_scsi_pt_transport_err(const void * vp)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
return (ptp->io_hdr.host_status << 8) + ptp->io_hdr.driver_status;
}
int get_scsi_pt_os_err(const void * vp)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
return ptp->os_err;
}
@@ -335,7 +336,7 @@ static const char * linux_driver_suggests[] = {
char * get_scsi_pt_transport_err_str(const void * vp, int max_b_len, char * b)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
int ds = ptp->io_hdr.driver_status;
int hs = ptp->io_hdr.host_status;
int n, m;
@@ -376,7 +377,7 @@ char * get_scsi_pt_transport_err_str(const void * vp, int max_b_len, char * b)
char * get_scsi_pt_os_err_str(const void * vp,
int max_b_len, char * b)
{
- const struct sg_pt_linux_scsi * ptp = vp;
+ const struct sg_pt_linux_scsi * ptp = (const struct sg_pt_linux_scsi *)vp;
const char * cp;
cp = safe_strerror(ptp->os_err);
diff --git a/sg_pt_win32.c b/sg_pt_win32.c
index 552fea3c..7434b9c3 100644
--- a/sg_pt_win32.c
+++ b/sg_pt_win32.c
@@ -27,10 +27,11 @@
*
*/
-/* version 1.00 2006/10/6 */
+/* version 1.01 2006/11/19 */
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
diff --git a/sg_rbuf.8 b/sg_rbuf.8
index 4ef56999..6813ad68 100644
--- a/sg_rbuf.8
+++ b/sg_rbuf.8
@@ -1,83 +1,101 @@
-.TH SG_RBUF "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_RBUF "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_rbuf \- reads data using SCSI READ BUFFER command
.SH SYNOPSIS
.B sg_rbuf
-[\fI-b=<num_KiB>\fR] [\fI-d\fR] [\fI-m\fR] [\fI-q\fR]
-[\fI-s=<num_MiB>\fR] [\fI-t\fR] [\fI-v\fR] [\fI-V\fR] \fI<scsi_device>\fR
+[\fI\-\-buffer=EACH\fR] [\fI\-\-dio\fR] [\fI\-\-help\fR] [\fI\-\-mmap\fR]
+[\fI\-\-quick\fR] [\fI\-\-size=OVERALL\fR] [\fI\-\-test\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.PP
+.B sg_rbuf
+[\fI\-b=EACH_KIB\fR] [\fI\-d\fR] [\fI\-m\fR] [\fI\-q\fR]
+[\fI\-s=OVERALL_MIB\fR] [\fI\-t\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-This command reads data with the SCSI READ BUFFER command
-and then discards it. Typically the data being read is from
-a disk's memory cache. It is assumed that the data
-is sourced quickly (although this is not guaranteed by the SCSI
-standards) so that it is faster than reading data from the
-media. This command is designed for timing transfer speeds
-across a SCSI transport.
-.TP
--b=<num_KiB>
-size of each transfer (in Kilobytes == 1024). The default is
-the actual available buffer size returned by the READ
-BUFFER (descriptor) command. The maximum is the same as the
-default, hence this argument can only be used to reduce the size
-of each transfer to less than the device's actual available buffer
-size.
-.TP
--d
-use direct IO if available. This option is only available if
-the given device is a sg driver device node (e.g. /dev/sg1).
-In this case the sg driver will attempt
-to configure the DMA from the SCSI adapter to transfer directly
-into user memory. This will eliminate the copy via kernel buffers.
-If not available then this will be reported and indirect IO will
-be done instead.
-.TP
--m
-use memory mapped IO if available. This option is only available if
-the given device is a sg driver device node (e.g. /dev/sg1).
-In this case the sg driver will attempt
-to configure the DMA from the SCSI adapter to transfer directly
-into user memory. This will eliminate the copy via kernel buffers.
-.TP
--q
-only transfer the data into kernel buffers (typically by DMA from
-the SCSI adapter card) and do not move it into the user space.
-This option is only available if the given device is a sg driver
-device node (e.g. /dev/sg1).
+This command reads data with the SCSI READ BUFFER command and then discards
+it. Typically the data being read is from a disk's memory cache. It is
+assumed that the data is sourced quickly (although this is not guaranteed
+by the SCSI standards) so that it is faster than reading data from the media.
+This command is designed for timing transfer speeds across a SCSI transport.
+.PP
+To fetch the data with a SCSI READ BUFFER command and optionally decode it
+see the sg_read_buffer utility. There is also a sg_write_buffer utility
+useful for downloading firmware amongst other things.
+.PP
+This utility supports two command line syntaxes, the preferred one is
+shown first in the synopsis and explained in this section. A later section
+on the old command line syntax outlines the second group of options.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-b\fR, \fB\-\-buffer\fR=\fIEACH\fR
+where \fIEACH\fR is the number of bytes to be transferred by each READ
+BUFFER command. The default is the actual available buffer size returned
+by the READ BUFFER (descriptor) command. The maximum is
+the same as the default, hence this argument can only be used to reduce the
+size of each transfer to less than the device's actual available buffer size.
.TP
--s=<num_MiB>
-size of total transfer (in Megabytes == 1024^2). The default is
-200 MiB, the maximum is 4095 MiB. The actual number of bytes
-transferred may be slightly less since all transfers are the
-same size (and an integer division is involved rounding towards zero).
+\fB\-d\fR, \fB\-\-dio\fR
+use direct IO if available. This option is only available if the \fIDEVICE\fR
+is a sg driver device node (e.g. /dev/sg1). In this case the sg driver will
+attempt to configure the DMA from the SCSI adapter to transfer directly into
+user memory. This will eliminate the copy via kernel buffers. If not
+available then this will be reported and indirect IO will be done instead.
.TP
--t
+\fB\-h\fR, \fB\-\-help\fR
+print usage message then exit.
+.TP
+\fB\-m\fR, \fB\-\-mmap\fR
+use memory mapped IO if available. This option is only available if the
+\fIDEVICE\fR is a sg driver device node (e.g. /dev/sg1). In this case the
+sg driver will attempt to configure the DMA from the SCSI adapter to transfer
+directly into user memory. This will eliminate the copy via kernel buffers.
+.TP
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
+.TP
+\fB\-q\fR, \fB\-\-quick\fR
+only transfer the data into kernel buffers (typically by DMA from the SCSI
+adapter card) and do not move it into the user space. This option is only
+available if the \fIDEVICE\fR is a sg driver device node (e.g. /dev/sg1).
+.TP
+\fB\-s\fR, \fB\-\-size\fR=\fIOVERALL\fR
+where \fIOVERALL\fR is the size of total transfer in bytes. The default is
+200 MiB (200*1024*1024 bytes). The actual number of bytes transferred may
+be slightly less than requested since all transfers are the same size (and
+an integer division is involved rounding towards zero).
+.TP
+\fB\-t\fR, \fB\-\-time\fR
times the bulk data transfer component of this command. The elapsed time
is printed out plus a MB/sec calculation. In this case "MB" is 1,000,000
bytes. The gettimeofday() system call is used internally for the time
calculation.
.TP
--v
-increase level of verbosity (print out SCSI command bytes before
-executing it). '-vv' and '-vvv' are also accepted yielding greater
-verbosity.
+\fB\-v\fR, \fB\-\-verbose\fR
+increase level of verbosity. Can be used multiple times.
.TP
--V
+\fB\-V\fR, \fB\-\-version\fR
print out version string then exit.
-.PP
-This command is typically used on modern SCSI disks which have
-a RAM cache on their drive electronics. If no IO to the magnetic
-media, or slower devices like flash RAM, is involved then
-the disk may be able to source data fast enough to saturate
-the bandwidth of the SCSI transport. The bottleneck may then be
-the DMA element in the HBA, the Linux drivers or the host machine's
+.SH NOTES
+This command is typically used on modern SCSI disks which have a RAM cache
+in their drive electronics. If no IO to the magnetic media, or slower devices
+like flash RAM, is involved then the disk may be able to source data fast
+enough to saturate the bandwidth of the SCSI transport. The bottleneck may
+then be the DMA element in the HBA, the Linux drivers or the host machine's
hardware (e.g. speed of RAM).
+.PP
+\fIEACH\fR and \fIOVERALL\fR may include one of these multiplicative suffixes:
+c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
+MB *1,000,000 . This pattern continues for "G", "T" and "P". The latter two
+suffixes can only be used for \fIOVERALL\fR.
+Also a suffix of the form "x<n>" multiplies the leading number by <n>.
+These multiplicative suffixes are compatible with GNU's dd command (since
+2002) which claims compliance with SI and with IEC 60027\-2.
.SH EXAMPLES
.PP
-On the test system /dev/sg0 corresponds to a fast disk
-on a U2W SCSI bus (max 80 MB/sec). The disk specifications
-state that its cache is 4 MB.
+On the test system /dev/sg0 corresponds to a fast disk on a U2W SCSI
+bus (max 80 MB/sec). The disk specifications state that its cache is 4 MB.
.br
$ time ./sg_rbuf /dev/sg0
.br
@@ -92,10 +110,10 @@ Read 200 MiB (actual 199 MiB, 209531584 bytes),
real 0m5.072s, user 0m0.000s, sys 0m2.280s
.PP
So that is approximately 40 MB/sec at 40 % utilization. Now with
-the addition of the "-q" option this throughput improves and the
+the addition of the "\-q" option this throughput improves and the
utilization drops to 0%.
.br
- $ time ./sg_rbuf -q /dev/sg0
+ $ time ./sg_rbuf \-q /dev/sg0
.br
READ BUFFER reports: buffer capacity=3434944,
.br
@@ -109,14 +127,56 @@ real 0m2.784s, user 0m0.000s, sys 0m0.000s
.SH EXIT STATUS
The exit status of sg_rbuf is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using '\-\-old' (or '\-O) as the first option.
+.TP
+\fB\-b\fR=\fIEACH_KIB\fR
+where \fIEACH_KIB\fR is the number of Kilobytes (i.e. 1024 byte units) to be
+transferred by each READ BUFFER command. Similar to the
+\fI\-\-buffer=EACH\fR option in the main description but the units are
+different.
+.TP
+\fB\-d\fR
+use direct IO if available. Equivalent to the \fI\-\-dio\fR option in the
+main description.
+.TP
+\fB\-m\fR
+use memory mapped IO if available. Equivalent to the \fI\-\-mmap\fR option
+in the main description.
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-q\fR
+only transfer the data into kernel buffers (typically by DMA from
+the SCSI adapter card) and do not move it into the user space.
+Equivalent to the \fI\-\-quick\fR option in the main description.
+.TP
+\fB\-s\fR=\fIOVERALL_MIB\fR
+where \fIOVERALL_MIB\fR is the size of total transfer in Megabytes (1048576
+bytes). Similar to the \fI\-\-size=OVERALL\fR option in the main description
+but the units are different.
+.TP
+\fB\-t\fR
+times the bulk data transfer component of this command. Equivalent to
+the \fI\-\-time\fR option in the main description.
+.TP
+\fB\-v\fR
+increase level of verbosity. Can be used multiple times.
+.TP
+\fB\-V\fR
+print out version string then exit.
.SH AUTHOR
Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000-2006 Douglas Gilbert
+Copyright \(co 2000\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B sg_test_rwbuf(sg3_utils)
+.B sg_read_buffer, sg_write_buffer, sg_test_rwbuf(all in sg3_utils)
diff --git a/sg_rbuf.c b/sg_rbuf.c
index 24fa4a9b..f4a71499 100644
--- a/sg_rbuf.c
+++ b/sg_rbuf.c
@@ -1,5 +1,7 @@
#define _XOPEN_SOURCE 500
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <unistd.h>
#include <signal.h>
@@ -8,6 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -18,7 +21,7 @@
/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg")
device driver.
-* Copyright (C) 1999-2006 D. Gilbert
+* Copyright (C) 1999-2007 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)
@@ -33,7 +36,7 @@
#define RB_MODE_DESC 3
#define RB_MODE_DATA 2
#define RB_DESC_LEN 4
-#define RB_MIB_TO_READ 200
+#define RB_DEF_SIZE (200*1024*1024)
#define RB_OPCODE 0x3C
#define RB_CMD_LEN 10
@@ -43,21 +46,71 @@
#define SG_FLAG_MMAP_IO 4
#endif
-#define ME "sg_rbuf: "
-static char * version_str = "4.85 20061003";
+static char * version_str = "4.87 20070129";
+
+static struct option long_options[] = {
+ {"buffer", 1, 0, 'b'},
+ {"dio", 0, 0, 'd'},
+ {"help", 0, 0, 'h'},
+ {"mmap", 0, 0, 'm'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"quick", 0, 0, 'q'},
+ {"size", 1, 0, 's'},
+ {"time", 0, 0, 't'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+struct opts_t {
+ int do_buffer;
+ int do_dio;
+ int do_help;
+ int do_mmap;
+ int do_quick;
+ long long do_size;
+ int do_time;
+ int do_verbose;
+ int do_version;
+ const char * device_name;
+ int opt_new;
+};
static void usage()
{
- printf("Usage: sg_rbuf [-b=num] [-d] [-m] [-q] [-s=num] [-t] "
- "[-v] [-V]\n <scsi_device>\n");
+ fprintf(stderr, "Usage: sg_rbuf [--buffer=EACH] [--dio] [--help] "
+ "[--mmap] [--quick]\n"
+ " [--size=OVERALL] [--time] [--verbose] "
+ "[--version] DEVICE\n");
+ fprintf(stderr, " where:\n"
+ " --buffer=EACH|-b EACH buffer size to use (in bytes)\n"
+ " --dio|-d requests dio ('-q' overrides it)\n"
+ " --help|-h print usage message then exit\n"
+ " --mmap|-m requests mmap-ed IO (overrides -q, -d)\n"
+ " --quick|-q quick, don't xfer to user space\n");
+ fprintf(stderr,
+ " --size=OVERALL|-s OVERALL total size to read (in bytes)\n"
+ " default: 200 MiB\n"
+ " --time|-t time the data transfer\n"
+ " --verbose|-v increase verbosity (more debug)\n"
+ " --version|-V print version string then exit\n\n"
+ "Use SCSI READ BUFFER command (data mode, buffer id 0) "
+ "repeatedly\n");
+}
+
+static void usage_old()
+{
+ printf("Usage: sg_rbuf [-b=EACH_KIB] [-d] [-m] [-q] [-s=OVERALL_MIB] "
+ "[-t] [-v] [-V]\n DEVICE\n");
printf(" where:\n");
- printf(" -b=num num is buffer size to use (in KiB)\n");
+ printf(" -b=EACH_KIB num is buffer size to use (in KiB)\n");
printf(" -d requests dio ('-q' overrides it)\n");
printf(" -m requests mmap-ed IO (overrides -q, -d)\n");
printf(" -q quick, don't xfer to user space\n");
- printf(" -s=num num is total size to read (in MiB) (default: "
- "200 MiB)\n");
+ printf(" -s=OVERALL_MIB num is total size to read (in MiB) "
+ "(default: 200 MiB)\n");
printf(" maximum total size is 4000 MiB\n");
printf(" -t time the data transfer\n");
printf(" -v increase verbosity (more debug)\n");
@@ -66,34 +119,105 @@ static void usage()
"repeatedly\n");
}
-int main(int argc, char * argv[])
+static void usage_for(const struct opts_t * optsp)
{
- int sg_fd, res, j, m, plen, jmp_out;
- unsigned int k, num;
- unsigned char rbCmdBlk [RB_CMD_LEN];
- unsigned char * rbBuff = NULL;
- void * rawp = NULL;
- unsigned char sense_buffer[32];
- int buf_capacity = 0;
- int do_quick = 0;
- int do_dio = 0;
- int do_mmap = 0;
- int do_time = 0;
- int verbose = 0;
- int buf_size = 0;
- unsigned int total_size_mib = RB_MIB_TO_READ;
- const char * file_name = 0;
+ if (optsp->opt_new)
+ usage();
+ else
+ usage_old();
+}
+
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c, n;
+ long long nn;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "b:dhmNOqs:tvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'b':
+ n = sg_get_num(optarg);
+ if (n < 0) {
+ fprintf(stderr, "bad argument to '--buffer'\n");
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_buffer = n;
+ break;
+ case 'd':
+ ++optsp->do_dio;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'm':
+ ++optsp->do_mmap;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'q':
+ ++optsp->do_quick;
+ break;
+ case 's':
+ nn = sg_get_llnum(optarg);
+ if (nn < 0) {
+ fprintf(stderr, "bad argument to '--size'\n");
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_size = nn;
+ break;
+ case 't':
+ ++optsp->do_time;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage_for(optsp);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
+{
+ int k, jmp_out, plen, num;
+ long long nn;
const char * cp;
- size_t psz = getpagesize();
- int dio_incomplete = 0;
- struct sg_io_hdr io_hdr;
- struct timeval start_tm, end_tm;
-#ifdef SG_DEBUG
- int clear = 1;
-#endif
- for (j = 1; j < argc; ++j) {
- cp = argv[j];
+ for (k = 1; k < argc; ++k) {
+ cp = argv[k];
plen = strlen(cp);
if (plen <= 0)
continue;
@@ -101,26 +225,32 @@ int main(int argc, char * argv[])
for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
switch (*cp) {
case 'd':
- do_dio = 1;
+ ++optsp->do_dio;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
break;
case 'm':
- do_mmap = 1;
+ ++optsp->do_mmap;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
break;
case 'q':
- do_quick = 1;
+ ++optsp->do_quick;
break;
case 't':
- do_time = 1;
+ ++optsp->do_time;
break;
case 'v':
- ++verbose;
+ ++optsp->do_verbose;
break;
case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
- case '?':
- usage();
- return 0;
+ ++optsp->do_version;
+ break;
default:
jmp_out = 1;
break;
@@ -131,58 +261,122 @@ int main(int argc, char * argv[])
if (plen <= 0)
continue;
if (0 == strncmp("b=", cp, 2)) {
- m = 2;
- num = sscanf(cp + m, "%d", &buf_size);
- if ((1 != num) || (buf_size <= 0)) {
+ num = sscanf(cp + 2, "%d", &optsp->do_buffer);
+ if ((1 != num) || (optsp->do_buffer <= 0)) {
printf("Couldn't decode number after 'b=' option\n");
- usage();
+ usage_for(optsp);
return SG_LIB_SYNTAX_ERROR;
}
- buf_size *= 1024;
+ optsp->do_buffer *= 1024;
}
else if (0 == strncmp("s=", cp, 2)) {
- m = 2;
- num = sscanf(cp + m, "%u", &total_size_mib);
- if (1 != num) {
+ nn = sg_get_llnum(optarg);
+ if (nn < 0) {
printf("Couldn't decode number after 's=' option\n");
- usage();
+ usage_for(optsp);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (jmp_out) {
+ optsp->do_size = nn;
+ optsp->do_size *= 1024 * 1024;
+ } else if (0 == strncmp("-old", cp, 4))
+ ;
+ else if (jmp_out) {
fprintf(stderr, "Unrecognized option: %s\n", cp);
- usage();
+ usage_for(optsp);
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == file_name)
- file_name = cp;
+ } else if (0 == optsp->device_name)
+ optsp->device_name = cp;
else {
fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
- usage();
+ "%s\n", optsp->device_name, cp);
+ usage_for(optsp);
return SG_LIB_SYNTAX_ERROR;
}
}
- if (0 == file_name) {
- fprintf(stderr, "No <scsi_device> argument given\n");
- usage();
+ return 0;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
+
+
+int main(int argc, char * argv[])
+{
+ int sg_fd, res, j;
+ unsigned int k, num;
+ unsigned char rbCmdBlk [RB_CMD_LEN];
+ unsigned char * rbBuff = NULL;
+ void * rawp = NULL;
+ unsigned char sense_buffer[32];
+ int buf_capacity = 0;
+ int buf_size = 0;
+ long long total_size = RB_DEF_SIZE;
+ size_t psz = getpagesize();
+ int dio_incomplete = 0;
+ struct sg_io_hdr io_hdr;
+ struct timeval start_tm, end_tm;
+#ifdef SG_DEBUG
+ int clear = 1;
+#endif
+ struct opts_t opts;
+
+ memset(&opts, 0, sizeof(opts));
+ res = process_cl(&opts, argc, argv);
+ if (res)
return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ usage_for(&opts);
+ return 0;
}
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
+ }
+
+ if (NULL == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ usage_for(&opts);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ if (opts.do_buffer > 0)
+ buf_size = opts.do_buffer;
+ if (opts.do_size > 0)
+ total_size = opts.do_size;
- sg_fd = open(file_name, O_RDONLY | O_NONBLOCK);
+ sg_fd = open(opts.device_name, O_RDONLY | O_NONBLOCK);
if (sg_fd < 0) {
- perror(ME "open error");
+ perror("device open error");
return SG_LIB_FILE_ERROR;
}
/* Don't worry, being very careful not to write to a none-sg file ... */
- if (do_mmap) {
- do_dio = 0;
- do_quick = 0;
+ if (opts.do_mmap) {
+ opts.do_dio = 0;
+ opts.do_quick = 0;
}
if (NULL == (rawp = malloc(512))) {
- printf(ME "out of memory (query)\n");
+ printf("out of memory (query)\n");
return SG_LIB_CAT_OTHER;
}
- rbBuff = rawp;
+ rbBuff = (unsigned char *)rawp;
memset(rbCmdBlk, 0, RB_CMD_LEN);
rbCmdBlk[0] = RB_OPCODE;
@@ -198,7 +392,7 @@ int main(int argc, char * argv[])
io_hdr.cmdp = rbCmdBlk;
io_hdr.sbp = sense_buffer;
io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */
- if (verbose) {
+ if (opts.do_verbose) {
fprintf(stderr, " Read buffer cdb: ");
for (k = 0; k < RB_CMD_LEN; ++k)
fprintf(stderr, "%02x ", rbCmdBlk[k]);
@@ -207,24 +401,25 @@ int main(int argc, char * argv[])
/* do normal IO to find RB size (not dio or mmap-ed at this stage) */
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror(ME "SG_IO READ BUFFER descriptor error");
+ perror("SG_IO READ BUFFER descriptor error");
if (rawp) free(rawp);
return SG_LIB_CAT_OTHER;
}
- if (verbose > 2)
+ if (opts.do_verbose > 2)
fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
/* now for the error processing */
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
sg_chk_n_print3("READ BUFFER descriptor, continuing", &io_hdr,
- verbose > 1);
+ opts.do_verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
break;
default: /* won't bother decoding other categories */
- sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr, verbose > 1);
+ sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr,
+ opts.do_verbose > 1);
if (rawp) free(rawp);
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
}
@@ -246,43 +441,48 @@ int main(int argc, char * argv[])
rawp = NULL;
}
- if (! do_dio) {
+ if (! opts.do_dio) {
k = buf_size;
- if (do_mmap && (0 != (k % psz)))
+ if (opts.do_mmap && (0 != (k % psz)))
k = ((k / psz) + 1) * psz; /* round up to page size */
res = ioctl(sg_fd, SG_SET_RESERVED_SIZE, &k);
if (res < 0)
- perror(ME "SG_SET_RESERVED_SIZE error");
+ perror("SG_SET_RESERVED_SIZE error");
}
- if (do_mmap) {
- rbBuff = mmap(NULL, buf_size, PROT_READ, MAP_SHARED, sg_fd, 0);
+ if (opts.do_mmap) {
+ rbBuff = (unsigned char *)mmap(NULL, buf_size, PROT_READ, MAP_SHARED,
+ sg_fd, 0);
if (MAP_FAILED == rbBuff) {
- if (ENOMEM == errno)
- printf(ME "mmap() out of memory, try a smaller "
- "buffer size than %d KiB\n"
- " [with '-b=<n>' where <n> is in KB]\n",
- buf_size / 1024);
- else
- perror(ME "error using mmap()");
+ if (ENOMEM == errno) {
+ fprintf(stderr, "mmap() out of memory, try a smaller "
+ "buffer size than %d bytes\n", buf_size);
+ if (opts.opt_new)
+ fprintf(stderr, " [with '--buffer=EACH' where EACH "
+ "is in bytes]\n");
+ else
+ fprintf(stderr, " [with '-b=EACH' where EACH is in "
+ "KiB]\n");
+ } else
+ perror("error using mmap()");
return SG_LIB_CAT_OTHER;
}
}
else { /* non mmap-ed IO */
- rawp = malloc(buf_size + (do_dio ? psz : 0));
+ rawp = (unsigned char *)malloc(buf_size + (opts.do_dio ? psz : 0));
if (NULL == rawp) {
- printf(ME "out of memory (data)\n");
+ printf("out of memory (data)\n");
return SG_LIB_CAT_OTHER;
}
- if (do_dio) /* align to page boundary */
+ if (opts.do_dio) /* align to page boundary */
rbBuff= (unsigned char *)(((unsigned long)rawp + psz - 1) &
(~(psz - 1)));
else
- rbBuff = rawp;
+ rbBuff = (unsigned char *)rawp;
}
- num = (total_size_mib * 1024U * 1024U) / (unsigned int)buf_size;
- if (do_time) {
+ num = total_size / buf_size;
+ if (opts.do_time) {
start_tm.tv_sec = 0;
start_tm.tv_usec = 0;
gettimeofday(&start_tm, NULL);
@@ -305,19 +505,19 @@ int main(int argc, char * argv[])
io_hdr.mx_sb_len = sizeof(sense_buffer);
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.dxfer_len = buf_size;
- if (! do_mmap)
+ if (! opts.do_mmap)
io_hdr.dxferp = rbBuff;
io_hdr.cmdp = rbCmdBlk;
io_hdr.sbp = sense_buffer;
io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
io_hdr.pack_id = k;
- if (do_mmap)
+ if (opts.do_mmap)
io_hdr.flags |= SG_FLAG_MMAP_IO;
- else if (do_dio)
+ else if (opts.do_dio)
io_hdr.flags |= SG_FLAG_DIRECT_IO;
- else if (do_quick)
+ else if (opts.do_quick)
io_hdr.flags |= SG_FLAG_NO_DXFER;
- if (verbose > 1) {
+ if (opts.do_verbose > 1) {
fprintf(stderr, " Read buffer cdb: ");
for (j = 0; j < RB_CMD_LEN; ++j)
fprintf(stderr, "%02x ", rbCmdBlk[j]);
@@ -325,18 +525,22 @@ int main(int argc, char * argv[])
}
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- if (ENOMEM == errno)
- printf(ME "SG_IO data; out of memory, try a smaller "
- "buffer size than %d KiB\n"
- " [with '-b=<n>' where <n> is in KB]\n",
- buf_size / 1024);
- else
- perror(ME "SG_IO READ BUFFER data error");
+ if (ENOMEM == errno) {
+ fprintf(stderr, "SG_IO data: out of memory, try a smaller "
+ "buffer size than %d bytes\n", buf_size);
+ if (opts.opt_new)
+ fprintf(stderr, " [with '--buffer=EACH' where EACH "
+ "is in bytes]\n");
+ else
+ fprintf(stderr, " [with '-b=EACH' where EACH is in "
+ "KiB]\n");
+ } else
+ perror("SG_IO READ BUFFER data error");
if (rawp) free(rawp);
return SG_LIB_CAT_OTHER;
}
- if (verbose > 2)
+ if (opts.do_verbose > 2)
fprintf(stderr, " duration=%u ms\n",
io_hdr.duration);
/* now for the error processing */
@@ -346,14 +550,15 @@ int main(int argc, char * argv[])
break;
case SG_LIB_CAT_RECOVERED:
sg_chk_n_print3("READ BUFFER data, continuing", &io_hdr,
- verbose > 1);
+ opts.do_verbose > 1);
break;
default: /* won't bother decoding other categories */
- sg_chk_n_print3("READ BUFFER data error", &io_hdr, verbose > 1);
+ sg_chk_n_print3("READ BUFFER data error", &io_hdr,
+ opts.do_verbose > 1);
if (rawp) free(rawp);
return (res >= 0) ? res : SG_LIB_CAT_OTHER;
}
- if (do_dio &&
+ if (opts.do_dio &&
((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
dio_incomplete = 1; /* flag that dio not done (completely) */
@@ -368,7 +573,7 @@ int main(int argc, char * argv[])
}
#endif
}
- if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
+ if ((opts.do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
struct timeval res_tm;
double a, b;
@@ -391,14 +596,14 @@ int main(int argc, char * argv[])
}
if (dio_incomplete)
printf(">> direct IO requested but not done\n");
- printf("Read %u MiB (actual %u MiB, %u bytes), buffer size=%d KiB\n",
- total_size_mib, (num * buf_size) / 1048576, num * buf_size,
- buf_size / 1024);
+ printf("Read %lld MiB (actual: %lld bytes), buffer size=%d KiB "
+ "(%d bytes)\n", (total_size / (1024 * 1024)),
+ (long long)num * buf_size, buf_size / 1024, buf_size);
if (rawp) free(rawp);
res = close(sg_fd);
if (res < 0) {
- perror(ME "close error");
+ perror("close error");
return SG_LIB_FILE_ERROR;
}
#ifdef SG_DEBUG
diff --git a/sg_rdac.8 b/sg_rdac.8
index 3a39522b..42c456a6 100644
--- a/sg_rdac.8
+++ b/sg_rdac.8
@@ -1,9 +1,9 @@
-.TH SG_RDAC "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_RDAC "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_rdac \- Display or Modify RDAC Redundant Controller Page
.SH SYNOPSIS
.B sg_rdac
-[\fI-a\fR] [\fI-f=<lun>\fR] [\fI-v\fR] [\fI-V\fR] \fI<sg_device>\fR
+[\fI\-a\fR] [\fI\-f=LUN\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -11,18 +11,19 @@ sg_rdac displays or modifies the RDAC controller settings via the
Redundant Controller Page (0x2C). When modifying the settings it
allows to transfer the ownership of individual drives to the
controller the command was received on.
+.SH OPTIONS
.TP
--a
+\fB\-a\fR
Transfer all (visible) devices
.TP
--f=<lun>
-Transfer the device with LUN <lun>. This command will only work if
-the controller supports 'Dual Active Mode' (aka active/active mode).
+\fB\-f\fR=\fILUN\fR
+Transfer the device identified by \fILUN\fR. This command will only work
+if the controller supports 'Dual Active Mode' (aka active/active mode).
.TP
--v
+\fB\-v\fR
be verbose
.TP
--V
+\fB\-V\fR
print version string then exit
.SH EXIT STATUS
The exit status of sg_rdac is 0 when it is successful. Otherwise see
@@ -32,7 +33,7 @@ Written by Hannes Reinecke <hare at suse dot com>, based on sg_emc_trespass.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2006 Hannes Reinecke, Douglas Gilbert.
+Copyright \(co 2006\-2007 Hannes Reinecke, Douglas Gilbert.
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_rdac.c b/sg_rdac.c
index 90992f45..befbb511 100644
--- a/sg_rdac.c
+++ b/sg_rdac.c
@@ -3,7 +3,7 @@
*
* Retrieve / set RDAC options.
*
- * Copyright (C) 2006 Hannes Reinecke <hare@suse.de>
+ * Copyright (C) 2006-2007 Hannes Reinecke <hare@suse.de>
*
* Based on sg_modes.c and sg_emc_trespass.c; credits from there apply.
*
@@ -17,15 +17,12 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
+
#include "sg_lib.h"
#include "sg_cmds_basic.h"
-static char * version_str = "1.05 20061015";
+static char * version_str = "1.06 20070101";
unsigned char mode6_hdr[] = {
75, /* Length */
@@ -294,13 +291,14 @@ static void print_rdac_mode( unsigned char *ptr )
static void usage()
{
- printf("Usage: sg_rdac [-a] [-f=<lun>] [-v] [-V] <scsi_device>\n"
- " where -a transfer all devices to the controller\n"
- " serving <scsi_device>.\n"
- " -f=<lun> transfer the device with LUN <lun> to the\n"
- " controller serving <scsi_device>\n"
- " -v verbose\n"
- " -V print version then exit\n\n"
+ printf("Usage: sg_rdac [-a] [-f=LUN] [-v] [-V] DEVICE\n"
+ " where:\n"
+ " -a transfer all devices to the controller\n"
+ " serving DEVICE.\n"
+ " -f=LUN transfer the device at LUN to the\n"
+ " controller serving DEVICE\n"
+ " -v verbose\n"
+ " -V print version then exit\n\n"
" Display/Modify RDAC Redundant Controller Page 0x2c.\n"
" If [-a] or [-f] is not specified the current settings"
" are displayed.\n");
@@ -353,15 +351,15 @@ int main(int argc, char * argv[])
usage();
return SG_LIB_SYNTAX_ERROR;
}
-
- fd = open(file_name, O_RDWR | O_NONBLOCK);
+
+ fd = sg_cmds_open_device(file_name, 0 /* rw */, do_verbose);
if (fd < 0) {
- fprintf(stderr, "Error trying to open %s\n", file_name);
- perror("");
+ fprintf(stderr, "open error: %s: %s\n", file_name,
+ safe_strerror(-fd));
usage();
return SG_LIB_FILE_ERROR;
}
-
+
if (fail_all) {
res = fail_all_paths(fd);
} else if (fail_path) {
@@ -389,7 +387,7 @@ int main(int argc, char * argv[])
else if (res)
fprintf(stderr," mode sense failed\n");
- res = close(fd);
+ res = sg_cmds_close_device(fd);
if (res < 0) {
fprintf(stderr, "close error: %s\n", safe_strerror(-res));
if (0 == ret)
diff --git a/sg_read.8 b/sg_read.8
index bdefde55..3bba47a5 100644
--- a/sg_read.8
+++ b/sg_read.8
@@ -1,12 +1,13 @@
-.TH SG_READ "8" "July 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_READ "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_read \- read blocks of data continually from same offset
.SH SYNOPSIS
.B sg_read
-[\fIblk_sgio=0|1\fR] [\fIbpt=<n>\fR] [\fIbs=<n>\fR] [\fIcdbsz=6|10|12|16\fR]
-\fIcount=<n>\fR [\fIdio=0|1\fR] [\fIdpo=0|1\fR] [\fIfua=0|1\fR]
-\fIif=<ifile>\fR [\fImmap=0|1\fR] [\fIno_dxfer=0|1\fR] [\fIodir=0|1\fR]
-[\fIskip=<n>\fR] [\fItime=<n>\fR] [\fI--help\fR] [\fI--version\fR]
+[\fIblk_sgio=\fR0|1] [\fIbpt=BPT\fR] [\fIbs=BS\fR] [\fIcdbsz=\fR6|10|12|16]
+\fIcount=COUNT\fR [\fIdio=\fR0|1] [\fIdpo=\fR0|1] [\fIfua=\fR0|1]
+\fIif=IFILE\fR [\fImmap=\fR0|1] [\fIno_dxfer=\fR0|1] [\fIodir=\fR0|1]
+[\fIskip=SKIP\fR] [\fItime=TI\fR] [\fIverbose=VERB\fR] [\fI\-\-help\fR]
+[\fI\-\-version\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -16,92 +17,95 @@ logical block address (lba). This can be used to test (or time) disk
caching, SCSI (or some other) transport throughput, and/or SCSI
command overhead.
.PP
-When the 'count' argument is positive, then up to 'bpt' blocks are read
-at a time, until the 'count' is exhausted. Each read operation
-starts at the same lba which, if 'skip' is not given, is the beginning
-of the file or device.
+When the \fICOUNT\fR value is positive, then up to \fIBPT\fR blocks are
+read at a time, until the \fICOUNT\fR is exhausted. Each read operation
+starts at the same lba which, if \fISKIP\fR is not given, is the
+beginning of the file or device.
.PP
-The 'count' argument may be negative when '<ifile>' is a sg device
-or is a block device with 'blk_sgio=1' set. Alternatively 'bpt=0'
-may be given. In these cases |'count'| "zero block" SCSI READ commands
+The \fICOUNT\fR value may be negative when \fIIFILE\fR is a sg device
+or is a block device with 'blk_sgio=1' set. Alternatively 'bpt=0' may
+be given. In these cases |\fICOUNT\fR| "zero block" SCSI READ commands
are issued. "Zero block" means "do nothing" for SCSI READ 10, 12 and
16 byte commands (but not for the 6 byte variant). In practice "zero
block" SCSI READ commands have low latency and so are one way to measure
SCSI command overhead.
+.SH OPTIONS
.TP
-blk_sgio=0 | 1
+\fBblk_sgio\fR=0 | 1
The default action of this utility is to use the Unix read() command when
-the <ifile> is a block device. In lk 2.6 many block devices can handle
+the \fIIFILE\fR is a block device. In lk 2.6 many block devices can handle
SCSI commands issued via the SG_IO ioctl. So when this option is set
-the SG_IO ioctl sends SCSI READ commands to <ifile> if it is a block
+the SG_IO ioctl sends SCSI READ commands to \fIIFILE\fR if it is a block
device.
.TP
-bpt=BLOCKS
-each read operation will be made using this number of blocks (or less if
-near the end of 'count'). Default is 128. Note also that each read
-operation starts at the same lba (as given by 'skip=<n>' or 0). If 'bpt=0'
-then the 'count' is interpreted as the number of zero block READ SCSI
-commands to issue.
+\fBbpt\fR=\fIBPT\fR
+where \fIBPT\fR is the maximum number of blocks each read operation fetches.
+Fewer blocks will be fetched when the remaining \fICOUNT\fR is less than
+\fIBPT\fR. The default value for \fIBPT\fR is 128. Note that each read
+operation starts at the same lba (as given by \fIskip=SKIP\fR or 0).
+If 'bpt=0' then the \fICOUNT\fR is interpreted as the number of zero
+block SCSI READ commands to issue.
.TP
-bs=BYTES
-this
+\fBbs\fR=\fIBS\fR
+where \fIBS\fR is the size (in bytes) of each block read. This
.B must
be the block size of the physical device (defaults to 512) if SCSI commands
-are being issued to <ifile>.
+are being issued to \fIIFILE\fR.
.TP
-cdbsz=6 | 10 | 12 | 16
+\fBcdbsz\fR=6 | 10 | 12 | 16
size of SCSI READ commands issued on sg device names, or block devices
if 'blk_sgio=1' is given. Default is 10 byte SCSI READ cdbs.
.TP
-count=BLOCKS
-read this number of blocks when BLOCKS is a positive number. When BLOCKS is
-negative then |BLOCKS| SCSI READ commands are performed requesting zero blocks
-to be transferred. The 'count=' argument must be given.
+\fBcount\fR=\fICOUNT\fR
+when \fICOUNT\fR is a positive number, read that number of blocks,
+typically with multiple read operations. When \fICOUNT\fR is negative then
+|\fICOUNT\fR| SCSI READ commands are performed requesting zero blocks
+to be transferred. This option is mandatory.
.TP
-dio=0 | 1
+\fBdio\fR=0 | 1
default is 0 which selects indirect IO. Value of 1 attempts direct
IO which, if not available, falls back to indirect IO and notes this
-at completion. This option is only active if <ifile> is an sg device.
+at completion. This option is only active if \fIIFILE\fR is an sg device.
If direct IO is selected and /proc/scsi/sg/allow_dio
has the value of 0 then a warning is issued (and indirect IO is performed)
.TP
-dpo=0 | 1
+\fBdpo\fR=0 | 1
when set the disable page out (DPO) bit in SCSI READ commands is set.
Otherwise the DPO bit is cleared (default).
.TP
-fua=0 | 1
+\fBfua\fR=0 | 1
when set the force unit access (FUA) bit in SCSI READ commands is set.
Otherwise the FUA bit is cleared (default).
.TP
-if=<ifile>
-read from this <ifile>. This argument must be given. If the <ifile> is a
-normal file then it must be seekable (if ('count' > 'bpt') or 'skip' is
-given). Hence stdin is not acceptable (and giving "-" as the <ifile>
-argument is reported as an error).
+\fBif\fR=\fIIFILE\fR
+read from this \fIIFILE\fR. This argument must be given. If the \fIIFILE\fR
+is a normal file then it must be seekable (if (\fICOUNT\fR > \fIBPT\fR) or
+\fIskip=SKIP\fR is given). Hence stdin is not acceptable (and giving "\-"
+as the \fIIFILE\fR argument is reported as an error).
.TP
-mmap= 0 | 1
+\fBmmap\fR=0 | 1
default is 0 which selects indirect IO. Value of 1 causes memory mapped
IO to be performed. Selecting both dio and mmap is an error. This option
-is only active if <ifile> is an sg device.
+is only active if \fIIFILE\fR is an sg device.
.TP
-no_dxfer= 0 | 1
+\fBno_dxfer\fR=0 | 1
when set then DMA transfers from the device are made into kernel buffers
but no further (i.e. there is no second copy into the user space). The
default value is 0 in which case transfers are made into the user space.
When neither mmap nor dio is set then data transfer are copied via
kernel buffers (i.e. a double copy). Mainly for testing.
.TP
-odir= 0 | 1
-when set opens an <ifile> which is a block device with an additional
+\fBodir\fR=0 | 1
+when set opens an \fIIFILE\fR which is a block device with an additional
O_DIRECT flag. The default value is 0 (i.e. don't open block devices
O_DIRECT).
.TP
-skip=BLOCKS
-all read operations will start offset by BLOCKS bs-sized blocks
-from the start of input file (or device).
+\fBskip\fR=\fISKIP\fR
+all read operations will start offset by \fISKIP\fR bs\-sized blocks
+from the start of the input file (or device).
.TP
-time=<n>
-When 0 (default) doesn't perform timing.
+\fBtime\fR=\fITI\fR
+When \fITI\fR is 0 (default) doesn't perform timing.
When 1, times transfer and does throughput calculation, starting at the
first issued command until completion. When 2, times transfer and does
throughput calculation, starting at the second issued command until
@@ -109,18 +113,23 @@ completion. When 3 times from third command, etc. An average number of
commands (SCSI READs or Unix read()s) executed per second is also
output.
.TP
---help
+\fBverbose\fR=\fIVERB\fR
+as \fIVERB\fR increases so does the amount of debug output sent to stderr.
+Default value is zero which yields the minimum amount of debug output.
+A value of 1 reports extra information that is not repetitive.
+.TP
+\fB\-\-help\fR
Output the usage message then exit.
.TP
---version
+\fB\-\-version\fR
Output the version string then exit.
-.PP
+.SH NOTES
BYTES and BLOCKS may be followed by one of these multiplicative suffixes:
c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
MB *1,000,000; g G Gib *(2**30); GB *(10**9). Also a suffix of
the form "x<n>" multiplies the leading number by <n>. These multiplicative
suffixes are compatible with GNU's dd command (since 2002) which claims
-compliance with SI and with IEC 60027-2.
+compliance with SI and with IEC 60027\-2.
.PP
Alternatively numerical values can be given in hexadecimal preceded by
either "0x" or "0X" (or with a trailing "h" or "H"). When hex numbers are
@@ -169,7 +178,7 @@ Written by Doug Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000-2006 Douglas Gilbert
+Copyright \(co 2000\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_read.c b/sg_read.c
index 84346570..4702bc87 100644
--- a/sg_read.c
+++ b/sg_read.c
@@ -1,5 +1,7 @@
#define _XOPEN_SOURCE 500
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -18,10 +20,9 @@
#include <linux/major.h>
#include "sg_lib.h"
#include "sg_io_linux.h"
-#include "llseek.h"
/* A utility program for the Linux OS SCSI generic ("sg") device driver.
-* Copyright (C) 2001 - 2006 D. Gilbert
+* Copyright (C) 2001 - 2007 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)
@@ -40,7 +41,7 @@
*/
-static const char * version_str = "1.14 20061015";
+static const char * version_str = "1.17 20070121";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -148,28 +149,28 @@ static int dd_filetype(const char * filename)
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_read [blk_sgio=0|1] [bpt=<num>] [bs=<num>] "
+ "sg_read [blk_sgio=0|1] [bpt=BPT] [bs=BS] "
"[cdbsz=6|10|12|16]\n"
- " count=<num> [dio=0|1] [dpo=0|1] [fua=0|1] "
- "if=<infile>\n"
+ " count=COUNT [dio=0|1] [dpo=0|1] [fua=0|1] "
+ "if=IFILE\n"
" [mmap=0|1] [no_dfxer=0|1] [odir=0|1] "
- "[skip=<num>]\n"
- " [time=<num>] [verbose=<n>] [--help] "
+ "[skip=SKIP]\n"
+ " [time=TI] [verbose=VERB] [--help] "
"[--version]\n"
" where:\n"
" blk_sgio 0->normal IO for block devices, 1->SCSI commands "
"via SG_IO\n"
" bpt is blocks_per_transfer (default is 128, or 64 KiB "
- "for def 'bs')\n"
- " setting 'bpt=0' will do 'count' zero block SCSI "
+ "for default BS)\n"
+ " setting 'bpt=0' will do COUNT zero block SCSI "
"READs\n"
- " bs must match sector size if 'if' accessed via SCSI "
+ " bs must match sector size if IFILE accessed via SCSI "
"commands\n"
" (def=512)\n"
" cdbsz size of SCSI READ command (default is 10)\n"
- " count total bytes read will be 'bs'*'count' (if no "
+ " count total bytes read will be BS*COUNT (if no "
"error)\n"
- " (if negative, do |count| zero block SCSI READs)\n"
+ " (if negative, do |COUNT| zero block SCSI READs)\n"
" dio 1-> attempt direct IO on sg device, 0->indirect IO "
"(def)\n");
fprintf(stderr,
@@ -619,10 +620,10 @@ int main(int argc, char * argv[])
fprintf(stderr, "Opened %s for Unix reads with flags=0x%x\n",
inf, flags);
if (skip > 0) {
- llse_loff_t offset = skip;
+ off64_t offset = skip;
offset *= bs; /* could exceed 32 bits here! */
- if (llse_llseek(infd, offset, SEEK_SET) < 0) {
+ if (lseek64(infd, offset, SEEK_SET) < 0) {
snprintf(ebuff, EBUFF_SZ,
ME "couldn't skip to required position on %s", inf);
perror(ebuff);
@@ -637,7 +638,7 @@ int main(int argc, char * argv[])
if (dd_count > 0) {
if (do_dio || do_odir || (FT_RAW & in_type)) {
- wrkBuff = malloc(bs * bpt + psz);
+ wrkBuff = (unsigned char *)malloc(bs * bpt + psz);
if (0 == wrkBuff) {
fprintf(stderr, "Not enough user memory for aligned "
"storage\n");
@@ -646,14 +647,14 @@ int main(int argc, char * argv[])
wrkPos = (unsigned char *)(((unsigned long)wrkBuff + psz - 1) &
(~(psz - 1)));
} else if (do_mmap) {
- wrkPos = mmap(NULL, bs * bpt, PROT_READ | PROT_WRITE,
- MAP_SHARED, infd, 0);
+ wrkPos = (unsigned char *)mmap(NULL, bs * bpt,
+ PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0);
if (MAP_FAILED == wrkPos) {
perror(ME "error from mmap()");
return SG_LIB_CAT_OTHER;
}
} else {
- wrkBuff = malloc(bs * bpt);
+ wrkBuff = (unsigned char *)malloc(bs * bpt);
if (0 == wrkBuff) {
fprintf(stderr, "Not enough user memory\n");
return SG_LIB_CAT_OTHER;
@@ -732,10 +733,10 @@ int main(int argc, char * argv[])
}
} else {
if (iters > 0) { /* subsequent iteration reset skip position */
- llse_loff_t offset = skip;
+ off64_t offset = skip;
offset *= bs; /* could exceed 32 bits here! */
- if (llse_llseek(infd, offset, SEEK_SET) < 0) {
+ if (lseek64(infd, offset, SEEK_SET) < 0) {
perror(ME "could not reset skip position");
break;
}
diff --git a/sg_read_buffer.8 b/sg_read_buffer.8
new file mode 100644
index 00000000..511f7944
--- /dev/null
+++ b/sg_read_buffer.8
@@ -0,0 +1,72 @@
+.TH SG_READ_BUFFER "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
+.SH NAME
+sg_read_buffer \- send a SCSI READ BUFFER command
+.SH SYNOPSIS
+.B sg_read_buffer
+[\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id=ID\fR] [\fI\-\-length=LEN\fR]
+[\fI\-\-mode=MO\fR] [\fI\-\-offset=OFF\fR] [\fI\-\-raw\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.SH DESCRIPTION
+.\" Add any additional description here
+.PP
+Sends a SCSI READ BUFFER command to the \fIDEVICE\fR, and if there
+is a response either decodes it, prints it in hexadecimal or sends
+it in binary to stdout. If a response is received for a "descriptor"
+mode then, in the absence of \fI\-\-hex\fR and \fI\-\-raw\fR, it is
+decoded. Response for non-descriptor modes are output in hexadecimal
+unless the \fI\-\-raw\fR option is given.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+output the usage message then exit. If used multiple times also prints
+the mode names and their acronyms.
+.TP
+\fB\-H\fR, \fB\-\-hex\fR
+output the response in hexadecimal.
+.TP
+\fB\-i\fR, \fB\-\-id\fR=\fIID\fR
+this option sets the buffer id field in the cdb. \fIID\fR is a value between
+0 (default) and 255 inclusive.
+.TP
+\fB\-l\fR, \fB\-\-length\fR=\fILEN\fR
+where \fILEN\fR is the length, in bytes, that is placed in the "allocation
+length" field in the cdb. The default value is 4 (bytes). The device may
+respond with less bytes.
+.TP
+\fB\-m\fR, \fB\-\-mode\fR=\fIMO\fR
+this option sets the mode field in the cdb. \fIMO\fR is a value between
+0 (default) and 31 inclusive. Alternatively an abbreviation can be given.
+To list the available mode abbreviations given an invalid
+one (e.g. '\-\-mode=xxx').
+.TP
+\fB\-o\fR, \fB\-\-offset\fR=\fIOFF\fR
+this option sets the buffer offset field in the cdb. \fIOFF\fR is a value
+between 0 (default) and 2**24\-1 . It is a byte offset.
+.TP
+\fB\-r\fR, \fB\-\-raw\fR
+if a response is received then it is sent in binary to stdout.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+increase the level of verbosity, (i.e. debug output).
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+print the version string and then exit.
+.SH NOTES
+All numbers given with options are assumed to be decimal.
+Alternatively numerical values can be given in hexadecimal preceded by
+either "0x" or "0X" (or has a trailing "h" or "H").
+.SH EXIT STATUS
+The exit status of sg_read_buffer is 0 when it is successful. Otherwise
+see the sg3_utils(8) man page.
+.SH AUTHORS
+Written by Luben Tuikov and Douglas Gilbert.
+.SH "REPORTING BUGS"
+Report bugs to <dgilbert at interlog dot com>.
+.SH COPYRIGHT
+Copyright \(co 2006\-2007 Luben Tuikov and Douglas Gilbert
+.br
+This software is distributed under a FreeBSD license. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH "SEE ALSO"
+.B sg_write_buffer(sg3_utils)
diff --git a/sg_read_buffer.c b/sg_read_buffer.c
new file mode 100644
index 00000000..84d39c81
--- /dev/null
+++ b/sg_read_buffer.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2006-2007 Luben Tuikov and Douglas Gilbert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "sg_lib.h"
+#include "sg_cmds_basic.h"
+#include "sg_cmds_extra.h"
+
+/*
+ * This utility issues the SCSI READ BUFFER command to the given device.
+ */
+
+static char * version_str = "1.03 20070121";
+
+#define ME "sg_read_buffer: "
+
+
+static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"id", 1, 0, 'i'},
+ {"length", 1, 0, 'l'},
+ {"mode", 1, 0, 'm'},
+ {"offset", 1, 0, 'o'},
+ {"raw", 0, 0, 'r'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+static void usage()
+{
+ fprintf(stderr, "Usage: "
+ "sg_read_buffer [--help] [--hex] [--id=ID] [--length=LEN] "
+ "[--mode=MO]\n"
+ " [--offset=OFF] [--raw] [--verbose] "
+ "[--version] DEVICE\n"
+ " where:\n"
+ " --help|-h print out usage message\n"
+ " --hex|-H print output in hex\n"
+ " --id=ID|-i ID buffer identifier (0 (default) to 255)\n"
+ " --length=LEN|-l LEN length in bytes to read (def: 4)\n"
+ " --mode=MO|-m MO read buffer mode, MO is number or "
+ "acronym (def: 0)\n"
+ " --off=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n"
+ " --raw|-r output response to stdout\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ " Numbers given in options are decimal unless they have a "
+ "hex indicator\n"
+ "Performs a SCSI READ BUFFER command\n"
+ );
+
+}
+
+#define MODE_HEADER_DATA 0
+#define MODE_VENDOR 1
+#define MODE_DATA 2
+#define MODE_DESCRIPTOR 3
+#define MODE_ECHO_BUFFER 0x0A
+#define MODE_ECHO_BDESC 0x0B
+#define MODE_EN_EX_ECHO 0x1A
+#define MODE_ERR_HISTORY 0x1C
+
+static struct mode_s {
+ char *mode_string;
+ int mode;
+ char *comment;
+} modes[] = {
+ { "hd", MODE_HEADER_DATA, "combined header and data"},
+ { "vendor", MODE_VENDOR, "vendor specific"},
+ { "data", MODE_DATA, "data"},
+ { "desc", MODE_DESCRIPTOR, "descriptor"},
+ { "echo", MODE_ECHO_BUFFER, "echo (spc-2)"},
+ { "echo_desc", MODE_ECHO_BDESC, "echo descriptor (spc-2)"},
+ { "en_ex", MODE_EN_EX_ECHO,
+ "enable expander communications protocol and echo buffer (spc-3)"},
+ { "err_hist", MODE_ERR_HISTORY, "retrieve error history (spc-4)"},
+};
+
+#define NUM_MODES ((int)(sizeof(modes)/sizeof(modes[0])))
+
+static void print_modes(void)
+{
+ int k;
+
+ fprintf(stderr, "The modes parameter argument can be numeric "
+ "(hex or decimal)\nor symbolic:\n");
+ for (k = 0; k < NUM_MODES; k++) {
+ fprintf(stderr, " %2d (0x%02x) %-16s%s\n", modes[k].mode,
+ modes[k].mode, modes[k].mode_string, modes[k].comment);
+ }
+}
+
+static void dStrRaw(const char* str, int len)
+{
+ int k;
+
+ for (k = 0 ; k < len; ++k)
+ printf("%c", str[k]);
+}
+
+int main(int argc, char * argv[])
+{
+ int sg_fd, res, c, len, k;
+ int do_help = 0;
+ int do_hex = 0;
+ int rb_id = 0;
+ int rb_len = 4;
+ int rb_mode = 0;
+ int rb_offset = 0;
+ int do_raw = 0;
+ int verbose = 0;
+ char device_name[256];
+ unsigned char * resp;
+ int ret = 0;
+
+ memset(device_name, 0, sizeof device_name);
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "hHi:l:m:o:rvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ case '?':
+ ++do_help;
+ break;
+ case 'H':
+ ++do_hex;
+ break;
+ case 'i':
+ rb_id = sg_get_num(optarg);
+ if ((rb_id < 0) || (rb_id > 255)) {
+ fprintf(stderr, "argument to '--id' should be in the range "
+ "0 to 255\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'l':
+ rb_len = sg_get_num(optarg);
+ if (rb_len < 0) {
+ fprintf(stderr, "bad argument to '--length'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'm':
+ if (isdigit(*optarg)) {
+ rb_mode = sg_get_num(optarg);
+ if ((rb_mode < 0) || (rb_mode > 31)) {
+ fprintf(stderr, "argument to '--mode' should be in the "
+ "range 0 to 31\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else {
+ len = strlen(optarg);
+ for (k = 0; k < NUM_MODES; ++k) {
+ if (0 == strncmp(modes[k].mode_string, optarg, len)) {
+ rb_mode = modes[k].mode;
+ break;
+ }
+ }
+ if (NUM_MODES == k) {
+ print_modes();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ break;
+ case 'o':
+ rb_offset = sg_get_num(optarg);
+ if (rb_offset < 0) {
+ fprintf(stderr, "bad argument to '--offset'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'r':
+ ++do_raw;
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'V':
+ fprintf(stderr, ME "version: %s\n", version_str);
+ return 0;
+ default:
+ fprintf(stderr, "unrecognised switch code 0x%x ??\n", c);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (do_help) {
+ if (do_help > 1) {
+ usage();
+ fprintf(stderr, "\n");
+ print_modes();
+ } else
+ usage();
+ return 0;
+ }
+ if (optind < argc) {
+ if ('\0' == device_name[0]) {
+ strncpy(device_name, argv[optind], sizeof(device_name) - 1);
+ device_name[sizeof(device_name) - 1] = '\0';
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+
+ if (0 == device_name[0]) {
+ fprintf(stderr, "missing device name!\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ if (rb_len > 0) {
+ resp = (unsigned char *)malloc(rb_len);
+ if (NULL == resp) {
+ fprintf(stderr, "unable to allocate %d bytes on the heap\n",
+ rb_len);
+ return SG_LIB_CAT_OTHER;
+ }
+ memset(resp, 0, rb_len);
+ } else
+ resp = NULL;
+
+ sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose);
+ if (sg_fd < 0) {
+ fprintf(stderr, ME "open error: %s: %s\n", device_name,
+ safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+
+ res = sg_ll_read_buffer(sg_fd, rb_mode, rb_id, rb_offset, resp,
+ rb_len, 1, verbose);
+ if (0 != res) {
+ ret = res;
+ switch (res) {
+ case SG_LIB_CAT_NOT_READY:
+ fprintf(stderr, "Read buffer failed, device not ready\n");
+ break;
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ fprintf(stderr, "Read buffer not done, unit attention\n");
+ break;
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ fprintf(stderr, "Read buffer, aborted command\n");
+ break;
+ case SG_LIB_CAT_INVALID_OP:
+ fprintf(stderr, "Read buffer command not supported\n");
+ break;
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ fprintf(stderr, "bad field in Read buffer cdb\n");
+ break;
+ default:
+ fprintf(stderr, "Read buffer failed res=%d\n", res);
+ break;
+ }
+ } else if (rb_len > 0) {
+ if (do_raw)
+ dStrRaw((const char *)resp, rb_len);
+ else if (do_hex || (rb_len < 4))
+ dStrHex((const char *)resp, rb_len, 1);
+ else {
+ switch (rb_mode) {
+ case MODE_DESCRIPTOR:
+ k = (resp[1] << 16) | (resp[2] << 8) | resp[3];
+ printf("OFFSET BOUNDARY: %d, Buffer offset alignment: %d-byte\n",
+ resp[0], (1 << resp[0]));
+ printf("BUFFER CAPACITY: %d (0x%x)\n", k, k);
+ break;
+ case MODE_ECHO_BDESC:
+ k = ((resp[2] & 0x1F) << 8) | resp[3];
+
+ printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0);
+ printf("Echo buffer capacity: %d (0x%x)\n", k, k);
+ break;
+ default:
+ dStrHex((const char *)resp, rb_len, 1);
+ break;
+ }
+ }
+ }
+
+ if (resp)
+ free(resp);
+ res = sg_cmds_close_device(sg_fd);
+ if (res < 0) {
+ fprintf(stderr, "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/sg_read_long.8 b/sg_read_long.8
index 5a616742..30482fae 100644
--- a/sg_read_long.8
+++ b/sg_read_long.8
@@ -1,72 +1,75 @@
-.TH SG_READ_LONG "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_READ_LONG "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_read_long \- calls a READ LONG command on a SCSI device
+sg_read_long \- send a SCSI READ LONG command
.SH SYNOPSIS
.B sg_read_long
-[\fI--16\fR] [\fI--correct\fR] [\fI--help\fR] [\fI--lba=<num>\fR]
-[\fI--out=<name>\fR] [\fI--pblock\fR] [\fI--verbose\fR] [\fI--version\fR]
-[\fI--xfer_len=<num>\fR] \fI<scsi_device>\fR
+[\fI\-\-16\fR] [\fI\-\-correct\fR] [\fI\-\-help\fR] [\fI\-\-lba=LBA\fR]
+[\fI\-\-out=OF\fR] [\fI\-\-pblock\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+[\fI\-\-xfer_len=BTL\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send READ LONG command to a SCSI device. The read
-buffer is output in hex and ASCII to stdout or placed in a file.
-Note that the data returned includes the logical block data (typically
-512 bytes for a disk) plus ECC information (whose format is proprietary)
-plus optionally other proprietary data.
+Send SCSI READ LONG command to \fIDEVICE\fR. The read buffer is output in hex
+and ASCII to stdout or placed in a file. Note that the data returned includes
+the logical block data (typically 512 bytes for a disk) plus ECC
+information (whose format is proprietary) plus optionally other proprietary
+data.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---16 | -S
-attempts a READ LONG(16) SCSI command. The default action is to attempt
-a READ LONG(10) SCSI command. The READ LONG(10) command has a 32 bit
-field for the lba while READ LONG(16) has a 64 bit field.
+\fB\-S\fR, \fB\-\-16\fR
+uses a SCSI READ LONG(16) command. The default action is to use a SCSI
+READ LONG(10) command. The READ LONG(10) command has a 32 bit field for
+the lba while READ LONG(16) has a 64 bit field.
.TP
---correct | -c
-sets the 'CORRCT' bit in the READ LONG SCSI command. When set the data is
+\fB\-c\fR, \fB\-\-correct\fR
+sets the 'CORRCT' bit in the SCSI READ LONG command. When set the data is
corrected by the ECC before being transferred back to this utility. The
default is to leave the 'CORRCT' bit clear in which case the data is
not corrected.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---lba=<num> | -l <num>
-the logical block address of the sector to read. Assumed to be in
-decimal unless prefixed with '0x'. Defaults to lba 0. If the lba is
-larger than can fit in 32 bits then the '--16' form should be used.
+\fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR
+where \fILBA\fR is the logical block address of the sector to read. Assumed
+to be in decimal unless prefixed with '0x' (or has a trailing 'h'). Defaults
+to lba 0. If the lba is larger than can fit in 32 bits then the \fI\-\-16\fR
+option should be used.
.TP
---out=<name> | -o <name>
-instead of outputting ASCII hex to stdout, try to send it to the file
-called <name>. If '-' is given as the <name> then the (binary) output
-is sent to stdout. Note that all informative and error output is
+\fB\-o\fR, \fB\-\-out\fR=\fIOF\fR
+instead of outputting ASCII hex to stdout, send it in binary to the
+file called \fIOF\fR. If '\-' is given for \fIOF\fR then the (binary)
+output is sent to stdout. Note that all informative and error output is
sent to stderr.
.TP
---pblock | -p
-sets the 'PBLOCK' bit in the READ LONG SCSI command. When set the
+\fB\-p\fR, \fB\-\-pblock\fR
+sets the 'PBLOCK' bit in the SCSI READ LONG command. When set the
physical block (plus ECC data) containing the requested logical block
address is read. The default is to leave the 'PBLOCK' bit clear in
which case the logical block (plus any ECC data) is read.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
.TP
---xfer_len=<num> | -x <num>
-the transfer length in bytes (default to 520). If the given value (or the
-default) does not match the "long" block size of the device, the
-appropriate xfer_len value is derived from the error response and
+\fB\-x\fR, \fB\-\-xfer_len\fR=\fIBTL\fR
+where \fIBTL\fR is the byte transfer length (default to 520). If the
+given value (or the default) does not match the "long" block size of the
+device, the appropriate \fIBTL\fR is deduced from the error response and
printed (to stderr). The idea is that the user will retry this utility
with the correct transfer length.
-.PP
+.SH NOTES
If a defective block is found and its contents, if any, has been
retrieved then "sg_reassign" could be used to map out the defective
block. Associated with such an action the number of elements in
-the "grown" defect list could be monitored (with "sg_reassign --grown")
+the "grown" defect list could be monitored (with "sg_reassign \-\-grown")
as the disk could be nearing the end of its useful lifetime.
.PP
-The lba and xfer_len numerical arguments may be followed by the following
-multiplicative suffixes:
+The \fILBA\fR and \fIBTL\fR (transfer length) arguments may be followed by
+the following multiplicative suffixes:
c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
MB *1,000,000; g G GiB *1,073,741,824; and GB *1,000,000,000 . Also a suffix
of the form "x<n>" multiplies the leading number by <n>.
@@ -86,7 +89,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_read_long.c b/sg_read_long.c
index 49c3b902..5a576a23 100644
--- a/sg_read_long.c
+++ b/sg_read_long.c
@@ -5,13 +5,15 @@
#include <string.h>
#include <getopt.h>
#include <errno.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
/* A utility program for the Linux OS SCSI subsystem.
- * Copyright (C) 2004-2006 D. Gilbert
+ * Copyright (C) 2004-2007 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)
@@ -24,7 +26,7 @@
the sector data and the ECC bytes.
*/
-static char * version_str = "1.12 20061012";
+static char * version_str = "1.14 20070129";
#define MAX_XFER_LEN 10000
@@ -49,26 +51,27 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_read_long [--16] [--correct] [--help] [--lba=<num>] "
- "[--out=<name>]\n"
+ "sg_read_long [--16] [--correct] [--help] [--lba=LBA] "
+ "[--out=OF]\n"
" [--pblock] [--verbose] [--version] "
- "[--xfer_len=<num>]\n"
- " <scsi_device>\n"
+ "[--xfer_len=BTL]\n"
+ " DEVICE\n"
" where:\n"
- " --16|-S do READ LONG(16) (default: "
+ " --16|-S do READ LONG(16) (default: "
"READ LONG(10))\n"
- " --correct|-c use ECC to correct data "
+ " --correct|-c use ECC to correct data "
"(default: don't)\n"
- " --help|-h print out usage message\n"
- " --lba=<num>|-l <num> logical block address"
+ " --help|-h print out usage message\n"
+ " --lba=LBA|-l LBA logical block address"
" (default: 0)\n"
- " --out=<name>|-o <name> output to file <name>\n"
- " --verbose|-v increase verbosity\n"
- " --version|-V print version string and"
+ " --out=OF|-o OF output in binary to file named OF\n"
+ " --pblock|-p fetch physical block containing LBA\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and"
" exit\n"
- " --xfer_len=<num>|-x <num> transfer length (< 10000)"
+ " --xfer_len=BTL|-x BTL byte transfer length (< 10000)"
" default 520\n\n"
- "Perform a READ LONG (10 or 16) SCSI command\n"
+ "Perform a SCSI READ LONG (10 or 16) command\n"
);
}
@@ -78,7 +81,7 @@ static int process_read_long(int sg_fd, int do_16, int pblock, int correct,
int xfer_len, int verbose)
{
int offset, res;
- char * ten_or;
+ const char * ten_or;
if (do_16)
res = sg_ll_read_long16(sg_fd, pblock, correct, llba, data_out,
@@ -228,23 +231,24 @@ int main(int argc, char * argv[])
}
if (NULL == (rawp = malloc(MAX_XFER_LEN))) {
- fprintf(stderr, ME "out of memory (query)\n");
+ fprintf(stderr, ME "out of memory\n");
sg_cmds_close_device(sg_fd);
return SG_LIB_SYNTAX_ERROR;
}
- readLongBuff = rawp;
+ readLongBuff = (unsigned char *)rawp;
memset(rawp, 0x0, MAX_XFER_LEN);
fprintf(stderr, ME "issue read long (%s) to device %s\n xfer_len=%d "
- "(0x%x), lba=%llu (0x%llx), correct=%d\n", (do_16 ? "16" : "10"),
- device_name, xfer_len, xfer_len, llba, llba, correct);
+ "(0x%x), lba=%" PRIu64 " (0x%" PRIx64 "), correct=%d\n",
+ (do_16 ? "16" : "10"), device_name, xfer_len, xfer_len, llba,
+ llba, correct);
if (process_read_long(sg_fd, do_16, pblock, correct, llba, readLongBuff,
xfer_len, verbose))
goto err_out;
if ('\0' == out_fname[0])
- dStrHex(rawp, xfer_len, 0);
+ dStrHex((const char *)rawp, xfer_len, 0);
else {
got_stdout = (0 == strcmp(out_fname, "-")) ? 1 : 0;
if (got_stdout)
diff --git a/sg_readcap.8 b/sg_readcap.8
index 4697931e..9400a519 100644
--- a/sg_readcap.8
+++ b/sg_readcap.8
@@ -1,95 +1,157 @@
-.TH SG_READCAP "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_READCAP "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_readcap \- calls a READ CAPACITY command on a SCSI device
+sg_readcap \- sends a SCSI READ CAPACITY command
.SH SYNOPSIS
.B sg_readcap
-[\fI-16\fR] [\fI-h\fR] [\fI-H\fR] [\fI-lba=<block>\fR] [\fI-pmi\fR]
-[\fI-r\fR] [\fI-v\fR] [\fI-V\fR] <\fIdevice\fR>
+[\fI\-\-brief\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-lba=LBA\fR]
+[\fI\-\-long\fR] [\fI\-\-pmi\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] \fIDEVICE\fR
+.PP
+.B sg_readcap
+[\fI\-16\fR] [\fI\-b\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-lba=LBA\fR]
+[\fI\-pmi\fR] [\fI\-r\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-The normal usage is to find the number of blocks (and block size)
-of the given device and output them.
+The normal action of the SCSI READ CAPACITY command is to fetch the number
+of blocks (and block size) from the \fIDEVICE\fR.
.PP
The SCSI READ CAPACITY command (both 10 and 16 byte cdbs) actually yield
the block address of the last block and the block size. The number of
blocks is thus one plus the block address of the last block (as blocks
are counted origin zero (i.e. starting at block zero)). This is the source
-of many "off by one" errors which are often seen as medium or out of range
-errors when the reported last block is read.
+of many "off by one" errors.
.PP
-Device capacity is the product of the number of blocks and block size.
+Device capacity is the product of the number of blocks by the block size.
This utility outputs this figure in bytes, MiB (1048576 bytes per MiB)
and GB (1000000000 bytes per GB).
+.PP
+This utility supports two command line syntaxes, the preferred one is
+shown first in the synopsis and explained in this section. A later section
+on the old command line syntax outlines the second group of options.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
--16
-Use the 16 byte cdb variant of the READ CAPACITY command. The default
-action is to use the 10 byte cdb variant which limits the maximum
-block address to (2**32 - 2). When a 10 byte cdb READ CAPACITY command
-is used on a device whose size is too large then a last block address
-of 0xffffffff is returned (if the device complies with SBC-2).
-.TP
--b
-utility outputs two hex numbers (prefixed with '0x' and space separated)
+\fB\-b\fR, \fB\-\-brief\fR
+outputs two hex numbers (prefixed with '0x' and space separated)
to stdout. The first number is the maximum number of blocks on the
device (which is one plus the lba of the last accessible block). The
second number is the size of each block. If the operation fails
then "0x0 0x0" is written to stdout.
.TP
--h
-output the usage message then exit. Giving the '-?' option also outputs
-the usage message then exits.
+\fB\-h\fR, \fB\-\-help\fR
+print out the usage message then exit.
.TP
--H
+\fB\-H\fR, \fB\-\-hex\fR
output the response to the READ CAPACITY command (either the 10 or 16
byte cdb variant) in ASCII hexadecimal on stdout.
.TP
--lba=<block>
-used in conjunction with "-pmi" option. This variant of READ CAPACITY will
-yield the last block address after "<block>" prior to a delay. For a
-disk, given a "<block>" address it yields the highest numbered block on
-the same cylinder (i.e. before the heads need to move). "<block>" is
-in hex (from 0 to ffffffff) and defaults to zero.
+\fB\-L\fR, \fB\-\-lba\fR=\fILBA\fR
+used in conjunction with \fI\-\-pmi\fR option. This variant of READ CAPACITY
+will yield the last block address after \fILBA\fR prior to a delay. For a
+disk, given a \fILBA\fR it yields the highest numbered block on the same
+cylinder (i.e. before the heads need to move). \fILBA\fR is assumed to be
+decimal unless prefixed by "0x" or it has a trailing "h". Defaults to 0.
.TP
--pmi
+\fB\-l\fR, \fB\-\-long\fR
+Use the 16 byte cdb variant of the READ CAPACITY command. The default
+action is to use the 10 byte cdb variant which limits the maximum
+block address to (2**32 \- 2). When a 10 byte cdb READ CAPACITY command
+is used on a device whose size is too large then a last block address
+of 0xffffffff is returned (if the device complies with SBC\-2).
+.TP
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
+.TP
+\fB\-p\fR, \fB\-\-pmi\fR
partial medium indicator: for finding the next block address prior to
-some delay (e.g. head movement). In the absence of this switch, the
+some delay (e.g. head movement). In the absence of this option, the
total number of blocks and the block size of the device are output.
+Used in conjunction with the \fI\-\-lba=LBA\fR option.
.TP
---raw | -r
-output response in binary (to stdout).
+\fB\-r\fR, \fB\-\-raw\fR
+output response in binary to stdout.
.TP
--v
-verbose: print out cdb of issued commands prior to execution. '-vv'
-and '-vvv' are also accepted yielding greater verbosity.
+\fB\-v\fR, \fB\-\-verbose\fR
+increase level of verbosity. Can be used multiple times.
.TP
--V
+\fB\-V\fR, \fB\-\-version\fR
outputs version string then exits.
-.PP
-If sg_readcap is called without the '-16' option then the 10 byte cdb
-version: READ CAPACITY (10) is sent to the <device>. If the number
-of blocks in the response is reported as 0xffffffff (i.e. (2**32 - 1) )
-and the '-H' option has not been given, then READ CAPACITY (16) is
-called and its response is output.
+.SH NOTES
+If sg_readcap is called without the \fI\-\-long\fR option then the 10 byte
+cdb version (i.e. READ CAPACITY (10)) is sent to the \fIDEVICE\fR. If the
+number of blocks in the response is reported as
+0xffffffff (i.e. (2**32 \- 1) ) and the \fI\-\-hex\fR option has not been
+given, then READ CAPACITY (16) is called and its response is output.
.PP
The read capacity(16) response shows additional information not found
in the read capacity(10) response. This includes protection information
and the number of logical blocks per physical block. So even though
-the media size may not exceed what read capacity(10) can show, it may
-still be useful to examine the response to read capacity(16).
+the media size may not exceed what READ CAPACITY(10) can show, it may
+still be useful to examine the response to READ CAPACITY(16).
.PP
-In the 2.4 series of Linux kernels the given device must be
-a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example "sg_readcap /dev/sda"
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI
+generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks
+and DVD drives) can also be specified. For example "sg_readcap /dev/sda"
and "sg_readcap /dev/hdd" (if /dev/hdd is a ATAPI CD/DVD device) will
work in the 2.6 series kernels.
.SH EXIT STATUS
The exit status of sg_readcap is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using '\-\-old' (or '\-O) as the first option.
+.TP
+\fB\-16\fR
+Use the 16 byte cdb variant of the READ CAPACITY command.
+Equivalent to \fI\-\-long\fR in the main description.
+.TP
+\fB\-b\fR
+utility outputs two hex numbers (prefixed with '0x' and space separated) to
+stdout. The first number is the maximum number of blocks on the device (which
+is one plus the lba of the last accessible block). The second number is the
+size of each block. If the operation fails then "0x0 0x0" is written to
+stdout. Equivalent to \fI\-\-brief\fR in the main description.
+.TP
+\fB\-h\fR
+output the usage message then exit. Giving the \fI\-?\fR option also outputs
+the usage message then exits.
+.TP
+\fB\-H\fR
+output the response to the READ CAPACITY command (either the 10 or 16
+byte cdb variant) in ASCII hexadecimal on stdout.
+.TP
+\fB\-lba\fR=\fILBA\fR
+used in conjunction with \fI\-pmi\fR option. This variant of READ CAPACITY
+will yield the last block address after \fILBA\fR prior to a delay.
+Equivalent to \fI\-\-lba=LBA\fR in the main description.
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-pmi\fR
+partial medium indicator: for finding the next block address prior to
+some delay (e.g. head movement). In the absence of this switch, the
+total number of blocks and the block size of the device are output.
+Equivalent to \fI\-\-pmi\fR in the main description.
+.TP
+\fB\-r\fR
+output response in binary (to stdout).
+.TP
+\fB\-v\fR
+verbose: print out cdb of issued commands prior to execution. '\-vv'
+and '\-vvv' are also accepted yielding greater verbosity.
+.TP
+\fB\-V\fR
+outputs version string then exits.
.SH AUTHORS
Written by Douglas Gilbert
.SH COPYRIGHT
-Copyright \(co 1999-2006 Douglas Gilbert
+Copyright \(co 1999\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH "SEE ALSO"
+.B sg_inq(sg3_utils)
diff --git a/sg_readcap.c b/sg_readcap.c
index 7669c314..76f08134 100644
--- a/sg_readcap.c
+++ b/sg_readcap.c
@@ -3,6 +3,9 @@
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
+#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -10,80 +13,209 @@
/* This code is does a SCSI READ CAPACITY command on the given device
and outputs the result.
-* Copyright (C) 1999 - 2006 D. Gilbert
+* Copyright (C) 1999 - 2007 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)
* any later version.
- This program will only work with Linux 2.4 and 2.6 kernels (i.e.
- those that support the SG_IO ioctl). Another version of this program
- that should work on the 2.0, 2.2 and 2.4 series of Linux kernels no
- matter which of those environments it was compiled and built under
- can be found in the sg_utils package (e.g. sg_utils-1.02).
+ This program was originally written with Linux 2.4 kernel series.
+ It should now also build for the Linux 2.6 kernel series and various
+ other operating systems.
*/
-static char * version_str = "3.79 20061015";
+static char * version_str = "3.81 20070129";
#define ME "sg_readcap: "
#define RCAP_REPLY_LEN 8
#define RCAP16_REPLY_LEN 32
+static struct option long_options[] = {
+ {"brief", 0, 0, 'b'},
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"lba", 1, 0, 'L'},
+ {"long", 0, 0, 'l'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"pmi", 0, 0, 'p'},
+ {"raw", 0, 0, 'r'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
-void usage ()
+struct opts_t {
+ int do_brief;
+ int do_help;
+ int do_hex;
+ int do_lba;
+ int do_long;
+ int do_pmi;
+ int do_raw;
+ int do_verbose;
+ int do_version;
+ unsigned long long llba;
+ const char * device_name;
+ int opt_new;
+};
+
+static void usage()
+{
+ fprintf(stderr, "Usage: sg_readcap [--brief] [--help] [--hex] "
+ "[--lba=LBA] [--long] [--pmi]\n"
+ " [--raw] [--verbose] [--version] "
+ "DEVICE\n"
+ " where:\n"
+ " --brief|-b brief, two hex numbers: number of blocks "
+ "and block size\n"
+ " --help|-h print this usage message and exit\n"
+ " --hex|-H output response in hexadecimal to stdout\n"
+ " --lba=LBA|-L LBA yields the last block prior to (head "
+ "movement) delay\n"
+ " after LBA [in decimal (def: 0) "
+ "valid with '--pmi']\n"
+ " --long|-l use READ CAPACITY (16) cdb (def: use "
+ "10 byte cdb)\n"
+ " --pmi|-p partial medium indicator (without this "
+ "option shows\n"
+ " total disk capacity)\n"
+ " --raw|-r output response in binary to stdout\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Perform a SCSI READ CAPACITY (10 or 16) command\n");
+}
+
+static void usage_old()
{
- fprintf(stderr, "Usage: sg_readcap [-16] [-b] [-h] [-H] [-lba=<block>] "
+ fprintf(stderr, "Usage: sg_readcap [-16] [-b] [-h] [-H] [-lba=LBA] "
"[-pmi] [-r] [-v] [-V]\n"
- " <device>\n"
+ " DEVICE\n"
" where:\n"
" -16 use READ CAPACITY (16) cdb (def: use "
"10 byte cdb)\n"
" -b brief, two hex numbers: number of blocks "
"and block size\n"
- " -h output this usage message and exit\n"
+ " -h print this usage message and exit\n"
" -H output response in hexadecimal to stdout\n"
- " -lba=<block> yields the last block prior to (head "
+ " -lba=LBA yields the last block prior to (head "
"movement) delay\n"
- " after <block> [in hex (def: 0) "
+ " after LBA [in hex (def: 0) "
"valid with -pmi]\n"
- " -pmi partial medium indicator (without this switch "
+ " -pmi partial medium indicator (without this option "
"shows total\n"
" disk capacity)\n"
" -r output response in binary to stdout\n"
" -v increase verbosity\n"
- " -V output version string and exit\n\n"
- "Perform a READ CAPACITY SCSI command\n");
+ " -V print version string and exit\n\n"
+ "Perform a SCSI READ CAPACITY command\n");
}
-static void dStrRaw(const char* str, int len)
+static void usage_for(const struct opts_t * optsp)
{
- int k;
+ if (optsp->opt_new)
+ usage();
+ else
+ usage_old();
+}
- for (k = 0 ; k < len; ++k)
- printf("%c", str[k]);
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c;
+ int a_one = 0;
+ long long nn;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "16bhHlL:NOprvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case '1':
+ ++a_one;
+ break;
+ case '6':
+ if (a_one)
+ ++optsp->do_long;
+ break;
+ case 'b':
+ ++optsp->do_brief;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'l':
+ ++optsp->do_long;
+ break;
+ case 'L':
+ nn = sg_get_llnum(optarg);
+ if (-1 == nn) {
+ fprintf(stderr, "bad argument to '--lba='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->llba = nn;
+ /* force READ_CAPACITY16 for large lbas */
+ if (optsp->llba > 0xfffffffeULL)
+ ++optsp->do_long;
+ ++optsp->do_lba;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'p':
+ ++optsp->do_pmi;
+ break;
+ case 'r':
+ ++optsp->do_raw;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
}
-int main(int argc, char * argv[])
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
{
- int sg_fd, k, res, num, plen, jmp_out;
- unsigned int lba = 0;
- unsigned long long llba = 0;
- unsigned long long u, llast_blk_addr;
- int brief = 0;
- int do_hex = 0;
- int pmi = 0;
- int do16 = 0;
- int do_raw = 0;
- int verbose = 0;
- int ret = 0;
- unsigned int last_blk_addr, block_size;
- const char * file_name = 0;
+ int k, jmp_out, plen, num;
const char * cp;
- unsigned char resp_buff[RCAP16_REPLY_LEN];
+ unsigned long long uu;
- memset(resp_buff, 0, sizeof(resp_buff));
for (k = 1; k < argc; ++k) {
cp = argv[k];
plen = strlen(cp);
@@ -94,39 +226,44 @@ int main(int argc, char * argv[])
switch (*cp) {
case '1':
if ('6' == *(cp + 1)) {
- do16 = 1;
+ ++optsp->do_long;
++cp;
--plen;
} else
jmp_out = 1;
break;
case 'b':
- brief = 1;
+ ++optsp->do_brief;
break;
case 'h':
case '?':
- usage();
- return 0;
+ ++optsp->do_help;
+ break;
case 'H':
- ++do_hex;
+ ++optsp->do_hex;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
break;
case 'p':
if (0 == strncmp("pmi", cp, 3)) {
- pmi = 1;
+ ++optsp->do_pmi;
cp += 2;
plen -= 2;
} else
jmp_out = 1;
break;
case 'r':
- ++do_raw;
+ ++optsp->do_raw;
break;
case 'v':
- ++verbose;
+ ++optsp->do_verbose;
break;
case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
+ ++optsp->do_version;
+ break;
default:
jmp_out = 1;
break;
@@ -137,58 +274,116 @@ int main(int argc, char * argv[])
if (plen <= 0)
continue;
if (0 == strncmp("lba=", cp, 4)) {
- num = sscanf(cp + 4, "%llx", &u);
+ num = sscanf(cp + 4, "%" SCNx64 "", &uu);
if (1 != num) {
printf("Bad value after 'lba=' option\n");
usage();
return SG_LIB_SYNTAX_ERROR;
}
- llba = u;
- if (llba > 0xfffffffeULL)
- do16 = 1; /* force READ_CAPACITY16 for large lbas */
- lba = (unsigned int)llba;
- } else if (jmp_out) {
+ /* force READ_CAPACITY16 for large lbas */
+ if (uu > 0xfffffffeULL)
+ ++optsp->do_long;
+ optsp->llba = uu;
+ ++optsp->do_lba;
+ } else if (0 == strncmp("-old", cp, 4))
+ ;
+ else if (jmp_out) {
fprintf(stderr, "Unrecognized option: %s\n", cp);
usage();
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == file_name)
- file_name = cp;
+ } else if (0 == optsp->device_name)
+ optsp->device_name = cp;
else {
fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
+ "%s\n", optsp->device_name, cp);
usage();
return SG_LIB_SYNTAX_ERROR;
}
}
-
- if (0 == file_name) {
- fprintf(stderr, "No <device> argument given\n");
- usage();
+ return 0;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
+
+static void dStrRaw(const char* str, int len)
+{
+ int k;
+
+ for (k = 0 ; k < len; ++k)
+ printf("%c", str[k]);
+}
+
+int main(int argc, char * argv[])
+{
+ int sg_fd, k, res;
+ unsigned long long llast_blk_addr;
+ int ret = 0;
+ unsigned int last_blk_addr, block_size;
+ unsigned char resp_buff[RCAP16_REPLY_LEN];
+ struct opts_t opts;
+
+ memset(&opts, 0, sizeof(opts));
+ res = process_cl(&opts, argc, argv);
+ if (res)
return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ usage_for(&opts);
+ return 0;
}
- if ((0 == pmi) && (lba > 0)) {
- fprintf(stderr, ME "lba can only be non-zero when pmi is set\n");
- usage();
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
+ }
+
+ if (NULL == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ usage_for(&opts);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ memset(resp_buff, 0, sizeof(resp_buff));
+
+ if ((0 == opts.do_pmi) && (opts.llba > 0)) {
+ fprintf(stderr, ME "lba can only be non-zero when '--pmi' is set\n");
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- if ((sg_fd = sg_cmds_open_device(file_name,
- (do16 ? 0 /* rw */ : 1), verbose)) < 0) {
- fprintf(stderr, ME "error opening file: %s: %s\n", file_name,
+ if ((sg_fd = sg_cmds_open_device(opts.device_name,
+ (opts.do_long ? 0 /* rw */ : 1), opts.do_verbose)) < 0) {
+ fprintf(stderr, ME "error opening file: %s: %s\n", opts.device_name,
safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- if (! do16) {
- res = sg_ll_readcap_10(sg_fd, pmi, lba, resp_buff, RCAP_REPLY_LEN,
- 0, verbose);
+ if (! opts.do_long) {
+ res = sg_ll_readcap_10(sg_fd, opts.do_pmi, (unsigned int)opts.llba,
+ resp_buff, RCAP_REPLY_LEN, 0, opts.do_verbose);
ret = res;
if (0 == res) {
- if (do_hex || do_raw) {
- if (do_hex)
- dStrHex((const char *)resp_buff, RCAP_REPLY_LEN, 1);
- else
+ if (opts.do_hex || opts.do_raw) {
+ if (opts.do_raw)
dStrRaw((const char *)resp_buff, RCAP_REPLY_LEN);
+ else
+ dStrHex((const char *)resp_buff, RCAP_REPLY_LEN, 1);
goto good;
}
last_blk_addr = ((resp_buff[0] << 24) | (resp_buff[1] << 16) |
@@ -196,20 +391,20 @@ int main(int argc, char * argv[])
if (0xffffffff != last_blk_addr) {
block_size = ((resp_buff[4] << 24) | (resp_buff[5] << 16) |
(resp_buff[6] << 8) | resp_buff[7]);
- if (brief) {
+ if (opts.do_brief) {
printf("0x%x 0x%x\n", last_blk_addr + 1, block_size);
goto good;
}
printf("Read Capacity results:\n");
- if (pmi)
- printf(" PMI mode: given lba=0x%x, last lba before "
- "delay=0x%x\n", lba, last_blk_addr);
+ if (opts.do_pmi)
+ printf(" PMI mode: given lba=0x%" PRIx64 ", last lba "
+ "before delay=0x%x\n", opts.llba, last_blk_addr);
else
printf(" Last logical block address=%u (0x%x), Number "
"of blocks=%u\n", last_blk_addr, last_blk_addr,
last_blk_addr + 1);
printf(" Logical block length=%u bytes\n", block_size);
- if (! pmi) {
+ if (! opts.do_pmi) {
unsigned long long total_sz = last_blk_addr + 1;
double sz_mb, sz_gb;
@@ -219,25 +414,31 @@ int main(int argc, char * argv[])
sz_gb = ((double)(last_blk_addr + 1) * block_size) /
(double)(1000000000L);
printf("Hence:\n");
- printf(" Device size: %llu bytes, %.1f MiB, %.2f GB\n",
- total_sz, sz_mb, sz_gb);
+#ifdef SG3_UTILS_MINGW
+ printf(" Device size: %" PRIu64 " bytes, %g MiB, %g "
+ "GB\n", total_sz, sz_mb, sz_gb);
+#else
+ printf(" Device size: %" PRIu64 " bytes, %.1f MiB, "
+ "%.2f GB\n", total_sz, sz_mb, sz_gb);
+#endif
}
goto good;
} else {
printf("READ CAPACITY (10) indicates device capacity too "
"large\n now trying 16 byte cdb variant\n");
- do16 = 1;
+ opts.do_long = 1;
}
} else if (SG_LIB_CAT_INVALID_OP == res) {
- do16 = 1;
+ opts.do_long = 1;
sg_cmds_close_device(sg_fd);
- if ((sg_fd = sg_cmds_open_device(file_name, 0 /*rw */, verbose))
+ if ((sg_fd = sg_cmds_open_device(opts.device_name, 0 /*rw */,
+ opts.do_verbose))
< 0) {
fprintf(stderr, ME "error re-opening file: %s (rw): %s\n",
- file_name, safe_strerror(-sg_fd));
+ opts.device_name, safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- if (verbose)
+ if (opts.do_verbose)
fprintf(stderr, "READ CAPACITY (10) not supported, trying "
"READ CAPACITY (16)\n");
} else if (SG_LIB_CAT_ILLEGAL_REQ == res)
@@ -246,20 +447,20 @@ int main(int argc, char * argv[])
fprintf(stderr, "READ CAPACITY (10) failed, device not ready\n");
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
fprintf(stderr, "READ CAPACITY (10) failed, aborted command\n");
- else if (! verbose)
+ else if (! opts.do_verbose)
fprintf(stderr, "READ CAPACITY (10) failed [res=%d], try "
"with '-v'\n", res);
}
- if (do16) {
- res = sg_ll_readcap_16(sg_fd, pmi, llba, resp_buff, RCAP16_REPLY_LEN,
- 0, verbose);
+ if (opts.do_long) {
+ res = sg_ll_readcap_16(sg_fd, opts.do_pmi, opts.llba, resp_buff,
+ RCAP16_REPLY_LEN, 0, opts.do_verbose);
ret = res;
if (0 == res) {
- if (do_hex || do_raw) {
- if (do_hex)
- dStrHex((const char *)resp_buff, RCAP16_REPLY_LEN, 1);
- else
+ if (opts.do_hex || opts.do_raw) {
+ if (opts.do_raw)
dStrRaw((const char *)resp_buff, RCAP16_REPLY_LEN);
+ else
+ dStrHex((const char *)resp_buff, RCAP16_REPLY_LEN, 1);
goto good;
}
for (k = 0, llast_blk_addr = 0; k < 8; ++k) {
@@ -268,27 +469,28 @@ int main(int argc, char * argv[])
}
block_size = ((resp_buff[8] << 24) | (resp_buff[9] << 16) |
(resp_buff[10] << 8) | resp_buff[11]);
- if (brief) {
- printf("0x%llx 0x%x\n", llast_blk_addr + 1, block_size);
+ if (opts.do_brief) {
+ printf("0x%" PRIx64 " 0x%x\n", llast_blk_addr + 1, block_size);
goto good;
}
printf("Read Capacity results:\n");
printf(" Protection: prot_en=%d, p_type=%d\n",
!!(resp_buff[12] & 0x1), ((resp_buff[12] >> 1) & 0x7));
- if (pmi)
- printf(" PMI mode: given lba=0x%llx, last lba before "
- "delay=0x%llx\n", llba, llast_blk_addr);
+ if (opts.do_pmi)
+ printf(" PMI mode: given lba=0x%" PRIx64 ", last lba "
+ "before delay=0x%" PRIx64 "\n", opts.llba,
+ llast_blk_addr);
else
- printf(" Last logical block address=%llu (0x%llx), Number "
- "of logical blocks=%llu\n", llast_blk_addr,
- llast_blk_addr, llast_blk_addr + 1);
+ printf(" Last logical block address=%" PRIu64 " (0x%"
+ PRIx64 "), Number of logical blocks=%" PRIu64 "\n",
+ llast_blk_addr, llast_blk_addr, llast_blk_addr + 1);
printf(" Logical block length=%u bytes\n", block_size);
printf(" Logical blocks per physical block=%d (log base 2) "
"[actual=%d]\n", (resp_buff[13] & 0xf),
(1 << (resp_buff[13] & 0xf)));
printf(" Lowest aligned logical block address=%d\n",
((resp_buff[14] & 0x3f) << 8) + resp_buff[15]);
- if (! pmi) {
+ if (! opts.do_pmi) {
unsigned long long total_sz = llast_blk_addr + 1;
double sz_mb, sz_gb;
@@ -298,8 +500,13 @@ int main(int argc, char * argv[])
sz_gb = ((double)(llast_blk_addr + 1) * block_size) /
(double)(1000000000L);
printf("Hence:\n");
- printf(" Device size: %llu bytes, %.1f MiB, %.2f GB\n",
+#ifdef SG3_UTILS_MINGW
+ printf(" Device size: %" PRIu64 " bytes, %g MiB, %g GB\n",
total_sz, sz_mb, sz_gb);
+#else
+ printf(" Device size: %" PRIu64 " bytes, %.1f MiB, %.2f "
+ "GB\n", total_sz, sz_mb, sz_gb);
+#endif
}
goto good;
}
@@ -310,12 +517,13 @@ int main(int argc, char * argv[])
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
fprintf(stderr, "READ CAPACITY (16) failed, aborted command\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "bad field in READ CAPACITY (10) cdb\n");
- else if (! verbose)
+ fprintf(stderr, "bad field in READ CAPACITY (16) cdb "
+ "including unsupported service action\n");
+ else if (! opts.do_verbose)
fprintf(stderr, "READ CAPACITY (16) failed [res=%d], try "
"with '-v'\n", res);
}
- if (brief)
+ if (opts.do_brief)
printf("0x0 0x0\n");
good:
diff --git a/sg_reassign.8 b/sg_reassign.8
index cbe7a6fb..649227e3 100644
--- a/sg_reassign.8
+++ b/sg_reassign.8
@@ -1,53 +1,55 @@
-.TH SG_REASSIGN "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_REASSIGN "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_reassign \- reassign defective blocks on the given (disk) device
+sg_reassign \- sends a SCSI REASSIGN BLOCKS command
.SH SYNOPSIS
.B sg_reassign
-[\fI--address=<n>,<n>...\fR] [\fI--dummy\fR] [\fI--eight=0|1\fR]
-[\fI--grown\fR] [\fI--help\fR] [\fI--longlist=0|1\fR] [\fI--primary\fR]
-[\fI--verbose\fR] [\fI--version\fR] \fI<scsi_device>\fR
+[\fI\-\-address=A,A...\fR] [\fI\-\-dummy\fR] [\fI\-\-eight=0|1\fR]
+[\fI\-\-grown\fR] [\fI\-\-help\fR] [\fI\-\-longlist=0|1\fR]
+[\fI\-\-primary\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send a REASSIGN BLOCKS SCSI command to the given device. Alternatively
+Send a SCSI REASSIGN BLOCKS command to \fIDEVICE\fR. Alternatively
this utility can find the number of element in a "grown" or "primary"
-defect list with a READ DEFECT DATA (10) SCSI command. These SCSI commands
-are defined in SBC-2 for direct access devices (e.g. a disk). Reassign
+defect list with a SCSI READ DEFECT DATA (10) command. These SCSI commands
+are defined in SBC\-2 for direct access devices (e.g. a disk). Reassign
blocks is designed to change the physical location of a logical block
that is known or suspected to be defective to another area on the
media. Disks are typically formatted with blocks held in reserve
for this situation.
.PP
-If neither the '--grown' nor '--primary' option is supplied then one
-or more addresses need to be given. If the address (or all of
-the addresses) fit into 4 bytes and '--eight=1' is not given then
-the parameter block passed to the given device is made up of
-4 byte logical block addresses. If any of the addresses need
-more than 4 bytes to represent (i.e. >= 2**32) or '--eight=1' is given
-then the parameter block passed to the given device is made up of
-8 byte logical block addresses.
+If neither the \fI\-\-grown\fR nor \fI\-\-primary\fR option is supplied
+then one or more addresses need to be given. If the address (or all of
+the addresses) fit into 4 bytes and '\-\-eight=1' is not given then the
+parameter block passed to \fIDEVICE\fR is made up of 4 byte logical block
+addresses. If any of the addresses need more than 4 bytes to
+represent (i.e. >= 2**32) or '\-\-eight=1' is given then the parameter block
+passed to \fIDEVICE\fR is made up of 8 byte logical block addresses.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---address=<n>,<n>... | -a <n>,<n>...
-string of comma separated numbers. Each number is interpreted as decimal
-unless prefixed by '0x' or '0X' (or it has a trailing 'h' or 'H'). If
-multiple logical block addresses are given they must be separated by a
-comma. At least one address must be given.
+\fB\-a\fR, \fB\-\-address\fR=\fIA,A...\fR
+where \fIA,A...\fR is a string of comma separated numbers. Each number
+is interpreted as decimal unless prefixed by '0x' or '0X' (or it has a
+trailing 'h' or 'H'). If multiple logical block addresses are given they
+must be separated by a comma. At least one address must be given.
.TP
---address=- | -a -
+\fB\-a\fR, \fB\-\-address\fR=\-
reads one or more logical block addresses from stdin. These may be comma,
space, tab or linefeed (newline) separated. If a line contains "#" then
the remaining characters on that line are ignored. Otherwise each non
-separator character should resolve to a decimal number unless prefixed
-by '0x' or '0X'. At least one address must be given.
+separator sequence of characters should resolve to a decimal number
+unless prefixed by '0x' or '0X' (or has a trailing 'h'). At least one
+address must be given.
.TP
---dummy | -d
-prepare for but do not execute the REASSIGN BLOCKS SCSI command. Since
-the REASSIGN BLOCKS SCSI command is essentially irreversible, paranoid
+\fB\-d\fR, \fB\-\-dummy\fR
+prepare for but do not execute the SCSI REASSIGN BLOCKS command. Since
+the REASSIGN BLOCKS command is essentially irreversible, paranoid
users may wish to check the invocation of this utility before reassigning
-defective blocks on a disk. Useful with '-v -v' for those who wish to
+defective blocks on a disk. Useful with '\-vv' for those who wish to
view the parameter block that will accompany the command.
.TP
---eight=0|1 | -e 0|1
+\fB\-e\fR, \fB\-\-eight\fR=0 | 1
when value is 1 then it sets the 'LONGLBA' flag in the command indicating
that the addresses in the associated parameter block are 8 byte quantities.
When value is 0 then it clears the 'LONGLBA' flag in the command indicating
@@ -55,53 +57,52 @@ that the addresses in the associated parameter block are 4 byte quantities.
If this option is not given then 4 byte quantities are assumed unless one
of the address is too large.
.TP
---grown | -g
-use the READ DEFECT DATA (10) SCSI command to determine the number of
+\fB\-g\fR, \fB\-\-grown\fR
+use the SCSI READ DEFECT DATA (10) command to determine the number of
elements in the "grown defect list". When this option is given there
is no reassignment of blocks (i.e. this utility is passive). When this
-option is given then the '--address=' option is not permitted. See
+option is given then the \fI\-\-address=\fR option is not permitted. See
the discussion below concerning the relationship between reassigned blocks
and the grown defect list. This list is sometimes referred to as the GLIST.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---longlist=0|1 | -l 0|1
+\fB\-l\fR, \fB\-\-longlist\fR=0 | 1
sets the REASSIGN BLOCKS cdb field of the same name to the given value.
Only 1000 addresses are permitted so there should be no need to specify
a value of 1. The short list variant restricts the parameter block
length to 2 ** 16 bytes (i.e. about 16000 4 byte addresses or 8000
8 byte addresses). Added for completeness.
.TP
---primary | -p
-use the READ DEFECT DATA (10) SCSI command to determine the number of
+\fB\-p\fR, \fB\-\-primary\fR
+use the SCSI READ DEFECT DATA (10) command to determine the number of
elements in the "primary defect list" which is established during the
manufacturing process. When this option is given there is no reassignment
of blocks (i.e. this utility is passive). When this option is given then
-the '--address=' option is not permitted. This list is sometimes referred
-to as the PLIST.
+the \fI\-\-address=\fR option is not permitted. This list is sometimes
+referred to as the PLIST.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
-Note that if the ARRE field (for reads) and/or the AWRE field (for
-writes) are set in the "Read Write Error Recovery" mode page then
-recoverable read and/or write errors cause automatic reassignment
-of the defective block. The PER bit in the same mode page controls
-whether a RECOVERED ERROR sense key is reported on not (PER=1 implies
-do report). Irrespective of the ARRE, AWRE or PER field settings,
-the error counter log pages reflect any errors (recovered or otherwise).
-Whenever a block is reassigned, a new entry is added in the "grown"
-defect list. Apart from doing selftests (see sg_senddiag or
-smartmontools) regularly, monitoring the grown defect list of a disk is
+.SH NOTES
+Note that if the ARRE field (for reads) and/or the AWRE field (for writes)
+are set in the "Read Write Error Recovery" mode page then recoverable read
+and/or write errors cause automatic reassignment of the defective block. The
+PER bit in the same mode page controls whether a RECOVERED ERROR sense key
+is reported on not (PER=1 implies do report). Irrespective of the ARRE, AWRE
+or PER field settings, the error counter log pages reflect any
+errors (recovered or otherwise). Whenever a block is reassigned, a new entry
+is added in the "grown" defect list. Apart from doing selftests (see
+sg_senddiag or smartmontools) regularly, monitoring the grown defect list of a disk is
a reasonable metric of its health. If the grown list starts growing
quickly that is an ominous sign. The best grown defect lists are empty
ones. The number of elements in the grown defect list can be viewed with
-the '--grown' option. The contents of the grown defect list can be
-viewed with the 'sginfo -G' utility.
+the \fI\-\-grown\fR option. The contents of the grown defect list can be
+viewed with the 'sginfo \-G' utility.
.PP
If an unrecoverable error is detected at a logical block address then
REASSIGN BLOCKS is needed to reassign the block. Also if the ARRE and/or
@@ -117,11 +118,11 @@ is exhausted subsequent invocations of this utility may result in
a sense key of hardware error and an additional sense of 'No defect
spare location available'. The next step would be to reformat the
disk (or get a replacement).
-.SH NOTES
-The SBC-2 draft standard (revision 16) notes that when multiple addresses
-are given to the REASSIGN BLOCKS SCSI command and there is some failure
+.PP
+The SBC\-2 draft standard (revision 16) notes that when multiple addresses
+are given to the SCSI REASSIGN BLOCKS command and there is some failure
at one of the later addresses then all addresses prior to that have already
-be reassigned. Care should be taken in such a case. Re-executing the command
+be reassigned. Care should be taken in such a case. Re\-executing the command
with the same addresses will cause the earlier addresses to be reassigned
again. At some stage the disk will run out of reserved locations.
So unless a large number of addresses are involved it may be safer to
@@ -134,10 +135,10 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2005-2006 Douglas Gilbert
+Copyright \(co 2005\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B sg_format(sg3_utils), sdparm(sdparm), sginfo(sg3_utils)
+.B sg_format,sginfo,sg_senddiag(all in sg3_utils), sdparm(sdparm),
.B smartmontools(internet, sourceforge)
diff --git a/sg_reassign.c b/sg_reassign.c
index 4123f42e..3a8f99fd 100644
--- a/sg_reassign.c
+++ b/sg_reassign.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2006 Douglas Gilbert.
+ * Copyright (c) 2005-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,8 @@
#include <ctype.h>
#include <getopt.h>
#include <limits.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -49,7 +51,7 @@
* vendor specific data is written.
*/
-static char * version_str = "1.08 20061015";
+static char * version_str = "1.11 20070127";
#define ME "sg_reassign: "
@@ -64,6 +66,7 @@ static struct option long_options[] = {
{"eight", 1, 0, 'e'},
{"grown", 0, 0, 'g'},
{"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
{"longlist", 1, 0, 'l'},
{"primary", 0, 0, 'p'},
{"verbose", 0, 0, 'v'},
@@ -74,39 +77,39 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_reassign [--address=<n>[,<n>...]] [--dummy] [--eight=0|1] "
+ "sg_reassign [--address=A,A...] [--dummy] [--eight=0|1] "
"[--grown]\n"
- " [--help] [--longlist=0|1] [--primary] "
+ " [--help] [--hex] [--longlist=0|1] [--primary] "
"[--verbose]\n"
- " [--version] <scsi_device>\n"
+ " [--version] DEVICE\n"
" where:\n"
- " --address=<n>[,<n>...]\n"
- " -a <n>[,<n>...] comma separated logical block "
+ " --address=A,A...|-a A,A... comma separated logical block "
"addresses\n"
- " (at least one required)\n"
- " --address=- | -a - read stdin for logical block "
+ " one or more, assumed to be "
+ "decimal\n"
+ " --address=-|-a - read stdin for logical block "
"addresses\n"
- " --dummy | -d prepare but do not execute "
- "REASSIGN BLOCKS\n"
- " command\n"
+ " --dummy|-d prepare but do not execute REASSIGN "
+ "BLOCKS command\n"
" --eight=0|1\n"
- " -e 0|1 force eight byte (64 bit) lbas "
+ " -e 0|1 force eight byte (64 bit) lbas "
"when 1,\n"
- " four byte (32 bit) lbas when 0 "
+ " four byte (32 bit) lbas when 0 "
"(def)\n"
- " --grown | -g fetch grown defect list length, "
+ " --grown|-g fetch grown defect list length, "
"don't reassign\n"
- " --help | -h print out usage message\n"
+ " --help|-h print out usage message\n"
+ " --hex|-H print response in hex (for '-g' or "
+ "'-p')\n"
" --longlist=0|1\n"
- " -l 0|1 use 4 byte list length when "
- "'--longlist=1',\n"
- " safe to ignore and use 2 byte "
- "list length\n"
- " --primary | -p fetch primary defect list length, "
+ " -l 0|1 use 4 byte list length when 1, safe to "
+ "ignore\n"
+ " which default to 2 byte list length\n"
+ " --primary|-p fetch primary defect list length, "
"don't reassign\n"
- " --verbose | -v increase verbosity\n"
- " --version | -V print version string and exit\n\n"
- "Perform a REASSIGN BLOCKS SCSI command (or READ DEFECT LIST)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Perform a SCSI REASSIGN BLOCKS command (or READ DEFECT LIST)\n"
);
}
@@ -124,16 +127,16 @@ long long get_llnum(const char * buf)
len = strlen(buf);
commap = strchr(buf + 1, ',');
if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
- res = sscanf(buf + 2, "%llx", &unum);
+ res = sscanf(buf + 2, "%" SCNx64 "", &unum);
num = unum;
} else if (commap && ('H' == toupper(*(commap - 1)))) {
- res = sscanf(buf, "%llx", &unum);
+ res = sscanf(buf, "%" SCNx64 "", &unum);
num = unum;
} else if ((NULL == commap) && ('H' == toupper(buf[len - 1]))) {
- res = sscanf(buf, "%llx", &unum);
+ res = sscanf(buf, "%" SCNx64 "", &unum);
num = unum;
} else
- res = sscanf(buf, "%lld", &num);
+ res = sscanf(buf, "%" SCNd64 "", &num);
if (1 == res)
return num;
else
@@ -257,6 +260,7 @@ int main(int argc, char * argv[])
int eight = -1;
int addr_arr_len = 0;
int grown = 0;
+ int do_hex = 0;
int longlist = 0;
int primary = 0;
int verbose = 0;
@@ -270,7 +274,7 @@ int main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "a:de:ghl:pvV", long_options,
+ c = getopt_long(argc, argv, "a:de:ghHl:pvV", long_options,
&option_index);
if (c == -1)
break;
@@ -304,6 +308,9 @@ int main(int argc, char * argv[])
case '?':
usage();
return 0;
+ case 'H':
+ ++do_hex;
+ break;
case 'l':
num = sscanf(optarg, "%d", &res);
if ((1 == num) && ((0 == res) || (1 == res)))
@@ -411,7 +418,7 @@ int main(int argc, char * argv[])
if (verbose) {
fprintf(stderr, " Would have reassigned these blocks:\n");
for (j = 0; j < addr_arr_len; ++j)
- printf(" 0x%llx\n", addr_arr[j]);
+ printf(" 0x%" PRIx64 "\n", addr_arr[j]);
}
return 0;
}
@@ -462,6 +469,10 @@ int main(int argc, char * argv[])
fprintf(stderr, "READ DEFECT DATA (10) failed\n");
goto err_out;
}
+ if (do_hex) {
+ dStrHex((const char *)param_arr, param_len, 1);
+ goto err_out; /* ret is zero */
+ }
lstp = "";
got_grown = !!(param_arr[1] & 0x8);
got_primary = !!(param_arr[1] & 0x10);
diff --git a/sg_requests.8 b/sg_requests.8
index 5dc7c8e4..1e349a62 100644
--- a/sg_requests.8
+++ b/sg_requests.8
@@ -1,68 +1,70 @@
-.TH SG_REQUESTS "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_REQUESTS "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_requests \- send one or more SCSI REQUEST SENSE commands
.SH SYNOPSIS
.B sg_requests
-[\fI--desc\fR] [\fI--help\fR] [\fI--hex\fR] [\fI--num=<n>\fR]
-[\fI--raw\fR] [\fI--status\fR] [\fI--time\fR] [\fI--verbose\fR]
-[\fI--version\fR] \fI<scsi_device>\fR
+[\fI\-\-desc\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-num=NUM\fR]
+[\fI\-\-raw\fR] [\fI\-\-status\fR] [\fI\-\-time\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send REQUEST SENSE command to a SCSI device and output the response
-which is expected to be in sense data format. Both fixed and descriptor
-format are supported.
+Send REQUEST SENSE command to \fIDEVICE\fR and output the response which is
+expected to be in sense data format. Both fixed and descriptor format are
+supported.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---desc | -d
-sets the 'DESC' bit in the REQUEST SENSE SCSI command. The given device
+\fB\-d\fR, \fB\-\-desc\fR
+sets the DESC bit in the REQUEST SENSE SCSI cdb. The \fIDEVICE\fR
should return sense data in descriptor (rather than fixed) format. This
-will only occur if the given device recognizes descriptor format (SPC-3
-and later). If the device is pre SPC-3 then setting a bit in a reserved
+will only occur if the \fIDEVICE\fR recognizes descriptor format (SPC\-3
+and later). If the device is pre SPC\-3 then setting a bit in a reserved
field may cause a check condition status with an illegal request sense key.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---hex | -H
+\fB\-H\fR, \fB\-\-hex\fR
output response in ASCII hexadecimal.
.TP
---num=<n> | -n <n>
-perform <n> SCSI REQUEST SENSE commands, stopping whe either <n> is
-reached or an error occurs. The default value for <n> is 1 .
+\fB\-n\fR, \fB\-\-num\fR=\fINUM\fR
+perform \fINUM\fR SCSI REQUEST SENSE commands, stopping when either \fINUM\fR
+is reached or an error occurs. The default value for \fINUM\fR is 1 .
.TP
---raw | -r
+\fB\-r\fR, \fB\-\-raw\fR
output response in binary (to stdout).
.TP
---status | -s
+\fB\-s\fR, \fB\-\-status\fR
if the last REQUEST SENSE finished without error (from SCSI status or
-autosense) then the contents of the parameter data is analysed as
+autosense) then the contents of the parameter data are analysed as
sense data and the exit status is set accordingly. The default
action (when this option is not given) is to ignore the contents
of the parameter data for the purposes of setting the exit status.
-Some types of error set a sense key of "NO SENSE" with non-zero
+Some types of error set a sense key of "NO SENSE" with non\-zero
information in the additional sense code (e.g. the FAILURE PREDICTION
THRESHOLD EXCEEDED group of codes); this results in an exit status
value of 10. If the sense key is "NO SENSE" and both asc and ascq are
zero then the exit status is set to 0 . See the sg3_utils(8) man page
for exit status values.
.TP
---time | -t
+\fB\-t\fR, \fB\-\-time\fR
time the SCSI REQUEST SENSE command(s) and calculate the average number
of operations per second.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
Additionally the response (if received) is output in ASCII-HEX. Use
this option multiple times for greater verbosity.
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
+.SH NOTES
In SCSI 1 and 2 the REQUEST SENSE command was very important for error
and warning processing in SCSI. The autosense capability rendered this
command almost superfluous.
.PP
-However recent SCSI drafts (e.g. SPC-3 rev 23 and SBC-2 rev 16) increase
+However recent SCSI drafts (e.g. SPC\-3 rev 23 and SBC\-2 rev 16) increase
the utility of the REQUEST SENSE command. Idle and standby power
conditions can now be detected with this command; a progress indication
is given during FORMAT (when that command was started with with IMMED=1
@@ -71,9 +73,9 @@ set (e.g. by a tape drive). Interestingly the sense key is set
to "no sense" while the asc/ascq code convey the information (e.g.
0x5e/0x4 "Standby condition activated by command").
.PP
-The REQUEST SENSE command is not marked as mandatory in SPC-3 (i.e. for
-all SCSI devices) but is marked as mandatory in SBC-2 (i.e. for disks),
-SSC-3 (i.e. for tapes) and MMC-4 (i.e. for CD/DVD drives).
+The REQUEST SENSE command is not marked as mandatory in SPC\-3 (i.e. for
+all SCSI devices) but is marked as mandatory in SBC\-2 (i.e. for disks),
+SSC\-3 (i.e. for tapes) and MMC\-4 (i.e. for CD/DVD drives).
.SH EXIT STATUS
The exit status of sg_requests is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
@@ -82,9 +84,9 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B sg_format(sg3_utils)
+.B sg3_utils
diff --git a/sg_requests.c b/sg_requests.c
index 40936647..1959a96e 100644
--- a/sg_requests.c
+++ b/sg_requests.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,7 @@
* This program issues the SCSI command REQUEST SENSE to the given SCSI device.
*/
-static char * version_str = "1.16 20061012";
+static char * version_str = "1.17 20070127";
#define REQUEST_SENSE_BUFF_LEN 252
@@ -67,15 +67,15 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_requests [--desc] [--help] [--hex] [--num=<n>] [--raw]\n"
+ "sg_requests [--desc] [--help] [--hex] [--num=NUM] [--raw]\n"
" [--status] [--time] [--verbose] [--version] "
- "<scsi_device>\n"
+ "DEVICE\n"
" where:\n"
" --desc|-d set flag for descriptor sense "
"format\n"
" --help|-h print out usage message\n"
" --hex|-H output in hexadecimal\n"
- " --num=<n>|-n <n> number of REQUEST SENSE commands "
+ " --num=NUM|-n NUM number of REQUEST SENSE commands "
"to send (def: 1)\n"
" --raw|-r output in binary (to stdout)\n"
" --status|-s set exit status from parameter data "
@@ -85,7 +85,7 @@ static void usage()
"per second\n"
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
- "Perform a REQUEST SENSE SCSI command\n"
+ "Performs a SCSI REQUEST SENSE command\n"
);
}
@@ -111,7 +111,9 @@ int main(int argc, char * argv[])
int verbose = 0;
char device_name[256];
int ret = 0;
+#ifndef SG3_UTILS_MINGW
struct timeval start_tm, end_tm;
+#endif
memset(device_name, 0, sizeof device_name);
while (1) {
@@ -188,11 +190,13 @@ int main(int argc, char * argv[])
return SG_LIB_FILE_ERROR;
}
+#ifndef SG3_UTILS_MINGW
if (do_time) {
start_tm.tv_sec = 0;
start_tm.tv_usec = 0;
gettimeofday(&start_tm, NULL);
}
+#endif
requestSenseBuff[0] = '\0';
requestSenseBuff[7] = '\0';
@@ -242,6 +246,7 @@ int main(int argc, char * argv[])
}
}
}
+#ifndef SG3_UTILS_MINGW
if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
struct timeval res_tm;
double a, b;
@@ -263,6 +268,7 @@ int main(int argc, char * argv[])
else
printf("\n");
}
+#endif
res = sg_cmds_close_device(sg_fd);
if (res < 0) {
fprintf(stderr, "close error: %s\n", safe_strerror(-res));
diff --git a/sg_reset.8 b/sg_reset.8
index 38a43eb1..8c10e7e0 100644
--- a/sg_reset.8
+++ b/sg_reset.8
@@ -1,17 +1,17 @@
-.TH SG_RESET "8" "May 2005" "sg3_utils-1.15" SG3_UTILS
+.TH SG_RESET "8" "December 2006" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_reset \- sends SCSI device, bus or host reset; or checks reset state
.SH SYNOPSIS
.B sg_reset
-[\fI-b\fR] [\fI-d\fR] [\fI-h\fR] [\fI-V\fR]
-<\fIscsi_device\fR>
+[\fI\-b\fR] [\fI\-d\fR] [\fI\-h\fR] [\fI\-V\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-The sg_reset utility with no options (other than the device name)
-reports on the reset state (e.g. if a reset is underway) of the
-given device. When given a '-d', '-b', or '-h' option it requests
-a device, bus or host reset respectively.
+The sg_reset utility with no options (other than \fIDEVICE\fR) reports on
+the reset state (e.g. if a reset is underway) of \fIDEVICE\fR. When given
+a \fI\-d\fR, \fI\-b\fR, or \fI\-h\fR option it requests a device, bus or
+host reset respectively.
.PP
In the linux kernel 2.6 series this utility can be called on sd,
sr (cd/dvd), st or sg device nodes; if the user has appropriate
@@ -21,22 +21,26 @@ In the linux kernel 2.4 series support for this utility first
appeared in lk 2.4.19 and could only be called on sg device
nodes. Various vendors made this capability available in their
kernels prior to lk 2.4.19.
+.SH OPTIONS
.TP
--b
+\fB\-b\fR
attempt a SCSI bus reset. This would normally be tried if the
-device reset (i.e. option '-d') was not successful.
+device reset (i.e. option \fI\-d\fR) was not successful.
.TP
--d
+\fB\-d\fR
attempt a SCSI device reset. If the device seems stuck, this is
the first reset that should be tried. This assumes the linux
scsi mid level error handler is not already in the process
-of resetting this device.
+of resetting \fIDEVICE\fR.
.TP
--h
+\fB\-h\fR
attempt a host adapter reset. This would normally be tried if both
-device reset (i.e. option '-d') and bus reset (i.e. option '-b')
+device reset (i.e. option \fI\-d\fR) and bus reset (i.e. option \fI\-b\fR)
were not successful.
-.PP
+.TP
+\fB\-V\fR
+prints the version string then exits.
+.SH NOTES
The error recovery code within the linux kernel when faced
with SCSI commands timing out and no response from the
device (LU), first tries a device reset and if that is
@@ -47,7 +51,7 @@ to reset with this utility. The "device,bus,host"
order is also recommended (i.e. first start with the smallest
hammer).
.PP
-SAM-4 defines a hard reset (which includes a device power on
+SAM\-4 defines a hard reset (which includes a device power on
and a transport reset), a logical unit reset and a I_T nexus
reset. A LU reset and an I_T nexus reset can be requested via
task management function (and support for LU reset is mandatory).
@@ -55,17 +59,17 @@ In Linux the SCSI subsystem leaves it up to the low level drivers
as to whether a "device reset" is only for the addressed LU or
all the LUs in the device that contains the addressed LU.
The "bus reset" is a transport reset. A "host reset" attempts
-to re-initialize the HBA that the request passes through on
-route to the given device. Obviously a "host reset" and
+to re\-initialize the HBA that the request passes through on
+route to the \fIDEVICE\fR. Obviously a "host reset" and
a "bus reset" can cause collateral damage.
.PP
This utility does not allow individual SCSI commands (or tasks
-as they are called in SAM-4) to be aborted. SAM-4 defines
+as they are called in SAM\-4) to be aborted. SAM\-4 defines
ABORT TASK and ABORT TASK SET task management functions for that.
.SH AUTHORS
Written by Douglas Gilbert.
.SH COPYRIGHT
-Copyright \(co 1999-2006 Douglas Gilbert
+Copyright \(co 1999\-2006 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_reset.c b/sg_reset.c
index 09c82abe..4d6efa98 100644
--- a/sg_reset.c
+++ b/sg_reset.c
@@ -11,7 +11,7 @@
/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg")
device driver.
-* Copyright (C) 1999-2006 D. Gilbert
+* Copyright (C) 1999-2007 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)
@@ -24,7 +24,7 @@
#define ME "sg_reset: "
-static char * version_str = "0.54 20061015";
+static char * version_str = "0.55 20070125";
#ifndef SG_SCSI_RESET
#define SG_SCSI_RESET 0x2284
@@ -66,7 +66,7 @@ int main(int argc, char * argv[])
}
if (0 == file_name) {
printf(
- "Usage: 'sg_reset [-b] [-d] [-h] [-V] <scsi_device>'\n");
+ "Usage: sg_reset [-b] [-d] [-h] [-V] DEVICE\n");
printf(" where: -b attempt a SCSI bus reset\n");
printf(" -d attempt a SCSI device reset\n");
printf(" -h attempt a host adapter reset\n");
diff --git a/sg_rmsn.8 b/sg_rmsn.8
index 82cc608c..aed7154a 100644
--- a/sg_rmsn.8
+++ b/sg_rmsn.8
@@ -1,43 +1,45 @@
-.TH SG_RMSN "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_RMSN "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_rmsn \- read media serial number
+sg_rmsn \- sends a SCSI READ MEDIA SERIAL NUMBER command
.SH SYNOPSIS
.B sg_rmsn
-[\fI--help\fR] [\fI--raw\fR]
-[\fI--verbose\fR] [\fI--version\fR] \fI<scsi_device>\fR
+[\fI\-\-help\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send a READ MEDIA SERIAL NUMBER SCSI command to the given device and
-outputs the response.
+Send a SCSI READ MEDIA SERIAL NUMBER command to \fIDEVICE\fR and outputs
+the response.
.PP
-This command is described in SPC-3 found at www.t10.org . It was
-originally added to SPC-3 in revision 11 (2003/2/12). It is not an
+This command is described in SPC\-3 found at www.t10.org . It was
+originally added to SPC\-3 in revision 11 (2003/2/12). It is not an
mandatory command and the author has not seen any SCSI devices
that support it.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---raw | -r
+\fB\-r\fR, \fB\-\-raw\fR
sends the serial number (if found) to stdout. This output may contain
-non-printable characters (e.g. the serial number is padded with NULLs
+non\-printable characters (e.g. the serial number is padded with NULLs
at the end so its length is a multiple of 4). The default action is
-to print the serial number out in ASCII-HEX with ASCII characters to
+to print the serial number out in ASCII\-HEX with ASCII characters to
the right. All error messages are sent to stderr.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
+.SH NOTES
Device identification information is also found in a standard INQUIRY
response and its VPD pages (see sg_vpd). The relevant VPD pages are
the "device identification page" (VPD page 0x83) and the "unit serial
number" page (VPD page 0x80).
.PP
-The MMC-4 command set for CDs and DVDs has a "media serial number"
+The MMC\-4 command set for CDs and DVDs has a "media serial number"
feature (0x109) [and a "logical unit serial number" feature]. These
can be viewed with sg_get_config.
.SH EXIT STATUS
@@ -48,7 +50,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2005-2006 Douglas Gilbert
+Copyright \(co 2005\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_rmsn.c b/sg_rmsn.c
index e0c25be4..edb48eb3 100644
--- a/sg_rmsn.c
+++ b/sg_rmsn.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2006 Douglas Gilbert.
+ * Copyright (c) 2005-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@
* to the given SCSI device.
*/
-static char * version_str = "1.04 20061012";
+static char * version_str = "1.06 20070127";
#define ME "sg_rmsn: "
@@ -63,13 +63,14 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_rmsn [--help] [--raw] [--verbose] [--version] <scsi_device>\n"
- " where: --help|-h print out usage message\n"
- " --raw|-r output serial number to stdout "
+ "sg_rmsn [--help] [--raw] [--verbose] [--version] DEVICE\n"
+ " where:\n"
+ " --help|-h print out usage message\n"
+ " --raw|-r output serial number to stdout "
"(potentially binary)\n"
- " --verbose|-v increase verbosity\n"
- " --version|-V print version string and exit\n\n"
- "Performs a READ MEDIA SERIAL NUMBER SCSI command\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Performs a SCSI READ MEDIA SERIAL NUMBER command\n"
);
}
@@ -160,7 +161,7 @@ int main(int argc, char * argv[])
goto err_out;
}
sn_len += 4;
- ucp = malloc(sn_len);
+ ucp = (unsigned char *)malloc(sn_len);
if (NULL == ucp) {
fprintf(stderr, " Out of memory (ram)\n");
goto err_out;
@@ -193,7 +194,8 @@ int main(int argc, char * argv[])
fprintf(stderr, "Read Media Serial Number failed, aborted "
"command\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "bad field in Read Media Serial Number cdb\n");
+ fprintf(stderr, "bad field in Read Media Serial Number cdb "
+ "including unsupported service action\n");
else {
fprintf(stderr, "Read Media Serial Number failed\n");
if (0 == verbose)
diff --git a/sg_rtpg.8 b/sg_rtpg.8
index 165960af..8af0157d 100644
--- a/sg_rtpg.8
+++ b/sg_rtpg.8
@@ -1,37 +1,42 @@
-.TH SG_RTPG "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_RTPG "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_rtpg \- report target port groups
+sg_rtpg \- sends a SCSI REPORT TARGET PORT GROUPS command
.SH SYNOPSIS
.B sg_rtpg
-[\fI--decode\fR] [\fI--help\fR] [\fI--hex\fR]
-[\fI--verbose\fR] [\fI--version\fR] \fI<scsi_device>\fR
+[\fI\-\-decode\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-raw\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send a REPORT TARGET PORT GROUPS SCSI command to the given device and
+Send a SCSI REPORT TARGET PORT GROUPS command to \fIDEVICE\fR and
outputs the response.
.PP
-Target port group access is described in SPC-3 found at www.t10.org
+Target port group access is described in SPC\-3 found at www.t10.org
in section 5.8 (in rev 21c dated 2005/1/15). The Report Target Port
Groups command is also described in that document.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---decode | -d
+\fB\-d\fR, \fB\-\-decode\fR
decodes the status code and asymmetric access state from each
target port group descriptor returned. The default action is not
to decode these values.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---hex | -H
+\fB\-H\fR, \fB\-\-hex\fR
output response in hex (rather than partially or fully decode it).
.TP
---verbose | -v
+\fB\-r\fR, \fB\-\-raw\fR
+output response in binary to stdout.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
+.SH NOTES
The Report Target Port Groups command should be supported whenever the TPGS
bits in a standard INQUIRY response are greater than zero. [View with
sg_inq utility.]
@@ -43,7 +48,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Christophe Varoqui and Douglas Gilbert
+Copyright \(co 2004\-2007 Christophe Varoqui and Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_rtpg.c b/sg_rtpg.c
index 17a989cd..7798ea93 100644
--- a/sg_rtpg.c
+++ b/sg_rtpg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Christophe Varoqui and Douglas Gilbert.
+ * Copyright (c) 2004-2007 Christophe Varoqui and Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@
* to the given SCSI device.
*/
-static char * version_str = "1.08 20060907";
+static char * version_str = "1.11 20070127";
#define REPORT_TGT_GRP_BUFF_LEN 1024
@@ -86,6 +86,7 @@ static struct option long_options[] = {
{"decode", 0, 0, 'd'},
{"help", 0, 0, 'h'},
{"hex", 0, 0, 'H'},
+ {"raw", 0, 0, 'r'},
{"verbose", 0, 0, 'v'},
{"version", 0, 0, 'V'},
{0, 0, 0, 0},
@@ -94,18 +95,29 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_rtpg [--decode] [--help] [--hex] [--verbose] [--version]\n"
- " <scsi_device>\n"
- " where: --decode|-d decode status and asym. access state\n"
- " --help|-h print out usage message\n"
- " --hex|-H print out response in hex\n"
- " --verbose|-v increase verbosity\n"
- " --version|-V print version string and exit\n\n"
- "Performs a REPORT TARGET PORT GROUPS SCSI command\n"
+ "sg_rtpg [--decode] [--help] [--hex] [--raw] [--verbose] "
+ "[--version]\n"
+ " DEVICE\n"
+ " where:\n"
+ " --decode|-d decode status and asym. access state\n"
+ " --help|-h print out usage message\n"
+ " --hex|-H print out response in hex\n"
+ " --raw|-r output response in binary to stdout\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Performs a SCSI REPORT TARGET PORT GROUPS command\n"
);
}
+static void dStrRaw(const char* str, int len)
+{
+ int k;
+
+ for (k = 0 ; k < len; ++k)
+ printf("%c", str[k]);
+}
+
static void decode_status(const int st)
{
switch (st) {
@@ -155,6 +167,7 @@ int main(int argc, char * argv[])
unsigned char * ucp;
int decode = 0;
int hex = 0;
+ int raw = 0;
int verbose = 0;
char device_name[256];
int ret = 0;
@@ -163,7 +176,7 @@ int main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "dhHvV", long_options,
+ c = getopt_long(argc, argv, "dhHrvV", long_options,
&option_index);
if (c == -1)
break;
@@ -179,6 +192,9 @@ int main(int argc, char * argv[])
case 'H':
hex = 1;
break;
+ case 'r':
+ raw = 1;
+ break;
case 'v':
++verbose;
break;
@@ -234,16 +250,22 @@ int main(int argc, char * argv[])
(reportTgtGrpBuff[1] << 16) +
(reportTgtGrpBuff[2] << 8) +
reportTgtGrpBuff[3] + 4;
- printf("Report list length = %d\n", report_len);
if (report_len > (int)sizeof(reportTgtGrpBuff)) {
trunc = 1;
- printf(" <<report too long for internal buffer,"
- " output truncated\n");
+ fprintf(stderr, " <<report too long for internal buffer,"
+ " output truncated\n");
+ report_len = (int)sizeof(reportTgtGrpBuff);
+ }
+ if (raw) {
+ dStrRaw((const char *)reportTgtGrpBuff, report_len);
+ goto err_out;
}
+ if (verbose)
+ printf("Report list length = %d\n", report_len);
if (hex) {
- fprintf(stderr, "\nOutput response in hex\n");
- dStrHex((const char *)reportTgtGrpBuff,
- (trunc ? (int)sizeof(reportTgtGrpBuff) : report_len), 1);
+ if (verbose)
+ fprintf(stderr, "\nOutput response in hex:\n");
+ dStrHex((const char *)reportTgtGrpBuff, report_len, 1);
goto err_out;
}
printf("Report target port groups:\n");
@@ -288,7 +310,8 @@ int main(int argc, char * argv[])
} else if (SG_LIB_CAT_INVALID_OP == res)
fprintf(stderr, "Report Target Port Groups command not supported\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "bad field in Report Target Port Groups cdb\n");
+ fprintf(stderr, "bad field in Report Target Port Groups cdb "
+ "including unsupported service action\n");
else if (SG_LIB_CAT_UNIT_ATTENTION == res)
fprintf(stderr, "Report Target Port Groups, unit attention\n");
else if (SG_LIB_CAT_ABORTED_COMMAND == res)
diff --git a/sg_sat_identify.8 b/sg_sat_identify.8
index b4fb6171..7e7ef973 100644
--- a/sg_sat_identify.8
+++ b/sg_sat_identify.8
@@ -1,69 +1,71 @@
-.TH SG_SAT_IDENTIFY "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_SAT_IDENTIFY "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_sat_identify \- call an ATA IDENTIFY (PACKET) DEVICE command via a
+sg_sat_identify \- sends a ATA IDENTIFY (PACKET) DEVICE command via a
SCSI to ATA Translation (SAT) layer
.SH SYNOPSIS
.B sg_sat_identify
-[\fI--chk_cond\fR] [\fI--help\fR] [\fI--hex\fR] [\fI--len=<12|16>\fR]
-[\fI--packet\fR] [\fI--raw\fR] [\fI--verbose\fR] [\fI--version\fR]
-\fI<device>\fR
+[\fI\-\-chk_cond\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-len=\fR12|16]
+[\fI\-\-packet\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
This utility sends either an ATA IDENTIFY DEVICE command or an ATA IDENTIFY
-PACKET DEVICE command and outputs the response. The devices that respond
-to these commands are ATA disks and ATAPI devices respectively. Rather
-than send these commands directly to the device they are sent via a SCSI
-transport which is assumed to contain a SCSI to ATA Translation (SAT)
-Layer (SATL). The SAT standard (latest draft: sat-r09.pdf at www.t10.org)
-defines two "ATA PASS-THROUGH" SCSI commands: one using a 16 byte "cdb"
+PACKET DEVICE command to \fIDEVICE\fR and outputs the response. The devices
+that respond to these commands are ATA disks and ATAPI devices respectively.
+Rather than send these commands directly to the device they are sent via a
+SCSI transport which is assumed to contain a SCSI to ATA Translation (SAT)
+Layer (SATL). The SAT standard (latest draft: sat\-r09.pdf at www.t10.org)
+defines two SCSI "ATA PASS\-THROUGH" commands: one using a 16 byte "cdb"
and the other with a 12 byte cdb. This utility defaults to using the 16
byte cdb variant.
.PP
The SATL may be in an operating system driver, in host bus adapter firmware
or in some external enclosure.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---chk_cond | -c
-sets the bit of the same name in the ATA PASS-THROUGH SCSI command. The
+\fB\-c\fR, \fB\-\-chk_cond\fR
+sets the CK_COND bit in the ATA PASS\-THROUGH SCSI cdb. The
default setting is clear (i.e. 0). When set the SATL should yield a
sense buffer containing a ATA Result descriptor irrespective of whether
the command succeeded or failed. When clear the SATL should only yield
a sense buffer containing a ATA Result descriptor if the command failed.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
outputs the usage message summarizing command line options
-then exits. Ignores <device> if given.
+then exits. Ignores \fIDEVICE\fR if given.
.TP
---hex | -H
+\fB\-H\fR, \fB\-\-hex\fR
outputs the ATA IDENTIFY (PACKET) DEVICE response in hex. The default
-action (i.e. without any '-H' options) is to output the response in
+action (i.e. without any '\-H' options) is to output the response in
hex, grouped in 16 bit words (i.e. the ATA standard's preference).
When given once, the response is output in ASCII hex bytes (i.e. the
-SCSI standard's preference). When given twice (i.e. '-HH') the output
+SCSI standard's preference). When given twice (i.e. '\-HH') the output
is in hex, grouped in 16 bit words, the same as the default but without
-a header. When given thrice (i.e. '-HHH') the output is in hex, grouped in
-16 bit words, in a format that is acceptable for 'hdparm --Istdin' to
+a header. When given thrice (i.e. '\-HHH') the output is in hex, grouped in
+16 bit words, in a format that is acceptable for 'hdparm \-\-Istdin' to
process.
.TP
---len=<12|16> | -l <12|16>
-this is the length of the SCSI cdb used for the ATA PASS-THROUGH commands.
+\fB\-l\fR, \fB\-\-len\fR=12 | 16
+this is the length of the SCSI cdb used for the ATA PASS\-THROUGH commands.
The argument can either be 12 or 16. The default is 16. The larger cdb
size is needed for 48 bit LBA addressing of ATA devices. On the other
hand some SCSI transports cannot convey SCSI commands longer than 12 bytes.
.TP
---packet | -p
+\fB\-p\fR, \fB\-\-packet\fR
send an ATA IDENTIFY PACKET DEVICE command (via the SATL). The default
action is to send an ATA IDENTIFY DEVICE command.
.TP
---raw | -r
+\fB\-r\fR, \fB\-\-raw\fR
output the ATA IDENTIFY (PACKET) DEVICE response in binary. The output
should be piped to a file or another utility when this option is used.
The binary is sent to stdout, and errors are sent to stderr.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increases the level or verbosity.
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print out version string
.SH NOTES
Since the response to the IDENTIFY (PACKET) DEVICE command is very
@@ -71,7 +73,14 @@ important for the correct use of an ATA(PI) device (and is typically the
first command sent), a SATL should provide an ATA Information VPD page
which contains the similar information.
.PP
-In the 2.4 series of Linux kernels the given device must be
+The SCSI ATA PASS\-THROUGH (12) command's opcode is 0xa1 and it clashes with
+the MMC set's BLANK command used by cd/dvd writers. So a SATL in front
+of an ATAPI device that uses MMC (i.e. has peripheral device type 5)
+probably should treat opcode 0xa1 as a BLANK command and send it through
+to the cd/dvd drive. The ATA PASS\-THROUGH (16) command's opcode (0x85)
+does not clash with anything so it is a better choice.
+.PP
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be
a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
and ATAPI DVDs) can also be specified. For example "sg_inq /dev/sda"
will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char"
@@ -84,7 +93,7 @@ Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2006 Douglas Gilbert
+Copyright \(co 2006\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_sat_identify.c b/sg_sat_identify.c
index 01d343d6..99117e0b 100644
--- a/sg_sat_identify.c
+++ b/sg_sat_identify.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Douglas Gilbert.
+ * Copyright (c) 2006-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,9 +47,9 @@
#define SAT_ATA_PASS_THROUGH16 0x85
#define SAT_ATA_PASS_THROUGH16_LEN 16
-#define SAT_ATA_PASS_THROUGH12 0xa1
+#define SAT_ATA_PASS_THROUGH12 0xa1 /* clashes with MMC BLANK comand */
#define SAT_ATA_PASS_THROUGH12_LEN 12
-#define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) descriptor */
+#define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */
#define ATA_IDENTIFY_DEVICE 0xec
#define ATA_IDENTIFY_PACKET_DEVICE 0xa1
@@ -59,7 +59,7 @@
#define EBUFF_SZ 256
-static char * version_str = "1.02 20061015";
+static char * version_str = "1.03 20070130";
static struct option long_options[] = {
{"chk_cond", 0, 0, 'c'},
@@ -76,22 +76,23 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_sat_identify [--chk_cond] [--help] [--hex] [--len=<n>] "
+ "sg_sat_identify [--chk_cond] [--help] [--hex] [--len=16|12] "
"[--packet]\n"
" [--raw] [--verbose] [--version] "
- "<device>\n"
+ "DEVICE\n"
" where:\n"
- " --chk_cond|-c sets chk_cond bit in cdb (def: 0)\n"
- " --help|-h print out usage message then exit\n"
- " --hex|-H output response in hex\n"
- " --len=<n>|-l <n> cdb length, 12 or 16 bytes (default: 16)\n"
- " --packet|-p do IDENTIFY PACKET DEVICE (def: IDENTIFY "
+ " --chk_cond|-c sets chk_cond bit in cdb (def: 0)\n"
+ " --help|-h print out usage message then exit\n"
+ " --hex|-H output response in hex\n"
+ " --len=16|12 | -l 16|12 cdb length: 16 or 12 bytes "
+ "(default: 16)\n"
+ " --packet|-p do IDENTIFY PACKET DEVICE (def: IDENTIFY "
"DEVICE) command\n"
- " --raw|-r output response in binary to stdout\n"
- " --verbose|-v increase verbosity\n"
- " --version|-V print version string and exit\n\n"
- "Performs a IDENTIFY (PACKET) DEVICE ATA command via a SAT "
- "pass through\n");
+ " --raw|-r output response in binary to stdout\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Performs a ATA IDENTIFY (PACKET) DEVICE command via a SAT "
+ "layer\n");
}
static void dStrRaw(const char* str, int len)
@@ -182,8 +183,8 @@ static int do_identify_dev(int sg_fd, int do_packet, int cdb_len,
if ((0x0 == ssh.asc) && (0x1d == ssh.ascq)) {
if (SAT_ATA_RETURN_DESC != ata_return_desc[0]) {
if (verbose)
- fprintf(stderr, "did not find ATA return sense "
- "descriptor\n");
+ fprintf(stderr, "did not find ATA Return "
+ "(sense) Descriptor\n");
return SG_LIB_CAT_RECOVERED;
}
got_ard = 1;
diff --git a/sg_scan.8 b/sg_scan.8
index 126ca972..81da76c5 100644
--- a/sg_scan.8
+++ b/sg_scan.8
@@ -1,51 +1,52 @@
-.TH SG_SCAN "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_SCAN "8" "December 2006" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_scan \- does a scan of sg devices (or given SCSI/ATAPI/ATA devices) and
prints the results
.SH SYNOPSIS
.B sg_scan
-[\fI-a\fR]
-[\fI-i\fR]
-[\fI-n\fR]
-[\fI-w\fR]
-[\fI-x\fR]
-[\fI<sam_dev>\fR]*
+[\fI\-a\fR]
+[\fI\-i\fR]
+[\fI\-n\fR]
+[\fI\-w\fR]
+[\fI\-x\fR]
+[\fIDEVICE\fR]*
.SH DESCRIPTION
.\" Add any additional description here
.PP
-If no <sam_dev> device names are given, sg_scan does a scan of the sg
+If no \fIDEVICE\fR names are given, sg_scan does a scan of the sg
devices and outputs a line of information for each sg device that is
-currently bound to a SCSI device. Once any <sam_dev> is given only the
-given <sam_dev>s are scanned.
-Devices are opened with the O_NONBLOCK flag so that the scan will
+currently bound to a SCSI device. If one or more \fIDEVICE\fRs are given
+only those devices are scanned.
+Each device is opened with the O_NONBLOCK flag so that the scan will
not "hang" on any device that another process holds an O_EXCL lock on.
.PP
-Any given <sam_devs> device names are expected to comply
+Any given \fIDEVICE\fR name is expected to comply
with (to some extent) the Storage Architecture Model (SAM see www.t10.org).
Any device names associated with the Linux SCSI subsystem (e.g. /dev/sda
and /dev/st0m) are suitable. Devices names associated with ATAPI
devices (e.g. most CD/DVD drives and ATAPI tape drives) are also suitable.
If the device does not fall into the above categories then an ATA
IDENTIFY command is tried.
+.SH OPTIONS
.TP
--a
+\fB\-a\fR
do alphabetical scan (i.e. sga, sgb, sgc). Note that sg device nodes with
an alphabetical index have been deprecated since the linux kernel 2.2
series.
.TP
--i
+\fB\-i\fR
do a SCSI INQUIRY, output results in a second (indented) line. If the device
is an ATA disk then output information from an ATA IDENTIFY command
.TP
--n
+\fB\-n\fR
do numeric scan (i.e. sg0, sg1...) [default]
.TP
--w
-use a read/write flag when opening sg device (default is read-only)
+\fB\-w\fR
+use a read/write flag when opening sg device (default is read\-only)
.TP
--x
+\fB\-x\fR
extra information output about queuing
-.PP
+.SH NOTES
This utility was written at a time when hotplugging of SCSI devices
was not supported in Linux. It used a simple algorithm to scan sg
device nodes in ascending numeric or alphabetical order, stopping
@@ -64,7 +65,7 @@ the sg3_utils(8) man page.
.SH AUTHORS
Written by D. Gilbert and F. Jansen
.SH COPYRIGHT
-Copyright \(co 1999-2006 Douglas Gilbert
+Copyright \(co 1999\-2006 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_scan.8l b/sg_scan.8l
index 126ca972..81da76c5 100644
--- a/sg_scan.8l
+++ b/sg_scan.8l
@@ -1,51 +1,52 @@
-.TH SG_SCAN "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_SCAN "8" "December 2006" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_scan \- does a scan of sg devices (or given SCSI/ATAPI/ATA devices) and
prints the results
.SH SYNOPSIS
.B sg_scan
-[\fI-a\fR]
-[\fI-i\fR]
-[\fI-n\fR]
-[\fI-w\fR]
-[\fI-x\fR]
-[\fI<sam_dev>\fR]*
+[\fI\-a\fR]
+[\fI\-i\fR]
+[\fI\-n\fR]
+[\fI\-w\fR]
+[\fI\-x\fR]
+[\fIDEVICE\fR]*
.SH DESCRIPTION
.\" Add any additional description here
.PP
-If no <sam_dev> device names are given, sg_scan does a scan of the sg
+If no \fIDEVICE\fR names are given, sg_scan does a scan of the sg
devices and outputs a line of information for each sg device that is
-currently bound to a SCSI device. Once any <sam_dev> is given only the
-given <sam_dev>s are scanned.
-Devices are opened with the O_NONBLOCK flag so that the scan will
+currently bound to a SCSI device. If one or more \fIDEVICE\fRs are given
+only those devices are scanned.
+Each device is opened with the O_NONBLOCK flag so that the scan will
not "hang" on any device that another process holds an O_EXCL lock on.
.PP
-Any given <sam_devs> device names are expected to comply
+Any given \fIDEVICE\fR name is expected to comply
with (to some extent) the Storage Architecture Model (SAM see www.t10.org).
Any device names associated with the Linux SCSI subsystem (e.g. /dev/sda
and /dev/st0m) are suitable. Devices names associated with ATAPI
devices (e.g. most CD/DVD drives and ATAPI tape drives) are also suitable.
If the device does not fall into the above categories then an ATA
IDENTIFY command is tried.
+.SH OPTIONS
.TP
--a
+\fB\-a\fR
do alphabetical scan (i.e. sga, sgb, sgc). Note that sg device nodes with
an alphabetical index have been deprecated since the linux kernel 2.2
series.
.TP
--i
+\fB\-i\fR
do a SCSI INQUIRY, output results in a second (indented) line. If the device
is an ATA disk then output information from an ATA IDENTIFY command
.TP
--n
+\fB\-n\fR
do numeric scan (i.e. sg0, sg1...) [default]
.TP
--w
-use a read/write flag when opening sg device (default is read-only)
+\fB\-w\fR
+use a read/write flag when opening sg device (default is read\-only)
.TP
--x
+\fB\-x\fR
extra information output about queuing
-.PP
+.SH NOTES
This utility was written at a time when hotplugging of SCSI devices
was not supported in Linux. It used a simple algorithm to scan sg
device nodes in ascending numeric or alphabetical order, stopping
@@ -64,7 +65,7 @@ the sg3_utils(8) man page.
.SH AUTHORS
Written by D. Gilbert and F. Jansen
.SH COPYRIGHT
-Copyright \(co 1999-2006 Douglas Gilbert
+Copyright \(co 1999\-2006 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_scan.8w b/sg_scan.8w
index 3a4ec728..1ce68e35 100644
--- a/sg_scan.8w
+++ b/sg_scan.8w
@@ -1,10 +1,11 @@
-.TH SG_SCAN "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_SCAN "8" "December 2006" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_scan \- scan scsi devices, volume names, physical drives,
cdrom/dvd drives and tapes and show relationships
.SH SYNOPSIS
.B sg_scan
-[\fI--help\fR] [\fI--letter=<vl>\fR] [\fI--verbose\fR] [\fI--version\fR]
+[\fI\-\-help\fR] [\fI\-\-letter=VL\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -21,7 +22,7 @@ starting at 0 allocated in ascending order as devices are discovered (and
sometimes rediscovered).
.PP
Then there is a lower level device name which starts with a SCSI (pseudo)
-adapter name of the form "SCSI<n>:". To this is added sub-addressing
+adapter name of the form "SCSI<n>:". To this is added sub\-addressing
in the form of a "bus" number, a "target" identifier and a lun (logical
unit number). The "bus" number is also known as a "PathId". These
components are combined by the utility to make a device name of the
@@ -49,8 +50,8 @@ the "scsi" device name or blanks if there is none. Next follows the volume
letter (if any) optionally followed by a "+" to indicate more volume letters
map to this device. Next is one of the class device names or blanks followed
by a concatenation of the INQUIRY response strings. Windows often
-manufactures INQUIRY response strings for non-SCSI devices (e.g. a parallel
-ATA disk at "C:") and doesn't quite obey the SCSI-2 rules for an INQUIRY
+manufactures INQUIRY response strings for non\-SCSI devices (e.g. a parallel
+ATA disk at "C:") and doesn't quite obey the SCSI\-2 rules for an INQUIRY
response. If this utility sees that it places a "*" after the INQUIRY
response strings.
.PP
@@ -61,26 +62,27 @@ An educated guess could be made but could be tricked, for example,
by two USB sticks with the same model and manufacturer.
.PP
For more information see the NOTES section below.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
outputs the usage message summarizing command line options
then exits.
.TP
---letter=<vl> | -l <vl>
+\fB\-l\fR, \fB\-\-letter\fR=\fIVL\fR
normally when a device a multiple volume names (e.g. a disk with two
partitions recognized by Windows) then the lowest letter volume name in
alphabetical order is output, followed by a "+". Hence subsequent matching
volume letters are not shown. If the user is interested in a particular
-volume name then its letter can be given as the "<vl>" argument and if
+volume name then its letter can be given as the \fIVL\fR argument and if
found it will be output rather than the lowest volume name.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increases the level or verbosity.
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print out version string
.SH NOTES
-.PP
This utility uses the SCSI Pass Through (direct) [SPT] interface rather
than Adaptec's ASPI32. ASPI32 requires a dll not distributed with
Windows. Using the SPT interface requires that a user has administrative
@@ -89,19 +91,19 @@ earlier Windows operating systems). The target Windows operating systems
are currently Windows 2000, 2003 and XP (and their variants).
.PP
If no class device name is found then "pdt=<num>" is placed at the end
-of the line. This is the SCSI "peripheral device type" (see SPC-4 at
-http://www.t10.org). Some values are: 0 -> disks, 1 -> tapes, 3 ->
-processor, 5 -> cd/dvds, 8 -> medium changers, 13 -> SES devices.
+of the line. This is the SCSI "peripheral device type" (see SPC\-4 at
+http://www.t10.org). Some values are: 0 \-> disks, 1 \-> tapes, 3 \->
+processor, 5 \-> cd/dvds, 8 \-> medium changers, 13 \-> SES devices.
.PP
The DOS device names given the the CreateFile() call all start with a "\\.\"
string. That can be given but if not will be supplied automatically. For
the SCSI lower level interface the adapter name (e.g. "SCSI2:") is given
-to the CreateFile() call and the sub-addressing (i.e. bus, target and lun)
+to the CreateFile() call and the sub\-addressing (i.e. bus, target and lun)
is given to each SCSI pass through command.
.PP
Scanning devices that are hot unplugged and replugged often can be
problematic, especially with the class device names. Each time a device is
-removed and re-added it gets a larger class device name (e.g. "PD3"
+removed and re\-added it gets a larger class device name (e.g. "PD3"
becomes "PD4" leaving "PD3" unused). This utility stops scanning class
devices after it find 8 consecutive "holes". If this turns out to be a
problem then adjustments will be made.
diff --git a/sg_scan.c b/sg_scan.c
index a8d8c817..9676b9b8 100644
--- a/sg_scan.c
+++ b/sg_scan.c
@@ -3,7 +3,9 @@
*/
#ifdef SG3_UTILS_LINUX
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -23,7 +25,7 @@
/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg")
device driver.
-* Copyright (C) 1999 - 2006 D. Gilbert
+* Copyright (C) 1999 - 2007 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)
@@ -47,7 +49,7 @@
F. Jansen - modification to extend beyond 26 sg devices.
*/
-static char * version_str = "4.08 20060623";
+static char * version_str = "4.09 20070125";
#define ME "sg_scan: "
@@ -92,17 +94,17 @@ static unsigned char inqCmdBlk[INQ_CMD_LEN] =
void usage()
{
- printf("Usage: 'sg_scan [-a] [-i] [-n] [-v] [-V] [-w] [-x] "
- "[<sam_dev>]*'\n");
- printf(" where: -a do alpha scan (ie sga, sgb, sgc)\n");
- printf(" -i do SCSI INQUIRY, output results\n");
- printf(" -n do numeric scan (ie sg0, sg1...) [default]\n");
- printf(" -v increase verbosity\n");
- printf(" -V output version string then exit\n");
- printf(" -w force open with read/write flag\n");
- printf(" -x extra information output about queuing\n");
- printf(" <sam_dev> name of device that understands SAM command"
- " set\n");
+ printf("Usage: sg_scan [-a] [-i] [-n] [-v] [-V] [-w] [-x] "
+ "[DEVICE]*\n");
+ printf(" where:\n");
+ printf(" -a do alpha scan (ie sga, sgb, sgc)\n");
+ printf(" -i do SCSI INQUIRY, output results\n");
+ printf(" -n do numeric scan (ie sg0, sg1...) [default]\n");
+ printf(" -v increase verbosity\n");
+ printf(" -V output version string then exit\n");
+ printf(" -w force open with read/write flag\n");
+ printf(" -x extra information output about queuing\n");
+ printf(" DEVICE name of device\n");
}
static int scandir_select(const struct dirent * s)
@@ -190,7 +192,7 @@ int main(int argc, char * argv[])
const char * cp;
struct stat a_stat;
- if ((gen_index_arr = malloc(max_file_args * sizeof(int))))
+ if ((gen_index_arr = (int *)malloc(max_file_args * sizeof(int))))
memset(gen_index_arr, 0, max_file_args * sizeof(int));
else {
printf(ME "Out of memory\n");
@@ -649,8 +651,8 @@ int try_ata_identity(const char * file_namep, int ata_fd, int do_inq)
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <string.h>
-#include <errno.h>
#include <ctype.h>
#include <getopt.h>
@@ -668,7 +670,7 @@ int try_ata_identity(const char * file_namep, int ata_fd, int do_inq)
#define INQUIRY_CMD 0x12
#define INQUIRY_CMDLEN 6
-static char * version_str = "1.01 (win32) 20061014";
+static char * version_str = "1.04 (win32) 20070101";
struct w_scsi_elem {
char in_use;
@@ -692,7 +694,7 @@ struct w_scsi_elem {
unsigned char inq_resp[SCSI2_INQ_RESP_LEN];
};
-static struct w_scsi_elem w_scsi_arr[MAX_SCSI_ELEMS];
+static struct w_scsi_elem * w_scsi_arr;
static int next_unused_scsi_elem = 0;
static int next_elem_after_scsi_adapter_valid = 0;
@@ -709,10 +711,11 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr,
- "Usage: sg_scan [--help] [--verbose] [--version]\n");
+ "Usage: sg_scan [--help] [--letter=VL] [--verbose] "
+ "[--version]\n");
fprintf(stderr,
" --help|-h output this usage message then exit\n"
- " --letter=<vl>|-l <vl> volume letter (e.g. 'F' for F:) "
+ " --letter=VL|-l VL volume letter (e.g. 'F' for F:) "
"to find\n"
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
@@ -886,10 +889,13 @@ static int sg_do_wscan(char letter, int verbose)
sep->dubious_scsi = 1;
if (verbose > 1) {
- fprintf(stderr, "%s: PathId=%d TargetId=%d Lun=%d ",
- adapter_name, pid->PathId, pid->TargetId, pid->Lun);
- fprintf(stderr, " DeviceClaimed=%d\n", pid->DeviceClaimed);
- dStrHex((const char *)(pid->InquiryData), pid->InquiryDataLength, 0);
+ fprintf(stderr, "%s: PathId=%d TargetId=%d "
+ "Lun=%d ", adapter_name, pid->PathId,
+ pid->TargetId, pid->Lun);
+ fprintf(stderr, " DeviceClaimed=%d\n",
+ pid->DeviceClaimed);
+ dStrHex((const char *)(pid->InquiryData),
+ pid->InquiryDataLength, 0);
}
off = pid->NextInquiryDataOffset;
}
@@ -921,8 +927,8 @@ static int sg_do_wscan(char letter, int verbose)
OPEN_EXISTING, 0, NULL);
if (fh != INVALID_HANDLE_VALUE) {
success = DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS,
- NULL, 0, inqDataBuff, sizeof(inqDataBuff),
- &dummy, FALSE);
+ NULL, 0, inqDataBuff,
+ sizeof(inqDataBuff), &dummy, FALSE);
if (success) {
PSCSI_ADDRESS pa;
@@ -967,7 +973,8 @@ static int sg_do_wscan(char letter, int verbose)
if (verbose > 1) {
err = GetLastError();
fprintf(stderr, "%c: IOCTL_SCSI_GET_ADDRESS err=%lu\n\t"
- "%s", 'C' + k, err, get_err_str(err, sizeof(b), b));
+ "%s", 'C' + k, err,
+ get_err_str(err, sizeof(b), b));
}
}
if (fetchInquiry(fh, inqResp, sizeof(inqResp), &sptdw,
@@ -1008,15 +1015,16 @@ static int sg_do_wscan(char letter, int verbose)
for (k = 0; k < MAX_PHYSICALDRIVE_NUM; ++k) {
matched = 0;
sep = NULL;
- snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\PhysicalDrive%d", k);
+ snprintf(adapter_name, sizeof (adapter_name),
+ "\\\\.\\PhysicalDrive%d", k);
fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (fh != INVALID_HANDLE_VALUE) {
hole_count = 0;
success = DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS,
- NULL, 0, inqDataBuff, sizeof(inqDataBuff),
- &dummy, FALSE);
+ NULL, 0, inqDataBuff,
+ sizeof(inqDataBuff), &dummy, FALSE);
if (success) {
PSCSI_ADDRESS pa;
@@ -1111,8 +1119,8 @@ static int sg_do_wscan(char letter, int verbose)
if (fh != INVALID_HANDLE_VALUE) {
hole_count = 0;
success = DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS,
- NULL, 0, inqDataBuff, sizeof(inqDataBuff),
- &dummy, FALSE);
+ NULL, 0, inqDataBuff,
+ sizeof(inqDataBuff), &dummy, FALSE);
if (success) {
PSCSI_ADDRESS pa;
@@ -1150,8 +1158,9 @@ static int sg_do_wscan(char letter, int verbose)
} else {
if (verbose > 1) {
err = GetLastError();
- fprintf(stderr, "CDROM%d: IOCTL_SCSI_GET_ADDRESS err=%lu\n\t"
- "%s", k, err, get_err_str(err, sizeof(b), b));
+ fprintf(stderr, "CDROM%d: IOCTL_SCSI_GET_ADDRESS "
+ "err=%lu\n\t%s", k, err,
+ get_err_str(err, sizeof(b), b));
}
}
if (fetchInquiry(fh, inqResp, sizeof(inqResp), &sptdw,
@@ -1207,8 +1216,8 @@ static int sg_do_wscan(char letter, int verbose)
if (fh != INVALID_HANDLE_VALUE) {
hole_count = 0;
success = DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS,
- NULL, 0, inqDataBuff, sizeof(inqDataBuff),
- &dummy, FALSE);
+ NULL, 0, inqDataBuff,
+ sizeof(inqDataBuff), &dummy, FALSE);
if (success) {
PSCSI_ADDRESS pa;
@@ -1343,7 +1352,7 @@ static int sg_do_wscan(char letter, int verbose)
int main(int argc, char * argv[])
{
- int c;
+ int c, ret;
int verbose = 0;
int vol_letter = 0;
@@ -1391,7 +1400,12 @@ int main(int argc, char * argv[])
}
}
- return sg_do_wscan(vol_letter, verbose);
+ w_scsi_arr = malloc(sizeof(struct w_scsi_elem) * MAX_SCSI_ELEMS);
+
+ ret = sg_do_wscan(vol_letter, verbose);
+
+ free(w_scsi_arr);
+ return ret;
}
#endif
diff --git a/sg_senddiag.8 b/sg_senddiag.8
index 009dad66..c04767ab 100644
--- a/sg_senddiag.8
+++ b/sg_senddiag.8
@@ -1,154 +1,241 @@
-.TH SG_SENDDIAG "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_SENDDIAG "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_senddiag \- performs a SCSI SEND DIAGNOSTIC command
.SH SYNOPSIS
.B sg_senddiag
-[\fI-doff\fR] [\fI-e\fR] [\fI-h\fR] [\fI-H\fR] [\fI-l\fR] [\fI-pf\fR]
-[\fI-raw=<h>,<h>... | -raw=-\fR]
-[\fI-s=<self_test_code>\fR] [\fI-t\fR] [\fI-uoff\fR] [\fI-v\fR]
-[\fI-V\fR] [\fI-?\fR] \fI<scsi_device>\fR
+[\fI\-\-doff\fR] [\fI\-\-extdur\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR]
+[\fI\-\-list\fR] [\fI\-\-pf\fR] [\fI\-\-raw=H,H...\fR] [\fI\-\-raw=\-\fR]
+[\fI\-\-selftest=ST\fR] [\fI\-\-test\fR] [\fI\-\-uoff\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.PP
+.B sg_senddiag
+[\fI\-doff\fR] [\fI\-e\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-l\fR] [\fI\-pf\fR]
+[\fI\-raw=H,H...\fR] [\fI\-raw=\-\fR] [\fI\-s=ST\fR] [\fI\-t\fR]
+[\fI\-uoff\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-This utility sends a SEND DIAGNOSTIC SCSI command to the given device.
-It can issue self tests, find supported diagnostic pages or
-send arbitrary diagnostic pages.
+This utility sends a SCSI SEND DIAGNOSTIC command to the \fIDEVICE\fR. It
+can issue self-tests, find supported diagnostic pages or send arbitrary
+diagnostic pages.
.PP
-When the '-l' option and a <scsi_device> are given then the utility
-sends a RECEIVE DIAGNOSTIC RESULTS SCSI command to fetch the response (i.e.
+When the \fI\-\-list\fR option and a \fIDEVICE\fR are given then the utility
+sends a SCSI RECEIVE DIAGNOSTIC RESULTS command to fetch the response (i.e.
the page numbers of supported diagnostic pages).
.PP
-When the '-l' option is given without a <scsi_device> then a
-list of diagnostic page names and their numbers, known by this
-utility, are listed.
+When the \fI\-\-list\fR option is given without a \fIDEVICE\fR then a list of
+diagnostic page names and their numbers, known by this utility, are listed.
+.PP
+This utility supports two command line syntaxes, the preferred one is
+shown first in the synopsis and explained in this section. A later section
+on the old command line syntax outlines the second group of options.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
--doff
+\fB\-d\fR, \fB\-\-doff\fR
set the Device Offline (DevOffL) bit (default is clear). Only significant
-when '-t' option is set for the default self test. When set other operations
-on any logical units controlled by the this device server (target) may be
-affected (delayed) while a default self test is underway.
+when \fI\-\-test\fR option is set for the default self-test. When set other
+operations on any logical units controlled by the this device server (target)
+may be affected (delayed) while a default self-test is underway.
.TP
--e
-outputs the expected extended self test duration. The duration
-is given in seconds (and minutes in parentheses). This figure is obtained
-from mode page 0xa (control page).
+\fB\-e\fR, \fB\-\-extdur\fR
+outputs the expected extended self-test duration. The duration is given in
+seconds (and minutes in parentheses). This figure is obtained from mode page
+0xa (i.e. the control mode page).
.TP
--h
-outputs response from RECEIVE DIAGNOSTIC RESULTS in hex rather than decode
-it.
+\fB\-h\fR, \fB\-\-help\fR
+print usage message then exit.
.TP
--H
+\fB\-H\fR, \fB\-\-hex\fR
outputs response from RECEIVE DIAGNOSTIC RESULTS in hex rather than decode it.
.TP
--l
-when a <scsi_device> is also given lists the names of all diagnostic
-pages supported by this device. The request is sent via a SEND DIAGNOSTIC
-command (with the "pf" bit set) and the response is fetched by a RECEIVE
-DIAGNOSTIC RESULTS command. When used in the absence of a <scsi_device>
+\fB\-l\fR, \fB\-\-list\fR
+when a \fIDEVICE\fR is also given lists the names of all diagnostic pages
+supported by this device. The request is sent via a SEND DIAGNOSTIC
+command (with the "pF" bit set) and the response is fetched by a RECEIVE
+DIAGNOSTIC RESULTS command. When used in the absence of a \fI\-\-list\fR
argument then a list of diagnostic page names and their numbers, known
by this utility, are listed.
.TP
--pf
-set Page Format (PF) bit. By default it is clear (i.e. 0) unless
-the list ('-l') option is given in which case the Page Format
-bit is set (as required by SPC-3).
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
+.TP
+\fB\-p\fR, \fB\-\-pf\fR
+set Page Format (PF) bit. By default it is clear (i.e. 0) unless the
+list \fI\-\-list\fR option is given in which case the Page Format
+bit is set (as required by SPC\-3).
.TP
--raw=<h>,<h>...
+\fB\-r\fR, \fB\-\-raw\fR=\fIH,H...\fR
string of comma separated hex numbers each of which should resolve to
a byte value (i.e. 0 to ff inclusive). This sequence forms a diagnostic
-page to be sent with the SEND DIAGNOSTIC SCSI command. Mostly likely
-the '-pf' option should also be given.
+page to be sent with the SCSI SEND DIAGNOSTIC command. Mostly likely
+the \fI\-\-pf\fR option should also be given.
.TP
--raw=-
+\fB\-r\fR, \fB\-\-raw=\-\fR
reads sequence of bytes from stdin. The sequence may be comma, space, tab
or linefeed (newline) separated. If a line contains "#" then the remaining
characters on that line are ignored. Otherwise each non separator character
should resolve to a byte value (i.e. 0 to ff inclusive). This sequence forms
-a diagnostic page to be sent with the SEND DIAGNOSTIC SCSI command. Mostly
-likely the '-pf' option should also be given.
+a diagnostic page to be sent with the SCSI SEND DIAGNOSTIC command. Mostly
+likely the \fI\-\-pf\fR option should also be given.
.TP
--s=<self_test_code>
-the default value is 0 which is inactive. A value of 1 selects a background
-short self test; 2 selects a background extended self test; 5 selects a
-foreground short self test; 6 selects a foreground extended test. A value
-of 4 will abort a (background) self test that is in progress. This
-option is mutually exclusive with default self test (i.e. '-t').
+\fB\-s\fR, \fB\-\-selftest\fR=\fIST\fR
+where \fIST\fR is the self-test code. The default value is 0 which is
+inactive. A value of 1 selects a background short self-test; 2 selects a
+background extended self-test; 5 selects a foreground short self-test; 6
+selects a foreground extended test. A value of 4 will abort a (background)
+self-test that is in progress. This option is mutually exclusive with
+default self-test (i.e. \fI\-\-test\fR).
.TP
--t
+\fB\-t\fR, \fB\-\-test\fR
sets the _default_ Self Test (SelfTest) bit. By default this is clear (0).
-The '-s=<num>' option should not be active together with this option.
-Both the '-doff' and/or '-uoff' options can be used with this option.
+The \fI\-\-selftest=ST\fR option should not be active together with this
+option. Both the \fI\-\-doff\fR and/or \fI\-\-uoff\fR options can be used
+with this option.
.TP
--uoff
+\fB\-u\fR, \fB\-\-uoff\fR
set the Unit Offline (UnitOffL) bit (default is clear). Only significant
-when '-t' option is set for the default self test. When set other operations
-on this logical unit may be affected (delayed) while a default self test
-is underway. Some devices (e.g. Fujitsu disks) do more tests when this
-bit is set.
+when \fI\-\-test\fR option is set for the default self-test. When set other
+operations on this logical unit may be affected (delayed) while a default
+self-test is underway. Some devices (e.g. Fujitsu disks) do more tests
+when this bit is set.
.TP
--v
-increase level of verbosity: print out SCSI commands in hex prior to
-sending them to the device.
+\fB\-v\fR, \fB\-\-verbose\fR
+increase level of verbosity. Can be used multiple times.
.TP
--V
+\fB\-V\fR, \fB\-\-version\fR
print out version string then exit.
-.TP
--?
-output usage message. Ignore all other parameters.
-.PP
-All devices should support the default self test. The 'short' self test
-codes should complete in 2 minutes or less. The 'extended' self test
-codes' maximum duration is vendor specific (e.g. a little over 10
-minutes with my disks). The foreground self test codes wait until they
-are completed while the background self test codes return immediately.
-The results of both foreground and background self test codes are
-placed in the 'self test results' log page (see sg_logs). The SCSI command
-timeout for this utility is set to 60 minutes to allow for slow foreground
-extended self tests.
+.SH NOTES
+All devices should support the default self-test. The 'short' self-test
+codes should complete in 2 minutes or less. The 'extended' self-test
+codes' maximum duration is vendor specific (e.g. a little over 10 minutes
+with the author's disks). The foreground self-test codes wait until they
+are completed while the background self-test codes return immediately. The
+results of both foreground and background self-test codes are placed in
+the 'self-test results' log page (see sg_logs). The SCSI command timeout
+for this utility is set to 60 minutes to allow for slow foreground extended
+self-tests.
.PP
-If the given device is a disk then no file systems residing on that disk
-should be mounted during a foreground self test. The reason is that
-other SCSI commands may become queued behind the foreground self test and
-timeout.
+If the \fIDEVICE\fR is a disk then no file systems residing on that disk
+should be mounted during a foreground self-test. The reason is that other
+SCSI commands may become queued behind the foreground self-test and timeout.
.PP
-When the '-raw=' option is given then self tests should not be
-selected. However the '-pf' (i.e. "page format") option should be given.
-The length of the diagnostic page to be sent is derived from the number
-of bytes given to the '-raw=' option. The diagnostic page code (number)
-should be the first byte of the sequence (i.e. as dictated by SPC-3
-diagnostic page format). The SAS 1.1 protocol specific diagnostic page
-could be sent with this option, for example. The examples subdirectory
-in the sg3_utils packages contains two example scripts that turn on
-the CJTPAT (jitter pattern) on some SAS disks (one script for each phy).
-One possible invocation
-is: 'sg_senddiag -pf -raw=- /dev/sg2 < .../sdiag_sas_p1_cjtpat.txt'
+When the \fI\-\-raw=H,H...\fR option is given then self-tests should not
+be selected. However the \fB\-\-pf\fR (i.e. "page format") option should be
+given. The length of the diagnostic page to be sent is derived from the
+number of bytes given to the \fI\-\-raw=H,H...\fR option. The diagnostic
+page code (number) should be the first byte of the sequence (i.e. as
+dictated by SPC\-3 diagnostic page format). The SAS 1.1 protocol specific
+diagnostic page could be sent with this option, for example. The examples
+subdirectory in the sg3_utils packages contains two example scripts that
+turn on the CJTPAT (jitter pattern) on some SAS disks (one script for each
+phy). One possible invocation
+is: 'sg_senddiag \-\-pf \-\-raw=\- /dev/sg2 < .../sdiag_sas_p1_cjtpat.txt'
.PP
Arbitrary diagnostic pages can be read (in hex) with the sg_ses
-utility (not only those defined in SES-2).
+utility (not only those defined in SES\-2).
.PP
If the utility is used with no options (e.g. "sg_senddiag /dev/sg1")
-Then a degenerate SEND DIAGNOSTIC SCSI command is sent with zero
+Then a degenerate SCSI SEND DIAGNOSTIC command is sent with zero
in all its fields apart from the opcode. Some devices report this
as an error while others ignore it. It is not entirely clear from
-SPC-3 if it is invalid to send such a command.
+SPC\-3 if it is invalid to send such a command.
.PP
-In the 2.4 series of Linux kernels the given device must be
-a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example 'sg_senddiag -t /dev/sda'
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI
+generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks and
+DVD drives) can also be specified. For example 'sg_senddiag \-t /dev/sda'
will work in the 2.6 series kernels.
.PP
To access SCSI enclosures see the sg_ses utility. sg_ses uses the
-SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS SCSI commands as outlined
-in the SES-2 (draft) standard.
+SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS commands as outlined
+in the SES\-2 (draft) standard.
.SH EXIT STATUS
The exit status of sg_senddiag is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using '\-\-old' (or '\-O) as the first option.
+.TP
+\fB\-doff\fR
+set the Device Offline (DevOffL) bit (default is clear). Only significant
+when \fI\-t\fR option is set for the default self-test. Equivalent to
+\fI\-\-doff\fR in the main description.
+.TP
+\fB\-e\fR
+outputs the expected extended self-test duration. Equivalent to
+\fI\-\-extdur\fR in the main description.
+.TP
+\fB\-h\fR
+outputs response from RECEIVE DIAGNOSTIC RESULTS in hex rather than decode
+it.
+.TP
+\fB\-H\fR
+outputs response from RECEIVE DIAGNOSTIC RESULTS in hex rather than decode it.
+.TP
+\fB\-l\fR
+when a \fIDEVICE\fR is also given lists the names of all diagnostic
+pages supported by this device. The request is sent via a SEND DIAGNOSTIC
+command (with the "pf" bit set) and the response is fetched by a RECEIVE
+DIAGNOSTIC RESULTS command. When used in the absence of a \fIDEVICE\fR
+argument then a list of diagnostic page names and their numbers, known
+by this utility, are listed.
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-pf\fR
+set Page Format (PF) bit. By default it is clear (i.e. 0) unless
+the \fI\-l\fR option is given in which case the Page Format bit is set
+(as required by SPC\-3).
+.TP
+\fB\-raw\fR=\fIH,H...\fR
+string of comma separated hex numbers each of which should resolve to
+a byte value (i.e. 0 to ff inclusive). This sequence forms a diagnostic
+page to be sent with the SCSI SEND DIAGNOSTIC command. Mostly likely
+the \fI\-pf\fR option should also be given.
+.TP
+\fB\-raw=-\fR
+reads sequence of bytes from stdin. The sequence may be comma, space, tab
+or linefeed (newline) separated. If a line contains "#" then the remaining
+characters on that line are ignored. Otherwise each non separator character
+should resolve to a byte value (i.e. 0 to ff inclusive). This sequence forms
+a diagnostic page to be sent with the SCSI SEND DIAGNOSTIC command. Mostly
+likely the \fI\-pf\fR option should also be given.
+.TP
+\fB\-s\fR=\fIST\fR
+where \fIST\fR is the self-test code. The default value is 0 which is
+inactive. A value of 1 selects a background short self-test; 2 selects
+a background extended self-test; 5 selects a foreground short self-test;
+6 selects a foreground extended test. A value of 4 will abort
+a (background) self-test that is in progress. This option is mutually
+exclusive with default self-test (i.e. \fI\-t\fR).
+.TP
+\fB\-t\fR
+sets the _default_ Self Test (SelfTest) bit. By default this is clear (0).
+The \fI\-s=ST\fR option should not be active together with this option.
+Both the \fI\-doff\fR and/or \fI\-uoff\fR options can be used with this
+option.
+.TP
+\fB\-uoff\fR
+set the Unit Offline (UnitOffL) bit (default is clear). Equivalent to
+\fI\-\-uoff\fR in the main description.
+.TP
+\fB\-v\fR
+increase level of verbosity. Can be used multiple times.
+.TP
+\fB\-V\fR
+print out version string then exit.
+.TP
+\fB\-?\fR
+output usage message. Ignore all other parameters.
.SH AUTHOR
Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2003-2006 Douglas Gilbert
+Copyright \(co 2003\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_senddiag.c b/sg_senddiag.c
index 6c596167..1b354219 100644
--- a/sg_senddiag.c
+++ b/sg_senddiag.c
@@ -4,13 +4,14 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <getopt.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
/* A utility program for the Linux OS SCSI generic ("sg") device driver.
-* Copyright (C) 2003-2006 D. Gilbert
+* Copyright (C) 2003-2007 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)
@@ -20,12 +21,324 @@
the SCSI RECEIVE DIAGNOSTIC command to list supported diagnostic pages.
*/
-static char * version_str = "0.31 20061012";
+static char * version_str = "0.34 20070127";
#define ME "sg_senddiag: "
#define MX_ALLOC_LEN (1024 * 4)
+static struct option long_options[] = {
+ {"doff", 0, 0, 'd'},
+ {"extdur", 0, 0, 'e'},
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"list", 0, 0, 'l'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"pf", 0, 0, 'p'},
+ {"raw", 1, 0, 'r'},
+ {"selftest", 1, 0, 's'},
+ {"test", 0, 0, 't'},
+ {"uoff", 0, 0, 'u'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+struct opts_t {
+ int do_doff;
+ int do_extdur;
+ int do_help;
+ int do_hex;
+ int do_list;
+ int do_pf;
+ int do_raw;
+ int do_selftest;
+ int do_deftest;
+ int do_uoff;
+ int do_verbose;
+ int do_version;
+ const char * device_name;
+ const char * raw_arg;
+ int opt_new;
+};
+
+static void usage()
+{
+ printf("Usage: sg_senddiag [--doff] [--extdur] [--help] [--hex] "
+ "[--list] [--pf]\n"
+ " [--raw=H,H...] [--selftest=ST] "
+ "[--test] [--uoff]\n"
+ " [--verbose] [--version] "
+ "[DEVICE]\n"
+ " where:\n"
+ " --doff|-d device online (def: 0, only with '--test')\n"
+ " --extdur|-e duration of an extended self-test (from mode "
+ "page 0xa)\n"
+ " --help|-h print usage message then exit\n"
+ " --hex|H output in hex\n"
+ " --list|-l list supported page codes (with or without "
+ "DEVICE)\n"
+ " --pf|-p set PF bit (def: 0)\n"
+ " --raw=H,H...|-r H,H... sequence of hex bytes to form "
+ "diag page to send\n"
+ " --raw=-|-r - read stdin for sequence of bytes to send\n"
+ " --selftest=ST|-s ST self-test code, default: 0 "
+ "(inactive)\n"
+ " 1->background short, 2->background "
+ "extended\n"
+ " 4->abort test\n"
+ " 5->foreground short, 6->foreground "
+ "extended\n"
+ " --test|-t default self-test\n"
+ " --uoff|-u unit offline (def: 0, only with '--test')\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V output version string then exit\n\n"
+ "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC "
+ "RESULTS) command\n"
+ );
+}
+
+static void usage_old()
+{
+ printf("Usage: sg_senddiag [-doff] [-e] [-h] [-H] [-l] [-pf]"
+ " [-raw=H,H...]\n"
+ " [-s=SF] [-t] [-uoff] [-v] [-V] "
+ "[DEVICE]\n"
+ " where:\n"
+ " -doff device online (def: 0, only with '-t')\n"
+ " -e duration of an extended self-test (from mode page "
+ "0xa)\n"
+ " -h output in hex\n"
+ " -H output in hex (same as '-h')\n"
+ " -l list supported page codes\n"
+ " -pf set PF bit (def: 0)\n"
+ " -raw=H,H... sequence of bytes to form diag page to "
+ "send\n"
+ " -raw=- read stdin for sequence of bytes to send\n"
+ " -s=SF self-test code (def: 0)\n"
+ " 1->background short, 2->background extended,"
+ " 4->abort test\n"
+ " 5->foreground short, 6->foreground extended\n"
+ " -t default self-test\n"
+ " -uoff unit offline (def: 0, only with '-t')\n"
+ " -v increase verbosity (print issued SCSI cmds)\n"
+ " -V output version string\n"
+ " -? output this usage message\n\n"
+ "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC "
+ "RESULTS) command\n"
+ );
+}
+
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c, n;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "dehHlNOpr:s:tuvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'd':
+ optsp->do_doff = 1;
+ break;
+ case 'e':
+ optsp->do_extdur = 1;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'l':
+ ++optsp->do_list;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'p':
+ optsp->do_pf = 1;
+ break;
+ case 'r':
+ optsp->raw_arg = optarg;
+ optsp->do_raw = 1;
+ break;
+ case 's':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 7)) {
+ fprintf(stderr, "bad argument to '--selftest='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_selftest = n;
+ break;
+ case 't':
+ optsp->do_deftest = 1;
+ break;
+ case 'u':
+ optsp->do_uoff = 1;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
+{
+ int k, jmp_out, plen, num;
+ unsigned int u;
+ const char * cp;
+
+ for (k = 1; k < argc; ++k) {
+ cp = argv[k];
+ plen = strlen(cp);
+ if (plen <= 0)
+ continue;
+ if ('-' == *cp) {
+ for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
+ switch (*cp) {
+ case 'd':
+ if (0 == strncmp("doff", cp, 4)) {
+ optsp->do_doff = 1;
+ cp += 3;
+ plen -= 3;
+ } else
+ jmp_out = 1;
+ break;
+ case 'e':
+ optsp->do_extdur = 1;
+ break;
+ case 'h':
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'l':
+ ++optsp->do_list;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case 'p':
+ if (0 == strncmp("pf", cp, 2)) {
+ optsp->do_pf = 1;
+ ++cp;
+ --plen;
+ } else
+ jmp_out = 1;
+ break;
+ case 't':
+ optsp->do_deftest = 1;
+ break;
+ case 'u':
+ if (0 == strncmp("uoff", cp, 4)) {
+ optsp->do_uoff = 1;
+ cp += 3;
+ plen -= 3;
+ } else
+ jmp_out = 1;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case '?':
+ ++optsp->do_help;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+ if (0 == strncmp("raw=", cp, 4)) {
+ optsp->raw_arg = cp + 4;
+ optsp->do_raw = 1;
+ } else if (0 == strncmp("s=", cp, 2)) {
+ num = sscanf(cp + 2, "%x", &u);
+ if ((1 != num) || (u > 7)) {
+ printf("Bad page code after '-s=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_selftest = u;
+ } else if (0 == strncmp("-old", cp, 5))
+ ;
+ else if (jmp_out) {
+ fprintf(stderr, "Unrecognized option: %s\n", cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == optsp->device_name)
+ optsp->device_name = cp;
+ else {
+ fprintf(stderr, "too many arguments, got: %s, not expecting: "
+ "%s\n", optsp->device_name, cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
/* Return of 0 -> success, otherwise see sg_ll_send_diag() */
static int do_senddiag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
@@ -35,7 +348,7 @@ static int do_senddiag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
int long_duration = 0;
if ((0 == sf_bit) && ((5 == sf_code) || (6 == sf_code)))
- long_duration = 1; /* foreground self tests */
+ long_duration = 1; /* foreground self-tests */
return sg_ll_send_diag(sg_fd, sf_code, pf_bit, sf_bit, devofl_bit,
unitofl_bit, long_duration, outgoing_pg,
outgoing_len, noisy, verbose);
@@ -240,192 +553,120 @@ static void list_page_codes()
(pcdp->desc ? pcdp->desc : "<unknown>"));
}
-static void usage()
-{
- printf("Usage: sg_senddiag [-doff] [-e] [-h] [-H] [-l] [-pf]"
- " [-raw=<h>,<h>...]\n"
- " [-s=<self_test_code>] [-t] [-uoff] [-v] "
- "[-V]\n"
- " [<scsi_device>]\n"
- " where:\n"
- " -doff device online (def: 0, only with '-t')\n"
- " -e duration of an extended test (from mode page 0xa)\n"
- " -h output in hex\n"
- " -H output in hex (same as '-h')\n"
- " -l list supported page codes\n"
- " -pf set PF bit (def: 0)\n"
- " -raw=<h>,<h>... sequence of bytes to form diag page to "
- "send\n"
- " -raw=- read stdin for sequence of bytes to send\n"
- " -s=<self_test_code> (def: 0)\n"
- " 1->background short, 2->background extended,"
- " 4->abort test\n"
- " 5->foreground short, 6->foreground extended\n"
- " -t default self test\n"
- " -uoff unit online (def: 0, only with '-t')\n"
- " -v increase verbosity (print issued SCSI cmds)\n"
- " -V output version string\n"
- " -? output this usage message\n\n"
- "Performs a SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC RESULTS)"
- " SCSI command\n"
- );
-}
-
int main(int argc, char * argv[])
{
- int sg_fd, k, num, rsp_len, plen, jmp_out, res;
- const char * file_name = 0;
+ int sg_fd, k, num, rsp_len, res;
unsigned char rsp_buff[MX_ALLOC_LEN];
int rsp_buff_size = MX_ALLOC_LEN;
- unsigned int u;
- int self_test_code = 0;
- int do_pf = 0;
- int do_doff = 0;
- int do_hex = 0;
- int do_list = 0;
- int do_def_test = 0;
- int do_uoff = 0;
- int do_ext_time = 0;
- int do_raw = 0;
- int verbose = 0;
int read_in_len = 0;
const char * cp;
unsigned char read_in[MX_ALLOC_LEN];
int ret = 0;
+ struct opts_t opts;
- for (k = 1; k < argc; ++k) {
- cp = argv[k];
- plen = strlen(cp);
- if (plen <= 0)
- continue;
- if ('-' == *cp) {
- for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
- switch (*cp) {
- case 'd':
- if (0 == strncmp("doff", cp, 4)) {
- do_doff = 1;
- cp += 3;
- plen -= 3;
- } else
- jmp_out = 1;
- break;
- case 'e':
- do_ext_time = 1;
- break;
- case 'h':
- case 'H':
- do_hex = 1;
- break;
- case 'l':
- do_list = 1;
- break;
- case 'p':
- if (0 == strncmp("pf", cp, 2)) {
- do_pf = 1;
- ++cp;
- --plen;
- } else
- jmp_out = 1;
- break;
- case 't':
- do_def_test = 1;
- break;
- case 'u':
- if (0 == strncmp("uoff", cp, 4)) {
- do_uoff = 1;
- cp += 3;
- plen -= 3;
- } else
- jmp_out = 1;
- break;
- case 'v':
- ++verbose;
- break;
- case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
- case '?':
- usage();
- return 0;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
- }
- if (plen <= 0)
- continue;
- if (0 == strncmp("raw=", cp, 4)) {
- if (build_diag_page(cp + 4, read_in, &read_in_len,
- sizeof(read_in))) {
- printf("Bad sequence after 'raw=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- do_raw = 1;
- } else if (0 == strncmp("s=", cp, 2)) {
- num = sscanf(cp + 2, "%x", &u);
- if ((1 != num) || (u > 7)) {
- printf("Bad page code after 's=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- self_test_code = u;
- } else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n", cp);
+ memset(&opts, 0, sizeof(opts));
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
+ return 0;
+ }
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
+ }
+
+ if (NULL == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_raw) {
+ if (build_diag_page(opts.raw_arg, read_in, &read_in_len,
+ sizeof(read_in))) {
+ if (opts.opt_new) {
+ printf("Bad sequence after '--raw=' option\n");
usage();
- return SG_LIB_SYNTAX_ERROR;
+ } else {
+ printf("Bad sequence after '-raw=' option\n");
+ usage_old();
}
- } else if (0 == file_name)
- file_name = cp;
- else {
- fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
- usage();
return SG_LIB_SYNTAX_ERROR;
}
}
- if ((do_doff || do_uoff) && (! do_def_test)) {
- printf("setting -doff or -uoff only useful when -t is set\n");
- usage();
+ if ((opts.do_doff || opts.do_uoff) && (! opts.do_deftest)) {
+ if (opts.opt_new) {
+ printf("setting --doff or --uoff only useful when -t is set\n");
+ usage();
+ } else {
+ printf("setting -doff or -uoff only useful when -t is set\n");
+ usage_old();
+ }
return SG_LIB_SYNTAX_ERROR;
}
- if ((self_test_code > 0) && do_def_test) {
- printf("either set -s=<num> or -t (not both)\n");
- usage();
+ if ((opts.do_selftest > 0) && opts.do_deftest) {
+ if (opts.opt_new) {
+ printf("either set --selftest=SF or --test (not both)\n");
+ usage();
+ } else {
+ printf("either set -s=SF or -t (not both)\n");
+ usage_old();
+ }
return SG_LIB_SYNTAX_ERROR;
}
- if (do_raw) {
- if ((self_test_code > 0) || do_def_test || do_ext_time || do_list) {
- printf("'--raw=' cannot be used with self tests, '-e' or "
- "'-l'\n");
- usage();
+ if (opts.do_raw) {
+ if ((opts.do_selftest > 0) || opts.do_deftest || opts.do_extdur ||
+ opts.do_list) {
+ if (opts.opt_new) {
+ printf("'--raw=' cannot be used with self-tests, '-e' or "
+ "'-l'\n");
+ usage();
+ } else {
+ printf("'-raw=' cannot be used with self-tests, '-e' or "
+ "'-l'\n");
+ usage_old();
+ }
return SG_LIB_SYNTAX_ERROR;
}
- if (! do_pf)
- printf(">>> warning, '-pf' probably should be used with "
- "'--raw='\n");
+ if (! opts.do_pf) {
+ if (opts.opt_new)
+ printf(">>> warning, '--pf' probably should be used with "
+ "'--raw='\n");
+ else
+ printf(">>> warning, '-pf' probably should be used with "
+ "'-raw='\n");
+ }
}
- if (0 == file_name) {
- if (do_list) {
+ if (NULL == opts.device_name) {
+ if (opts.do_list) {
list_page_codes();
return 0;
}
- fprintf(stderr, "No <scsi_device> argument given\n");
- usage();
+ fprintf(stderr, "No DEVICE argument given\n");
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- if ((sg_fd = sg_cmds_open_device(file_name, 0 /* rw */, verbose)) < 0) {
- fprintf(stderr, ME "error opening file: %s: %s\n", file_name,
+ if ((sg_fd = sg_cmds_open_device(opts.device_name, 0 /* rw */,
+ opts.do_verbose)) < 0) {
+ fprintf(stderr, ME "error opening file: %s: %s\n", opts.device_name,
safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- if (do_ext_time) {
- res = do_modes_0a(sg_fd, rsp_buff, 32, 1, 0, verbose);
+ if (opts.do_extdur) {
+ res = do_modes_0a(sg_fd, rsp_buff, 32, 1, 0, opts.do_verbose);
if (0 == res) {
/* Assume mode sense(10) response without block descriptors */
num = (rsp_buff[0] << 8) + rsp_buff[1] - 6;
@@ -433,8 +674,13 @@ int main(int argc, char * argv[])
int secs;
secs = (rsp_buff[18] << 8) + rsp_buff[19];
+#ifdef SG3_UTILS_MINGW
+ printf("Expected extended self-test duration=%d seconds "
+ "(%g minutes)\n", secs, secs / 60.0);
+#else
printf("Expected extended self-test duration=%d seconds "
"(%.2f minutes)\n", secs, secs / 60.0);
+#endif
} else
printf("Extended self-test duration not available\n");
} else {
@@ -442,16 +688,16 @@ int main(int argc, char * argv[])
printf("Extended self-test duration (mode page 0xa) failed\n");
goto err_out9;
}
- } else if (do_list) {
+ } else if (opts.do_list) {
memset(rsp_buff, 0, sizeof(rsp_buff));
res = do_senddiag(sg_fd, 0, 1 /* pf */, 0, 0, 0, rsp_buff, 4, 1,
- verbose);
+ opts.do_verbose);
if (0 == res) {
if (0 == sg_ll_receive_diag(sg_fd, 0, 0, rsp_buff,
- rsp_buff_size, 1, verbose)) {
+ rsp_buff_size, 1, opts.do_verbose)) {
printf("Supported diagnostic pages response:\n");
rsp_len = (rsp_buff[2] << 8) + rsp_buff[3] + 4;
- if (do_hex)
+ if (opts.do_hex)
dStrHex((const char *)rsp_buff, rsp_len, 1);
else {
for (k = 0; k < (rsp_len - 4); ++k) {
@@ -470,21 +716,22 @@ int main(int argc, char * argv[])
ret = res;
goto err_out;
}
- } else if (do_raw) {
- res = do_senddiag(sg_fd, 0, do_pf, 0, 0, 0, read_in, read_in_len, 1,
- verbose);
+ } else if (opts.do_raw) {
+ res = do_senddiag(sg_fd, 0, opts.do_pf, 0, 0, 0, read_in,
+ read_in_len, 1, opts.do_verbose);
if (res) {
ret = res;
goto err_out;
}
} else {
- res = do_senddiag(sg_fd, self_test_code, do_pf, do_def_test,
- do_doff, do_uoff, NULL, 0, 1, verbose);
+ res = do_senddiag(sg_fd, opts.do_selftest, opts.do_pf,
+ opts.do_deftest, opts.do_doff, opts.do_uoff, NULL,
+ 0, 1, opts.do_verbose);
if (0 == res) {
- if ((5 == self_test_code) || (6 == self_test_code))
- printf("Foreground self test returned GOOD status\n");
- else if (do_def_test && (! do_doff) && (! do_uoff))
- printf("Default self test returned GOOD status\n");
+ if ((5 == opts.do_selftest) || (6 == opts.do_selftest))
+ printf("Foreground self-test returned GOOD status\n");
+ else if (opts.do_deftest && (! opts.do_doff) && (! opts.do_uoff))
+ printf("Default self-test returned GOOD status\n");
} else {
ret = res;
goto err_out;
@@ -506,7 +753,7 @@ err_out:
else
fprintf(stderr, "SEND DIAGNOSTIC command, failed\n");
err_out9:
- if (verbose < 2)
+ if (opts.do_verbose < 2)
fprintf(stderr, " try again with '-vv' for more information\n");
res = sg_cmds_close_device(sg_fd);
if ((res < 0) && (0 == ret))
diff --git a/sg_ses.8 b/sg_ses.8
index 0c5f2711..cff80d70 100644
--- a/sg_ses.8
+++ b/sg_ses.8
@@ -1,103 +1,107 @@
-.TH SG_SES "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_SES "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_ses \- send controls and fetch status from a SCSI Enclosure
Services (SES) device
.SH SYNOPSIS
.B sg_ses
-[\fI--byte1=<n>\fR] [\fI--control\fR] [\fI--data=<h>,<h>...\fR]
-[\fI--filter\fR] [\fI--help\fR] [\fI--hex\fR] [\fI--inner-hex\fR]
-[\fI--list\fR] [\fI--page=<page_code>\fR] [\fI--raw\fR]
-[\fI--status\fR] [\fI--verbose\fR] [\fI--version\fR] \fI<scsi_device>\fR
+[\fI\-\-byte1=B1\fR] [\fI\-\-control\fR] [\fI\-\-data=H,H...\fR]
+[\fI\-\-filter\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inner\-hex\fR]
+[\fI\-\-list\fR] [\fI\-\-page=PG\fR] [\fI\-\-raw\fR] [\fI\-\-status\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
Send controls to a SES device (via a SCSI SEND DIAGNOSTIC command)
or fetches status (via a SCSI RECEIVE DIAGNOSTIC RESULTS command).
-The given <scsi_device> should be a SES device which may be a dedicated
+The \fIDEVICE\fR should be a SES device which may be a dedicated
enclosure services processor (INQUIRY peripheral device type 0xd) or
attached to another type of SCSI device (e.g. a disk) in which case
the EncServ bit set in its INQUIRY response.
.PP
-If no options are given (only the <scsi_device> name) then all
+If no options are given (only the \fIDEVICE\fR argument) then all
diagnostic pages supported by the device (including SES pages)
are listed.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---byte=<n> | -b <n>
+\fB\-b\fR, \fB\-\-byte\fR=\fIB1\fR
some control pages need byte 1 (i.e. the second byte) of the cdb set.
-Only required in rare cases when the '--control' option is also set.
-Default is 0; <n> is in decimal unless it is prefixed by '0x'
+Only required in rare cases when the \fI\-\-control\fR option is also set.
+Default is 0; \fIB1\fR is in decimal unless it is prefixed by '0x'
or '0X' (or has a trailing 'h' or 'H').
.TP
---control | -c
-will send control information to the given device via a SCSI SEND
-DIAGNOSTIC command. Cannot give both this option and '--status'.
+\fB\-c\fR, \fB\-\-control\fR
+will send control information to the \fIDEVICE\fR via a SCSI SEND
+DIAGNOSTIC command. Cannot give both this option and \fI\-\-status\fR.
The Enclosure control, String Out, Threshold Out, Array control (obsolete
-in SES-2) and Subenclosure String Out diagnostic pages can be set currently.
+in SES\-2) and Subenclosure String Out diagnostic pages can be set currently.
.TP
---data=<h>,<h>... | -d <h>,<h>...
+\fB\-d\fR, \fB\-\-data\fR=\fIH,H...\fR
permits a string of comma separated (ASCII) hex digits to be
specified (limit 512). This allows the parameters to a control diagnostic
page to be specified. The string given should not include the first 4
bytes (i.e. page code and length). See next entry for using stdin.
.TP
---data=- | -d -
+\fB\-d\fR, \fB\-\-data\fR=-
reads a data string from stdin. Spaces, tabs and line feeds additionally
are permitted as separators.
.TP
---filter | -f
+\fB\-f\fR, \fB\-\-filter\fR
cuts down on the amount of output from the enclosure status diagnostic
page. When this option is given, any line which has all its binary flags
cleared (i.e. 0) is filtered out (i.e. ignored). If a line has some other
value on it (e.g. a temperature) then it is output.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---hex | -H
+\fB\-H\fR, \fB\-\-hex\fR
output the response in hexadecimal.
.TP
---inner-hex | -i
+\fB\-i\fR, \fB\-\-inner\-hex\fR
the outer levels of a status diagnostic page are decoded and printed out
but the innermost level (e.g. the element status descriptor) is output in
hex.
.TP
---list | -l
-list all known diagnostic page names and SES elements. <scsi_device>
+\fB\-l\fR, \fB\-\-list\fR
+list all known diagnostic page names and SES elements. \fIDEVICE\fR
is ignored and utility exits.
.TP
---page=<page_code> | -p <page_code>
-Supply a <page_code>. Assumed to be in decimal unless prefixed by 0x for
-hex. Valid range is 0 to 255 (0x0 to 0xff) inclusive. Default is
+\fB\-p\fR, \fB\-\-page\fR=\fIPG\fR
+where \fIPG\fR is a page code. Assumed to be in decimal unless prefixed by
+0x for hex. Valid range is 0 to 255 (0x0 to 0xff) inclusive. Default is
page_code 0 (i.e. "Supported diagnostic pages").
.TP
---raw | -r
+\fB\-r\fR, \fB\-\-raw\fR
outputs the chosen status page in (ASCII) hex in a format suitable for
-a later invocation using the '--data=" option. A status diagnostic page
-less its first 4 bytes (page code and length) is output.
+a later invocation using the \fI\-\-data=\fR option. A status diagnostic
+page less its first 4 bytes (page code and length) is output.
+When used twice (e.g. \fI\-rr\fR) outputs full diagnostic page in binary
+to stdout.
.TP
---status | -s
-will fetch status diagnostic page from the given device via a SCSI RECEIVE
-DIAGNOSTIC RESULTS command. If this option is not given and '--control' is
-not given then '--status' is assumed.
+\fB\-s\fR, \fB\-\-status\fR
+will fetch status diagnostic page from the \fIDEVICE\fR via a SCSI RECEIVE
+DIAGNOSTIC RESULTS command. If this option is not given and
+\fI\-\-control\fR is not given then \fI\-\-status\fR is assumed.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
+.SH NOTES
Currently all status pages, control pages and element types defined in
-SES-2 revision 15 (13th May 2006) are decoded.
+SES\-2 revision 15 (13th May 2006) are decoded.
.PP
This utility can be used to fetch arbitrary (i.e. non SES) diagnostic
-pages (using the READ DIAGNOSTIC SCSI command). To this end the '--page='
-and '--hex' options would be appropriate. Arbitrary diagnostic pages can
-be sent to a device with the sg_senddiag utility.
+pages (using the SCSI READ DIAGNOSTIC command). To this end the
+\fI\-\-page=PG\fR and \fI\-\-hex\fR options would be appropriate. Arbitrary
+diagnostic pages can be sent to a device with the sg_senddiag utility.
.PP
-There is a related command set called SAF-TE (SCSI attached fault-tolerant
+There is a related command set called SAF\-TE (SCSI attached fault\-tolerant
enclosure) for enclosure (including RAID) status and control. SCSI devices
-that support SAF-TE report "Processor" peripheral device type (0x3) in their
-INQUIRY response. See safte-monitor on the internet.
+that support SAF\-TE report "Processor" peripheral device type (0x3) in their
+INQUIRY response. See safte\-monitor on the internet.
.SH EXAMPLES
To view the supported pages:
.PP
@@ -105,32 +109,32 @@ To view the supported pages:
.PP
To view the configuration page:
.PP
- sg_ses --page=1 /dev/sda
+ sg_ses \-\-page=1 /dev/sda
.PP
To view the status page:
.PP
- sg_ses --page=2 /dev/sda
+ sg_ses \-\-page=2 /dev/sda
.PP
Changing a temperature threshold is possible, if a little awkward. The
current thresholds can be shown with:
.PP
- sg_ses --page=5 /dev/sda
+ sg_ses \-\-page=5 /dev/sda
.PP
The threshold to be changed can be chosen. Then output the threshold page
in hex (suitable for editing) with:
.PP
- sg_ses --page=5 --raw /dev/sda > t
+ sg_ses \-\-page=5 \-\-raw /dev/sda > t
.PP
-Then with the aid of the SES-2 document (in revision 9: section 6.1.8)
+Then with the aid of the SES\-2 document (in revision 9: section 6.1.8)
use your favourite editor to change t. The change can be sent to the
device with:
.PP
- sg_ses --control --page=5 --data=- /dev/sda < t
+ sg_ses \-\-control \-\-page=5 \-\-data=\- /dev/sda < t
.PP
If the above is successful, the threshold should have been changed. To
check try:
.PP
- sg_ses --page=5 /dev/sda
+ sg_ses \-\-page=5 /dev/sda
.PP
again.
.SH EXIT STATUS
@@ -141,9 +145,9 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B sg_inq, sg_senddiag (in sg3_utils package); safte-monitor (internet)
+.B sg_inq, sg_senddiag (in sg3_utils package); safte\-monitor (internet)
diff --git a/sg_ses.c b/sg_ses.c
index 143b6e52..89db718c 100644
--- a/sg_ses.c
+++ b/sg_ses.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,13 +38,12 @@
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
-/* A utility program for the Linux OS SCSI subsystem.
- *
+/*
* This program issues SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS
- *commands tailored for SES (enclosure) devices.
+ * commands tailored for SES (enclosure) devices.
*/
-static char * version_str = "1.29 20061012"; /* ses2r15 */
+static char * version_str = "1.32 20070128"; /* ses2r15 */
#define MX_ALLOC_LEN 4096
#define MX_ELEM_HDR 512
@@ -75,18 +74,20 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_ses [--byte1=<n>] [--control] [--data=<h>...] [--filter] "
+ "sg_ses [--byte1=B1] [--control] [--data=H,H...] [--filter] "
"[--help]\n"
- " [--hex] [--inner-hex] [--list] [--page=<n>] [--raw] "
+ " [--hex] [--inner-hex] [--list] [--page=PG] [--raw] "
"[--status]\n"
- " [--verbose] [--version] <scsi_device>\n"
+ " [--verbose] [--version] DEVICE\n"
" where:\n"
- " --byte1=<n>|-b <n> byte 1 (2nd byte) for some control "
+ " --byte1=B1|-b B1 byte 1 (2nd byte) for some control "
"pages\n"
" --control|-c send control information (def: fetch "
"status)\n"
- " --data=<h>,<h>...|-d <h>... string of hex for control "
- "pages\n"
+ " --data=H,H...|-d H,H... string of ASCII hex bytes for "
+ "control pages\n"
+ " --data=- | -d - fetch string of ASCII hex bytes from "
+ "stdin\n"
" --filter|-f filter out enclosure status clear "
"flags\n"
" --help|-h print out usage message\n"
@@ -95,10 +96,12 @@ static void usage()
" status page in hex\n"
" --list|-l list known pages and elements (ignore"
" device)\n"
- " --page=<n>|-p <n> page code <n> (prefix with '0x' "
+ " --page=PG|-p PG SES page code PG (prefix with '0x' "
"for hex; def: 0)\n"
- " --raw|-r print status page in hex suitable "
- "for '-d'\n"
+ " --raw|-r print status page in ASCII hex suitable "
+ "for '-d';\n"
+ " when used twice outputs page in binary "
+ "to stdout\n"
" --status|-s fetch status information\n"
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
@@ -253,6 +256,14 @@ struct element_hdr {
static struct element_hdr element_hdr_arr[MX_ELEM_HDR];
+static void dStrRaw(const char* str, int len)
+{
+ int k;
+
+ for (k = 0 ; k < len; ++k)
+ printf("%c", str[k]);
+}
+
static void ses_configuration_sdg(const unsigned char * resp, int resp_len)
{
int j, k, el, num_subs, sum_elem_types;
@@ -670,16 +681,26 @@ static void print_element_status(const char * pad,
"Crit Under=%d\n", pad, !!(statp[1] & 0x80),
!!(statp[1] & 0x8), !!(statp[1] & 0x4),!!(statp[1] & 0x2),
!!(statp[1] & 0x1));
+#ifdef SG3_UTILS_MINGW
+ printf("%sVoltage: %g volts\n", pad,
+ ((int)(short)((statp[2] << 8) + statp[3]) / 100.0));
+#else
printf("%sVoltage: %.2f volts\n", pad,
((int)(short)((statp[2] << 8) + statp[3]) / 100.0));
+#endif
break;
case 0x13: /* Current sensor */
if ((! filter) || (0x8a & statp[1]))
printf("%sIdent=%d, Warn Over=%d, Crit Over=%d\n", pad,
!!(statp[1] & 0x80), !!(statp[1] & 0x8),
!!(statp[1] & 0x2));
+#ifdef SG3_UTILS_MINGW
+ printf("%sCurrent: %g amps\n", pad,
+ ((int)(short)((statp[2] << 8) + statp[3]) / 100.0));
+#else
printf("%sCurrent: %.2f amps\n", pad,
((int)(short)((statp[2] << 8) + statp[3]) / 100.0));
+#endif
break;
case 0x14: /* SCSI target port */
if ((! filter) || ((0x80 & statp[1]) || (0x1 & statp[2]) ||
@@ -862,14 +883,26 @@ static void ses_threshold_helper(const char * pad, const unsigned char *tp,
printf("low critical=%s (in minutes)\n", b);
break;
case 0x12: /* voltage */
+#ifdef SG3_UTILS_MINGW
+ printf("%s%s: high critical=%g %%, high warning=%g %%\n", pad,
+ buff, 0.5 * tp[0], 0.5 * tp[1]);
+ printf("%s low warning=%g %%, low critical=%g %% (from nominal "
+ "voltage)\n", pad, 0.5 * tp[2], 0.5 * tp[3]);
+#else
printf("%s%s: high critical=%.1f %%, high warning=%.1f %%\n", pad,
buff, 0.5 * tp[0], 0.5 * tp[1]);
printf("%s low warning=%.1f %%, low critical=%.1f %% (from nominal "
"voltage)\n", pad, 0.5 * tp[2], 0.5 * tp[3]);
+#endif
break;
case 0x13: /* current */
+#ifdef SG3_UTILS_MINGW
+ printf("%s%s: high critical=%g %%, high warning=%g %%\n", pad,
+ buff, 0.5 * tp[0], 0.5 * tp[1]);
+#else
printf("%s%s: high critical=%.1f %%, high warning=%.1f %%\n", pad,
buff, 0.5 * tp[0], 0.5 * tp[1]);
+#endif
printf("%s (above nominal current)\n", pad);
break;
default:
@@ -1144,8 +1177,6 @@ static void ses_additional_elem_sdg(const struct element_hdr * ehp,
}
ucp = resp + 8;
for (k = 0; k < num_telems; ++k) {
- if ((ucp + 1) > last_ucp)
- goto truncated;
elem_type = ehp[k].etype;
if (! ((1 == elem_type) || /* device */
(0x14 == elem_type) || /* scsi target */
@@ -1153,6 +1184,8 @@ static void ses_additional_elem_sdg(const struct element_hdr * ehp,
(0x17 == elem_type) || /* array */
(0x18 == elem_type))) /* SAS expander */
continue; /* skip if not one of above element types */
+ if ((ucp + 1) > last_ucp)
+ goto truncated;
cp = find_element_desc(elem_type);
if (cp)
printf(" Element type: %s, subenclosure id: %d\n",
@@ -1443,9 +1476,12 @@ static int ses_process_status(int sg_fd, int page_code, int do_raw,
"but got 0x%x\n", page_code, rsp_buff[0]);
dStrHex((const char *)rsp_buff, rsp_len, 0);
}
- } else if (do_raw)
- dStrHex((const char *)rsp_buff + 4, rsp_len - 4, -1);
- else if (do_hex) {
+ } else if (do_raw) {
+ if (1 == do_raw)
+ dStrHex((const char *)rsp_buff + 4, rsp_len - 4, -1);
+ else
+ dStrRaw((const char *)rsp_buff, rsp_len);
+ } else if (do_hex) {
if (cp)
printf("Response in hex from diagnostic page: %s\n", cp);
else
@@ -1613,7 +1649,7 @@ int main(int argc, char * argv[])
}
break;
case 'c':
- do_control = 1;
+ ++do_control;
break;
case 'd':
memset(data_arr, 0, sizeof(data_arr));
@@ -1634,10 +1670,10 @@ int main(int argc, char * argv[])
++do_hex;
break;
case 'i':
- inner_hex = 1;
+ ++inner_hex;
break;
case 'l':
- do_list = 1;
+ ++do_list;
break;
case 'p':
page_code = sg_get_num(optarg);
@@ -1648,10 +1684,10 @@ int main(int argc, char * argv[])
}
break;
case 'r':
- do_raw = 1;
+ ++do_raw;
break;
case 's':
- do_status = 1;
+ ++do_status;
break;
case 'v':
++verbose;
@@ -1700,7 +1736,7 @@ int main(int argc, char * argv[])
fprintf(stderr, "cannot have both '--control' and '--status'\n");
usage();
return SG_LIB_SYNTAX_ERROR;
- } else if (1 == do_control) {
+ } else if (do_control) {
if (! do_data) {
fprintf(stderr, "need to give '--data' in control mode\n");
usage();
diff --git a/sg_start.8 b/sg_start.8
index 9c17808d..f129f1a1 100644
--- a/sg_start.8
+++ b/sg_start.8
@@ -1,121 +1,128 @@
-.TH SG_START "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_START "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_start \- starts (spins-up) or stops (spins down) device, load or
+sg_start \- send SCSI START STOP UNIT command to start, stop, load or
eject medium
.SH SYNOPSIS
.B sg_start
-[\fI--eject\fR] [\fI--fl=<n>\fR] [\fI-i\fR] [\fI--imm=0|1\fR] [\fI--load\fR]
-[\fI--loej\fR] [\fI--pc=<n>\fR] [\fI--start\fR] [\fI--stop\fR] [\fI-v\fR]
-[\fI-V\fR] [\fI0|1\fR] \fI<device>\fR
+[\fI0\fR] [\fI1\fR] [\fI\-\-eject\fR] [\fI\-\-help\fR] [\fI\-\-fl=FL\fR]
+[\fI\-\-immed\fR] [\fI\-\-load\fR] [\fI\-\-loej\fR] [\fI\-\-pc=PC\fR]
+[\fI\-\-start\fR] [\fI\-\-stop\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+\fIDEVICE\fR
+.PP
+.B sg_start
+[\fI\-\-eject\fR] [\fI\-\-fl=FL\fR] [\fI\-i\fR] [\fI\-\-imm=0|1\fR]
+[\fI\-\-load\fR] [\fI\-\-loej\fR] [\fI\-\-pc=PC\fR] [\fI\-\-start\fR]
+[\fI\-\-stop\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI0|1\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-sg_start sends a START STOP UNIT SCSI command to the given device with
-the selected options. The most used options are '--stop' to spin down a disk
-and '--start' to spin up a disk. Using 'sg_start --start /dev/sda' on a disk
-that is already spinning is harmless. There is also finer grain control
-with "power conditions": active, idle and standby. In some contexts
-the "stop" state can be considered an additional power condition.
+sg_start sends a SCSI START STOP UNIT command to the \fIDEVICE\fR with
+the selected options. The most used options are \fI\-\-stop\fR to spin
+down a disk and \fI\-\-start\fR to spin up a disk. Using \fI\-\-start\fR
+on a disk that is already spinning is harmless. There is also finer grain
+control with "power conditions": active, idle and standby. This is set
+with the \fI\-\-pc=PC\fR option. In some contexts the "stop" state can
+be considered an additional power condition.
.PP
-Devices that contain removable media such as cd/dvds can use the '--loej'
-flag to load the medium when used in conjunction with '--start' (i.e. load
-medium then spin up). Alternatively '--loej' may be used to eject the medium
-when used alone or when used in conjunction with '--stop' (i.e. spin down
-then eject medium). More simply the loading and ejecting of a removable
-medium can be requested with the '--load' and '--eject' options.
+Devices that contain removable media such as cd/dvds can use the
+\fI\-\-loej\fR option to load the medium when used in conjunction
+with \fI\-\-start\fR (i.e. load medium then spin up). Alternatively
+\fI\-\-loej\fR may be used to eject the medium when used in conjunction
+with \fI\-\-stop\fR (i.e. spin down then eject medium). More simply, the
+loading or ejecting of a removable medium can be requested with the
+\fI\-\-load\fR or \fI\-\-eject\fR' option.
.PP
-If no option or argument is given then a '--start' is assumed; as the
+If no option or argument is given then a \fI\-\-start\fR is assumed; as the
utility's name suggests.
+.PP
+This utility supports two command line syntaxes, the preferred one is
+shown first in the synopsis and explained in this section. A later
+section on the old command line syntax outlines the second group of
+options.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
-0
-stop (spin-down) given device.
-Active when '--pc=" is not given or '--pc=0'.
+\fB0\fR
+same action as \fI\-\-stop\fR.
.TP
-1
-start (spin-up) given device.
-Active when '--pc=" is not given or '--pc=0'. Harmless if device has
-already started (or is in the process of starting).
+\fB1\fR
+same action as \fI\-\-start\fR.
.TP
---eject
+\fB\-e\fR, \fB\-\-eject\fR
stop the medium and eject it from the drive. Only appropriate for a
device with removable medium. Might be ignored (prevented), see below.
.TP
---fl=<n>
-sets the format layer number for the disc to "jump" to (defined in
-MMC-5). Values of '<n>' can be 0 to 3. When this option is chosen,
-the FL, LoEj and Start bits are set in the cdb as required by MMC-5; thus
-the user does not need to set the '--start' and/or '--load' options.
+\fB\-h\fR, \fB\-\-help\fR
+print out the usage message then exit.
.TP
--i
+\fB\-f\fR, \fB\-\-fl\fR=\fIFL\fR
+sets the format layer number for the disc to "jump" to (defined in MMC-5).
+Values of \fIFL\fR can be 0 to 3. When this option is chosen, the FL, LoEj
+and Start bits are set in the cdb as required by MMC-5; thus the user does
+not need to set the \fI\-\-start\fR and/or \fI\-\-load\fR options.
+.TP
+\fB\-i\fR, \fB\-\-immed\fR
sets the IMM bit on the START STOP UNIT command so this utility will
-return immediately and not wait for the media to spin down. Same
-effect as '--imm=1'. The default action (without this option or
-a '--imm=1' option) is to wait until the media spins down before
-returning.
-.TP
---imm=0|1
-when the immediate bit is 1 then this utility returns immediately after
-the device has received the command. When this option is 0 (the default)
-then the utility returns once the command has completed its action
-(i.e. it waits until the device is started or stopped).
-.TP
---load
-load the medium in the drive and start it. Only appropriate for a
-removable medium.
-.TP
---loej
-load the media when the unit is started or eject it when the unit is
-stopped. This option is ignored if 'pc > 0'. Default is off (i.e. don't
-attempt to load or eject media). If a start/start indication is not
-given (neither "--start" nor "--stop") and this option is given then a
-stop and eject action is assumed.
-.TP
---pc=<n>
-set the 'power conditions' value (in hex); 0 to f (inclusive) are valid.
-Default value is 0.
-When '--pc=0' then '--eject', '--load', '--loej', '--start' and '--stop'
-are active. Some common values are 1 for the active power condition (SBC);
-2 for the idle power condition; 3 for the standby power condition; 5 for
-sleep power condition (MMC); 7 for LU_CONTROL (SBC), 0xa (decimal 10) for
-FORCE_IDLE_0 (SBC) and 0xb (decimal 11) for FORCE_STANDBY_0 (SBC).
-See recent SBC-3, MMC-5 and SAS drafts at www.t10.org for more information.
-.TP
---start
-start (spin-up) given device. Using this option on an already started
-device is harmless. Same meaning as "1" argument.
-.TP
---stop
-stop (spin-down) given device. Same meaning as "0" argument.
-.TP
--v
-verbose: outputs SCSI command in hex to console before with executing
-it. '-vv' and '-vvv' are also accepted yielding greater verbosity.
+return immediately and not wait for the media to complete the requested
+action. The default is to wait until the media to complete the requested
+action before returning.
+.TP
+\fB\-l\fR, \fB\-\-load\fR
+load the medium in the drive and start it. Only appropriate for a removable
+medium.
+.TP
+\fB\-L\fR, \fB\-\-loej\fR
+sets the LOEJ bit on the START STOP UNIT command. This loads the media when
+the unit is started or eject it when the unit is stopped (i.e. works in
+conjunction with START bit in cdb). This option is ignored if 'pc > 0'.
+Default is off (i.e. don't attempt to load or eject media). If a start/start
+indication is not given (i.e. neither \fI\-\-start\fR nor \fI\-\-stop\fR)
+and this option is given then a load and start action is assumed.
+.TP
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
+.TP
+\fB\-p\fR, \fB\-\-pc\fR=\fIPC\fR
+where \fIPC\fR is the 'power conditions' value. 0 to 15 (inclusive) are valid.
+Default value is 0. When '\-\-pc=0' then \fB\-\-eject\fR, \fB\-\-load\fR,
+\fB\-\-loej\fR, \fB\-\-start\fR and \fB\-\-stop\fR are active. Some common
+values are 1 for the "active" power condition (SBC); 2 for the idle power
+condition; 3 for the standby power condition; 5 for sleep power
+condition (MMC); 7 for LU_CONTROL (SBC), 0xa (decimal 10) for
+FORCE_IDLE_0 (SBC) and 0xb (decimal 11) for FORCE_STANDBY_0 (SBC). See recent
+SBC\-3, MMC\-5 and SAS drafts at www.t10.org for more information.
.TP
--V
+\fB\-s\fR, \fB\-\-start\fR
+start (spin\-up) the device. This sets the START bit in the cdb. Using
+this option on an already started device is harmless. In the absence of
+other options, this option defaults (i.e. set the START cdb bit).
+.TP
+\fB\-S\fR, \fB\-\-stop\fR
+stop (spin\-down) the device. This clears the START bit in the cdb.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+increase the level of verbosity. Can be used multiple times.
+.TP
+\fB\-V\fR, \fB\-\-version\fR
print out version string then exit.
-.PP
-All options, other than '-v' and '-V', can be given with a single "-".
-For example: "sg_start -stop /dev/sda" and "sg_start --stop /dev/sda"
-are equivalent. The single "-" form is for backward compatibility.
-.PP
-To avoid confusion, only one of "0", "1", "--load", "--eject", "--start"
-and "--stop" can be given.
+.SH NOTES
+To avoid confusion, only one of \fI0\fR, \fI1\fR \fI\-\-eject\fR,
+\fI\-\-load\fR, \fI\-\-start\fR and \fI\-\-stop\fR should be given.
.PP
There is an associated "power condition" mode page (0x1a) in which timer
values can be set for transitioning to either idle or standby state after
-a period of inactivity. The sdparm utility can be used to view the
-power condition mode page and if required change it.
-If a device is in either idle or standby power condition state then
-a REQUEST SENSE command (see the sg_requests utility) should yield
-a sense key of "no sense" and an additional sense code of "Low
-power condition on" on recent SCSI devices.
+a period of inactivity. The sdparm utility can be used to view the power
+condition mode page and if required change it. If a device is in either
+idle or standby power condition state then a REQUEST SENSE command (see
+the sg_requests utility) should yield a sense key of "no sense" and an
+additional sense code of "Low power condition on" on recent SCSI devices.
.PP
-Ejection of removable media (e.g. 'sg_start --eject /dev/hdd' where
+Ejection of removable media (e.g. 'sg_start \-\-eject /dev/hdd' where
the device is an ATAPI cd/dvd drive) may be prevented by a prior
-PREVENT ALLOW MEDIUM REMOVAL SCSI command (see sg_prevent). In this
+SCSI PREVENT ALLOW MEDIUM REMOVAL command (see sg_prevent). In this
case this utility should fail with an error generated by the device:
illegal request / medium removal prevented. This can be overridden
-using sg_prevent or 'sdparm --command=unlock /dev/hdd'.
+using sg_prevent or, for example, 'sdparm \-\-command=unlock /dev/hdd'.
.PP
The SCSI TEST UNIT READY command can be used to find out whether a
device is ready to transfer data. If rotating media is stopped or
@@ -123,24 +130,93 @@ still coming up to speed, then the TEST UNIT READY command will yield
a "not ready" sense key and an more informative additional sense
code. See the sg_turs utility.
.PP
-In the 2.4 series of Linux kernels the given device must be
-a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example "sg_start 0 /dev/sda"
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI
+generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks
+and DVD drives) can also be specified. For example "sg_start 0 /dev/sda"
will work in the 2.6 series kernels.
-.SH NOTES
-Earlier versions had a '-s' option to perform a SYNCHRONIZE CACHE command
-before the START STOP UNIT command was issued. According to recent SBC-2
-drafts this is done implicitly if required. Hence the "-s" option has been
-dropped.
.SH EXIT STATUS
The exit status of sg_start is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using '\-\-old' (or '\-O) as the first option.
+.PP
+Note that the action of \fI\-\-loej\fR is slightly different in the older
+interface: when neither \fI\-\-start\fR nor \fI\-\-stop\fR (nor proxies
+for them) are given, \fI\-\-loej\fR performs an eject operation. In the
+same situation the newer interface will perform a load operation.
+.PP
+Earlier versions of sg_start had a '\-s' option to perform a SYNCHRONIZE
+CACHE command before the START STOP UNIT command was issued. According to
+recent SBC\-2 drafts this is done implicitly if required. Hence the '\-s'
+option has been dropped.
+.PP
+All options, other than '\-v' and '\-V', can be given with a single "\-".
+For example: "sg_start \-stop /dev/sda" and "sg_start \-\-stop /dev/sda"
+are equivalent. The single "\-" form is for backward compatibility.
+.TP
+\fB0\fR
+stop (spin\-down) \fIDEVICE\fR.
+.TP
+\fB1\fR
+start (spin\-up) \fIDEVICE\fR.
+.TP
+\fB\-\-eject\fR
+stop the medium and eject it from the drive.
+.TP
+\fB\-\-fl\fR=\fIFL\fR
+sets the format layer number for the disc to "jump" to (defined in MMC\-5).
+.TP
+\fB\-i\fR
+sets the IMM bit on the START STOP UNIT command so this utility will return
+immediately and not wait for the media to spin down. Same effect
+as '\-\-imm=1'. The default action (without this option or a '\-\-imm=1'
+option) is to wait until the media spins down before returning.
+.TP
+\fB\-\-imm\fR=\fI0|1\fR
+when the immediate bit is 1 then this utility returns immediately after the
+device has received the command. When this option is 0 (the default) then the
+utility returns once the command has completed its action (i.e. it waits
+until the device is started or stopped).
+.TP
+\fB\-\-load\fR
+load the medium in the drive and start it.
+.TP
+\fB\-\-loej\fR
+sets the LOEJ bit in the START STOP UNIT cdb. When a "start" operation is
+indicated, then a load and start is performed. When a "stop" operation is
+indicated, then a stop and eject is performed. When neither a "start"
+or "stop" operation is indicated does a stop and eject. [Note that the last
+action differs from the new interface in which the option of this name
+defaults to load and start.]
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-\-pc\fR=\fIPC\fR
+where \fIPC\fR is the 'power conditions' value (in hex). 0 to f (inclusive)
+are valid. Default value is 0.
+.TP
+\fB\-\-start\fR
+start (spin\-up) \fIDEVICE\fR.
+.TP
+\fB\-\-stop\fR
+stop (spin\-down) \fIDEVICE\fR. Same meaning as "0" argument.
+.TP
+\fB\-v\fR
+verbose: outputs SCSI command in hex to console before with executing
+it. '\-vv' and '\-vvv' are also accepted yielding greater verbosity.
+.TP
+\fB\-V\fR
+print out version string then exit.
.SH AUTHOR
Written by K. Garloff and D. Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2002-2006 Kurt Garloff, Douglas Gilbert
+Copyright \(co 2002\-2007 Kurt Garloff, Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_start.c b/sg_start.c
index 1c617515..4e08880d 100644
--- a/sg_start.c
+++ b/sg_start.c
@@ -3,46 +3,117 @@
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
+#include <getopt.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
/*
- * Copyright (C) 1999-2006 D. Gilbert
+ * Copyright (C) 1999-2007 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)
* any later version.
- Since this code has been used in the past to form the backbone of
- some Linux apps based on the "sg" device driver, it has been
- strengthened.
-
Start/Stop parameter by Kurt Garloff <garloff at suse dot de>, 6/2000
Sync cache parameter by Kurt Garloff <garloff at suse dot de>, 1/2001
Guard block device answering sg's ioctls.
<dgilbert at interlog dot com> 12/2002
Convert to SG_IO ioctl so can use sg or block devices in 2.6.* 3/2003
+
+ This utility was written for the Linux 2.4 kernel series. It should
+ now build for the Linux 2.6 kernel series and various other Operating
+ Systems.
*/
-static char * version_str = "0.51 20061016";
+static char * version_str = "0.55 20070128";
+
+static struct option long_options[] = {
+ {"eject", 0, 0, 'e'},
+ {"fl", 1, 0, 'f'},
+ {"help", 0, 0, 'h'},
+ {"immed", 0, 0, 'i'},
+ {"load", 0, 0, 'l'},
+ {"loej", 0, 0, 'L'},
+ {"new", 0, 0, 'N'},
+ {"old", 0, 0, 'O'},
+ {"pc", 1, 0, 'p'},
+ {"start", 0, 0, 's'},
+ {"stop", 0, 0, 'S'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+struct opts_t {
+ int do_eject;
+ int do_fl;
+ int do_help;
+ int do_immed;
+ int do_load;
+ int do_loej;
+ int do_pc;
+ int do_start;
+ int do_stop;
+ int do_verbose;
+ int do_version;
+ const char * device_name;
+ int opt_new;
+};
+
+void usage()
+{
+ fprintf(stderr, "Usage: sg_start [--eject] [--fl=FL] [--help] "
+ "[--immed] [--load] [--loej]\n"
+ " [--pc=PC] [--start] [--stop] "
+ "[--verbose] [--version]\n"
+ " DEVICE\n"
+ " where:\n"
+ " --eject|-e stop unit then eject the medium\n"
+ " --fl=FL|-f FL format layer number (mmc5)\n"
+ " --help|-h print usage message then exit\n"
+ " --immed|-i device should return control after "
+ "receiving cdb,\n"
+ " default action is to wait until action "
+ "is complete\n"
+ " --load|-l load medium then start the unit\n"
+ " --loej|-L load or eject, corresponds to LOEJ bit "
+ "in cdb;\n"
+ " load when START bit also set, else "
+ "eject\n"
+ " --pc=PC|-p PC power conditions: 0 (default) -> no "
+ "power condition,\n"
+ " 1 -> active, 2 -> idle, 3 -> standby, "
+ "5 -> sleep (MMC)\n"
+ " --start|-s start unit, corresponds to START bit "
+ "in cdb,\n"
+ " default (START=1) if no other options "
+ "given\n"
+ " --stop|-S stop unit (e.g. spin down disk)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string then exit\n\n"
+ " Example: 'sg_start --stop /dev/sdb' stops unit\n"
+ " 'sg_start --eject /dev/scd0' stops unit and "
+ "ejects medium\n\n"
+ "Performs a SCSI START STOP UNIT command\n"
+ );
+}
-void usage ()
+void usage_old()
{
- fprintf(stderr, "Usage: sg_start [0] [1] [--eject] [--fl=<n>] "
+ fprintf(stderr, "Usage: sg_start [0] [1] [--eject] [--fl=FL] "
"[-i] [--imm=0|1]\n"
- " [--load] [--loej] [--pc=<n>] [--start] "
+ " [--load] [--loej] [--pc=PC] [--start] "
"[--stop] [-v] [-V]\n"
- "< device>\n"
+ " DEVICE\n"
" where:\n"
" 0 stop unit (e.g. spin down a disk or a "
"cd/dvd)\n"
" 1 start unit (e.g. spin up a disk or a "
"cd/dvd)\n"
" --eject stop then eject the medium\n"
- " --fl=<n> format layer number (mmc5)\n"
+ " --fl=FL format layer number (mmc5)\n"
" -i return immediately (same as '--imm=1')\n"
" --imm=0|1 0->await completion(def), 1->return "
"immediately\n"
@@ -50,7 +121,7 @@ void usage ()
" --loej load the medium if '-start' option is "
"also given\n"
" or stop unit and eject\n"
- " --pc=<n> power conditions (in hex, default 0 -> no "
+ " --pc=PC power conditions (in hex, default 0 -> no "
"power condition)\n"
" 1 -> active, 2 -> idle, 3 -> standby, "
"5 -> sleep (MMC)\n"
@@ -62,212 +133,373 @@ void usage ()
" Example: 'sg_start --stop /dev/sdb' stops unit\n"
" 'sg_start --eject /dev/scd0' stops unit and "
"ejects medium\n\n"
- "Performs a START STOP UNIT SCSI command\n"
+ "Performs a SCSI START STOP UNIT command\n"
);
- exit (1);
}
-int main(int argc, char * argv[])
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
{
- int startstop = -1;
- const char * file_name = 0;
- const char * cp;
- int k, fd, num, res, plen, jmp_out;
- unsigned int u;
- int ambigu = 0;
- int immed = 0;
- int loej = 0;
- int fl_num = -1;
- int power_conds = 0;
- int verbose = 0;
- int ret = 0;
-
- for (k = 1; k < argc; ++k) {
- cp = argv[k];
- plen = strlen(cp);
- if (plen <= 0)
- continue;
- if ('-' == *cp) {
- for (--plen, ++cp, jmp_out = 0; plen > 0;
- --plen, ++cp) {
- switch (*cp) {
- case 'i':
- if ('\0' == *(cp + 1))
- immed = 1;
- else
- jmp_out = 1;
- break;
- case 'v':
- ++verbose;
- break;
- case 'V':
- fprintf(stderr, "Version string: "
- "%s\n", version_str);
- exit(0);
- case '?':
- usage();
- return 0;
- case '-':
- ++cp;
- --plen;
- jmp_out = 1;
- break;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
- }
- if (plen <= 0)
- continue;
+ int c, n, err;
- if (0 == strncmp(cp, "eject", 5)) {
- loej = 1;
- if (startstop == 1)
- ambigu = 1;
- else
- startstop = 0;
- } else if (0 == strncmp("fl=", cp, 3)) {
- num = sscanf(cp + 3, "%x", &u);
- if (1 != num) {
- fprintf(stderr, "Bad value after "
- "'fl=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- fl_num = u;
- } else if (0 == strncmp("imm=", cp, 4)) {
- num = sscanf(cp + 4, "%x", &u);
- if ((1 != num) || (u > 1)) {
- fprintf(stderr, "Bad value after "
- "'imm=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- immed = u;
- } else if (0 == strncmp(cp, "load", 4)) {
- loej = 1;
- if (startstop == 0)
- ambigu = 1;
- else
- startstop = 1;
- } else if (0 == strncmp(cp, "loej", 4))
- loej = 1;
- else if (0 == strncmp("pc=", cp, 3)) {
- num = sscanf(cp + 3, "%x", &u);
- if ((1 != num) || (u > 15)) {
- fprintf(stderr, "Bad value after "
- "after 'pc=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- power_conds = u;
- } else if (0 == strncmp(cp, "start", 5)) {
- if (startstop == 0)
- ambigu = 1;
- else
- startstop = 1;
- } else if (0 == strncmp(cp, "stop", 4)) {
- if (startstop == 1)
- ambigu = 1;
- else
- startstop = 0;
- } else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n",
- cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == strcmp("0", cp)) {
- if (startstop >= 0)
- ambigu = 1;
- else
- startstop = 0;
- } else if (0 == strcmp("1", cp)) {
- if (startstop >= 0)
- ambigu = 1;
- else
- startstop = 1;
- } else if (0 == file_name)
- file_name = cp;
- else {
- fprintf(stderr, "too many arguments, got: %s, not "
- "expecting: %s\n", file_name, cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- if (ambigu) {
- fprintf(stderr, "please, only one of 0, 1, --eject, "
- "--load, --start or --stop\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- }
-
- if (0 == file_name) {
- fprintf(stderr, "No <scsi_device> argument given\n");
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "ef:hilLNOp:sSvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'e':
+ ++optsp->do_eject;
+ ++optsp->do_loej;
+ break;
+ case 'f':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 3)) {
+ fprintf(stderr, "bad argument to '--fl='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ ++optsp->do_loej;
+ ++optsp->do_start;
+ optsp->do_fl = n;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'i':
+ ++optsp->do_immed;
+ break;
+ case 'l':
+ ++optsp->do_load;
+ ++optsp->do_loej;
+ break;
+ case 'L':
+ ++optsp->do_loej;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'p':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 15)) {
+ fprintf(stderr, "bad argument to '--pc='\n");
usage();
return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_pc = n;
+ break;
+ case 's':
+ ++optsp->do_start;
+ break;
+ case 'S':
+ ++optsp->do_stop;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
}
+ }
+ err = 0;
+ for (; optind < argc; ++optind) {
+ if (1 == strlen(argv[optind])) {
+ if (0 == strcmp("0", argv[optind])) {
+ ++optsp->do_stop;
+ continue;
+ } else if (0 == strcmp("1", argv[optind])) {
+ ++optsp->do_start;
+ continue;
+ }
+ }
+ if (NULL == optsp->device_name)
+ optsp->device_name = argv[optind];
+ else {
+ fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]);
+ ++err;
+ }
+ }
+ if (err) {
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ } else
+ return 0;
+}
- if (fl_num >= 0) {
- if (startstop == 0) {
- fprintf(stderr, "Giving '--fl=<n>' and '--stop' (or "
- "'--eject') is invalid\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
+{
+ int k, jmp_out, plen, num;
+ int ambigu = 0;
+ int startstop = -1;
+ unsigned int u;
+ const char * cp;
+
+ for (k = 1; k < argc; ++k) {
+ cp = argv[k];
+ plen = strlen(cp);
+ if (plen <= 0)
+ continue;
+ if ('-' == *cp) {
+ for (--plen, ++cp, jmp_out = 0; plen > 0;
+ --plen, ++cp) {
+ switch (*cp) {
+ case 'i':
+ if ('\0' == *(cp + 1))
+ optsp->do_immed = 1;
+ else
+ jmp_out = 1;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case '-':
+ ++cp;
+ --plen;
+ jmp_out = 1;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+
+ if (0 == strncmp(cp, "eject", 5)) {
+ optsp->do_loej = 1;
+ if (startstop == 1)
+ ambigu = 1;
+ else
+ startstop = 0;
+ } else if (0 == strncmp("fl=", cp, 3)) {
+ num = sscanf(cp + 3, "%x", &u);
+ if (1 != num) {
+ fprintf(stderr, "Bad value after 'fl=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ startstop = 1;
+ optsp->do_loej = 1;
+ optsp->do_fl = u;
+ } else if (0 == strncmp("imm=", cp, 4)) {
+ num = sscanf(cp + 4, "%x", &u);
+ if ((1 != num) || (u > 1)) {
+ fprintf(stderr, "Bad value after 'imm=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
}
- if (power_conds > 0) {
- fprintf(stderr, "Giving '--fl=<n>' and '--pc=<n>' "
- "when <n> is non-zero is invalid\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
+ optsp->do_immed = u;
+ } else if (0 == strncmp(cp, "load", 4)) {
+ optsp->do_loej = 1;
+ if (startstop == 0)
+ ambigu = 1;
+ else
+ startstop = 1;
+ } else if (0 == strncmp(cp, "loej", 4))
+ optsp->do_loej = 1;
+ else if (0 == strncmp("pc=", cp, 3)) {
+ num = sscanf(cp + 3, "%x", &u);
+ if ((1 != num) || (u > 15)) {
+ fprintf(stderr, "Bad value after after 'pc=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
}
- } else {
- if ((startstop == -1) && loej)
- startstop = 0;
- if ((startstop == -1) && (0 == power_conds))
- startstop = 1;
+ optsp->do_pc = u;
+ } else if (0 == strncmp(cp, "start", 5)) {
+ if (startstop == 0)
+ ambigu = 1;
+ else
+ startstop = 1;
+ } else if (0 == strncmp(cp, "stop", 4)) {
+ if (startstop == 1)
+ ambigu = 1;
+ else
+ startstop = 0;
+ } else if (0 == strncmp(cp, "old", 3))
+ ;
+ else if (jmp_out) {
+ fprintf(stderr, "Unrecognized option: %s\n", cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (0 == strcmp("0", cp)) {
+ if (1 == startstop)
+ ambigu = 1;
+ else
+ startstop = 0;
+ } else if (0 == strcmp("1", cp)) {
+ if (0 == startstop)
+ ambigu = 1;
+ else
+ startstop = 1;
+ } else if (0 == optsp->device_name)
+ optsp->device_name = cp;
+ else {
+ fprintf(stderr, "too many arguments, got: %s, not "
+ "expecting: %s\n", optsp->device_name, cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
}
-
- fd = sg_cmds_open_device(file_name, 0 /* rw */, verbose);
- if (fd < 0) {
- fprintf(stderr, "Error trying to open %s: %s\n",
- file_name, safe_strerror(-fd));
- return SG_LIB_FILE_ERROR;
+ if (ambigu) {
+ fprintf(stderr, "please, only one of 0, 1, --eject, "
+ "--load, --start or --stop\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ } else if (0 == startstop)
+ ++optsp->do_stop;
+ else if (1 == startstop)
+ ++optsp->do_start;
+ }
+ return 0;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
+
+
+int main(int argc, char * argv[])
+{
+ int fd, res;
+ int ret = 0;
+ struct opts_t opts;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.do_fl = -1; /* only when >= 0 set FL bit */
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
+ return 0;
+ }
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
+ }
+
+ if (opts.do_start && opts.do_stop) {
+ fprintf(stderr, "Ambiguous to give both '--start' and '--stop'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_load && opts.do_eject) {
+ fprintf(stderr, "Ambiguous to give both '--load' and '--eject'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_load)
+ opts.do_start = 1;
+ else if ((opts.do_eject) || (opts.do_stop))
+ opts.do_start = 0;
+ else if (opts.opt_new && opts.do_loej && (0 == opts.do_start))
+ opts.do_start = 1; /* --loej alone in new interface is load */
+ else if ((0 == opts.do_loej) && (-1 == opts.do_fl) && (0 == opts.do_pc))
+ opts.do_start = 1;
+ /* default action is to start when no other active options */
+
+ if (0 == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ if (opts.do_fl >= 0) {
+ if (opts.do_start == 0) {
+ fprintf(stderr, "Giving '--fl=FL' with '--stop' (or "
+ "'--eject') is invalid\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_pc > 0) {
+ fprintf(stderr, "Giving '--fl=FL' with '--pc=PC' "
+ "when PC is non-zero is invalid\n");
+ return SG_LIB_SYNTAX_ERROR;
}
+ }
+
+ fd = sg_cmds_open_device(opts.device_name, 0 /* rw */, opts.do_verbose);
+ if (fd < 0) {
+ fprintf(stderr, "Error trying to open %s: %s\n",
+ opts.device_name, safe_strerror(-fd));
+ return SG_LIB_FILE_ERROR;
+ }
- res = 0;
- if (fl_num >= 0)
- res = sg_ll_start_stop_unit(fd, immed, fl_num, power_conds,
- 1 /* fl */, 1 /* loej */,
- 1 /*start */, 1 /* noisy */,
- verbose);
- else if (power_conds > 0)
- res = sg_ll_start_stop_unit(fd, immed, 0, power_conds, 0, 0,
- 0, 1, verbose);
- else if (startstop != -1)
- res = sg_ll_start_stop_unit(fd, immed, 0, 0, 0, loej,
- startstop, 1, verbose);
- ret = res;
- if (res) {
- if (verbose < 2) {
- if (SG_LIB_CAT_INVALID_OP == res)
- fprintf(stderr, "command not supported\n");
- else if (SG_LIB_CAT_NOT_READY == res)
- fprintf(stderr, "device not ready\n");
- else if (SG_LIB_CAT_UNIT_ATTENTION == res)
- fprintf(stderr, "unit attention\n");
- else if (SG_LIB_CAT_ABORTED_COMMAND == res)
- fprintf(stderr, "aborted command\n");
- else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "invalid field in cdb\n");
- }
- fprintf(stderr, "START STOP UNIT command failed\n");
+ res = 0;
+ if (opts.do_fl >= 0)
+ res = sg_ll_start_stop_unit(fd, opts.do_immed, opts.do_fl, 0 /* pc */,
+ 1 /* fl */, 1 /* loej */,
+ 1 /*start */, 1 /* noisy */,
+ opts.do_verbose);
+ else if (opts.do_pc > 0)
+ res = sg_ll_start_stop_unit(fd, opts.do_immed, 0, opts.do_pc, 0, 0,
+ 0, 1, opts.do_verbose);
+ else
+ res = sg_ll_start_stop_unit(fd, opts.do_immed, 0, 0, 0, opts.do_loej,
+ opts.do_start, 1, opts.do_verbose);
+ ret = res;
+ if (res) {
+ if (opts.do_verbose < 2) {
+ if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, "command not supported\n");
+ else if (SG_LIB_CAT_NOT_READY == res)
+ fprintf(stderr, "device not ready\n");
+ else if (SG_LIB_CAT_UNIT_ATTENTION == res)
+ fprintf(stderr, "unit attention\n");
+ else if (SG_LIB_CAT_ABORTED_COMMAND == res)
+ fprintf(stderr, "aborted command\n");
+ else if (SG_LIB_CAT_ILLEGAL_REQ == res)
+ fprintf(stderr, "invalid field in cdb\n");
}
- res = sg_cmds_close_device(fd);
- if ((res < 0) && (0 == ret))
- return SG_LIB_FILE_ERROR;
- return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+ fprintf(stderr, "START STOP UNIT command failed\n");
+ }
+ res = sg_cmds_close_device(fd);
+ if ((res < 0) && (0 == ret))
+ return SG_LIB_FILE_ERROR;
+ return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
diff --git a/sg_sync.8 b/sg_sync.8
index 3b435acd..cf2cfc42 100644
--- a/sg_sync.8
+++ b/sg_sync.8
@@ -1,73 +1,76 @@
-.TH SG_SYNC "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_SYNC "8" "December 2006" "sg3_utils\-1.22" SG3_UTILS
.SH NAME
sg_sync \- send the scsi command synchronize cache
.SH SYNOPSIS
.B sg_sync
-[\fI--count=<n>\fR] [\fI--group=<n>\fR] [\fI--help\fR] [\fI--immed\fR]
-[\fI--lba=<n>\fR] [\fI--sync-nv\fR] [\fI--verbose\fR] [\fI--version\fR]
-\fI<scsi_device>\fR
+[\fI\-\-count=COUNT\fR] [\fI\-\-group=GROUP\fR] [\fI\-\-help\fR]
+[\fI\-\-immed\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-sync\-nv\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send SYNCHRONIZE CACHE (10) command to a SCSI device.
-This command is defined for SCSI block devices (see SBC-2). If successful
-this command makes sure that any blocks whose latest versions are held
-in (volatile) cache are written to (also termed as "synchronized with")
-the medium. If the '--sync-nv' option is given and the device has a
-non-volatile cache then any blocks whose latest versions are held
-in volatile cache are written to non-volatile cache.
+Send SYNCHRONIZE CACHE (10) command to \fIDEVICE\fR. This command is
+defined for SCSI block devices (see SBC\-2). If successful this command
+makes sure that any blocks whose latest versions are held in (volatile)
+cache are written to (also termed as "synchronized with") the medium. If
+the \fI\-\-sync\-nv\fR option is given and the device has a non\-volatile
+cache then any blocks whose latest versions are held in volatile cache are
+written to non\-volatile cache.
.PP
-If the arguments to '--lba' and '--count' are both zero (their defaults)
-then all blocks in the cache are synchronized. If '--lba' is greater than
-zero while '--count' is zero then blocks in the cache whose address
-is from and including the '--lba' argument to the highest lba on the
-device are synchronized. If both '--lba' and '--count' are non zero
-then blocks in the cache whose addresses lie in the range lba_argument to
-lba_argument+count_argument-1 inclusive are synchronized with the medium.
+If the \fILBA\fR and \fICOUNT\fR arguments are both zero (their defaults)
+then all blocks in the cache are synchronized. If \fILBA\fR is greater than
+zero while \fICOUNT\fR is zero then blocks in the cache whose addresses are
+from and including \fILBA\fR to the highest lba on the device are
+synchronized. If both \fILBA\fR and \fICOUNT\fR are non zero then blocks in
+the cache whose addresses lie in the range \fILBA\fR to
+\fILBA\fR+\fICOUNT\fR\-1 inclusive are synchronized with the medium.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---count=<n> | -c <n>
-number of block to synchronize from and including the '--lba' argument.
-Default value is 0. When 0 then all blocks in the (volatile) cache from
-and including the '--lba' argument to the highest block address are
+\fB\-c\fR, \fB\-\-count\fR=\fICOUNT\fR
+where \fICOUNT\fR is the number of blocks to synchronize from and including
+\fILBA\fR. Default value is 0. When 0 then all blocks in the (volatile) cache
+from and including \fILBA\fR argument to the highest block address are
synchronized.
.TP
---group=<n> | -g <n>
-the group number can be between 0 and 31 inclusive. The default value is 0 .
-Group numbers are used to segregate data collected within the device.
-This is a new feature in SBC-2 and can probably be ignored for the time
-being.
+\fB\-g\fR, \fB\-\-group\fR=\fIGROUP\fR
+where \fIGROUP\fR is the group number which can be between 0 and 31 inclusive.
+The default value is 0 . Group numbers are used to segregate data collected
+within the device. This is a new feature in SBC\-2 and can probably be
+ignored for the time being.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---imm | -i
-sets the "imm" bit in the SYNCHRONIZE CACHE command. This instructs the
+\fB\-i\fR, \fB\-\-immed\fR
+sets the IMMED bit in the SYNCHRONIZE CACHE command. This instructs the
device, if the format of the command is acceptable, to return a GOOD
status immediately rather than wait for the blocks in the (volatile)
cache to be synchronized with (i.e. written to) the medium (or the
-non-volatile cache).
+non\-volatile cache).
.TP
---lba=<n> | -l <n>
-the lowest logical block address in the (volatile) cache to synchronize
-to the medium (or the non-volatile cache). Default value is 0 .
+\fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR
+where \fILBA\fR is the lowest logical block address in the (volatile)
+cache to synchronize to the medium (or the non\-volatile cache). Default
+value is 0 .
.TP
---sync-nv | -s
-synchronize the (volatile) cache with the non-volatile cache. Without this
-option (or if there is no non-volatile cache in the device) the synchronization
-is with the medium.
+\fB\-s\fR, \fB\-\-sync-nv\fR
+synchronize the (volatile) cache with the non\-volatile cache. Without this
+option (or if there is no non\-volatile cache in the device) the
+synchronization is with the medium.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
-The arguments to --count, --group and --lba may be followed by one of these
-multiplicative suffixes:
+.SH NOTES
+The \fICOUNT\fR, \fIGROUP\fR and \fILBA\fR arguments may be followed by one
+of these multiplicative suffixes:
c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
MB *1,000,000 . This pattern continues for "G", "T" and "P". Also a suffix of
the form "x<n>" multiplies the leading number by <n>. The "T" and "P"
-suffixes can only be used for --count and --lba.
+suffixes can only be used for \fICOUNT\fR and \fILBA\fR.
.PP
Alternatively numerical values can be given in hexadecimal preceded by
either "0x" or "0X" (or with a trailing "h" or "H"). When hex numbers are
@@ -80,7 +83,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2006 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_sync.c b/sg_sync.c
index fe41930a..e6c250d2 100644
--- a/sg_sync.c
+++ b/sg_sync.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@
* (e.g. disks).
*/
-static char * version_str = "1.06 20061012";
+static char * version_str = "1.07 20070127";
#define ME "sg_sync: "
@@ -66,20 +66,19 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_sync [--count=<n>] [--group=<n>] [--help] [--immed]"
- " [--lba=<n>]\n"
- " [--sync-nv] [--verbose] [--version]"
- " <scsi_device>\n"
+ "sg_sync [--count=COUNT] [--group=GROUP] [--help] [--immed]\n"
+ " [--lba=LBA] [--sync-nv] [--verbose] [--version] "
+ "DEVICE\n"
" where:\n"
- " --count=<n>|-c <n> number of blocks to sync (def: 0 "
+ " --count=COUNT|-c COUNT number of blocks to sync (def: 0 "
"which implies\n"
- " rest of device)\n"
- " --group=<n>|-g <n> set group number (def: 0)\n"
+ " rest of device)\n"
+ " --group=GROUP|-g GROUP set group number (def: 0)\n"
" --help|-h print out usage message\n"
" --immed|-i command returns immediately when set "
"else wait\n"
" for 'sync' to complete\n"
- " --lba=<n>|-l <n> logical block address to start sync "
+ " --lba=LBA|-l LBA logical block address to start sync "
"operation\n"
" from (def: 0)\n"
" --sync-nv|-s synchronize to non-volatile storage "
@@ -87,7 +86,7 @@ static void usage()
" from medium)\n"
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
- "Performs a SYNCHRONIZE CACHE(10) SCSI command\n"
+ "Performs a SCSI SYNCHRONIZE CACHE(10) command\n"
);
}
diff --git a/sg_test_rwbuf.8 b/sg_test_rwbuf.8
index 08b12d8e..6230ac24 100644
--- a/sg_test_rwbuf.8
+++ b/sg_test_rwbuf.8
@@ -1,70 +1,71 @@
-.TH SG_TEST_RWBUF "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_TEST_RWBUF "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_test_rwbuf \- Tests the SCSI host adapter by issuing write and read
operations on a device's buffer and calculating checksums.
.SH SYNOPSIS
.B sg_test_rwbuf
-[\fI--addrd=<n>\fR] [\fI--addwr=<n>\fR] [\fI--help\fR]
-[\fI--quick\fR] \fI--size=<sz>\fR [\fI--times=<n>\fR] [\fI--verbose\fR]
-[\fI--version\fR] \fI<scsi_device>\fR
-.br
-or (an older deprecated format)
-.br
+[\fI\-\-addrd=AR\fR] [\fI\-\-addwr=AW\fR] [\fI\-\-help\fR]
+[\fI\-\-quick\fR] \fI\-\-size=SZ\fR [\fI\-\-times=NUM\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] \fIDEVICE\fR
+.PP
+or an older deprecated format
.B sg_test_rwbuf
-\fI<scsi_device>\fR \fI<sz>\fR [\fI<addwr>\fR] [\fI<addrd>\fR]
+\fIDEVICE\fR \fISZ\fR [\fIAW\fR] [\fIAR\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
-sg_test_rwbuf writes and reads back sz bytes to the internal buffer of
-<\fIscsi_device\fR> (e.g. /dev/sda or /dev/sg0). A pseudo random pattern is
+sg_test_rwbuf writes and reads back \fISZ\fR bytes to the internal buffer of
+\fIDEVICE\fR (e.g. /dev/sda or /dev/sg0). A pseudo random pattern is
written to the data buffer on the device then read back. If the same pattern
is found 'Success' is reported. If they do not match (checksums unequal) then
this is reported and up to 24 bytes from the first point of mismatch are
reported; the first line shows what was written and the second line shows
-what was received. For testing purposes, you can ask it to write <addwr> or
-read <addrd> additional bytes.
+what was received. For testing purposes, you can ask it to write \fIAW\fR or
+read \fIAR\fR additional bytes.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---addrd=<n> | -r <n>
-Read an additional <n> bytes (than indicated by <sz>) from the data buffer.
-Checksum is performed over the first <sz> bytes.
+\fB\-r\fR, \fB\-\-addrd\fR=\fIAR\fR
+Read an additional \fIAR\fR bytes (than indicated by \fISZ\fR) from the data
+buffer. Checksum is performed over the first \fISZ\fR bytes.
.TP
---addwr=<n> | -w <n>
-Write an additional <n> bytes (than indicated by <sz>) of zeroes into the
-data buffer. Checksum is generated over the first <sz> bytes.
+\fB\-w\fR, \fB\-\-addwr\fR=\fIAW\fR
+Write an additional \fIAW\fR bytes (than indicated by \fISZ\fR) of zeros
+into the data buffer. Checksum is generated over the first \fISZ\fR bytes.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
Print out a usage message the exit.
.TP
---quick | -q
+\fB\-q\fR, \fB\-\-quick\fR
Perform a READ BUFFER descriptor command to find out the available data
buffer length and offset, print them out then exit (without testing
with write/read sequences).
.TP
---size=<sz> | -s <sz>
-Size of buffer in bytes to be written then read and checked. This number
-needs to be less than on equal to the size of the device's data buffer
-which can be seen from the '--quick' option. Either this option or
-the '--quick' option should be given.
+\fB\-s\fR, \fB\-\-size\fR=\fISZ\fR
+where \fISZ\fRis teh size of buffer in bytes to be written then read and
+checked. This number needs to be less than on equal to the size of the
+device's data buffer which can be seen from the \fI\-\-quick\fR option.
+Either this option or the \fI\-\-quick\fR option should be given.
.TP
---times=<n> | -t <n>
-Number of times to repeat the write/read to buffer test. Default value
-is 1 .
+\fB\-t\fR, \fB\-\-times\fR=\fINUM\fR
+where \fINUM\fR is the number of times to repeat the write/read to buffer
+test. Default value is 1 .
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase verbosity of output.
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print version number (and data of last change) then exit.
-.PP
+.SH NOTES
The microcode in a SCSI device is _not_ modified by doing a WRITE BUFFER
command with its mode set to "data" (0x2) as done by this utility. Therefore
this utility is safe in that respect. [Mode values 0x4, 0x5, 0x6 and 0x7
-are the dangerous ones :-)]
+are the dangerous ones :\-)]
.PP
\fBWARNING\fR: If you access the device at the same time (e.g. because it's
a hard disk with a mounted file system on it) the device's buffer may be
used by the device itself for other data at the same time, and overwriting
-it may or may not cause data corruption! \fBHOWEVER\fR the SPC-3 draft
+it may or may not cause data corruption! \fBHOWEVER\fR the SPC\-3 draft
standard does state in its WRITE BUFFER command: "This command shall not
alter any medium of the logical unit when data mode ... is specified". This
implies that it _is_ safe to use this utility with devices that have mounted
@@ -78,7 +79,7 @@ the sg3_utils(8) man page.
.SH AUTHORS
Written by D. Gilbert and K. Garloff
.SH COPYRIGHT
-Copyright \(co 2000-2005 Douglas Gilbert, Kurt Garloff
+Copyright \(co 2000\-2006 Douglas Gilbert, Kurt Garloff
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_test_rwbuf.c b/sg_test_rwbuf.c
index 1b7b6ccb..53ab8d3d 100644
--- a/sg_test_rwbuf.c
+++ b/sg_test_rwbuf.c
@@ -9,7 +9,7 @@
* somebody else in the meantime.
* (c) 2000 Kurt Garloff <garloff at suse dot de>
* heavily based on Doug Gilbert's sg_rbuf program.
- * (c) 1999-2006 Doug Gilbert
+ * (c) 1999-2007 Doug 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
@@ -35,7 +35,7 @@
#include "sg_io_linux.h"
-static char * version_str = "1.03 20060811";
+static char * version_str = "1.05 20070121";
#define BPI (signed)(sizeof(int))
@@ -211,7 +211,7 @@ int read_buffer (int sg_fd, unsigned size)
int res, k;
unsigned char rbCmdBlk[] = {READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int bufSize = size + addread;
- unsigned char * rbBuff = malloc(bufSize);
+ unsigned char * rbBuff = (unsigned char *)malloc(bufSize);
unsigned char sense_buffer[32];
struct sg_io_hdr io_hdr;
@@ -267,7 +267,7 @@ int write_buffer (int sg_fd, unsigned size)
{
unsigned char wbCmdBlk[] = {WRITE_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int bufSize = size + addwrite;
- unsigned char * wbBuff = malloc(bufSize);
+ unsigned char * wbBuff = (unsigned char *)malloc(bufSize);
unsigned char sense_buffer[32];
struct sg_io_hdr io_hdr;
int k, res;
@@ -322,23 +322,22 @@ int write_buffer (int sg_fd, unsigned size)
void usage ()
{
- printf ("Usage: sg_test_rwbuf [--addrd=<n>] [--addwr=<n>] [--help] "
+ printf ("Usage: sg_test_rwbuf [--addrd=AR] [--addwr=AW] [--help] "
"[--quick]\n");
- printf (" --size=<sz> [--times=<n>] [--verbose] "
+ printf (" --size=SZ [--times=NUM] [--verbose] "
"[--version]\n"
- " <scsi_device>\n"
+ " DEVICE\n"
" or\n"
- " sg_test_rwbuf <scsi_device> <sz> [<addwr>] "
- "[<addrd>]\n");
+ " sg_test_rwbuf DEVICE SZ [AW] [AR]\n");
printf (" where:\n"
- " --addrd=<n> extra bytes to fetch during READ "
+ " --addrd=AR extra bytes to fetch during READ "
"BUFFER\n"
- " --addwr=<n> extra bytes to send to WRITE BUFFER\n"
+ " --addwr=AW extra bytes to send to WRITE BUFFER\n"
" --help output this usage message then exit\n"
" --quick output read buffer size then exit\n"
- " --size=<sz> size of buffer (in bytes) to write "
+ " --size=SZ size of buffer (in bytes) to write "
"then read back\n"
- " --times=<n> number of times to run test "
+ " --times=NUM number of times to run test "
"(default 1)\n"
" --verbose increase verbosity of output\n"
" --verbose output version then exit\n");
@@ -349,7 +348,7 @@ void usage ()
printf (" for other data at the same time, and overwriting it may or "
"may not\n");
printf (" cause data corruption!\n");
- printf ("(c) Douglas Gilbert, Kurt Garloff, 2000-2006, GNU GPL\n");
+ printf ("(c) Douglas Gilbert, Kurt Garloff, 2000-2007, GNU GPL\n");
}
@@ -494,7 +493,7 @@ int main (int argc, char * argv[])
goto err_out;
}
- cmpbuf = malloc (size);
+ cmpbuf = (unsigned char *)malloc(size);
for (k = 0; k < times; ++k) {
ret = write_buffer (sg_fd, size);
if (ret) {
diff --git a/sg_turs.8 b/sg_turs.8
index 3f5893e2..2018c63a 100644
--- a/sg_turs.8
+++ b/sg_turs.8
@@ -1,53 +1,95 @@
-.TH SG_TURS "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_TURS "8" "December 2006" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_turs \- executes a user specified number of TEST UNIT READY commands on
-the given device
+sg_turs \- send one or more SCSI TEST UNIT READY commands
.SH SYNOPSIS
.B sg_turs
-[\fI-n=<number of commands to send>\fR] [\fI-p\fR] [\fI-t\fR] [\fI-v\fR]
-[\fI-V\fR] <\fIscsi_device\fR>
+[\fI\-\-help\fR] [\fI\-\-number=NUM\fR] [\fI\-\-progress\fR] [\fI\-\-time\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.PP
+.B sg_turs
+[\fI\-n=NUM\fR] [\fI\-p\fR] [\fI\-t\fR] [\fI\-v\fR] [\fI\-V\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-sg_turs sends a number of TEST UNIT READY commands to a given SCSI
-device. Useful for timing the per command overhead. Note that
-TEST UNIT READY has no associated data, just a 6 byte command and a
-returned SCSI status value. If the SCSI status value is CHECK CONDITION
-then most modern initiators fetch sense data from the device (i.e.
-autosense).
-.TP
--n=<num>
-performs TEST UNIT READY "<num>" times. If not given defaults to 1.
+This utility sends one or more SCSI TEST UNIT READY commands to the
+\fIDEVICE\fR. This may be useful for timing the per command overhead.
+Note that TEST UNIT READY has no associated data, just a 6 byte command
+and a returned SCSI status value. If the SCSI status value is CHECK
+CONDITION then most modern initiators fetch sense data from
+the device (i.e. autosense).
+.PP
+This utility supports two command line syntaxes, the preferred one is
+shown first in the synopsis and explained in this section. A later section
+on the old command line syntax outlines the second group of options.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+print out the usage message then exit.
+.TP
+\fB\-n\fR, \fB\-\-number\fR=\fINUM\fR
+performs TEST UNIT READY \fINUM\fR times. If not given defaults to 1.
These suffix multipliers are permitted: c C *1; w W *2; b B *512;
k K KiB *1,024; KB *1,000; m M MiB *1,048,576; MB *1,000,000;
g G GiB *1,073,741,824; and GB *1,000,000,000 . Also a suffix of the
form "x<n>" multiplies the leading number by <n>. Alternatively a hex
-number may be given, prefixed by either '0x' or '0X' (or has a
-trailing 'h' or 'H').
+number may be given, prefixed by either '0x' or has a trailing 'h'.
+.TP
+\fB\-O\fR, \fB\-\-old\fR
+switch to older style options.
.TP
--p
-show progress indication (a percentage) if available. If <num> greater
-than one waits 30 seconds before subsequent checks. Exits when <num>
-is reached or there is no more progress indication. Ignores '-t' option.
+\fB\-p\fR, \fB\-\-progress\fR
+show progress indication (a percentage) if available. If \fI\-\-number=NUM\fR
+is given and \fINUM\fR is greater than 1 then waits 30 seconds before
+subsequent checks. Exits when \fINUM\fR is reached or there is no more
+progress indication. Ignores \fI\-\-time\fR option.
.TP
--t
+\fB\-t\fR, \fB\-\-time\fR
after completing the requested number of TEST UNIT READY commands, outputs
the total duration and the average number of commands executed per second.
.TP
--v
-increase level of verbosity: print out SCSI commands in hex prior to
-sending them to the device. '-vv' and '-vvv' are also accepted yielding
-greater verbosity.
+\fB\-v\fR, \fB\-\-verbose\fR
+increase level or verbosity.
.TP
--V
-print out version string then exit.
+\fB\-V\fR, \fB\-\-version\fR
+print version string then exit.
.SH EXIT STATUS
-The exit status of sg_verify is 0 when it is successful. Otherwise see
+The exit status of sg_turs is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
+.SH OLDER COMMAND LINE OPTIONS
+The options in this section were the only ones available prior to sg3_utils
+version 1.23 . In sg3_utils version 1.23 and later these older options can
+be selected by either setting the SG3_UTILS_OLD_OPTS environment variable
+or using '\-\-old' (or '\-O) as the first option.
+.TP
+\fB\-n\fR=\fINUM\fR
+performs TEST UNIT READY \fINUM\fR times. If not given defaults to 1.
+Equivalent to \fI\-\-number=NUM\fR in the main description.
+.TP
+\fB\-N\fR
+switch to the newer style options.
+.TP
+\fB\-p\fR
+show progress indication (a percentage) if available.
+Equivalent to \fI\-\-progress\fR in the main description.
+.TP
+\fB\-t\fR
+after completing the requested number of TEST UNIT READY commands, outputs
+the total duration and the average number of commands executed per second.
+Equivalent to \fI\-\-time\fR in the main description.
+.TP
+\fB\-v\fR
+increase level of verbosity.
+.TP
+\fB\-V\fR
+print out version string then exit.
.SH AUTHORS
Written by D. Gilbert
.SH COPYRIGHT
-Copyright \(co 2000-2006 Douglas Gilbert
+Copyright \(co 2000\-2006 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH "SEE ALSO"
+.B sg_inq(sg3_utils)
diff --git a/sg_turs.c b/sg_turs.c
index 0099bd71..b8dcb340 100644
--- a/sg_turs.c
+++ b/sg_turs.c
@@ -3,7 +3,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
+#ifndef SG3_UTILS_MINGW
#include <sys/time.h>
+#endif
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -13,23 +16,75 @@
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-2006 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)
-* any later version.
+ * Copyright (C) 2000-2007 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)
+ * any later version.
-*/
+ */
-static char * version_str = "3.22 20061003";
+static char * version_str = "3.26 20070127";
+
+#if defined(MSC_VER) || defined(__MINGW32__)
+#define HAVE_MS_SLEEP
+#endif
+
+#ifdef HAVE_MS_SLEEP
+#include <windows.h>
+#define sleep_for(seconds) Sleep( (seconds) * 1000)
+#else
+#define sleep_for(seconds) sleep(seconds)
+#endif
+
+static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"new", 0, 0, 'N'},
+ {"number", 1, 0, 'n'},
+ {"old", 0, 0, 'O'},
+ {"progress", 0, 0, 'p'},
+ {"time", 0, 0, 't'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+struct opts_t {
+ int do_help;
+ int do_number;
+ int do_progress;
+ int do_time;
+ int do_verbose;
+ int do_version;
+ const char * device_name;
+ int opt_new;
+};
static void usage()
{
- printf("Usage: sg_turs [-n=<num>] [-p] [-t] [-v] [-V] "
- "<device>\n"
+ printf("Usage: sg_turs [--help] [--number=NUM] [--progress] [--time] "
+ "[--verbose]\n"
+ " [--version] DEVICE\n"
+ " where:\n"
+ " --help|-h print usage message then exit\n"
+ " --number=NUM|-n NUM number of test_unit_ready commands "
+ "(def: 1)\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"
+ " --version|-V print version string then exit\n\n"
+ "Performs a SCSI TEST UNIT READY command (or many of them)\n");
+}
+
+static void usage_old()
+{
+ printf("Usage: sg_turs [-n=NUM] [-p] [-t] [-v] [-V] "
+ "DEVICE\n"
" where:\n"
- " -n=<num> number of test_unit_ready commands "
+ " -n=NUM number of test_unit_ready commands "
"(def: 1)\n"
" -p outputs progress indication (percentage) "
"if available\n"
@@ -37,23 +92,88 @@ static void usage()
"second\n"
" -v increase verbosity\n"
" -V print version string then exit\n\n"
- "Performs a TEST UNIT READY SCSI command (or many of them)\n");
+ "Performs a SCSI TEST UNIT READY command (or many of them)\n");
}
-int main(int argc, char * argv[])
+static void usage_for(const struct opts_t * optsp)
+{
+ if (optsp->opt_new)
+ usage();
+ else
+ usage_old();
+}
+
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c, n;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "hn:NOptvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'n':
+ n = sg_get_num(optarg);
+ if (n < 0) {
+ fprintf(stderr, "bad argument to '--number='\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_number = n;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'p':
+ ++optsp->do_progress;
+ break;
+ case 't':
+ ++optsp->do_time;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ return 0;
+}
+
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
{
- int sg_fd, k, plen, jmp_out, res;
- const char * file_name = 0;
+ int k, jmp_out, plen;
const char * cp;
- int num_turs = 1;
- int do_progress = 0;
- int progress;
- int num_errs = 0;
- int do_time = 0;
- int verbose = 0;
- int reported = 0;
- int ret = 0;
- struct timeval start_tm, end_tm;
for (k = 1; k < argc; ++k) {
cp = argv[k];
@@ -63,20 +183,25 @@ int main(int argc, char * argv[])
if ('-' == *cp) {
for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
switch (*cp) {
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
case 'p':
- do_progress = 1;
+ ++optsp->do_progress;
break;
case 't':
- do_time = 1;
+ ++optsp->do_time;
break;
case 'v':
- ++verbose;
+ ++optsp->do_verbose;
break;
case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
+ ++optsp->do_verbose;
+ break;
case '?':
- usage();
+ usage_old();
return 0;
default:
jmp_out = 1;
@@ -88,44 +213,95 @@ int main(int argc, char * argv[])
if (plen <= 0)
continue;
if (0 == strncmp("n=", cp, 2)) {
- num_turs = sg_get_num(cp + 2);
- if (num_turs <= 0) {
+ optsp->do_number = sg_get_num(cp + 2);
+ if (optsp->do_number <= 0) {
printf("Couldn't decode number after 'n=' option\n");
- usage();
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- } else if (jmp_out) {
+ } else if (0 == strncmp("-old", cp, 4))
+ ;
+ else if (jmp_out) {
fprintf(stderr, "Unrecognized option: %s\n", cp);
- usage();
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- } else if (0 == file_name)
- file_name = cp;
+ } else if (0 == optsp->device_name)
+ optsp->device_name = cp;
else {
fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
- usage();
+ "%s\n", optsp->device_name, cp);
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
}
- if (0 == file_name) {
- fprintf(stderr, "No <scsi_device> argument given\n");
- usage();
+ return 0;
+}
+
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
+ }
+ return res;
+}
+
+int main(int argc, char * argv[])
+{
+ int sg_fd, k, res, progress;
+ int num_errs = 0;
+ int reported = 0;
+ int ret = 0;
+#ifndef SG3_UTILS_MINGW
+ struct timeval start_tm, end_tm;
+#endif
+ struct opts_t opts;
+
+ memset(&opts, 0, sizeof(opts));
+ opts.do_number = 1;
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ usage_for(&opts);
+ return 0;
+ }
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
+ }
+
+ if (NULL == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ usage_for(&opts);
return SG_LIB_SYNTAX_ERROR;
}
- if ((sg_fd = sg_cmds_open_device(file_name, 1 /* ro */, verbose)) < 0) {
+ if ((sg_fd = sg_cmds_open_device(opts.device_name, 1 /* ro */,
+ opts.do_verbose)) < 0) {
fprintf(stderr, "sg_turs: error opening file: %s: %s\n",
- file_name, safe_strerror(-sg_fd));
+ opts.device_name, safe_strerror(-sg_fd));
return SG_LIB_FILE_ERROR;
}
- if (do_progress) {
- for (k = 0; k < num_turs; ++k) {
+ if (opts.do_progress) {
+ for (k = 0; k < opts.do_number; ++k) {
if (k > 0)
- sleep(30);
+ sleep_for(30);
progress = -1;
res = sg_ll_test_unit_ready_progress(sg_fd, k, &progress,
- ((1 == num_turs) ? 1 : 0), verbose);
+ ((1 == opts.do_number) ? 1 : 0), opts.do_verbose);
if (progress < 0) {
ret = res;
break;
@@ -133,28 +309,31 @@ int main(int argc, char * argv[])
printf("Progress indication: %d%% done\n",
(progress * 100) / 65536);
}
- if (num_turs > 1)
+ if (opts.do_number > 1)
printf("Completed %d Test Unit Ready commands\n",
- ((k < num_turs) ? k + 1 : k));
+ ((k < opts.do_number) ? k + 1 : k));
} else {
- if (do_time) {
+#ifndef SG3_UTILS_MINGW
+ if (opts.do_time) {
start_tm.tv_sec = 0;
start_tm.tv_usec = 0;
gettimeofday(&start_tm, NULL);
}
- for (k = 0; k < num_turs; ++k) {
- res = sg_ll_test_unit_ready(sg_fd, k, 0, verbose);
+#endif
+ for (k = 0; k < opts.do_number; ++k) {
+ res = sg_ll_test_unit_ready(sg_fd, k, 0, opts.do_verbose);
if (res) {
++num_errs;
ret = res;
- if ((1 == num_turs) && (SG_LIB_CAT_NOT_READY == res)) {
+ if ((1 == opts.do_number) && (SG_LIB_CAT_NOT_READY == res)) {
printf("device not ready\n");
reported = 1;
break;
}
}
}
- if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
+#ifndef SG3_UTILS_MINGW
+ if ((opts.do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
struct timeval res_tm;
double a, b;
@@ -167,7 +346,7 @@ int main(int argc, char * argv[])
}
a = res_tm.tv_sec;
a += (0.000001 * res_tm.tv_usec);
- b = (double)num_turs;
+ b = (double)opts.do_number;
printf("time to perform commands was %d.%06d secs",
(int)res_tm.tv_sec, (int)res_tm.tv_usec);
if (a > 0.00001)
@@ -175,10 +354,11 @@ int main(int argc, char * argv[])
else
printf("\n");
}
+#endif
- if (((num_turs > 1) || (num_errs > 0)) && (! reported))
+ if (((opts.do_number > 1) || (num_errs > 0)) && (! reported))
printf("Completed %d Test Unit Ready commands with %d errors\n",
- num_turs, num_errs);
+ opts.do_number, num_errs);
}
sg_cmds_close_device(sg_fd);
return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
diff --git a/sg_verify.8 b/sg_verify.8
index 2a953661..338f5d51 100644
--- a/sg_verify.8
+++ b/sg_verify.8
@@ -1,68 +1,67 @@
-.TH SG_VERIFY "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_VERIFY "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sg_verify \- invoke SCSI VERIFY command(s) on a block device
.SH SYNOPSIS
.B sg_verify
-[\fI--bpc=<n>\fR] [\fI--count=<n>\fR] [\fI--dpo\fR] [\fI--help\fR]
-[\fI--lba=<n>\fR] [\fI--verbose\fR] [\fI--version\fR]
-\fI<scsi_device>\fR
+[\fI\-\-bpc=BPC\fR] [\fI\-\-count=COUNT\fR] [\fI\-\-dpo\fR] [\fI\-\-help\fR]
+[\fI\-\-lba=LBA\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Sends one or more SCSI VERIFY commands to the given SCSI device.
-It is a 10 byte VERIFY command defined for block devices (see SBC-2
-at http://www.t10.org). Verify starts at the logical block address
-given by the '--lba=<n>' option and continues for '--count=<n>'
-blocks. No more than '--bpc=<n>' blocks are verified by each VERIFY
-command so if necessary multiple VERIFY commands are sent.
-No news is good news (i.e. if there are no verify errors detected
-no messages are sent to stderr and the Unix return status is 0).
+Sends one or more SCSI VERIFY commands to \fIDEVICE\fR. It is the 10 byte
+VERIFY command defined for block devices (see SBC\-2 at http://www.t10.org).
+Verify starts at the logical block address given by the \fI\-\-lba=LBA\fR
+option and continues for \fI\-\-count=COUNT\fR blocks. No more than
+\fI\-\-bpc=BPC\fR blocks are verified by each VERIFY command so if necessary
+multiple VERIFY commands are sent. No news is good news (i.e. if there are
+no verify errors detected no messages are sent to stderr and the Unix return
+status is 0).
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---bpc=<n> | -b <n>
-specifies the maximum number of blocks that will be verified by a
-single SCSI VERIFY command. The default value is 128 blocks which
-equates to 64 KB for a disk with 512 byte blocks. If the value <n>
-is less than the value given to --count then multiple SCSI VERIFY
-commands are sent to the device. For recent block devices (disks)
-this value may be constrained by the maximum transfer length field
-in the block limits VPD page.
+\fB\-b\fR, \fB\-\-bpc\fR=\fIBPC\fR
+where \fIBPC\fR specifies the maximum number of blocks that will be verified
+by a single SCSI VERIFY command. The default value is 128 blocks which
+equates to 64 KB for a disk with 512 byte blocks. If \fIBPC\fR is less than
+\fICOUNT\fR then multiple SCSI VERIFY commands are sent to the device. For
+recent block devices (disks) this value may be constrained by the maximum
+transfer length field in the block limits VPD page.
.TP
---dpo | -d
-disable page out changes the cache retention priority of blocks read on
-the device's cache to the lowest priority. This means that blocks read by
-other commands are more likely to remain in the device's cache.
-.TP
---count=<n> | -c <n>
-specifies the number of blocks to verify. The default value is 1 .
-If <n> is greater than the value associated with '--bpc' (or its default
-value of 128) then multiple SCSI VERIFY commands are sent to the
-device. The
+\fB\-c\fR, \fB\-\-count\fR=\fICOUNT\fR
+where \fICOUNT\fR specifies the number of blocks to verify. The default value
+is 1 . If \fICOUNT\fR is greater than \fIBPC\fR (or its default value of 128)
+then multiple SCSI VERIFY commands are sent to the device. The
.B sg_readcap
utility can be used to find the maximum number of blocks that a block
device (e.g. a disk) has.
.TP
---help | -h
+\fB\-d\fR, \fB\-\-dpo\fR
+disable page out changes the cache retention priority of blocks read on
+the device's cache to the lowest priority. This means that blocks read by
+other commands are more likely to remain in the device's cache.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---lba=<n> | -l <n>
-specifies the logical block address on the device to start the verify
-operation. <n> is assumed to be decimal unless prefixed by '0x' or
-a trailing 'h' (see below). The default value is 0 (i.e. the start of the
-device).
+\fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR
+where \fILBA\fR specifies the logical block address of the first block to
+start the verify operation. \fILBA\fR is assumed to be decimal unless prefixed
+by '0x' or a trailing 'h' (see below). The default value is 0 (i.e. the start
+of the device).
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
-The arguments to --bpc, --count and --lba may be followed by one of these
-multiplicative suffixes:
+.SH NOTES
+The \fIBPC\fR, \fICOUNT\fR and \fILBA\fR arguments may be followed by one of
+these multiplicative suffixes:
c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
MB *1,000,000; g G GiB *1,073,741,824; GB *1,000,000,000; t T TiB *(2**40);
TB *(10**12); p P PiB *(2**50) and PB *(10**15). The "T" and "P" based
-suffixes can only be used for --count and --lba. Also a suffix of the
-form "x<n>" multiplies the leading number by <n>.
+suffixes can only be used for \fICOUNT\fR and \fILBA\fR. Also a suffix of
+the form "x<n>" multiplies the leading number by <n>.
.PP
Alternatively numerical values can be given in hexadecimal preceded by
either "0x" or "0X" (or has a trailing "h" or "H"). When hex numbers are
@@ -70,7 +69,7 @@ given, multipliers cannot be used.
.PP
The amount of error correction and the number of retries attempted
before a block is considered defective are controlled in part by the
-Verify Error Recovery mode page. A note in the SBC-2 (draft)
+Verify Error Recovery mode page. A note in the SBC\-2 (draft)
standard advises that to minimize the number of checks (and hence
have the most "sensitive" verify check) do the following in that
mode page. Set the EER bit to 0, the PER bit to 1, the DTE bit to 1,
@@ -86,7 +85,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_verify.c b/sg_verify.c
index 8103619b..ebe408e9 100644
--- a/sg_verify.c
+++ b/sg_verify.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -43,7 +45,7 @@
* This program issues the SCSI VERIFY command to the given SCSI block device.
*/
-static char * version_str = "1.08 20061012";
+static char * version_str = "1.09 20070121";
#define ME "sg_verify: "
@@ -62,22 +64,23 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_verify [--bpc=<n>] [--count=<n>] [--dpo] [--help] [--lba=<n>]\n"
- " [--verbose] [--version] <scsi_device>\n"
+ "sg_verify [--bpc=BPC] [--count=COUNT] [--dpo] [--help] "
+ "[--lba=LBA]\n"
+ " [--verbose] [--version] DEVICE\n"
" where:\n"
- " --bpc=<n>|-b <n> max blocks per verify command "
+ " --bpc=BPC|-b BPC max blocks per verify command "
"(def 128)\n"
- " --count=<n>|-c <n> count of blocks to verify (def 1)\n"
- " --dpo|-d disable page out (cache retention "
+ " --count=COUNT|-c COUNT count of blocks to verify "
+ "(def 1)\n"
+ " --dpo|-d disable page out (cache retention "
"priority)\n"
- " --help|-h print out usage message\n"
- " --lba=<n>|-l <n> logical block address to start "
+ " --help|-h print out usage message\n"
+ " --lba=LBA|-l LBA logical block address to start "
"verify (def 0)\n"
- " --verbose|-v increase verbosity\n"
- " --version|-V print version string and exit\n\n"
- "Performs a VERIFY(10) SCSI command\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Performs a SCSI VERIFY(10) command\n"
);
-
}
int main(int argc, char * argv[])
@@ -107,15 +110,15 @@ int main(int argc, char * argv[])
switch (c) {
case 'b':
- bpc = sg_get_num(optarg);
- if (bpc < 1) {
+ bpc = sg_get_num(optarg);
+ if (bpc < 1) {
fprintf(stderr, "bad argument to '--bpc'\n");
return SG_LIB_SYNTAX_ERROR;
}
break;
case 'c':
- count = sg_get_llnum(optarg);
- if (count < 0) {
+ count = sg_get_llnum(optarg);
+ if (count < 0) {
fprintf(stderr, "bad argument to '--count'\n");
return SG_LIB_SYNTAX_ERROR;
}
@@ -128,8 +131,8 @@ int main(int argc, char * argv[])
usage();
return 0;
case 'l':
- ll = sg_get_llnum(optarg);
- if (-1 == ll) {
+ ll = sg_get_llnum(optarg);
+ if (-1 == ll) {
fprintf(stderr, "bad argument to '--lba'\n");
return SG_LIB_SYNTAX_ERROR;
}
@@ -207,19 +210,19 @@ int main(int argc, char * argv[])
break;
case SG_LIB_CAT_ILLEGAL_REQ:
fprintf(stderr, "bad field in Verify(10) cdb, near "
- "lba=0x%llx\n", lba);
+ "lba=0x%" PRIx64 "\n", lba);
break;
case SG_LIB_CAT_MEDIUM_HARD:
fprintf(stderr, "medium or hardware error near "
- "lba=0x%llx\n", lba);
+ "lba=0x%" PRIx64 "\n", lba);
break;
case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO:
fprintf(stderr, "medium or hardware error, reported "
"lba=0x%lx\n", info);
break;
default:
- fprintf(stderr, "Verify(10) failed near lba=%llu [0x%llx]\n",
- lba, lba);
+ fprintf(stderr, "Verify(10) failed near lba=%" PRIu64
+ " [0x%" PRIx64 "]\n", lba, lba);
break;
}
break;
@@ -227,9 +230,10 @@ int main(int argc, char * argv[])
}
if (verbose && (0 == ret) && (orig_count > 1))
- fprintf(stderr, "Verified %lld [0x%llx] blocks from lba %llu "
- "[0x%llx]\n without error\n", orig_count,
- (unsigned long long)orig_count, orig_lba, orig_lba);
+ fprintf(stderr, "Verified %" PRId64 " [0x%" PRIx64 "] blocks from "
+ "lba %" PRIu64 " [0x%" PRIx64 "]\n without error\n",
+ orig_count, (unsigned long long)orig_count, orig_lba,
+ orig_lba);
res = sg_cmds_close_device(sg_fd);
if (res < 0) {
diff --git a/sg_vpd.8 b/sg_vpd.8
index 451aaafd..1e0d6c51 100644
--- a/sg_vpd.8
+++ b/sg_vpd.8
@@ -1,81 +1,78 @@
-.TH SG_VPD "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_VPD "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_vpd \- outputs information retrieved from a Vital Product Data (VPD)
-page held by a SCSI device
+sg_vpd \- fetches Vital Product Data (VPD) pages using a SCSI INQUIRY command
.SH SYNOPSIS
.B sg_vpd
-[\fI--enumerate\fR] [\fI--help\fR] [\fI--hex\fR] [\fI--ident\fR]
-[\fI--long\fR] [\fI--page=<vpd_page>\fR] [\fI--quiet\fR] [\fI--raw\fR]
-[\fI--verbose\fR] [\fI--version\fR] \fI<device>\fR
+[\fI\-\-enumerate\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-ident\fR]
+[\fI\-\-long\fR] [\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
This utility fetches a Vital Product Data page and decodes it or
outputs it in ASCII hexadecimal or binary. VPD pages are fetched
-from SCSI devices by the INQUIRY command.
+with a SCSI INQUIRY command.
.PP
Probably the most important page is the Device Identification
-VPD page (page number: 0x83). Since SPC-3, support for this page
+VPD page (page number: 0x83). Since SPC\-3, support for this page
has been flagged as mandatory. This page can be fetched by
-using the '--ident' (or '-i') option.
+using the \fI\-\-ident\fR option.
.PP
-When no options are given, other than a '<device>', then the "Supported
+When no options are given, other than a \fIDEVICE\fR, then the "Supported
VPD pages" (0x0) VPD page is fetched and decoded.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---enumerate | -e
-list the names of the known VPD pages, first the standard
-pages, then the vendor specific pages. Each group is sorted
-in abbreviation order. The '<device>' and other options
-are ignored and this utility exits after listing the VPD page
-names.
+\fB\-e\fR, \fB\-\-enumerate\fR
+list the names of the known VPD pages, first the standard pages, then the
+vendor specific pages. Each group is sorted in abbreviation order. The
+\fIDEVICE\fR and other options are ignored and this utility exits afte
+listing the VPD page names.
.TP
---help | -h
-outputs the usage message summarizing command line options
-then exits. Ignores <device> if given.
+\fB\-h\fR, \fB\-\-help\fR
+outputs the usage message summarizing command line options then exits.
+Ignores \fIDEVICE\fR if given.
.TP
---hex | -H
+\fB\-H\fR, \fB\-\-hex\fR
outputs the requested VPD page in ASCII hexadecimal. Can be used multiple
times, see section on the ATA information vpd page.
.TP
---ident | -i
-decode the device identification (0x83) VPD page. When used
-once this option has the same effect as '--page=di'.
-When use twice then the short form of the device identification
-VPD page's logical unit designator is decoded. In the latter
-case this option has the same effect as '--quiet --page=di_lu'.
+\fB\-i\fR, \fB\-\-ident\fR
+decode the device identification (0x83) VPD page. When used once this option
+has the same effect as '\-\-page=di'. When use twice then the short form o
+the device identification VPD page's logical unit designator is decoded. In
+the latter case this option has the same effect as '\-\-quiet \-\-page=di_lu'.
.TP
---long | -l
-when decoding some VPD pages, give a little more output.
-For example the ATA Information VPD page only shows the
-signature (in hex) and the IDENTIFY (PACKET) DEVICE (in hex)
-when this option is given.
+\fB\-l\fR, \fB\-\-long\fR
+when decoding some VPD pages, give a little more output. For example the ATA
+Information VPD page only shows the signature (in hex) and the IDENTIFY
+(PACKET) DEVICE (in hex) when this option is given.
.TP
---page=<vpd_page> | -p <vpd_page>
-specifies the VPD page to be decoded or output. The '<vpd_page>'
-argument can either be an abbreviation, a number or a pair or
-numbers separated by a comma. The VPD page abbreviations can be
-seen by using the '--list' option. If a number is given it is
-assumed to be decimal unless it has a hexadecimal indicator which
-is either a leading '0x' or a trailing 'h'. If one number is given
-then it is assumed to be a VPD page number. If two numbers are given
-the second number indicates which vendor specific VPD page to
-decode when several pages share the same VPD page number.
-If this option is not given (nor '-i', '-l' or '-V') then the "Supported
-VPD pages" (0x0) VPD page is fetched and decoded.
+\fB\-p\fR, \fB\-\-page\fR=\fIPG\fR
+where \fIPG\fR is the VPD page to be decoded or output. The \fIPG\fR argument
+can either be an abbreviation, a number or a pair or numbers separated by a
+comma. The VPD page abbreviations can be seen by using the \fI\-\-enumerate\fR
+option. If a number is given it is assumed to be decimal unless it has a
+hexadecimal indicator which is either a leading '0x' or a trailing 'h'. If
+one number is given then it is assumed to be a VPD page number. If two
+numbers are given the second number indicates which vendor specific VPD page
+to decode when several pages share the same VPD page number. If this option
+is not given (nor '\-i', '\-l' nor '\-V') then the "Supported VPD pages" (0x0)
+VPD page is fetched and decoded.
.TP
---quiet | -q
+\fB\-q\fR, \fB\-\-quiet\fR
suppress the amount of decoding output.
.TP
---raw | -r
+\fB\-r\fR, \fB\-\-raw\fR
output requested VPD page in binary. The output should be piped to a
file or another utility when this option is used. The binary is
sent to stdout, and errors are sent to stderr.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increases the level or verbosity.
.TP
---version | -V
-print out version string
+\fB\-V\fR, \fB\-\-version\fR
+print out version string then exit.
.SH ATA INFORMATION VPD PAGE
This VPD page (0x89 or 'ai') is defined by the SCSI to ATA Translation
draft. It contains information about the SAT layer, the "signature" of
@@ -84,18 +81,18 @@ command. The latter part has 512 bytes of identity, capability and
settings data which the hdparm utility is capable of decoding (so this
utility doesn't decode it).
.PP
-To unclutter the output for this page, the signature and the
-IDENTIFY (PACKET) DEVICE response are not output unless the '--long'
-option (or '--hex' or '--raw') are given. When the '--long' option
-is given the IDENTIFY (PACKET) DEVICE response is output as
-256 (16 bit) words as is the fashion for ATA devices. To see that
-response as a string of bytes use the '-HH' option. To format the
-output suitable for hdparm to decode use either the '-HHH' or '-rr'
-option. For example if 'dev/sdb' is a SATA disk behind a SAT layer
-then this command: 'sg_vpd -p ai -HHH /dev/sdb | hdparm --Istdin'
+To unclutter the output for this page, the signature and the IDENTIFY (PACKET)
+DEVICE response are not output unless the \fI\-\-long\fR option (or
+\fI\-\-hex\fR or \fI\-\-raw\fR) are given. When the \fI\-\-long\fR option
+is given the IDENTIFY (PACKET) DEVICE response is output as 256 (16 bit)
+words as is the fashion for ATA devices. To see that response as a string of
+bytes use the '\-HH' option. To format the output suitable for hdparm to
+decode use either the '\-HHH' or '\-rr' option. For example if 'dev/sdb' is
+a SATA disk behind a SAT layer then this
+command: 'sg_vpd \-p ai \-HHH /dev/sdb | hdparm \-\-Istdin'
should decode the ATA IDENTIFY (PACKET) DEVICE response.
.SH NOTES
-In the 2.4 series of Linux kernels the given device must be
+In the 2.4 series of Linux kernels the \fIDEVICE\fR must be
a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
and ATAPI DVDs) can also be specified. For example "sg_inq /dev/sda"
will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char"
@@ -108,7 +105,7 @@ Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2006 Douglas Gilbert
+Copyright \(co 2006\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_vpd.c b/sg_vpd.c
index dfcb8e18..bcca5cd7 100644
--- a/sg_vpd.c
+++ b/sg_vpd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Douglas Gilbert.
+ * Copyright (c) 2006-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,8 @@
#include <string.h>
#include <ctype.h>
#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
@@ -47,7 +49,7 @@
*/
-static char * version_str = "0.16 20051012"; /* spc-4 rev 7a */
+static char * version_str = "0.18 20070121"; /* spc-4 rev 8 */
extern void svpd_enumerate_vendor(void);
extern int svpd_decode_vendor(int sg_fd, int num_vpd, int subvalue,
@@ -166,13 +168,12 @@ static void usage()
{
fprintf(stderr,
"Usage: sg_vpd [--enumerate] [--help] [--hex] [--ident] "
- "[--long]\n"
- " [--page=<vpd_page>] [--quiet] [--raw] "
- "[--verbose] [--version]\n"
- " <device>\n");
+ "[--long] [--page=PG]\n"
+ " [--quiet] [--raw] [--verbose] [--version] "
+ "DEVICE\n");
fprintf(stderr,
" where:\n"
- " --enumerate|-e enumerate known VPD pages names then "
+ " --enumerate|-e enumerate known VPD pages names then "
"exit\n"
" --help|-h output this usage message then exit\n"
" --hex|-H output page in ASCII hexadecimal\n"
@@ -181,12 +182,10 @@ static void usage()
" short logical unit designator (equiv: "
"'-qp di_lu')\n"
" --long|-l perform extra decoding\n"
- " --page=<vpd_page>|-p <vpd_page> fetch given VPD "
- "page\n"
- " <vpd_page> is an acronym, or a decimal "
- "number\n"
- " unless hex indicator is given (e.g. "
- "'0x83')\n"
+ " --page=PG|-p PG fetch VPD page where PG is an "
+ "acronym, or a decimal\n"
+ " number unless hex indicator "
+ "is given (e.g. '0x83')\n"
" --quiet|-q suppress some output when decoding\n"
" --raw|-r output page in binary\n"
" --verbose|-v increase verbosity\n"
@@ -723,7 +722,7 @@ static int decode_dev_ids(const char * print_if_found, unsigned char * buff,
id_ext <<= 8;
id_ext |= ip[m];
}
- printf(" Identifier extension: 0x%llx\n", id_ext);
+ printf(" Identifier extension: 0x%" PRIx64 "\n", id_ext);
} else if ((8 != i_len) && (12 != i_len)) {
fprintf(stderr, " << can only decode 8, 12 and 16 "
"byte ids>>\n");
@@ -739,8 +738,8 @@ static int decode_dev_ids(const char * print_if_found, unsigned char * buff,
vsei <<= 8;
vsei |= ip[ci_off + 3 + m];
}
- printf(" Vendor Specific Extension Identifier: 0x%llx\n",
- vsei);
+ printf(" Vendor Specific Extension Identifier: 0x%" PRIx64
+ "\n", vsei);
if (12 == i_len) {
d_id = ((ip[8] << 24) | (ip[9] << 16) | (ip[10] << 8) |
ip[11]);
@@ -799,8 +798,8 @@ static int decode_dev_ids(const char * print_if_found, unsigned char * buff,
}
if (long_out) {
printf(" NAA 5, IEEE Company_id: 0x%x\n", c_id);
- printf(" Vendor Specific Identifier: 0x%llx\n",
- vsei);
+ printf(" Vendor Specific Identifier: 0x%" PRIx64
+ "\n", vsei);
printf(" [0x");
for (m = 0; m < 8; ++m)
printf("%02x", (unsigned int)ip[m]);
@@ -827,8 +826,8 @@ static int decode_dev_ids(const char * print_if_found, unsigned char * buff,
}
if (long_out) {
printf(" NAA 6, IEEE Company_id: 0x%x\n", c_id);
- printf(" Vendor Specific Identifier: 0x%llx\n",
- vsei);
+ printf(" Vendor Specific Identifier: 0x%" PRIx64
+ "\n", vsei);
vsei = 0;
for (m = 0; m < 8; ++m) {
if (m > 0)
@@ -836,7 +835,7 @@ static int decode_dev_ids(const char * print_if_found, unsigned char * buff,
vsei |= ip[8 + m];
}
printf(" Vendor Specific Identifier Extension: "
- "0x%llx\n", vsei);
+ "0x%" PRIx64 "\n", vsei);
printf(" [0x");
for (m = 0; m < 16; ++m)
printf("%02x", (unsigned int)ip[m]);
@@ -924,7 +923,7 @@ static void decode_transport_id(const char * leadin, unsigned char * ucp,
unsigned long long ull;
int bump;
- for (k = 0, bump; k < len; k += bump, ucp += bump) {
+ for (k = 0, bump= 24; k < len; k += bump, ucp += bump) {
if ((len < 24) || (0 != (len % 4)))
printf("%sTransport Id short or not multiple of 4 "
"[length=%d]:\n", leadin, len);
@@ -993,7 +992,7 @@ static void decode_transport_id(const char * leadin, unsigned char * ucp,
ull <<= 8;
ull |= ucp[4 + j];
}
- printf("%s SAS address: 0x%llx\n", leadin, ull);
+ printf("%s SAS address: 0x%" PRIx64 "\n", leadin, ull);
if (0 != format_code)
printf("%s [Unexpected format code: %d]\n", leadin,
format_code);
@@ -1038,8 +1037,9 @@ static void decode_x_inq_vpd(unsigned char * buff, int len, int do_hex)
printf(" GRP_SUP=%d PRIOR_SUP=%d HEADSUP=%d ORDSUP=%d SIMPSUP=%d\n",
!!(buff[5] & 0x10), !!(buff[5] & 0x8), !!(buff[5] & 0x4),
!!(buff[5] & 0x2), !!(buff[5] & 0x1));
- printf(" CORR_D_SUP=%d NV_SUP=%d V_SUP=%d\n", !!(buff[6] & 0x80),
- !!(buff[6] & 0x2), !!(buff[6] & 0x1));
+ printf(" CORR_D_SUP=%d NV_SUP=%d V_SUP=%d LUICLR=%d\n",
+ !!(buff[6] & 0x4), !!(buff[6] & 0x2), !!(buff[6] & 0x1),
+ !!(buff[7] & 0x1));
}
static void decode_softw_inf_id(unsigned char * buff, int len, int do_hex)
@@ -1754,7 +1754,7 @@ int main(int argc, char * argv[])
}
}
if ('\0' == device_name[0]) {
- fprintf(stderr, "No <device> argument given\n");
+ fprintf(stderr, "No DEVICE argument given\n");
usage();
return SG_LIB_SYNTAX_ERROR;
}
diff --git a/sg_vpd_vendor.c b/sg_vpd_vendor.c
index b66d06d1..6d596571 100644
--- a/sg_vpd_vendor.c
+++ b/sg_vpd_vendor.c
@@ -32,8 +32,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include <getopt.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
diff --git a/sg_wr_mode.8 b/sg_wr_mode.8
index 9bd2de7c..639f7bb1 100644
--- a/sg_wr_mode.8
+++ b/sg_wr_mode.8
@@ -1,19 +1,20 @@
-.TH SG_WR_MODE "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SG_WR_MODE "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_wr_mode \- write mode page to given device
+sg_wr_mode \- write mode page
.SH SYNOPSIS
.B sg_wr_mode
-[\fI--contents=<h>,<h>...\fR] [\fI--dbd\fR] [\fI--force\fR] [\fI--help\fR]
-[\fI--len=<10|6>\fR] [\fI--mask=<h>,<h>...\fR] [\fI--page=<page_code>\fR]
-[\fI--save\fR] [\fI--verbose\fR] [\fI--version\fR] \fI<scsi_device>\fR
+[\fI\-\-contents=H,H...\fR] [\fI\-\-dbd\fR] [\fI\-\-force\fR]
+[\fI\-\-help\fR] [\fI\-\-len=\fR10|6\fR] [\fI\-\-mask=M,M...\fR]
+[\fI\-\-page=PG[,SPG]\fR] [\fI\-\-save\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] \fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Writes a modified mode page to the given device. Uses the MODE SENSE (6 or
-10 byte variant) SCSI command to fetch the existing mode data which
-includes a mode page (or subpage). It then combines that with the contents,
-potentially masked, and writes the modified mode page with the MODE
-SELECT (6 or 10 byte variant) SCSI command. This utility does not modify
+Writes a modified mode page to \fIDEVICE\fR. Uses the SCSI MODE SENSE (6
+or 10 byte variant) command to fetch the existing mode data which includes
+a mode page (or subpage). It then combines that with the contents,
+potentially masked, and writes the modified mode page with the SCSI MODE
+SELECT (6 or 10 byte variant) command. This utility does not modify
the block descriptor(s); if any block descriptors are fetched by the MODE
SENSE command then the same block descriptors are written back with the
following MODE SELECT command.
@@ -24,10 +25,10 @@ the existing mode page are printed out. In this case the mode page is
not altered on the device.
.PP
If the contents are specified, and a mask is not specified, then the contents
-must match the existing mode page in various aspects unless the '--force'
-option is given. These include length, mode page code and subpage code if
-applicable. If all is well then the contents string is written to the device
-as the new mode page.
+must match the existing mode page in various aspects unless the
+\fI\-\-force\fR option is given. These include length, mode page code and
+subpage code if applicable. If all is well then the contents string is
+written to \fIDEVICE\fR as the new mode page.
.PP
If both contents and mask strings are specified then only bit positions
in the contents corresponding to set bits in the mask are taken while the
@@ -42,27 +43,29 @@ The force option allows the contents string to be written as the new
mode page without any prior checks on the existing mode page. This should
only be required for vendor specific mode pages. The existing mode data
is ignored apart from the block descriptors which can be suppressed with
-the '--dbd' option if need be.
+the \fI\-\-dbd\fR option if need be.
.PP
Changing individual fields in a mode page is probably more easily done
with the sdparm utility. Fields can be identified by acronym or by a
numerical descriptor.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---contents=<h>,<h>... | -c <h>,<h>...
-string of comma separated hex numbers each of which should resolve to
-a byte value (i.e. 0 to ff inclusive). This is the new contents of the
-mode page to be written to the device, potentially filtered by the mask
-string.
+\fB\-c\fR, \fB\-\-contents\fR=\fIH,H...\fR
+where \fIH,H...\fR is a string of comma separated hex numbers each of
+which should resolve to a byte value (i.e. 0 to ff inclusive). This is the
+new contents of the mode page to be written to \fIDEVICE\fR, potentially
+filtered by the mask string.
.TP
---contents=- | -c -
-reads contents string from stdin. The string may be comma, space, tab
-or linefeed (newline) separated. If a line contains "#" then the remaining
-characters on that line are ignored. Otherwise each non separator character
-should resolve to a byte value (i.e. 0 to ff inclusive). This forms the new
-contents of the mode page to be written to the device, potentially filtered
-by the mask string.
+\fB\-c\fR, \fB\-\-contents\fR=-
+reads contents string from stdin. The numbers in the string may be comma,
+space, tab or linefeed (newline) separated. If a line contains "#" then the
+remaining characters on that line are ignored. Otherwise each non separator
+character should resolve to a byte value (i.e. 0 to ff inclusive). This
+forms the new contents of the mode page to be written to \fIDEVICE\fR,
+potentially filtered by the mask string.
.TP
---dbd | -d
+\fB\-d\fR, \fB\-\-dbd\fR
disable block descriptors (DBD flag in cdb). Some device types include
block descriptors in the mode data returned by a MODE SENSE command. If
so the same block descriptors are written by the MODE SELECT command.
@@ -70,65 +73,65 @@ This option instructs the MODE SENSE command not to return any block
descriptors. This would be a sensible default for this utility apart
from the fact that not all SCSI devices support the DBD bit in the cdb.
.TP
---force | -f
+\fB\-f\fR, \fB\-\-force\fR
force the contents string to be taken as the new mode page, or at least
-don't do checks on the existing mode page. Note that the device may still
-reject the new contents for the mode page. Cannot be given with
-the '--mask' option.
+doesn't do checks on the existing mode page. Note that \fIDEVICE\fR may
+still reject the new contents for the mode page. Cannot be given with
+the \fI\-\-mask=M,M...\fR option.
.TP
---help | -h
+\fB\-h\fR, \fB\-\-hex\fR
output the usage message then exit.
.TP
---len=<10|6> | -l <10|6>
-length of the SCSI commands (cdb) sent to device. The default is 10 so
-10 byte MODE SENSE and MODE SELECT commands are issued. Some old devices
+\fB\-l\fR, \fB\-\-len\fR=10 | 6
+length of the SCSI commands (cdb) sent to \fIDEVICE\fR. The default is 10
+so 10 byte MODE SENSE and MODE SELECT commands are issued. Some old devices
don't support the 10 byte variants hence this option.
.TP
---mask=<h>,<h>... | -m <h>,<h>...
-string of comma separated hex numbers each of which should resolve to
-a byte value (i.e. 0 to ff inclusive). The mask chooses (bit by bit)
-whether the new mode page comes from the contents (mask bit set) or from
-the existing mode page (mask bit clear). If the mask string is shorter
-than the contents string then the remaining bytes are taken from the
-contents string. If the contents string is shorter than the existing
+\fB\-m\fR, \fB\-\-mask\fR=\fIM,M...\fR
+where \fIM,M...\fR is a string of comma separated hex numbers each of which
+should resolve to a byte value (i.e. 0 to ff inclusive). The mask
+chooses (bit by bit) whether the new mode page comes from the contents (mask
+bit set) or from the existing mode page (mask bit clear). If the mask string
+is shorter than the contents string then the remaining bytes are taken from
+the contents string. If the contents string is shorter than the existing
mode page then the remaining bytes are taken from the existing mode
page (i.e. they are left unaltered).
.TP
---page=<page_code> | -p <page_code>
-the page code to fetch and modify. The page code is in hex and should
-be between 0 and 3e inclusive. Notice that the page code 3f to fetch
-all mode pages is disallowed.
+\fB\-p\fR, \fB\-\-page\fR=\fIPG\fR
+where \fIPG\fR is the page code value to fetch and modify. The page code is
+in hex and should be between 0 and 3e inclusive. Notice that page code
+3f to fetch all mode pages is disallowed.
.TP
---page=<page_code>,<subpage_code> | -p <page_code>,<subpage_code>
-the page and subpage code to fetch and modify. Both values are in hex.
-The subpage code should be between 0 and fe inclusive. Notice that the
-subpage code ff to fetch all mode subpages (for a given mode page or
-all mode pages in the case of 3f,ff) is disallowed.
+\fB\-p\fR, \fB\-\-page\fR=\fIPG,SPG\fR
+where \fIPG\fR is the page code value and \fISPG\fR is the subpage code value
+to fetch and modify. Both values are in hex. The subpage code should be
+between 0 and fe inclusive. Notice that subpage code ff to fetch all mode
+subpages (for a given mode page or all mode pages in the case of 3f,ff) is
+disallowed.
.TP
---save | -s
+\fB\-s\fR, \fB\-\-save\fR
changes the "saved" mode page when MODE SELECT is successful. By
-default (i.e. when '--save' is not used) only the "current" mode page
-values are changed when MODE SELECT is successful. In this case the
-new mode page will stay in effect until the device is reset (e.g.
-power cycled). When it restarts the "saved" values for the mode page
-will be re-instated. To make changes permanent then use the '--save'
-option.
+default (i.e. when \fI\-\-save\fR is not used) only the "current" mode page
+values are changed when MODE SELECT is successful. In this case the new mode
+page will stay in effect until the device is reset (e.g. power cycled).
+When it restarts the "saved" values for the mode page will be re\-instated.
+So to make changes permanent use the \fI\-\-save\fR option.
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the level of verbosity, (i.e. debug output).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
-.PP
+.SH NOTES
This utility does not check whether the contents string is trying to
modify parts of the mode page which are changeable. The device should
do that and if some part is not changeable then it should
report: "Invalid field in parameter list".
.PP
-Some mode pages are not savable. If so an attempt to use the '--save'
+Some mode pages are not savable. If so an attempt to use the \fI\-\-save\fR
option should cause an error to be reported from the device: "Illegal field
in cdb".
-.SH NOTES
+.PP
The device is required to do various checks before it accepts a new
mode page. If these checks fail then the mode page is not altered and
either a "parameter list length error" or an "invalid field in
@@ -137,10 +140,10 @@ parameter list" error is returned by the device in the sense data.
The recommended way to modify a mode page is to read it with a
MODE SENSE, modify some part of it then write it back to the
device with a MODE SELECT command. For example, reading an existing mode
-page can be accomplished with 'sg_modes -p=1a -r /dev/sdb > mp_1a.txt' (the
+page can be accomplished with 'sg_modes \-p=1a \-r /dev/sdb > mp_1a.txt' (the
power condition mode page). The mp_1a.txt file can be edited and then used
as the contents string to this
-utility (e.g. 'sg_wr_mode -p 1a -s -c - /dev/sdb < mp_1a.txt').
+utility (e.g. 'sg_wr_mode \-p 1a \-s \-c \- /dev/sdb < mp_1a.txt').
.PP
Two fields differ between what is read from the device with MODE SENSE and
what is written to the device with MODE SELECT:
@@ -148,31 +151,31 @@ the mode data length is reserved (i.e. zero(es)) in a MODE
SELECT command while the PS bit ((sub)page byte 0 bit 7) in each
mode (sub)page is reserved (zero) in a MODE SELECT command.
The PS bit given in the contents string is zeroed unless
-the '--force' option is selected.
+the \fI\-\-force\fR option is selected.
.SH EXAMPLES
-This utility can be used together with the sg_modes utility. To re-instate
+This utility can be used together with the sg_modes utility. To re\-instate
the default mode page values (i.e. the mode page values chosen by the
manufacturer of the device) as both the current and saved mode page
values the following sequence could be used:
.PP
- $ sg_modes -c=2 -p=1a -r /dev/sda > t
+ $ sg_modes \-c=2 \-p=1a \-r /dev/sda > t
.br
- $ sg_wr_mode --page=1a --contents=- --save /dev/sda < t
+ $ sg_wr_mode \-\-page=1a \-\-contents=\- \-\-save /dev/sda < t
.PP
Next is an example of using a mask to modify the "idle condition counter"
of the "power condition" mode page (0x1a) from 0x28 to 0x37. Note that the
change is not saved so the "idle condition counter" will revert to 0x28
after the next power cycle. The output from sg_modes is abridged.
.PP
- $ sg_modes -p=1a /dev/hdc
+ $ sg_modes \-p=1a /dev/hdc
.br
>> Power condition (mmc), page_control: current
.br
00 1a 0a 00 03 00 00 00 28 00 00 01 2c
.PP
- $ sg_wr_mode -p 1a -c 0,0,0,0,0,0,0,37 -m 0,0,0,0,0,0,0,ff /dev/hdc
+ $ sg_wr_mode \-p 1a \-c 0,0,0,0,0,0,0,37 \-m 0,0,0,0,0,0,0,ff /dev/hdc
.PP
- $ sg_modes -p=1a /dev/hdc
+ $ sg_modes \-p=1a /dev/hdc
.br
>> Power condition (mmc), page_control: current
.br
@@ -185,7 +188,7 @@ Written by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under a FreeBSD license. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_wr_mode.c b/sg_wr_mode.c
index 8cf32425..12b1dc67 100644
--- a/sg_wr_mode.c
+++ b/sg_wr_mode.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 Douglas Gilbert.
+ * Copyright (c) 2004-2007 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
* mode page on the given device.
*/
-static char * version_str = "1.07 20061012";
+static char * version_str = "1.08 20070127";
#define ME "sg_wr_mode: "
@@ -70,39 +70,39 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_wr_mode [--contents=<h>,<h>...] [--dbd] [--force] [--help]\n"
- " [--len=<10|6>] [--mask=<h>,<h>...]\n"
- " [--page=<page_code>[,<subpage_code]] [--save]\n"
- " [--verbose] [--version] <scsi_device>\n"
+ "sg_wr_mode [--contents=H,H...] [--dbd] [--force] [--help]\n"
+ " [--len=10|6] [--mask=M,M...] "
+ "[--page=PG[,SPG]] [--save]\n"
+ " [--verbose] [--version] DEVICE\n"
" where:\n"
- " --contents=<h>,<h>... | -c <h>,<h>... comma separated "
- "string of hex\n"
- " numbers that is mode page contents"
- " to write\n"
+ " --contents=H,H... | -c H,H... comma separated string "
+ "of hex numbers\n"
+ " that is mode page contents "
+ "to write\n"
" --contents=- | -c - read stdin for mode page contents"
" to write\n"
" --dbd | -d disable block descriptors (DBD bit"
" in cdb)\n"
" --force | -f force the contents to be written\n"
" --help | -h print out usage message\n"
- " --len=<10|6> | -l <10|6> use 10 byte (def) or 6 byte "
+ " --len=10|6 | -l 10|6 use 10 byte (def) or 6 byte "
"variants of\n"
- " MODE SENSE/SELECT\n"
- " --mask=<h>,<h>... | -m <h>,<h>... comma separated "
+ " SCSI MODE SENSE/SELECT commands\n"
+ " --mask=M,M... | -m M,M... comma separated "
"string of hex\n"
- " numbers that mask contents"
+ " numbers that mask contents"
" to write\n"
- " --page=<page_code> | -p <page_code> page_code to be "
- "written (in hex)\n"
- " --page=<page_code>,<subpage_code | -p <pc>,<spc> page "
- "and subpage\n"
- " code to be written (in hex)\n"
+ " --page=PG | -p PG page_code to be written (in hex)\n"
+ " --page=PG,SPG | -p PG,SPG page and subpage code to "
+ "be\n"
+ " written (in hex)\n"
" --save | -s set 'save page' (SP) bit; default "
"don't so\n"
" only 'current' values changed\n"
" --verbose | -v increase verbosity\n"
" --version | -V print version string and exit\n\n"
- "writes given mode page to device with MODE SELECT (6 or 10)\n"
+ "writes given mode page with SCSI MODE SELECT (10 or 6) "
+ "command\n"
);
}
diff --git a/sg_write_buffer.8 b/sg_write_buffer.8
new file mode 100644
index 00000000..77b0d2a7
--- /dev/null
+++ b/sg_write_buffer.8
@@ -0,0 +1,106 @@
+.TH SG_WRITE_BUFFER "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
+.SH NAME
+sg_write_buffer \- send a SCSI WRITE BUFFER command
+.SH SYNOPSIS
+.B sg_write_buffer
+[\fI\-\-help\fR] [\fI\-\-id=ID\fR] [\fI\-\-in=FILE\fR] [\fI\-\-length=LEN\fR]
+[\fI\-\-mode=MO\fR] [\fI\-\-offset=OFF\fR] [\fI\-\-raw\fR]
+[\fI\-\-skip=SKIP\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.SH DESCRIPTION
+.\" Add any additional description here
+.PP
+Sends a SCSI WRITE BUFFER command to \fIDEVICE\fR, along with data provided
+by the user. In some cases no data is required, or data can be read from the
+file given in the \fI\-\-in=FILE\fR option, or data is read from stdin when
+either \fI\-\-raw\fR or \fI\-\-in=\-\fR is given.
+.PP
+Some WRITE BUFFER command variants do not have associated data to send to the
+device, for example "activate_mc" ("activate deferred microcode").
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+output the usage message then exit. If used multiple times also prints
+the mode names and their acronyms.
+.TP
+\fB\-i\fR, \fB\-\-id\fR=\fIID\fR
+this option sets the buffer id field in the cdb. \fIID\fR is a value between
+0 (default) and 255 inclusive.
+.TP
+\fB\-I\fR, \fB\-\-in\fR=\fIFILE\fR
+read data from file \fIFILE\fR that will be sent with the WRITE BUFFER
+command. If \fIFILE\fR is '\-' then stdin is read until an EOF is
+detected (this is the same action as \fI\-\-raw\fR).
+.TP
+\fB\-l\fR, \fB\-\-length\fR=\fILEN\fR
+where \fILEN\fR is the length, in bytes, of data to be written to the device.
+If not given (and length cannot be deduced from \fI\-\-in=FILE\fR or
+\fI\-\-raw\fR) then defaults to zero. If the option is given and the length
+deduced from \fI\-\-in=FILE\fR or \fI\-\-raw\fR is less (or no data is
+provided), then bytes of 0xff are used as fill bytes.
+.TP
+\fB\-m\fR, \fB\-\-mode\fR=\fIMO\fR
+this option sets the mode field in the cdb. \fIMO\fR is a value between
+0 (default) and 31 inclusive. Alternatively an abbreviation can be given.
+To list the available mode abbreviations give an invalid
+one (e.g. '\-\-mode=xxx') or use the '\-hh' option.
+
+.TP
+\fB\-o\fR, \fB\-\-offset\fR=\fIOFF\fR
+this option sets the buffer offset field in the cdb. \fIOFF\fR is a value
+between 0 (default) and 2**24-1 . It is a byte offset.
+.TP
+\fB\-r\fR, \fB\-\-raw\fR
+read data from stdin until an EOF is detected. This data is sent with
+the WRITE BUFFER command to \fIDEVICE\fR. The action of this option is the
+same as using '\-\-in=\-'.
+.TP
+\fB\-s\fR, \fB\-\-skip\fR=\fISKIP\fR
+this option is only active when \fI\-\-in=FILE\fR is given and
+\fIFILE\fR is a regular file, rather than stdin. Data is read
+starting at byte offset \fISKIP\fR to the end of file (or the amount
+given by \fI\-\-length=LEN\fR). If not given the byte offset defaults to
+0 (i.e. the start of the file).
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+increase the level of verbosity, (i.e. debug output).
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+print the version string and then exit.
+.SH NOTES
+If no \fI\-\-length=LEN\fR is given this utility reads up to 8 MiB of data
+from the given file \fIFILE\fR (or stdin). If a larger amount of data is
+required then the \fI\-\-length=LEN\fR option should be given. The user
+should be aware that most operating systems have limits on the amount
+of data that can be sent with one SCSI command. In Linux this
+depends on the pass through mechanism used (e.g. block SG_IO or
+the sg driver) and various setting in sysfs in the linux lk 2.6
+series (e.g. /sys/block/sda/queue/max_sectors_kb).
+.PP
+Downloading incorrect microcode into a device has the ability to render
+that device inoperable. One would hope that the device vendor verifies
+the data before activating it. If the SCSI WRITE BUFFER command is given
+values in its cdb (e.g. \fILEN\fR) that are inappropriate (e.g. too large)
+then the device should respond with a sense key of ILLEGAL REQUEST and
+an additional sense code of INVALID FIELD in CDB. If a WRITE BUFFER
+command (or a sequence of them) fails due to device vendor verification
+checks then it should respond with a sense key of ILLEGAL REQUEST and
+an additional sense code of COMMAND SEQUENCE ERROR.
+.PP
+All numbers given with options are assumed to be decimal.
+Alternatively numerical values can be given in hexadecimal preceded by
+either "0x" or "0X" (or has a trailing "h" or "H").
+.SH EXIT STATUS
+The exit status of sg_write_buffer is 0 when it is successful. Otherwise
+see the sg3_utils(8) man page.
+.SH AUTHORS
+Written by Luben Tuikov and Douglas Gilbert.
+.SH "REPORTING BUGS"
+Report bugs to <dgilbert at interlog dot com>.
+.SH COPYRIGHT
+Copyright \(co 2006\-2007 Luben Tuikov and Douglas Gilbert
+.br
+This software is distributed under a FreeBSD license. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH "SEE ALSO"
+.B sg_read_buffer(sg3_utils)
diff --git a/sg_write_buffer.c b/sg_write_buffer.c
new file mode 100644
index 00000000..13de4d51
--- /dev/null
+++ b/sg_write_buffer.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2006-2007 Luben Tuikov and Douglas Gilbert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "sg_lib.h"
+#include "sg_cmds_basic.h"
+#include "sg_cmds_extra.h"
+
+/*
+ * This utility issues the SCSI WRITE BUFFER command to the given device.
+ */
+
+static char * version_str = "1.04 20070127"; /* spc4r08 */
+
+#define ME "sg_write_buffer: "
+#define DEF_XFER_LEN (8 * 1024 * 1024)
+#define EBUFF_SZ 256
+
+
+static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"id", 1, 0, 'i'},
+ {"in", 1, 0, 'I'},
+ {"length", 1, 0, 'l'},
+ {"mode", 1, 0, 'm'},
+ {"offset", 1, 0, 'o'},
+ {"raw", 0, 0, 'r'},
+ {"skip", 1, 0, 's'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+static void usage()
+{
+ fprintf(stderr, "Usage: "
+ "sg_write_buffer [--help] [--id=ID] [--in=FILE] "
+ "[--length=LEN]\n"
+ " [--mode=MO] [--offset=OFF] [--raw] "
+ "[--skip=SKIP]\n"
+ " [--verbose] [--version] DEVICE\n"
+ " where:\n"
+ " --help|-h print out usage message then exit\n"
+ " --id=ID|-i ID buffer identifier (0 (default) to "
+ "255)\n"
+ " --in=FILE|-I FILE read from FILE ('-I -' read "
+ "from stdin)\n"
+ " --length=LEN|-l LEN length in bytes to write; may be "
+ "deduced from FILE\n"
+ " --mode=MO|-m MO write buffer mode, MO is number or "
+ "acronym (def: 0)\n"
+ " --off=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n"
+ " --raw|-r read from stdin (same as '-I -')\n"
+ " --skip=SKIP|-s SKIP bytes in file FILE to skip before "
+ "reading\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ " Numbers given in options are decimal unless they have a "
+ "hex indicator\n"
+ "Performs a SCSI WRITE BUFFER command\n"
+ );
+
+}
+
+#define MODE_HEADER_DATA 0
+#define MODE_VENDOR 1
+#define MODE_DATA 2
+#define MODE_DNLD_MC 4
+#define MODE_DNLD_MC_SAVE 5
+#define MODE_DNLD_MC_OFFS 6
+#define MODE_DNLD_MC_OFFS_SAVE 7
+#define MODE_ECHO_BUFFER 0x0A
+#define MODE_DNLD_MC_OFFS_DEFER 0x0E
+#define MODE_ACTIVATE_MC 0x0F
+#define MODE_EN_EX_ECHO 0x1A
+#define MODE_DIS_EX 0x1B
+#define MODE_DNLD_ERR_HISTORY 0x1C
+
+
+static struct mode_s {
+ char *mode_string;
+ int mode;
+ char *comment;
+} modes[] = {
+ { "hd", MODE_HEADER_DATA, "combined header and data"},
+ { "vendor", MODE_VENDOR, "vendor specific"},
+ { "data", MODE_DATA, "data"},
+ { "dmc", MODE_DNLD_MC, "download microcode and activate"},
+ { "dmc_save", MODE_DNLD_MC_SAVE, "download microcode, save and "
+ "activate"},
+ { "dmc_offs", MODE_DNLD_MC_OFFS, "download microcode with offsets "
+ "and activate"},
+ { "dmc_offs_save", MODE_DNLD_MC_OFFS_SAVE, "download microcode with "
+ "offsets, save and activate"},
+ { "echo", MODE_ECHO_BUFFER, "echo (spc-2)"},
+ { "dmc_offs_defer", MODE_DNLD_MC_OFFS_DEFER, "download microcode "
+ "with offsets, save and defer activation (spc-4)"},
+ { "activate_mc", MODE_ACTIVATE_MC,
+ "Activate deferred microcode (spc-4)"},
+ { "en_ex", MODE_EN_EX_ECHO, "enable expander communications "
+ "protocol and echo buffer (spc-3)"},
+ { "dis_ex", MODE_DIS_EX, "disable expander communications "
+ "protocol (spc-3)"},
+ { "deh", MODE_DNLD_ERR_HISTORY, "Download error history "
+ "(spc-4)"},
+};
+
+#define NUM_MODES ((int)(sizeof(modes)/sizeof(modes[0])))
+
+static void print_modes(void)
+{
+ int k;
+
+ fprintf(stderr, "The modes parameter argument can be numeric "
+ "(hex or decimal)\nor symbolic:\n");
+ for (k = 0; k < NUM_MODES; k++) {
+ fprintf(stderr, " %2d (0x%02x) %-16s%s\n", modes[k].mode,
+ modes[k].mode, modes[k].mode_string, modes[k].comment);
+ }
+}
+
+
+int main(int argc, char * argv[])
+{
+ int sg_fd, infd, res, c, len, k, got_stdin;
+ int do_help = 0;
+ int wb_id = 0;
+ int wb_len = 0;
+ int wb_len_given = 0;
+ int wb_mode = 0;
+ int wb_offset = 0;
+ int wb_skip = 0;
+ int verbose = 0;
+ char device_name[256];
+ const char * file_name = NULL;
+ unsigned char * dop = NULL;
+ char ebuff[EBUFF_SZ];
+ int ret = 0;
+
+ memset(device_name, 0, sizeof device_name);
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "hi:I:l:m:o:rs:vV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ case '?':
+ ++do_help;
+ break;
+ case 'i':
+ wb_id = sg_get_num(optarg);
+ if ((wb_id < 0) || (wb_id > 255)) {
+ fprintf(stderr, "argument to '--id' should be in the range "
+ "0 to 255\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'I':
+ file_name = optarg;
+ break;
+ case 'l':
+ wb_len = sg_get_num(optarg);
+ if (wb_len < 0) {
+ fprintf(stderr, "bad argument to '--length'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ wb_len_given = 1;
+ break;
+ case 'm':
+ if (isdigit(*optarg)) {
+ wb_mode = sg_get_num(optarg);
+ if ((wb_mode < 0) || (wb_mode > 31)) {
+ fprintf(stderr, "argument to '--mode' should be in the "
+ "range 0 to 31\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else {
+ len = strlen(optarg);
+ for (k = 0; k < NUM_MODES; ++k) {
+ if (0 == strncmp(modes[k].mode_string, optarg, len)) {
+ wb_mode = modes[k].mode;
+ break;
+ }
+ }
+ if (NUM_MODES == k) {
+ print_modes();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ break;
+ case 'o':
+ wb_offset = sg_get_num(optarg);
+ if (wb_offset < 0) {
+ fprintf(stderr, "bad argument to '--offset'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'r':
+ file_name = "-";
+ break;
+ case 's':
+ wb_skip = sg_get_num(optarg);
+ if (wb_skip < 0) {
+ fprintf(stderr, "bad argument to '--skip'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'V':
+ fprintf(stderr, ME "version: %s\n", version_str);
+ return 0;
+ default:
+ fprintf(stderr, "unrecognised switch code 0x%x ??\n", c);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (do_help) {
+ if (do_help > 1) {
+ usage();
+ fprintf(stderr, "\n");
+ print_modes();
+ } else
+ usage();
+ return 0;
+ }
+ if (optind < argc) {
+ if ('\0' == device_name[0]) {
+ strncpy(device_name, argv[optind], sizeof(device_name) - 1);
+ device_name[sizeof(device_name) - 1] = '\0';
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+
+ if (0 == device_name[0]) {
+ fprintf(stderr, "missing device name!\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose);
+ if (sg_fd < 0) {
+ fprintf(stderr, ME "open error: %s: %s\n", device_name,
+ safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+ if (file_name || (wb_len > 0)) {
+ if (0 == wb_len)
+ wb_len = DEF_XFER_LEN;
+ if (NULL == (dop = (unsigned char *)malloc(wb_len))) {
+ fprintf(stderr, ME "out of memory\n");
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto err_out;
+ }
+ memset(dop, 0xff, wb_len);
+ if (file_name) {
+ got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0;
+ if (got_stdin) {
+ if (wb_skip > 0) {
+ fprintf(stderr, "Can't skip on stdin\n");
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
+ }
+ infd = 0;
+ } else {
+ if ((infd = open(file_name, O_RDONLY)) < 0) {
+ snprintf(ebuff, EBUFF_SZ,
+ ME "could not open %s for reading", file_name);
+ perror(ebuff);
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
+ }
+ if (wb_skip > 0) {
+ if (lseek(infd, wb_skip, SEEK_SET) < 0) {
+ snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to "
+ "required position on %s", file_name);
+ perror(ebuff);
+ close(infd);
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
+ }
+ }
+ }
+ res = read(infd, dop, wb_len);
+ if (res < 0) {
+ snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
+ file_name);
+ perror(ebuff);
+ if (! got_stdin)
+ close(infd);
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
+ }
+ if (res < wb_len) {
+ if (wb_len_given) {
+ fprintf(stderr, "tried to read %d bytes from %s, got "
+ "%d bytes\n", wb_len, file_name, res);
+ fprintf(stderr, "pad with 0xff bytes and continue\n");
+ } else {
+ if (verbose) {
+ fprintf(stderr, "tried to read %d bytes from %s, got "
+ "%d bytes\n", wb_len, file_name, res);
+ fprintf(stderr, "will write %d bytes\n", res);
+ }
+ wb_len = res;
+ }
+ }
+ if (! got_stdin)
+ close(infd);
+ }
+ }
+
+ res = sg_ll_write_buffer(sg_fd, wb_mode, wb_id, wb_offset, dop,
+ wb_len, 1, verbose);
+ if (0 != res) {
+ ret = res;
+ switch (res) {
+ case SG_LIB_CAT_NOT_READY:
+ fprintf(stderr, "Write buffer failed, device not ready\n");
+ break;
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ fprintf(stderr, "Write buffer not done, unit attention\n");
+ break;
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ fprintf(stderr, "Write buffer, aborted command\n");
+ break;
+ case SG_LIB_CAT_INVALID_OP:
+ fprintf(stderr, "Write buffer command not supported\n");
+ break;
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ fprintf(stderr, "bad field in Write buffer cdb\n");
+ break;
+ default:
+ fprintf(stderr, "Write buffer failed res=%d\n", res);
+ break;
+ }
+ }
+
+err_out:
+ if (dop)
+ free(dop);
+ res = sg_cmds_close_device(sg_fd);
+ if (res < 0) {
+ fprintf(stderr, "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/sg_write_long.8 b/sg_write_long.8
index ac245c0d..462aa942 100644
--- a/sg_write_long.8
+++ b/sg_write_long.8
@@ -1,19 +1,20 @@
-.TH SG_WRITE_LONG "8" "October 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SG_WRITE_LONG "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sg_write_long \- send the WRITE LONG SCSI command
+sg_write_long \- send the SCSI WRITE LONG command
.SH SYNOPSIS
.B sg_write_long
-[\fI--16\fR] [\fI--cor_dis\fR] [\fI--help\fR] [\fI--in=<name>\fR]
-[\fI--lba=<num>\fR] [\fI--pblock\fR] [\fI--verbose\fR] [\fI--version\fR]
-[\fI--wr_uncor\fR] [\fI--xfer_len=<num>\fR] \fI<scsi_device>\fR
+[\fI\-\-16\fR] [\fI\-\-cor_dis\fR] [\fI\-\-help\fR] [\fI\-\-in=IF\fR]
+[\fI\-\-lba=LBA\fR] [\fI\-\-pblock\fR] [\fI\-\-verbose\fR]
+[\fI\-\-version\fR] [\fI\-\-wr_uncor\fR] [\fI\-\-xfer_len=BTL\fR]
+\fIDEVICE\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send the WRITE LONG (10 or 16 byte) SCSI command to the given device.
-The buffer to be written to the device is filled with
+Send the SCSI WRITE LONG (10 or 16 byte) command to \fIDEVICE\fR. The buffer
+to be written to the \fIDEVICE\fR is filled with
.B 0xff
-bytes or read from the given file. This buffer includes the sector data
-and the ECC bytes.
+bytes or read from the \fIIF\fR file. This buffer includes the logical
+data (e.g. 512 bytes) and the ECC bytes.
.PP
This utility can be used to generate a MEDIUM ERROR at a specific logical
block address. This can be useful for testing error handling. Prior to
@@ -35,67 +36,69 @@ be taken with the settings in the "read write error recovery" mode page.
Specifically if the ARRE (for reads) and/or AWRE (for writes) are set
then recovered errors will cause the lba to be reassigned (and the old
location to be added to the grown defect list (PLIST)). This is not easily
-reversed and uses the (finite number) of spare blocks sets aside for
+reversed and uses the (finite number) of spare sectors set aside for
this purpose. If in doubt it is probably safest to clear the ARRE and
AWRE bits. These bits can be checked and modified with the sdparm utility.
-For example: "sdparm -c AWRE,ARRE /dev/sda" will clear the bits until
-the disk is rebooted (assuming the "saved" bits are not set).
+For example: "sdparm \-c AWRE,ARRE /dev/sda" will clear the bits until
+the disk is rebooted.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
.TP
---16 | -S
-send a WRITE LONG (16) SCSI command to the given device. The default
-action (in the absence of this option) is to send a WRITE LONG (10)
-SCSI command.
+\fB\-S\fR, \fB\-\-16\fR
+send a SCSI WRITE LONG (16) command to \fIDEVICE\fR. The default action (in
+the absence of this option) is to send a SCSI WRITE LONG (10) command.
.TP
---cor_dis | -c
+\fB\-c\fR, \fB\-\-cor_dis\fR
sets the correction disabled (i.e 'COR_DIS') bit. This inhibits various
other mechanisms such as automatic block reallocation, error recovery
and various informational exception conditions being triggered.
-This bit is new in SBC-3 .
+This bit is new in SBC\-3 .
.TP
---help | -h
+\fB\-h\fR, \fB\-\-help\fR
output the usage message then exit.
.TP
---in=<name> | -i <name>
-read data (binary) from given file <name> and use it for the WRITE LONG
-SCSI command. If <name> is "-" then stdin is read. If this option is
-not given then a buffer of 0xff bytes is written.
+\fB\-i\fR, \fB\-\-in\fR=\fIIF\fR
+read data (binary) from file named \fIIF\fR and use it for the SCSI WRITE
+LONG command. If \fIIF\fR is "\-" then stdin is read. If this option is
+not given then 0xff bytes are used as fill.
.TP
---lba=<num> | -l <num>
-the logical block address of the sector to corrupt. Defaults to lba 0
-which is a dangerous block to overwrite on a disk that is in use.
-Assumed to be in decimal unless prefixed with '0x'. If the lba is
-larger than can fit in 32 bits then the '--16' form should be used.
+\fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR
+where \fILBA\fR is the logical block address of the sector to overwrite.
+Defaults to lba 0 which is a dangerous block to overwrite on a disk that is
+in use. Assumed to be in decimal unless prefixed with '0x' or has a
+traling 'h'. If \fILBA\fR is larger than can fit in 32 bits then the
+\fI\-\-16\fR option should be used.
.TP
---pblock | -p
-sets the physical block (i.e 'PBLOCK') bit. This instructs the device
-to use the given data (unless '--wr_uncor' is also given) to write
-to the physical block containing the given lba. The default action
+\fB\-p\fR, \fB\-\-pblock\fR
+sets the physical block (i.e 'PBLOCK') bit. This instructs \fIDEVICE\fR
+to use the given data (unless \fI\-\-wr_uncor\fR is also given) to write
+to the physical block specified by \fILBA\fR. The default action
is to write to the logical block corresponding to the given lba.
-This bit is new in SBC-3 .
+This bit is new in SBC\-3 .
.TP
---verbose | -v
+\fB\-v\fR, \fB\-\-verbose\fR
increase the degree of verbosity (debug messages).
.TP
---version | -V
+\fB\-V\fR, \fB\-\-version\fR
output version string then exit.
.TP
---wr_uncor | -w
+\fB\-w\fR, \fB\-\-wr_uncor\fR
sets the "write uncorrected" (i.e 'WR_UNCOR') bit. This instructs the
-device to flag the given lba (or the physical block that contains it
-if '--pblock' is also given) as having an unrecoverable error
-associated with it. Note: no data is transferred to the device,
-other that the command (i.e. the cdb). The default action is to
-use the provided data (--xfer_len= bytes in length) and write it to
-the device. This bit is new in SBC-3 .
+\fIDEVICE\fR to flag the given lba (or the physical block that contains it
+if \fI\-\-pblock\fR is also given) as having an unrecoverable error
+associated with it. Note: no data is transferred to \fIDEVICE\fR,
+other than the command (i.e. the cdb). The default action is to
+use the provided data (\fI\-\-xfer_len=BTL\fR in length) and write it to
+\fIDEVICE\fR. This bit is new in SBC\-3 .
.TP
---xfer_len=<num>|-x <num>
-the transfer length in bytes (default to 520). If the given value (or the
-default) does not match the "long" block size of the device, nothing is
-written to the device and the appropriate xfer_len value is derived from the
-error response and printed (to stderr).
-.PP
-The lba and xfer_len numerical arguments may be followed by the following
-multiplicative suffixes:
+\fB\-x\fR, \fB\-\-xfer_len\fR=\fIBTL\fR
+where \fIBTL\fR is the byte transfer length (default to 520). If the
+given value (or the default) does not match the "long" block size of the
+device, nothing is written to \fIDEVICE\fR and the appropriate xfer_len value
+may be deduced from the error response which is printed (to stderr).
+.SH NOTES
+The \fILBA\fR and \fIBTL\fR (transfer length) arguments may be followed by
+the following multiplicative suffixes:
c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
MB *1,000,000; g G GiB *1,073,741,824; and GB *1,000,000,000 . Also a suffix
of the form "x<n>" multiplies the leading number by <n>.
@@ -103,22 +106,22 @@ of the form "x<n>" multiplies the leading number by <n>.
Alternatively numerical values can be given in hexadecimal preceded by
either "0x" or "0X" (or with a trailing "h" or "H"). When hex numbers are
given, multipliers cannot be used.
-.SH "NOTES"
+.PP
To read from a defective sector (that, for example, has been filled with
0xff bytes by this utility) use:
.PP
- sg_dd if=<scsi_device> skip=<lba> of=/dev/null bs=512 count=1
+ sg_dd if=\fIDEVICE\fR skip=\fILBA\fR of=/dev/null bs=512 count=1
.PP
To overwrite to a defective sector use:
.PP
- sg_dd of=<scsi_device> seek=<lba> if=/dev/zero bs=512 count=1
+ sg_dd of=\fIDEVICE\fR seek=\fILBA\fR if=/dev/zero bs=512 count=1
.PP
This will result in a sector (block) with 512 bytes of 0x0 without a
MEDIUM ERROR since the ECC and associated data will be well formed.
.PP
-The 10 byte WRITE LONG SCSI command limits the logical block address
-to a 32 bit quantity. For larger lbas use the '--16' option for the
-WRITE LONG (16) SCSI command.
+The 10 byte SCSI WRITE LONG command limits the logical block address
+to a 32 bit quantity. For larger lbas use the \fI\-\-16\fR option for the
+SCSI WRITE LONG (16) command.
.SH EXIT STATUS
The exit status of sg_write_long is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
@@ -127,7 +130,7 @@ Written by Saeed Bishara. Further work by Douglas Gilbert.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004-2006 Douglas Gilbert
+Copyright \(co 2004\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_write_long.c b/sg_write_long.c
index 230eaa71..b252e557 100644
--- a/sg_write_long.c
+++ b/sg_write_long.c
@@ -5,13 +5,15 @@
#include <string.h>
#include <errno.h>
#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
/* A utility program for the Linux OS SCSI subsystem.
- * Copyright (C) 2004-2006 D. Gilbert
+ * Copyright (C) 2004-2007 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)
@@ -26,7 +28,7 @@
This code was contributed by Saeed Bishara
*/
-static char * version_str = "1.12 20061015";
+static char * version_str = "1.14 20070129";
#define MAX_XFER_LEN 10000
@@ -54,30 +56,30 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_write_long [--16] [--cor_dis] [--help] [--in=<name>] "
- "[--lba=<num>]\n"
+ "sg_write_long [--16] [--cor_dis] [--help] [--in=IF] "
+ "[--lba=LBA]\n"
" [--pblock] [--verbose] [--version] "
"[--wr_uncor]\n"
- " [--xfer_len=<num>] <scsi_device>\n"
+ " [--xfer_len=BTL] DEVICE\n"
" where:\n"
- " --16|-S do WRITE LONG(16) (default: 10)\n"
- " --cor_dis|-c set correction disabled bit\n"
- " --help|-h print out usage message\n"
- " --in=<name>|-i <name> input from file <name> (default: "
- "write multiple\n"
- " 0xff bytes)\n"
- " --lba=<num>|-l <num> logical block address "
+ " --16|-S do WRITE LONG(16) (default: 10)\n"
+ " --cor_dis|-c set correction disabled bit\n"
+ " --help|-h print out usage message\n"
+ " --in=IF|-i IF input from file called IF (default: "
+ "use\n"
+ " 0xff bytes as fill)\n"
+ " --lba=LBA|-l LBA logical block address "
"(default: 0)\n"
- " --pblock|-p physical block (default: logical "
+ " --pblock|-p physical block (default: logical "
"block)\n"
- " --verbose|-v increase verbosity\n"
- " --version|-V print version string then exit\n"
- " --wr_uncore|-w set an uncorrectable error (no "
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string then exit\n"
+ " --wr_uncor|-w set an uncorrectable error (no "
"data transferred)\n"
- " --xfer_len=<num>|-x <num> transfer length (< 10000) "
+ " --xfer_len=BTL|-x BTL byte transfer length (< 10000) "
"(default:\n"
- " 520 bytes)\n\n"
- "Performs a WRITE LONG (10 or 16) SCSI command\n"
+ " 520 bytes)\n\n"
+ "Performs a SCSI WRITE LONG (10 or 16) command\n"
);
}
@@ -98,7 +100,7 @@ int main(int argc, char * argv[])
char device_name[256];
char file_name[256];
char ebuff[EBUFF_SZ];
- char * ten_or;
+ const char * ten_or;
int ret = 1;
memset(device_name, 0, sizeof device_name);
@@ -199,11 +201,11 @@ int main(int argc, char * argv[])
"'-in=' is ignored\n");
} else {
if (NULL == (rawp = malloc(MAX_XFER_LEN))) {
- fprintf(stderr, ME "out of memory (query)\n");
- sg_cmds_close_device(sg_fd);
- return SG_LIB_SYNTAX_ERROR;
+ fprintf(stderr, ME "out of memory\n");
+ ret = SG_LIB_FILE_ERROR;
+ goto err_out;
}
- writeLongBuff = rawp;
+ writeLongBuff = (unsigned char *)rawp;
memset(rawp, 0xff, MAX_XFER_LEN);
if (file_name[0]) {
got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0;
@@ -222,6 +224,8 @@ int main(int argc, char * argv[])
snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
file_name);
perror(ebuff);
+ if (! got_stdin)
+ close(infd);
goto err_out;
}
if (res < xfer_len) {
@@ -235,9 +239,9 @@ int main(int argc, char * argv[])
}
if (verbose)
fprintf(stderr, ME "issue write long to device %s\n\t\txfer_len= %d "
- "(0x%x), lba=%llu (0x%llx)\n cor_dis=%d, wr_uncor=%d, "
- "pblock=%d\n", device_name, xfer_len, xfer_len, llba, llba,
- cor_dis, wr_uncor, pblock);
+ "(0x%x), lba=%" PRIu64 " (0x%" PRIx64 ")\n cor_dis=%d, "
+ "wr_uncor=%d, pblock=%d\n", device_name, xfer_len, xfer_len,
+ llba, llba, cor_dis, wr_uncor, pblock);
ten_or = do_16 ? "16" : "10";
if (do_16)
diff --git a/sginfo.8 b/sginfo.8
index 0d2e7d6c..70cad43a 100644
--- a/sginfo.8
+++ b/sginfo.8
@@ -1,217 +1,217 @@
-.TH SGINFO "8" "September 2005" "sg3_utils-1.17" SG3_UTILS
+.TH SGINFO "8" "December 2006" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sginfo \- access mode page information for a SCSI (or ATAPI) device
.SH SYNOPSIS
.B sginfo
-[\fI-options\fR]
-[\fIdevice\fR]
-[\fIreplacement_parameters\fR]
+[\fIOPTIONS\fR]
+[\fIDEVICE\fR]
+[\fIREPLACEMENT_PARAMETERS\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
-sginfo is a port of the Linux scsiinfo program by Eric Youngdale. It
-uses SCSI generic (sg) devices; however in some cases the high level
-device name (i.e. sd, sr, st, osst, or hd) can also be used. The primary
-role of this program is to access mode page information. If permitted,
-mode page information can be altered. In addition information from
-the INQUIRY and READ DEFECTS commands are also available.
+sginfo is a port of the Linux
+.B scsiinfo
+program by Eric Youngdale. It uses SCSI generic (sg) devices; however in
+some cases the high level device name (i.e. sd, sr, st, osst, or hd) can
+also be used. The primary role of this program is to access mode page
+information. If permitted, mode page information can be altered. In
+addition information from the INQUIRY and READ DEFECTS commands are also
+available.
.PP
-Those interested in SCSI mode pages may find the sdparm utility
-easier use, especially for changing parameters.
+Those interested in SCSI mode pages may find the
+.B sdparm
+utility easier use, especially for changing parameters.
.PP
Four sets of values are maintained by a SCSI device for each mode
page: current (active), default (manufacturer's supplied values),
saved (values that are retained if the SCSI device is powered down),
and changeable (mask indicating those values that can be changed).
By default when a mode page is displayed the current values are
-shown. This can be overridden by "-M" (defaults), "-S" (saved)
-or "-m" (modifiable (i.e. changeable)).
+shown. This can be overridden by "\-M" (defaults), "\-S" (saved)
+or "\-m" (modifiable (i.e. changeable)).
.PP
-Many mode pages are decoded: for disks (see SBC-2), for CD/DVDs (see
-MMC-2/3/4/5), for tapes (see SSC-2) and for enclosures (see SES-2).
+Many mode pages are decoded: for disks (see SBC\-2), for CD/DVDs (see
+MMC\-2/3/4/5), for tapes (see SSC\-2) and for enclosures (see SES\-2).
Some mode pages common to all SCSI peripheral device types are defined
-in SPC-4 (primary commands). A decoded mode page has its field names
+in SPC\-4 (primary commands). A decoded mode page has its field names
in the first column and the corresponding value in the second column.
A "hex" mode page (and subpage) has its byte position in the first
column (in hex and starting at 0x2) and the corresponding hex value
-in the second column. Decoded pages can be viewed with the '-t' option
+in the second column. Decoded pages can be viewed with the '\-t' option
or with a specific option (e.g. 'c' for the caching mode page).
-Naturally decoded pages must be supplied by the given device and
+Naturally decoded pages must be supplied by the \fIDEVICE\fR and
recognised by this program. If supported by the device, decoded pages
may be modified. All mode pages (and subpages) that the device supports
-can be viewed in hex (and potentially modified) via the "-u" option
+can be viewed in hex (and potentially modified) via the "\-u" option
.PP
If no options are given that will cause mode page(s) or INQUIRY data
to be printed out, then a brief INQUIRY response is output. This
includes the vendor, product and revision level of the device.
+.SH OPTIONS
.TP
--6
+\fB\-6\fR
Perform 6 byte MODE SENSE and MODE SELECT commands; by default the
10 byte variants are used.
.TP
--a
+\fB\-a\fR
Display some INQUIRY data and the unit serial number followed by
all mode pages reported by the device. It is similar to
-the '-t 0x3f' option. If the mode page is known then it is output
+the '\-t 0x3f' option. If the mode page is known then it is output
in decoded form otherwise it is output in hexadecimal.
.TP
--A
+\fB\-A\fR
Display some INQUIRY data and the unit serial number followed by
all mode pages and all mode subpages reported by the device.
-It is similar to the '-t 0x3f,0xff' option. If a mode (sub)page
+It is similar to the '\-t 0x3f,0xff' option. If a mode (sub)page
is known then it is output in decoded form otherwise it is output in
hexadecimal.
.TP
--c
+\fB\-c\fR
Access information in the Caching mode page.
.TP
--C
+\fB\-C\fR
Access information in the Control mode Page.
.TP
--d
+\fB\-d\fR
Display defect lists (default format: index).
.TP
--D
-Access information in the Disconnect-Reconnect mode page.
+\fB\-D\fR
+Access information in the Disconnect\-Reconnect mode page.
.TP
--e
+\fB\-e\fR
Access information in the Error Recovery mode page.
.TP
--E
+\fB\-E\fR
Access information in the Control Extension mode page.
.TP
--f
+\fB\-f\fR
Access information in the Format Device mode page.
.TP
--Farg
+\fB\-F\fR\fIarg\fR
Format of the defect lists:
- -Flogical - logical block addresses (32 bit)
- -Flba64 - logical block addresses (64 bit)
- -Fphysical - physical blocks
- -Findex - defect bytes from index
- -Fhead - sort by head
+ \-Flogical \- logical block addresses (32 bit)
+ \-Flba64 \- logical block addresses (64 bit)
+ \-Fphysical \- physical blocks
+ \-Findex \- defect bytes from index
+ \-Fhead \- sort by head
.br
-Used in conjunction with "-d" or "-G". If a format is not given "index" is
+Used in conjunction with "\-d" or "\-G". If a format is not given "index" is
assumed.
.TP
--g
+\fB\-g\fR
Access information in the Rigid Disk Drive Geometry mode page.
.TP
--G
+\fB\-G\fR
Display grown defect list (default format: index).
.TP
--i
+\fB\-i\fR
Display the response to a standard INQUIRY command.
.TP
--I
+\fB\-I\fR
Access the Informational Exceptions mode page.
.TP
--l
+\fB\-l\fR
List known SCSI devices on the system.
.TP
--n
+\fB\-n\fR
Access information in the Notch and Partition mode page.
.TP
--N
+\fB\-N\fR
Negate (i.e. stop) mode page changes being placed in the "saved"
page (by default changes go to the current and the saved page).
-Only active when used together with '-R'.
+Only active when used together with '\-R'.
.TP
--P
+\fB\-P\fR
Access information in the Power Condition mode page.
.TP
--r
+\fB\-r\fR
Display all raw (or primary) SCSI device names visible in the /dev
directory. Examples are /dev/sda, /dev/st1 and /dev/scd2. Does not
list sg device names so devices such as a SCSI enclosure which only
have an sg device name are not listed.
.TP
--s
+\fB\-s\fR
Display information in the unit serial number page which is a
INQUIRY command variant.
.TP
--t <pn[,spn]>
-Display information from mode page number <pn> (and optionally sub
-page number <spn>) in decoded format (if known, otherwise in hex form).
-<pn> is a mode page number in a decimal number
-from 0 to 63 inclusive. "spn" is the mode subpage
-number and is assumed to be 0 if not given. "spn" is a
-decimal number from 1 to 255 inclusive. A page number of 63
-returns all pages supported by the device in ascending order
-except for page 0 which, if present, is last. Page 0 is vendor
-specific and not necessarily in mode page format.
-Alternatively hex values can be given for both <pn> and <spn> (both
-prefixed by '0x').
-.TP
--T
+\fB\-t\fR \fIPN\fR[,\fISPN\fR]
+Display information from mode page number \fIPN\fR (and optionally sub
+page number \fISPN\fR) in decoded format (if known, otherwise in hex form).
+\fIPN\fR is a mode page number in a decimal number from 0 to 63 inclusive.
+\fISPN\fR is the mode subpage number and is assumed to be 0 if not given.
+\fISPN\fR is a decimal number from 1 to 255 inclusive. A page number of 63
+returns all pages supported by the device in ascending order except for
+page 0 which, if present, is last. Page 0 is vendor specific and not
+necessarily in mode page format. Alternatively hex values can be given for
+both \fIPN\f and \fISPN\fR (both prefixed by '0x').
+.TP
+\fB\-t\fR
Trace commands (for debugging). When used once SCSI commands are shown
(in hex) and any errors from these SCSI commands are spelt out (i.e.
with a decoded and raw sense buffer). When used twice, the additional
data sent with mode select and the response from mode sense are
shown (in hex).
.TP
--u <pn[,spn]>
-Display information from mode page number <pn> (and optionally <spn>)
-in hex form. <pn> is a mode page number in a decimal number
-from 0 to 63 inclusive. "spn" is the mode subpage
-number and is assumed to be 0 if not given. "spn" is a
-decimal number from 1 to 255 inclusive. A page number of 63
-returns all pages supported by the device in ascending order
-except for page 0 which, if present, is last. Page 0 is vendor
-specific and not necessarily in mode page format.
-Alternatively hex values can be given for both <pn> and <spn> (both
-prefixed by '0x'). For example 63 and 0x3f are equivalent.
-.TP
--v
-Show version number and exit.
-.TP
--V
+\fB\-u\fR \fIPN\fR[,\fISPN\fR]
+Display information from mode page number \fIPN\fR (and optionally \fISPN\fR)
+in hex form. \fIPN\f is a mode page number in a decimal number from 0 to 63
+inclusive. \fISPN\fR is the mode subpage number and is assumed to be 0 if
+not given. \fISPN\fR is a decimal number from 1 to 255 inclusive. A page
+number of 63 returns all pages supported by the device in ascending order
+except for page 0 which, if present, is last. Page 0 is vendor specific and
+not necessarily in mode page format. Alternatively hex values can be given
+for both \fIPN\fR and \fISPN\fR (both prefixed by '0x'). For example 63 and
+0x3f are equivalent.
+.TP
+\fB\-v\fR
+.TP
+\fB\-V\fR
Access information in the Verify Error Recovery mode page.
.TP
--z
-do a single fetch for mode pages (over-estimating the expected length
+\fB\-z\fR
+do a single fetch for mode pages (over\-estimating the expected length
of the returned response). The default action is to do a double
fetch, the first fetch is to find the response length that could be
returned. Devices that closely adhere to SCSI standards should not
require this option, some real world devices do require it.
-.PP
+.SH ADVANCED OPTIONS
Only one of the following three options can be specified.
None of these three implies the current values are returned.
.TP
--m
+\fB\-m\fR
Display modifiable fields instead of current values
.TP
--M
+\fB\-M\fR
Display manufacturer's defaults instead of current values
.TP
--S
+\fB\-S\fR
Display saved defaults instead of current values
.PP
The following are advanced options, not generally suited for most users:
.TP
--X
+\fB\-X\fR
Display output values in a list. Make them suitable for editing and
-being given back to the '-R' (replace command).
+being given back to the '\-R' (replace command).
.TP
--R
-Replace parameters - best used with -X (expert use only)
+\fB\\-R\fR
+Replace parameters \- best used with \-X (expert use only)
.SH CHANGING MODE PAGE PARAMETERS
Firstly you should know what you are doing before changing existing
parameters. Taking the control page as an example, first list it out
-normally (e.g. "sginfo -C /dev/sda") and
+normally (e.g. "sginfo \-C /dev/sda") and
decide which parameter is to be changed (note its position relative
to the other lines output). Then execute the same sginfo command with
-the "-X" option added; this will output the parameter values in a
+the "\-X" option added; this will output the parameter values in a
single row in the same relative positions as the previous command. Now
-execute "sginfo -CXR /dev/sda ..." with the "..." replaced by the
+execute "sginfo \-CXR /dev/sda ..." with the "..." replaced by the
single row of values output by the previous command, with the relevant
parameter changed. Here is a simplified example:
.PP
- $ sginfo -C /dev/sda
+ $ sginfo \-C /dev/sda
.br
Control mode page (0xa)
.br
- -----------------------
+ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
.br
TST 0
.br
@@ -224,24 +224,24 @@ parameter changed. Here is a simplified example:
[Actually the Control page has more parameters that shown above.] Next
output those parameters in single line form:
.PP
- $ sginfo -CX /dev/sda
+ $ sginfo \-CX /dev/sda
.br
0 0 1 0
.PP
Let us assume that the GLTSD bit is to be cleared. The command that
will clear it is:
.PP
- $ sginfo -CXR /dev/sda 0 0 0 0
+ $ sginfo \-CXR /dev/sda 0 0 0 0
.PP
-The same number of parameters output by the "-CX" command needs to be
-placed at the end of the "-CXR" command line (after the device name).
+The same number of parameters output by the "\-CX" command needs to be
+placed at the end of the "\-CXR" command line (after the device name).
Now check that the change took effect:
.PP
- $ sginfo -C /dev/sda
+ $ sginfo \-C /dev/sda
.br
Control mode page (0xa)
.br
- -----------------------
+ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
.br
TST 0
.br
@@ -254,43 +254,43 @@ Now check that the change took effect:
When a mode page is "replaced" the default action is to change both the
current page and the saved page. [For some reason versions of sginfo and
scsiinfo prior to 2.0 did not change the "saved" page.] To change only
-the current mode page but not the corresponding saved page use the "-N"
+the current mode page but not the corresponding saved page use the "\-N"
option.
.PP
.SH GENERATING SCRIPT FILES AND HEX PAGES
-The "-aX" or "-AX" option generates output suitable for a script file.
+The "\-aX" or "\-AX" option generates output suitable for a script file.
Mode pages are output in list format (after the INQUIRY and serial
number) one page per line. To facilitate running the output as (part
of) a script file to assert chosen mode page values, each line is
-prefixed by "sginfo -t <pn>[,<spn>] -XR ". When such a script
-file is run, it will have the effect of re-asserting the mode
-page values to what they were when the "-aX" generated the output.
+prefixed by "sginfo \-t \fIPN\fR[,\fISPN\fR] \-XR ". When such a script
+file is run, it will have the effect of re\-asserting the mode
+page values to what they were when the "\-aX" generated the output.
.PP
All mode pages (and subpages) supported by the device can be accessed via
-the -t and -u options. To see all
-mode pages supported by the device use "-u 63". [To see all mode pages
-and all subpages use "-u 63,255".] To list the control mode page in
+the \-t and \-u options. To see all
+mode pages supported by the device use "\-u 63". [To see all mode pages
+and all subpages use "\-u 63,255".] To list the control mode page in
hex (mode page index in the first column and the corresponding byte
-value in the second column) use "-u 0xa". Mode pages (subpage code == 0)
+value in the second column) use "\-u 0xa". Mode pages (subpage code == 0)
start at index position 2 while subpages start at index position 4.
-If the "-Xu ..." option is used then a list a hex values each value
+If the "\-Xu ..." option is used then a list a hex values each value
prefixed by "@" is output. Mode (sub)page values can then be modified with
-with the "-RXu ..." option.
+with the "\-RXu ..." option.
.PP
.SH RESTRICTIONS
The SCSI MODE SENSE command yields block descriptors as well as a mode
page(s). This utility ignores block descriptors and does not display
them. The "disable block descriptor" switch (DBD) in the MODE SENSE command
is not set since some devices yield errors when it is set. When mode page
-values are being changed (the "-R" option), the same block descriptor
+values are being changed (the "\-R" option), the same block descriptor
obtained by reading the mode page (i.e. via a MODE SENSE command) is sent
back when the mode page is written (i.e. via a MODE SELECT command).
.PP
.SH REFERENCES
SCSI (draft) standards can be found at http://www.t10.org . The relevant
-documents are SPC-4 (mode pages common to all device types),
-SBC-2 (direct access devices [e.g. disks]), MMC-4 (CDs and DVDs) and
-SSC-2 (tapes).
+documents are SPC\-4 (mode pages common to all device types),
+SBC\-2 (direct access devices [e.g. disks]), MMC\-4 (CDs and DVDs) and
+SSC\-2 (tapes).
.PP
.SH AUTHORS
Written by Eric Youngdale, Michael Weller, Douglas Gilbert, Kurt Garloff,
diff --git a/sginfo.c b/sginfo.c
index 84d4ea20..b6090474 100644
--- a/sginfo.c
+++ b/sginfo.c
@@ -111,9 +111,11 @@
*/
#define _XOPEN_SOURCE 500
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
-static const char * version_str = "2.23 [20060826]";
+static const char * version_str = "2.25 [20070121]";
#include <stdio.h>
#include <string.h>
@@ -1475,7 +1477,7 @@ static int read_defect_list(int grown_only)
if (defectformat == HEAD_SORT_TOKEN) {
defectformat = 0x04;
sorthead = 1;
- headsp = malloc(sizeof(unsigned int) * MAX_HEADS);
+ headsp = (unsigned int *)malloc(sizeof(unsigned int) * MAX_HEADS);
if (headsp == NULL) {
perror("malloc failed");
return status;
@@ -1598,12 +1600,12 @@ static int read_defect_list(int grown_only)
if (len > 0) {
k = len + 8; /* length of defect list + header */
if (k > (int)sizeof(cbuffer)) {
- heapp = malloc(k);
+ heapp = (unsigned char *)malloc(k);
if (len > 0x80000 && NULL == heapp) {
len = 0x80000; /* go large: 512 KB */
k = len + 8;
- heapp = malloc(k);
+ heapp = (unsigned char *)malloc(k);
}
if (heapp != NULL)
bp = heapp;
@@ -1649,7 +1651,7 @@ trytenbyte:
}
k = len + 4; /* length of defect list + header */
if (k > (int)sizeof(cbuffer) && NULL == heapp) {
- heapp = malloc(k);
+ heapp = (unsigned char *)malloc(k);
if (heapp != NULL)
bp = heapp;
}
@@ -2754,7 +2756,7 @@ static int sas_phy_control_discover(struct mpage_info * mpi,
for (k = 0, p = pagestart + 8; k < num_phys; ++k, p += 48) {
intfield(p + 1, 1, "Phy Identifier");
bitfield(p + 4, "Attached Device type", 0x7, 4);
- bitfield(p + 5, "Negotiated Physical Link rate", 0xf, 0);
+ bitfield(p + 5, "Negotiated Logical Link rate", 0xf, 0);
bitfield(p + 6, "Attached SSP Initiator port", 0x1, 3);
bitfield(p + 6, "Attached STP Initiator port", 0x1, 2);
bitfield(p + 6, "Attached SMP Initiator port", 0x1, 1);
diff --git a/sgm_dd.8 b/sgm_dd.8
index 307e3c6b..f130d00f 100644
--- a/sgm_dd.8
+++ b/sgm_dd.8
@@ -1,17 +1,16 @@
-.TH SGM_DD "8" "June 2006" "sg3_utils-1.21" SG3_UTILS
+.TH SGM_DD "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
sgm_dd \- copies data to and from files and devices. Specialized for
devices that understand the SCSI command set and does memory mapped
transfers from sg devices.
.SH SYNOPSIS
.B sgm_dd
-[\fIbs=<n>\fR] [\fIcount=<n>\fR] [\fIibs=<n>\fR] [\fIif=<ifile>\fR]
-[\fIiflag=<flags>\fR] [\fIobs=<n>\fR] [\fIof=<ofile>\fR]
-[\fIoflag=<flags>\fR] [\fIseek=<n>\fR] [\fIskip=<n>\fR]
-[\fI--help\fR] [\fI--version\fR]
+[\fIbs=BS\fR] [\fIcount=COUNT\fR] [\fIibs=BS\fR] [\fIif=IFILE\fR]
+[\fIiflag=FLAGS\fR] [\fIobs=BS\fR] [\fIof=OFILE\fR] [\fIoflag=FLAGS\fR]
+[\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR] [\fI\-\-version\fR]
.PP
-[\fIbpt=<n>\fR] [\fIcdbsz=6|10|12|16\fR] [\fIdio=0|1\fR]
-[\fIsync=0|1\fR] [\fItime=0|1\fR] [\fIverbose=<n>\fR]
+[\fIbpt=BPT\fR] [\fIcdbsz=\fR6|10|12|16] [\fIdio=\fR0|1] [\fIsync=\fR0|1]
+[\fItime=\fR0|1] [\fIverbose=VERB\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -21,103 +20,107 @@ transfers on sg devices. Similar syntax and semantics to
.B dd(1)
but does not perform any conversions.
.PP
-Will only perform memory mapped transfers when <ifile> or <ofile> are
-SCSI generic (sg) devices. If both <ifile> and <ofile> are sg devices
-then memory mapped transfers are only performed on <ifile>.
+Will only perform memory mapped transfers when \fIIFILE\fR or \fIOFILE\fR
+are SCSI generic (sg) devices. If both \fIIFILE\fR and \fIOFILE\fR are
+sg devices then memory mapped transfers are only performed on \fIIFILE\fR.
.PP
The first group in the synopsis above are "standard" Unix
.B dd(1)
-arguments. The second group are extra arguments added by this utility.
+operands. The second group are extra options added by this utility.
Both groups are defined below.
+.SH OPTIONS
.TP
-bpt=BLOCKS
-each IO transaction will be made using this number of blocks (or less if
-near the end of count). Default is 128 for block sizes less that 2048
+\fBbpt\fR=\fIBPT\fR
+each IO transaction will be made using \fIBPT\fR blocks (or less if
+near the end of the copy). Default is 128 for block sizes less that 2048
bytes, otherwise the default is 32. So for bs=512 the reads and writes
will each convey 64 KiB of data by default (less if near the end of the
transfer or memory restrictions). When cd/dvd drives are accessed, the
block size is typically 2048 bytes and bpt defaults to 32 which again
implies 64 KiB transfers.
.TP
-bs=BYTES
-this
+\fBbs\fR=\fIBS\fR
+where \fIBS\fR
.B must
be the block size of the physical device. Note that this differs from
.B dd(1)
-which permits 'bs' to be an integral multiple. Default is 512 which
+which permits \fIBS\fR to be an integral multiple. Default is 512 which
is usually correct for disks but incorrect for cdroms (which normally
-have 2048 byte blocks).
+have 2048 byte blocks). For this utility the maximum size of each individual
+IO operation is \fIBS\fR * \fIBPT\fR bytes.
.TP
-cdbsz=6 | 10 | 12 | 16
+\fBcdbsz\fR=6 | 10 | 12 | 16
size of SCSI READ and/or WRITE commands issued on sg device names.
Default is 10 byte SCSI command blocks (unless calculations indicate
that a 4 byte block number may be exceeded, in which case it defaults
to 16 byte SCSI commands).
.TP
-count=BLOCKS
-copy this number of blocks from 'if' to 'of'. Default is the
-minimum (of 'if' and 'of') number of blocks that sg devices return from
-READ CAPACITY SCSI commands or that block devices (or their partitions)
-report. Normal files are not probed for their size. If 'skip'
-or 'seek' are given and the count is derived (i.e. not explicitly given)
-then the derived count is scaled back so that the copy will not overrun the
-device. If the file name is a block device partition and count is not given
-then the size of the partition rather than the size of the whole device is
-used. If count is not given and cannot be derived then an error message
-is issued and no copy takes place.
+\fBcount\fR=\fICOUNT\fR
+copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the
+minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices
+report from SCSI READ CAPACITY commands or that block devices (or their
+partitions) report. Normal files are not probed for their size. If
+\fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is derived (i.e.
+not explicitly given) then the derived count is scaled back so that the
+copy will not overrun the device. If the file name is a block device
+partition and \fICOUNT\fR is not given then the size of the partition rather
+than the size of the whole device is used. If \fICOUNT\fR is not given and
+cannot be derived then an error message is issued and no copy takes place.
.TP
-dio=0 | 1
-permits direct IO to be selected on the write-side (i.e. 'of'). Only
-allowed when the read-side (i.e. 'if') is a sg device. When 1 there
-may be a "zero copy" copy (i.e. mmap-ed transfer on the read into the user
-space and direct IO from there on the write, potentially two DMAs and
-no data copying from the CPU). Default is 0
+\fBdio\fR=0 | 1
+permits direct IO to be selected on the write\-side (i.e. on \fIOFILE\fR).
+Only allowed when the read\-side (i.e. \fIIFILE\fR) is a sg device. When
+1 there may be a "zero copy" copy (i.e. mmap\-ed transfer on the read into
+the user space and direct IO from there on the write, potentially two DMAs
+and no data copying from the CPU). Default is 0.
.TP
-ibs=BYTES
-if given must be the same as bs
+\fBibs\fR=\fIBS\fR
+if given must be the same as \fIBS\fR given to 'bs=' option.
.TP
-if=FILE
-read from FILE instead of stdin which is the default. A file name of "-"
-is taken to be stdin. Starts reading at the beginning of FILE
-unless 'skip' is given.
+\fBif\fR=\fIIFILE\fR
+read from \fIIFILE\fR instead of stdin. If \fIIFILE\fR is '\-' then stdin
+is read. Starts reading at the beginning of \fIIFILE\fR unless \fISKIP\fR
+is given.
.TP
-iflag=FLAGS
-where FLAGS is a comma separated list of one or more flags outlined below.
-These flags are associated with <ifile> and are ignored when <ifile> is
-stdin.
+\fBiflag\fR=\fIFLAGS\fR
+where \fIFLAGS\fR is a comma separated list of one or more flags outlined
+below. These flags are associated with \fIIFILE\fR and are ignored when
+\fIIFILE\fR is stdin.
.TP
-obs=BYTES
-if given must be the same as bs
+\fBobs\fR=\fIBS\fR
+if given must be the same as \fIBS\fR given to 'bs=' option.
.TP
-of=FILE
-write to FILE instead of stdout. A file name of - is taken to be stdout.
-If FILE is /dev/null then no actual writes are performed. If FILE is .
-(period) then it is treated the same way as /dev/null (this is a
-shorthand notation)
+\fBof\fR=\fIOFILE\fR
+write to \fIOFILE\fR instead of stdout. If \fIOFILE\fR is '\-' then writes
+to stdout. If \fIOFILE\fR is /dev/null then no actual writes are performed.
+If \fIOFILE\fR is '.' (period) then it is treated the same way as
+/dev/null (this is a shorthand notation). If \fIOFILE\fR exists then it
+is _not_ truncated; it is overwritten from the start of \fIOFILE\fR
+unless 'oflag=append' or \fISEEK\fR is given.
.TP
-oflag=FLAGS
-where FLAGS is a comma separated list of one or more flags outlined below.
-These flags are associated with <ofile> and are ignored when <ofile>
-is /dev/null, . (period), or stdout.
+\fBoflag\fR=\fIFLAGS\fR
+where \fIFLAGS\fR is a comma separated list of one or more flags outlined
+below. These flags are associated with \fIOFILE\fR and are ignored when
+\fIOFILE\fR is /dev/null, '.' (period), or stdout.
.TP
-seek=BLOCKS
-start writing BLOCKS bs-sized blocks from the start of the output file.
+\fBseek\fR=\fISEEK\fR
+start writing \fISEEK\fR bs\-sized blocks from the start of \fIOFILE\fR.
Default is block 0 (i.e. start of file).
.TP
-skip=BLOCKS
-start reading BLOCKS bs-sized blocks from the start of input file.
+\fBskip\fR=\fISKIP\fR
+start reading \fISKIP\fR bs\-sized blocks from the start of \fIIFILE\fR.
Default is block 0 (i.e. start of file).
.TP
-sync=0 | 1
-when 1, does SYNCHRONIZE CACHE command on 'of' at the end of the transfer.
-Only active when 'of' is a sg device file name
+\fBsync\fR=0 | 1
+when 1, does SYNCHRONIZE CACHE command on \fIOFILE\fR at the end of the
+transfer. Only active when \fIOFILE\fR is a sg device file name.
.TP
-time=0 | 1
+\fBtime\fR=0 | 1
when 1, times transfer and does throughput calculation, outputting the
-results (to stderr) at completion. When 0 (default) doesn't perform timing
+results (to stderr) at completion. When 0 (default) doesn't perform timing.
.TP
-verbose=<n>
-as <n> increases so does the amount of debug output sent to stderr.
+\fBverbose\fR=\fIVERB\fR
+as \fIVERB\fR increases so does the amount of debug output sent to stderr.
Default value is zero which yields the minimum amount of debug output.
A value of 1 reports extra information that is not repetitive. A value
2 reports cdbs and responses for SCSI commands that are not repetitive
@@ -125,53 +128,58 @@ A value of 1 reports extra information that is not repetitive. A value
repetitive. Values of 3 and 4 yield output for all SCSI commands (and
Unix read() and write() calls) so there can be a lot of output.
.TP
---version
-outputs version number information and exits
+\fB\-\-help\fR
+outputs usage message and exits.
+.TP
+\fB\-\-version\fR
+outputs version number information and exits.
.SH FLAGS
Here is a list of flags and their meanings:
.TP
append
-causes the O_APPEND flag to be added to the open of <ofile>. For normal
+causes the O_APPEND flag to be added to the open of \fIOFILE\fR. For normal
files this will lead to data appended to the end of any existing data.
-Cannot be used together with the 'seek=<n>' option as they conflict.
+Cannot be used together with the \fIseek=SEEK\fR option as they conflict.
The default action of this utility is to overwrite any existing data
-from the beginning of the file or, if 'seek=<n>' is given, starting at
-block <n>. Note that attempting to 'append' to a device file will
-usually be ignored or may cause an error to be reported.
+from the beginning of the file or, if \fISEEK\fR is given, starting at
+block \fISEEK\fR. Note that attempting to 'append' to a device file (e.g.
+a disk) will usually be ignored or may cause an error to be reported.
.TP
direct
-causes the O_DIRECT flag to be added to the open of <ifile> and/or <ofile>.
-This flag requires some memory alignment on IO. Hence user memory buffers
-are aligned to the page size. Has no effect on sg, normal or raw files.
+causes the O_DIRECT flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR. This flag requires some memory alignment on IO. Hence user
+memory buffers are aligned to the page size. Has no effect on sg, normal
+or raw files.
.TP
dpo
-set the DPO bit (disable page out) in READ and WRITE SCSI commands. Not
+set the DPO bit (disable page out) in SCSI READ and WRITE commands. Not
supported for 6 byte cdb variants of READ and WRITE. Indicates that
data is unlikely to be required to stay in device (e.g. disk) cache.
May speed media copy and/or cause a media copy to have less impact
on other device users.
.TP
dsync
-causes the O_SYNC flag to be added to the open of <ifile> and/or <ofile>.
-The "d" is prepended to lower confusion with the 'sync=0|1' option which
-has another action (i.e. a synchronisation to media at the end of the
-transfer).
+causes the O_SYNC flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR. The "d" is prepended to lower confusion with the 'sync=0|1'
+option which has another action (i.e. a synchronisation to media at the
+end of the transfer).
.TP
excl
-causes the O_EXCL flag to be added to the open of <ifile> and/or <ofile>.
+causes the O_EXCL flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR.
.TP
fua
-causes the FUA (force unit access) bit to be set in READ and/or WRITE
-SCSI commands. This only has effect with sg devices. The 6 byte variants
-of the READ and WRITE SCSI commands do not support the FUA bit.
+causes the FUA (force unit access) bit to be set in SCSI READ and/or WRITE
+commands. This only has effect with sg devices. The 6 byte variants
+of the SCSI READ and WRITE commands do not support the FUA bit.
Only active for sg device file names.
.SH RETIRED OPTIONS
Here are some retired options that are still present:
.TP
fua=0 | 1 | 2 | 3
-force unit access bit. When 3, fua is set on both 'if' and 'of'; when 2, fua
-is set on 'if'; when 1, fua is set on 'of'; when 0 (default), fua is cleared
-on both. See the 'fua' flag.
+force unit access bit. When 3, fua is set on both \fIIFILE\fR and
+\fIOFILE\fR; when 2, fua is set on \fIIFILE\fR; when 1, fua is set on
+\fIOFILE\fR; when 0 (default), fua is cleared on both. See the 'fua' flag.
.SH NOTES
A raw device must be bound to a block device prior to using sgm_dd.
See
@@ -182,15 +190,16 @@ before use.
.PP
Raw device partition information can often be found with
.B fdisk(8)
-[the "-ul" argument is useful in this respect].
+[the "\-ul" argument is useful in this respect].
.PP
-BYTES and BLOCKS may be followed by one of these multiplicative suffixes:
+\fICOUNT\fR, \fISKIP\fR, \fISEEK\fR, \fIBPT\fR and \fIBS\fR may include one
+of these multiplicative suffixes:
c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
MB *1,000,000 . This pattern continues for "G", "T" and "P". The latter two
-suffixes can only be used for count, skip and seek values). Also a suffix of
-the form "x<n>" multiplies the leading number by <n>. These multiplicative
-suffixes are compatible with GNU's dd command (since 2002) which claims
-compliance with SI and with IEC 60027-2.
+suffixes can only be used for \fICOUNT\fR, \fISKIP\fR and \fISEEK\fR.
+Also a suffix of the form "x<n>" multiplies the leading number by <n>.
+These multiplicative suffixes are compatible with GNU's dd command (since
+2002) which claims compliance with SI and with IEC 60027\-2.
.PP
Alternatively numerical values can be given in hexadecimal preceded by
either "0x" or "0X" (or with a trailing "h" or "H"). When hex numbers are
@@ -215,7 +224,7 @@ All informative, warning and error output is sent to stderr so that
dd's output file can be stdout and remain unpolluted. If no options
are given, then the usage message is output and nothing else happens.
.PP
-For sg devices this utility issues READ and WRITE (SBC) SCSI commands
+For sg devices this utility issues SCSI READ and WRITE (SBC) commands
which are appropriate for disks and reading from CD/DVD drives. Those
commands are not formatted correctly for tape devices so sgm_dd should
not be used on tape devices.
@@ -245,7 +254,7 @@ Written by Doug Gilbert and Peter Allworth.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000-2006 Douglas Gilbert
+Copyright \(co 2000\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sgm_dd.c b/sgm_dd.c
index 1ea20653..d2c3bbd0 100644
--- a/sgm_dd.c
+++ b/sgm_dd.c
@@ -1,5 +1,7 @@
#define _XOPEN_SOURCE 500
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -21,12 +23,11 @@
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_io_linux.h"
-#include "llseek.h"
/* A utility program for copying files. Specialised for "files" that
* represent devices that understand the SCSI command set.
*
-* Copyright (C) 1999 - 2006 D. Gilbert and P. Allworth
+* Copyright (C) 1999 - 2007 D. Gilbert and P. Allworth
* 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)
@@ -54,7 +55,7 @@
This version is designed for the linux kernel 2.4 and 2.6 series.
*/
-static char * version_str = "1.28 20061003";
+static char * version_str = "1.31 20070123";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -246,33 +247,46 @@ static char * dd_filetype_str(int ft, char * buff)
void usage()
{
fprintf(stderr, "Usage: "
- "sgm_dd [bs=<n>] [count=<n>] [ibs=<n>] [if=<ifile>]"
- " [iflag=<flags>]\n"
- " [obs=<n>] [of=<ofile>] [oflag=<flags>] "
- "[seek=<n>] [skip=<n>]\n"
+ "sgm_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]"
+ " [iflag=FLAGS]\n"
+ " [obs=BS] [of=OFILE] [oflag=FLAGS] "
+ "[seek=SEEK] [skip=SKIP]\n"
" [--help] [--version]\n\n");
fprintf(stderr,
- " [bpt=<num>] [cdbsz=6|10|12|16] [dio=0|1] "
+ " [bpt=BPT] [cdbsz=6|10|12|16] [dio=0|1] "
"[fua=0|1|2|3]\n"
- " [sync=0|1] [time=<n>] [verbose=<n>]\n\n"
- " where:\n"
- " bpt is blocks_per_transfer (default is 128)\n"
- " bs must be device block size (default 512)\n"
- " cdbsz size of SCSI READ or WRITE command (default is 10)\n"
- " dio 0->indirect IO on write, 1->direct IO on write\n"
- " (only when read side is sg device (using mmap))\n"
- " fua force unit access: 0->don't(def), 1->of, 2->if, "
- "3->of+if\n");
+ " [sync=0|1] [time=0|1] [verbose=VERB]\n\n"
+ " where:\n"
+ " bpt is blocks_per_transfer (default is 128)\n"
+ " bs must be device block size (default 512)\n"
+ " cdbsz size of SCSI READ or WRITE cdb (default is 10)\n"
+ " count number of blocks to copy (def: device size)\n"
+ " dio 0->indirect IO on write, 1->direct IO on write\n"
+ " (only when read side is sg device (using mmap))\n"
+ " fua force unit access: 0->don't(def), 1->OFILE, "
+ "2->IFILE,\n"
+ " 3->OFILE+IFILE\n"
+ " if file or device to read from (def: stdin)\n");
fprintf(stderr,
- " iflag comma separated list from: [direct,dpo,dsync,excl,"
- "fua]\n"
- " oflag comma separated list from: [append,direct,dpo,"
+ " iflag comma separated list from: [direct,dpo,dsync,"
+ "excl,fua]\n"
+ " of file or device to write to (def: stdout), "
+ "OFILE of '.'\n"
+ " treated as /dev/null\n"
+ " oflag comma separated list from: [append,direct,dpo,"
"dsync,excl,fua]\n"
- " sync 0->no sync(def), 1->SYNCHRONIZE CACHE after xfer\n"
- " time 0->no timing(def), 1->time plus calculate "
+ " seek block position to start writing to OFILE\n"
+ " skip block position to start reading from IFILE\n"
+ " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE "
+ "after copy\n"
+ " time 0->no timing(def), 1->time plus calculate "
"throughput\n"
- " verbose 0->quiet(def), 1->some noise, 2->more noise, etc\n"
- " --version print version information then exit\n");
+ " verbose 0->quiet(def), 1->some noise, 2->more noise, "
+ "etc\n"
+ " --help print usage message then exit\n"
+ " --version print version information then exit\n\n"
+ "Copy from IFILE to OFILE, similar to dd command\n"
+ "specialized for SCSI devices for which mmap-ed IO attemped\n");
}
/* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */
@@ -707,6 +721,7 @@ int main(int argc, char * argv[])
int scsi_cdbsz_in = DEF_SCSI_CDBSZ;
int scsi_cdbsz_out = DEF_SCSI_CDBSZ;
int cdbsz_given = 0;
+ int do_coe = 0; /* dummy, just accept + ignore */
int do_sync = 0;
int do_dio = 0;
int num_dio_not_done = 0;
@@ -750,7 +765,9 @@ int main(int argc, char * argv[])
scsi_cdbsz_in = sg_get_num(buf);
scsi_cdbsz_out = scsi_cdbsz_in;
cdbsz_given = 1;
- } else if (0 == strcmp(key,"count")) {
+ } else if (0 == strcmp(key,"coe"))
+ do_coe = sg_get_num(buf); /* dummy, just accept + ignore */
+ else if (0 == strcmp(key,"count")) {
dd_count = sg_get_llnum(buf);
if (-1LL == dd_count) {
fprintf(stderr, ME "bad argument to 'count'\n");
@@ -914,8 +931,8 @@ int main(int argc, char * argv[])
return SG_LIB_FILE_ERROR;
}
}
- wrkMmap = mmap(NULL, in_res_sz, PROT_READ | PROT_WRITE,
- MAP_SHARED, infd, 0);
+ wrkMmap = (unsigned char *)mmap(NULL, in_res_sz,
+ PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0);
if (MAP_FAILED == wrkMmap) {
snprintf(ebuff, EBUFF_SZ,
ME "error using mmap() on file: %s", inf);
@@ -938,18 +955,19 @@ int main(int argc, char * argv[])
return SG_LIB_FILE_ERROR;
}
else if (skip > 0) {
- llse_loff_t offset = skip;
+ off64_t offset = skip;
offset *= blk_sz; /* could exceed 32 bits here! */
- if (llse_llseek(infd, offset, SEEK_SET) < 0) {
+ if (lseek64(infd, offset, SEEK_SET) < 0) {
snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to "
"required position on %s", inf);
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
if (verbose)
- fprintf(stderr, " >> skip: llseek SEEK_SET, "
- "byte offset=0x%llx\n", offset);
+ fprintf(stderr, " >> skip: lseek64 SEEK_SET, "
+ "byte offset=0x%llx\n",
+ (unsigned long long)offset);
}
}
}
@@ -997,8 +1015,8 @@ int main(int argc, char * argv[])
}
}
if (NULL == wrkMmap) {
- wrkMmap = mmap(NULL, out_res_sz, PROT_READ | PROT_WRITE,
- MAP_SHARED, outfd, 0);
+ wrkMmap = (unsigned char *)mmap(NULL, out_res_sz,
+ PROT_READ | PROT_WRITE, MAP_SHARED, outfd, 0);
if (MAP_FAILED == wrkMmap) {
snprintf(ebuff, EBUFF_SZ,
ME "error using mmap() on file: %s", outf);
@@ -1036,24 +1054,25 @@ int main(int argc, char * argv[])
}
}
if (seek > 0) {
- llse_loff_t offset = seek;
+ off64_t offset = seek;
offset *= blk_sz; /* could exceed 32 bits here! */
- if (llse_llseek(outfd, offset, SEEK_SET) < 0) {
+ if (lseek64(outfd, offset, SEEK_SET) < 0) {
snprintf(ebuff, EBUFF_SZ, ME "couldn't seek to "
"required position on %s", outf);
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
if (verbose)
- fprintf(stderr, " >> seek: llseek SEEK_SET, "
- "byte offset=0x%llx\n", offset);
+ fprintf(stderr, " >> seek: lseek64 SEEK_SET, "
+ "byte offset=0x%llx\n",
+ (unsigned long long)offset);
}
}
}
if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) {
- fprintf(stderr,
- "Can't have both 'if' as stdin _and_ 'of' as stdout\n");
+ fprintf(stderr, "Won't default both IFILE to stdin _and_ OFILE "
+ "to as stdout\n");
fprintf(stderr, "For more information use '--help'\n");
return SG_LIB_SYNTAX_ERROR;
}
@@ -1187,7 +1206,7 @@ int main(int argc, char * argv[])
wrkPos = wrkMmap;
else {
if ((FT_RAW == in_type) || (FT_RAW == out_type)) {
- wrkBuff = malloc(blk_sz * bpt + psz);
+ wrkBuff = (unsigned char *)malloc(blk_sz * bpt + psz);
if (0 == wrkBuff) {
fprintf(stderr, "Not enough user memory for raw\n");
return SG_LIB_FILE_ERROR;
@@ -1196,7 +1215,7 @@ int main(int argc, char * argv[])
(~(psz - 1)));
}
else {
- wrkBuff = malloc(blk_sz * bpt);
+ wrkBuff = (unsigned char *)malloc(blk_sz * bpt);
if (0 == wrkBuff) {
fprintf(stderr, "Not enough user memory\n");
return SG_LIB_FILE_ERROR;
diff --git a/sgp_dd.8 b/sgp_dd.8
index 85defe9a..03343237 100644
--- a/sgp_dd.8
+++ b/sgp_dd.8
@@ -1,16 +1,16 @@
-.TH SGP_DD "8" "July 2006" "sg3_utils-1.22" SG3_UTILS
+.TH SGP_DD "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS
.SH NAME
-sgp_dd \- copies data to and from files and devices. Specialised for
+sgp_dd \- copies data to and from files and devices. Specialized for
devices that understand the SCSI command set.
.SH SYNOPSIS
.B sgp_dd
-[\fIbs=<n>\fR] [\fIcount=<n>\fR] [\fIibs=<n>\fR] [\fIif=<ifile>\fR]
-[\fIiflag=<flags>\fR] [\fIobs=<n>\fR] [\fIof=<ofile>\fR]
-[\fIoflag=<flags>\fR] [\fIseek=<n>\fR] [\fIskip=<n>\fR]
-[\fI--help\fR] [\fI--version\fR]
+[\fIbs=BS\fR] [\fIcount=COUNT\fR] [\fIibs=BS\fR] [\fIif=IFILE\fR]
+[\fIiflag=FLAGS\fR] [\fIobs=BS\fR] [\fIof=OFILE\fR] [\fIoflag=FLAGS\fR]
+[\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR] [\fI\-\-version\fR]
.PP
-[\fIbpt=<n>\fR] [\fIcdbsz=6|10|12|16\fR] [\fIdeb=<n>\fR] [\fIdio=0|1\fR]
-[\fIsync=0|1\fR] [\fIthr=<n>\fR] [\fItime=0|1\fR] [\fIverbose=<n>\fR]
+[\fIbpt=BPT\fR] [\fIcoe=\fR0|1] [\fIcdbsz=\fR6|10|12|16] [\fIdeb=VERB\fR]
+[\fIdio=\fR0|1] [\fIsync=\fR0|1] [\fIthr=THR\fR] [\fItime=\fR0|1]
+[\fIverbose=VERB\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -22,129 +22,137 @@ the amount of parallelism. This improves speed in some cases.
.PP
The first group in the synopsis above are "standard" Unix
.B dd(1)
-arguments. The second group are extra arguments added by this utility.
+operands. The second group are extra options added by this utility.
Both groups are defined below.
+.SH OPTIONS
.TP
-bpt=BLOCKS
-each IO transaction will be made using this number of blocks (or less if
-near the end of count). Default is 128 for block sizes less that 2048
+\fBbpt\fR=\fIBPT\fR
+each IO transaction will be made using \fIBPT\fR blocks (or less if
+near the end of the copy). Default is 128 for block sizes less that 2048
bytes, otherwise the default is 32. So for bs=512 the reads and writes
will each convey 64 KiB of data by default (less if near the end of the
transfer or memory restrictions). When cd/dvd drives are accessed, the
block size is typically 2048 bytes and bpt defaults to 32 which again
implies 64 KiB transfers.
.TP
-bs=BYTES
-this
-.B must
+\fBbs\fR=\fIBS\fR
+where \fIBS\fR
+.B must
be the block size of the physical device. Note that this differs from
.B dd(1)
which permits 'bs' to be an integral multiple of the actual device block
size. Default is 512 which is usually correct for disks but incorrect for
cdroms (which normally have 2048 byte blocks).
.TP
-cdbsz=6 | 10 | 12 | 16
+\fBcdbsz\fR=6 | 10 | 12 | 16
size of SCSI READ and/or WRITE commands issued on sg device names.
Default is 10 byte SCSI command blocks (unless calculations indicate
that a 4 byte block number may be exceeded, in which case it defaults
to 16 byte SCSI commands).
.TP
-count=BLOCKS
-copy this number of blocks from 'if' to 'of'. Default is the minimum (
-of 'if' and 'of') number of blocks that sg devices return from READ
-CAPACITY SCSI commands or that block devices (or their partitions) report.
-Normal files are not probed for their size. If 'skip'
-or 'seek' are given and the count is deduced (i.e. not explicitly given)
-then that count is scaled back so that the copy will not overrun the
-device. If the file name is a block device partition and count is not given
-then the size of the partition rather than the size of the whole device is
-used. If count is not given and cannot be deduced then an error message
-is issued and no copy takes place.
+\fBcoe\fR=0 | 1
+set to 1 for continue on error. Only applies to errors on sg devices.
+Thus errors on other files will stop sgp_dd. Default is 0 which
+implies stop on any error. See the 'coe' flag for more information.
.TP
-deb=NUM
-outputs debug information. If NUM is 0 (default) then none and as NUM
-increases so does the amount of debug (max debug output when NUM is 9)
+\fBcount\fR=\fICOUNT\fR
+copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the
+minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices
+report from SCSI READ CAPACITY commands or that block devices (or their
+partitions) report. Normal files are not probed for their size. If
+\fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is deduced (i.e.
+not explicitly given) then that count is scaled back so that the copy will
+not overrun the device. If the file name is a block device partition and
+\fICOUNT\fR is not given then the size of the partition rather than the
+size of the whole device is used. If \fICOUNT\fR is not given and cannot be
+deduced then an error message is issued and no copy takes place.
.TP
-dio=0 | 1
+\fBdeb\fR=\fIVERB\fR
+outputs debug information. If \fIVERB\fR is 0 (default) then there is
+minimal debug information and as \fIVERB\fR increases so does the amount
+of debug (max debug output when \fIVERB\fR is 9).
+.TP
+\fBdio\fR=0 | 1
default is 0 which selects indirect IO. Value of 1 attempts direct
IO which, if not available, falls back to indirect IO and notes this
at completion. If direct IO is selected and /proc/scsi/sg/allow_dio
has the value of 0 then a warning is issued (and indirect IO is performed)
.TP
-ibs=BYTES
-if given must be the same value as 'bs'.
+\fBibs\fR=\fIBS\fR
+if given must be the same as \fIBS\fR given to 'bs=' option.
.TP
-if=FILE
-read from FILE instead of stdin. A file name of - is taken to be stdin.
-Starts reading at the beginning of FILE unless 'skip=<n>' is given.
+\fBif\fR=\fIIFILE\fR
+read from \fIIFILE\fR instead of stdin. If \fIIFILE\fR is '\-' then stdin
+is read. Starts reading at the beginning of \fIIFILE\fR unless \fISKIP\fR
+is given.
.TP
-iflag=FLAGS
-where FLAGS is a comma separated list of one or more flags outlined below.
-These flags are associated with <ifile> and are ignored when <ifile> is
-stdin.
+\fBiflag\fR=\fIFLAGS\fR
+where \fIFLAGS\fR is a comma separated list of one or more flags outlined
+below. These flags are associated with \fIIFILE\fR and are ignored when
+\fIIFILE\fR is stdin.
.TP
-obs=BYTES
-if given must be the same as 'bs'.
+\fBobs\fR=\fIBS\fR
+if given must be the same as \fIBS\fR given to 'bs=' option.
.TP
-of=FILE
-write to FILE instead of stdout. A file name of - is taken to be stdout.
-If FILE is /dev/null then no actual writes are performed. If FILE is .
-(period) then it is treated the same way as /dev/null (this is a
-shorthand notation). Starts (over-)writing at the beginning of FILE
-unless either 'seek=<n>' or 'oflag=append' is given (it is not permitted
-to give both).
+\fBof\fR=\fIOFILE\fR
+write to \fIOFILE\fR instead of stdout. If \fIOFILE\fR is '\-' then writes
+to stdout. If \fIOFILE\fR is /dev/null then no actual writes are performed.
+If \fIOFILE\fR is '.' (period) then it is treated the same way as
+/dev/null (this is a shorthand notation). If \fIOFILE\fR exists then it
+is _not_ truncated; it is overwritten from the start of \fIOFILE\fR
+unless 'oflag=append' or \fISEEK\fR is given.
.TP
-oflag=FLAGS
-where FLAGS is a comma separated list of one or more flags outlined below.
-These flags are associated with <ofile> and are ignored when <ofile>
-is /dev/null, . (period), or stdout.
+\fBoflag\fR=\fIFLAGS\fR
+where \fIFLAGS\fR is a comma separated list of one or more flags outlined
+below. These flags are associated with \fIOFILE\fR and are ignored when
+\fIOFILE\fR is /dev/null, '.' (period), or stdout.
.TP
-seek=BLOCKS
-start writing BLOCKS bs-sized blocks from the start of the output file.
+\fBseek\fR=\fISEEK\fR
+start writing \fISEEK\fR bs\-sized blocks from the start of \fIOFILE\fR.
Default is block 0 (i.e. start of file).
.TP
-skip=BLOCKS
-start reading BLOCKS bs-sized blocks from the start of input file.
+\fBskip\fR=\fISKIP\fR
+start reading \fISKIP\fR bs\-sized blocks from the start of \fIIFILE\fR.
Default is block 0 (i.e. start of file).
.TP
-sync=0 | 1
-when 1, does SYNCHRONIZE CACHE command on 'of' at the end of the transfer.
-Only active when 'of' is a sg device file name
+\fBsync\fR=0 | 1
+when 1, does SYNCHRONIZE CACHE command on \fIOFILE\fR at the end of the
+transfer. Only active when \fIOFILE\fR is a sg device file name.
.TP
-thr=NUM
-this is the number or worker threads (default 4) that attempt to
-copy in parallel. Minimum is 0 and maximum is 16
+\fBthr\fR=\fITHR\fR
+where \fITHR\fR is the number or worker threads (default 4) that attempt to
+copy in parallel. Minimum is 1 and maximum is 16.
.TP
-time=0 | 1
+\fBtime\fR=0 | 1
when 1, the transfer is timed and throughput calculation is
performed, outputting the results (to stderr) at completion. When
0 (default) no timing is performed.
.TP
-verbose=NUM
-increase verbosity. Same as 'deb=NUM'. Added for compatibility with
+\fBverbose\fR=\fIVERB\fR
+increase verbosity. Same as \fIdeb=VERB\fR. Added for compatibility with
sg_dd and sgm_dd.
.TP
---help
-outputs usage message and exits
+\fB\-\-help\fR
+outputs usage message and exits.
.TP
---version
-outputs version number information and exits
+\fB\-\-version\fR
+outputs version number information and exits.
.SH FLAGS
Here is a list of flags and their meanings:
.TP
append
-causes the O_APPEND flag to be added to the open of <ofile>. For normal
+causes the O_APPEND flag to be added to the open of \fIOFILE\fR. For normal
files this will lead to data appended to the end of any existing data.
-Cannot be used together with the 'seek=<n>' option as they conflict.
+Cannot be used together with the \fIseek=SEEK\fR option as they conflict.
The default action of this utility is to overwrite any existing data
-from the beginning of the file or, if 'seek=<n>' is given, starting at
-block <n>. Note that attempting to "append" to a device file will
-usually be ignored or may cause an error to be reported.
+from the beginning of the file or, if \fISEEK\fR is given, starting at
+block \fISEEK\fR. Note that attempting to 'append' to a device file (e.g.
+a disk) will usually be ignored or may cause an error to be reported.
.TP
coe
continue on error. When given with 'iflag=', an error that is detected
in a single SCSI command (typically 'bpt' blocks) is noted (by an error
-message sent to stderr), then zeroes are substituted into the buffer
+message sent to stderr), then zeros are substituted into the buffer
for the corresponding write operation and the copy continues. Note that the
.B sg_dd
utility is more sophisticated in such error situations when 'iflag=coe'.
@@ -152,30 +160,32 @@ When given with 'oflag=', any error reported by a SCSI WRITE command is
reported to stderr and the copy continues (as if nothing went wrong).
.TP
direct
-causes the O_DIRECT flag to be added to the open of <ifile> and/or <ofile>.
-This flag requires some memory alignment on IO. Hence user memory buffers
-are aligned to the page size. Has no effect on sg, normal or raw files.
+causes the O_DIRECT flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR. This flag requires some memory alignment on IO. Hence user
+memory buffers are aligned to the page size. Has no effect on sg, normal
+or raw files.
.TP
dpo
-set the DPO bit (disable page out) in READ and WRITE SCSI commands. Not
+set the DPO bit (disable page out) in SCSI READ and WRITE commands. Not
supported for 6 byte cdb variants of READ and WRITE. Indicates that
data is unlikely to be required to stay in device (e.g. disk) cache.
May speed media copy and/or cause a media copy to have less impact
on other device users.
.TP
dsync
-causes the O_SYNC flag to be added to the open of <ifile> and/or <ofile>.
-The "d" is prepended to lower confusion with the 'sync=0|1' option which
-has another action (i.e. a synchronisation to media at the end of the
-transfer).
+causes the O_SYNC flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR. The 'd' is prepended to lower confusion with the 'sync=0|1'
+option which has another action (i.e. a synchronisation to media at the
+end of the transfer).
.TP
excl
-causes the O_EXCL flag to be added to the open of <ifile> and/or <ofile>.
+causes the O_EXCL flag to be added to the open of \fIIFILE\fR and/or
+\fIOFILE\fR.
.TP
fua
-causes the FUA (force unit access) bit to be set in READ and/or WRITE
-SCSI commands. This only has effect with sg devices. The 6 byte variants
-of the READ and WRITE SCSI commands do not support the FUA bit.
+causes the FUA (force unit access) bit to be set in SCSI READ and/or WRITE
+commands. This only has effect with sg devices. The 6 byte variants
+of the SCSI READ and WRITE commands do not support the FUA bit.
Only active for sg device file names.
.SH RETIRED OPTIONS
Here are some retired options that are still present:
@@ -188,10 +198,11 @@ above. Similar to 'conv=noerror' in
utility. Default is 0 which implies stop on error. More advanced
coe=1 processing on reads is performed by the sg_dd utility.
.TP
+.TP
fua=0 | 1 | 2 | 3
-force unit access bit. When 3, fua is set on both 'if' and 'of'; when 2, fua
-is set on 'if'; when 1, fua is set on 'of'; when 0 (default), fua is cleared
-on both. See the 'fua' flag.
+force unit access bit. When 3, fua is set on both \fIIFILE\fR and
+\fIOFILE\fR; when 2, fua is set on \fIIFILE\fR;, when 1, fua is set on
+\fIOFILE\fR; when 0 (default), fua is cleared on both. See the 'fua' flag.
.SH NOTES
A raw device must be bound to a block device prior to using sgp_dd.
See
@@ -202,23 +213,24 @@ before use.
.PP
Raw device partition information can often be found with
.B fdisk(8)
-[the "-ul" argument is useful in this respect].
+[the "\-ul" argument is useful in this respect].
.PP
-BYTES and BLOCKS may be followed by one of these multiplicative suffixes:
+\fICOUNT\fR, \fISKIP\fR, \fISEEK\fR, \fIBPT\fR and \fIBS\fR may include one
+of these multiplicative suffixes:
c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576;
MB *1,000,000 . This pattern continues for "G", "T" and "P". The latter two
-suffixes can only be used for count, skip and seek values). Also a suffix of
-the form "x<n>" multiplies the leading number by <n>. These multiplicative
-suffixes are compatible with GNU's dd command (since 2002) which claims
-compliance with SI and with IEC 60027-2.
+suffixes can only be used for \fICOUNT\fR, \fISKIP\fR and \fISEEK\fR.
+Also a suffix of the form "x<n>" multiplies the leading number by <n>.
+These multiplicative suffixes are compatible with GNU's dd command (since
+2002) which claims compliance with SI and with IEC 60027\-2.
.PP
Alternatively numerical values can be given in hexadecimal preceded by
either "0x" or "0X". When hex numbers are given, multipliers cannot be
used.
.PP
-The count, skip and seek parameters can take 64 bit values (i.e. very
-big numbers). Other values are limited to what can fit in a signed
-32 bit number.
+The \fICOUNT\fR, \fISKIP\fR and \fISEEK\fR arguments can take 64 bit
+values (i.e. very big numbers). Other values are limited to what can fit in
+a signed 32 bit number.
.PP
Data usually gets to the user space in a 2 stage process: first the
SCSI adapter DMAs into kernel buffers and then the sg driver copies
@@ -289,12 +301,12 @@ Written by Doug Gilbert and Peter Allworth.
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2000-2006 Douglas Gilbert
+Copyright \(co 2000\-2007 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-A simpler, non-threaded version of this utility but with more
+A simpler, non\-threaded version of this utility but with more
advanced "continue on error" logic is called
.B sg_dd
and is also found in the sg3_utils package. The lmbench package contains
diff --git a/sgp_dd.c b/sgp_dd.c
index 38eb2fba..d531a892 100644
--- a/sgp_dd.c
+++ b/sgp_dd.c
@@ -1,5 +1,7 @@
#define _XOPEN_SOURCE 500
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -21,12 +23,11 @@
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_io_linux.h"
-#include "llseek.h"
/* A utility program for copying files. Specialised for "files" that
* represent devices that understand the SCSI command set.
*
-* Copyright (C) 1999 - 2006 D. Gilbert and P. Allworth
+* Copyright (C) 1999 - 2007 D. Gilbert and P. Allworth
* 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)
@@ -49,7 +50,7 @@
*/
-static char * version_str = "5.33 20061012";
+static char * version_str = "5.36 20070121";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -316,42 +317,50 @@ static int dd_filetype(const char * filename)
static void usage()
{
fprintf(stderr, "Usage: "
- "sgp_dd [bs=<n>] [count=<n>] [ibs=<n>] [if=<ifile>]"
- " [iflag=<flags>]\n"
- " [obs=<n>] [of=<ofile>] [oflag=<flags>] "
- "[seek=<n>] [skip=<n>]\n"
+ "sgp_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]"
+ " [iflag=FLAGS]\n"
+ " [obs=BS] [of=OFILE] [oflag=FLAGS] "
+ "[seek=SEEK] [skip=SKIP]\n"
" [--help] [--version]\n\n");
fprintf(stderr,
- " [bpt=<num>] [cdbsz=6|10|12|16] [coe=0|1] "
- "[deb=<n>] [dio=0|1]\n"
- " [fua=0|1|2|3] [sync=0|1] [thr=<n>] "
- "[time=0|1] [verbose=<n>]\n\n"
- " where:\n"
- " bpt is blocks_per_transfer (default is 128)\n"
- " bs must be device block size (default 512)\n"
- " cdbsz size of SCSI READ or WRITE command (default is 10)\n"
- " coe continue on error, 0->exit (def), "
+ " [bpt=BPT] [cdbsz=6|10|12|16] [coe=0|1] "
+ "[deb=VERB] [dio=0|1]\n"
+ " [fua=0|1|2|3] [sync=0|1] [thr=THR] "
+ "[time=0|1] [verbose=VERB]\n"
+ " where:\n"
+ " bpt is blocks_per_transfer (default is 128)\n"
+ " bs must be device block size (default 512)\n"
+ " cdbsz size of SCSI READ or WRITE cdb (default is 10)\n"
+ " coe continue on error, 0->exit (def), "
"1->zero + continue\n"
- " deb for debug, 0->none (def), > 0->varying degrees of "
+ " count number of blocks to copy (def: device size)\n"
+ " deb for debug, 0->none (def), > 0->varying degrees of "
"debug\n");
fprintf(stderr,
- " dio is direct IO, 1->attempt, 0->indirect IO (def)\n"
- " fua force unit access: 0->don't(def), 1->of, 2->if, "
- "3->of+if\n"
- " iflag comma separated list from: [coe,direct,dpo,dsync,"
+ " dio is direct IO, 1->attempt, 0->indirect IO (def)\n"
+ " fua force unit access: 0->don't(def), 1->OFILE, "
+ "2->IFILE,\n"
+ " 3->OFILE+IFILE\n"
+ " if file or device to read from (def: stdin)\n"
+ " iflag comma separated list from: [coe,direct,dpo,dsync,"
"excl,fua]\n"
- " oflag comma separated list from: [append,coe,direct,dpo,"
+ " of file or device to write to (def: stdout), "
+ "OFILE of '.'\n"
+ " treated as /dev/null\n"
+ " oflag comma separated list from: [append,coe,direct,dpo,"
"dsync,excl,\n"
- " fua]\n"
- " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on of after "
- "xfer\n"
- " thr is number of threads, must be > 0, default 4, "
+ " fua]\n"
+ " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE "
+ "after copy\n"
+ " thr is number of threads, must be > 0, default 4, "
"max 16\n"
- " time 0->no timing(def), 1->time plus calculate "
+ " time 0->no timing(def), 1->time plus calculate "
"throughput\n"
- " verbose same as 'deb=<n>', increase verbosity\n"
- " --help output this usage message then exit\n"
- " --version output version string then exit\n");
+ " verbose same as 'deb=VERB': increase verbosity\n"
+ " --help output this usage message then exit\n"
+ " --version output version string then exit\n"
+ "Copy from IFILE to OFILE, similar to dd command\n"
+ "specialized for SCSI devices, uses multiple POSIX threads\n");
}
static void guarded_stop_in(Rq_coll * clp)
@@ -497,7 +506,7 @@ static void * read_write_thread(void * v_clp)
memset(rep, 0, sizeof(Rq_elem));
psz = getpagesize();
- if (NULL == (rep->alloc_bp = malloc(sz + psz)))
+ if (NULL == (rep->alloc_bp = (unsigned char *)malloc(sz + psz)))
err_exit(ENOMEM, "out of memory creating user buffers\n");
rep->buffp = (unsigned char *)(((unsigned long)rep->alloc_bp + psz - 1) &
(~(psz - 1)));
@@ -1144,14 +1153,14 @@ int main(int argc, char * argv[])
if (0 == strcmp(key,"bpt")) {
rcoll.bpt = sg_get_num(buf);
if (-1 == rcoll.bpt) {
- fprintf(stderr, ME "bad argument to 'bpt'\n");
+ fprintf(stderr, ME "bad argument to 'bpt='\n");
return SG_LIB_SYNTAX_ERROR;
}
bpt_given = 1;
} else if (0 == strcmp(key,"bs")) {
rcoll.bs = sg_get_num(buf);
if (-1 == rcoll.bs) {
- fprintf(stderr, ME "bad argument to 'bs'\n");
+ fprintf(stderr, ME "bad argument to 'bs='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key,"cdbsz")) {
@@ -1164,7 +1173,7 @@ int main(int argc, char * argv[])
} else if (0 == strcmp(key,"count")) {
dd_count = sg_get_llnum(buf);
if (-1LL == dd_count) {
- fprintf(stderr, ME "bad argument to 'count'\n");
+ fprintf(stderr, ME "bad argument to 'count='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if ((0 == strncmp(key,"deb", 3)) ||
@@ -1181,7 +1190,7 @@ int main(int argc, char * argv[])
} else if (0 == strcmp(key,"ibs")) {
ibs = sg_get_num(buf);
if (-1 == ibs) {
- fprintf(stderr, ME "bad argument to 'ibs'\n");
+ fprintf(stderr, ME "bad argument to 'ibs='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (strcmp(key,"if") == 0) {
@@ -1192,13 +1201,13 @@ int main(int argc, char * argv[])
strncpy(inf, buf, INOUTF_SZ);
} else if (0 == strcmp(key, "iflag")) {
if (process_flags(buf, &rcoll.in_flags)) {
- fprintf(stderr, ME "bad argument to 'iflag'\n");
+ fprintf(stderr, ME "bad argument to 'iflag='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key,"obs")) {
obs = sg_get_num(buf);
if (-1 == obs) {
- fprintf(stderr, ME "bad argument to 'obs'\n");
+ fprintf(stderr, ME "bad argument to 'obs='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (strcmp(key,"of") == 0) {
@@ -1209,19 +1218,19 @@ int main(int argc, char * argv[])
strncpy(outf, buf, INOUTF_SZ);
} else if (0 == strcmp(key, "oflag")) {
if (process_flags(buf, &rcoll.out_flags)) {
- fprintf(stderr, ME "bad argument to 'oflag'\n");
+ fprintf(stderr, ME "bad argument to 'oflag='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key,"seek")) {
seek = sg_get_llnum(buf);
if (-1LL == seek) {
- fprintf(stderr, ME "bad argument to 'seek'\n");
+ fprintf(stderr, ME "bad argument to 'seek='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key,"skip")) {
skip = sg_get_llnum(buf);
if (-1LL == skip) {
- fprintf(stderr, ME "bad argument to 'skip'\n");
+ fprintf(stderr, ME "bad argument to 'skip='\n");
return SG_LIB_SYNTAX_ERROR;
}
} else if (0 == strcmp(key,"sync"))
@@ -1331,10 +1340,10 @@ int main(int argc, char * argv[])
return SG_LIB_FILE_ERROR;
}
else if (skip > 0) {
- llse_loff_t offset = skip;
+ off64_t offset = skip;
offset *= rcoll.bs; /* could exceed 32 here! */
- if (llse_llseek(rcoll.infd, offset, SEEK_SET) < 0) {
+ if (lseek64(rcoll.infd, offset, SEEK_SET) < 0) {
snprintf(ebuff, EBUFF_SZ,
ME "couldn't skip to required position on %s", inf);
perror(ebuff);
@@ -1399,10 +1408,10 @@ int main(int argc, char * argv[])
}
}
if (seek > 0) {
- llse_loff_t offset = seek;
+ off64_t offset = seek;
offset *= rcoll.bs; /* could exceed 32 bits here! */
- if (llse_llseek(rcoll.outfd, offset, SEEK_SET) < 0) {
+ if (lseek64(rcoll.outfd, offset, SEEK_SET) < 0) {
snprintf(ebuff, EBUFF_SZ,
ME "couldn't seek to required position on %s", outf);
perror(ebuff);
@@ -1412,7 +1421,7 @@ int main(int argc, char * argv[])
}
}
if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) {
- fprintf(stderr, "Can't have both 'if' as stdin _and_ 'of' as "
+ fprintf(stderr, "Won't default both IFILE to stdin _and_ OFILE to "
"stdout\n");
fprintf(stderr, "For more information use '--help'\n");
return SG_LIB_SYNTAX_ERROR;
diff --git a/utils/Makefile.freebsd b/utils/Makefile.freebsd
index 6bc1548d..44c2beae 100644
--- a/utils/Makefile.freebsd
+++ b/utils/Makefile.freebsd
@@ -30,7 +30,7 @@ hxascdmp: hxascdmp.o
$(LD) -o $@ $(LDFLAGS) $@.o
sg_chk_asc: sg_chk_asc.o ../sg_lib.o
- $(LD) -o $@ $(LDFLAGS) $@.o sg_lib.o
+ $(LD) -o $@ $(LDFLAGS) $@.o ../sg_lib.o
install: $(EXECS)
diff --git a/utils/Makefile.mingw b/utils/Makefile.mingw
new file mode 100644
index 00000000..d6f62604
--- /dev/null
+++ b/utils/Makefile.mingw
@@ -0,0 +1,33 @@
+# Assumes makefile is used in a MSYS shell with a MinGW compiler available.
+
+SHELL = /bin/sh
+
+CC = gcc
+LD = gcc
+
+EXECS = hxascdmp
+
+EXE_S = hxascdmp.exe
+
+# OS_FLAGS = -DSG3_UTILS_WIN32 -DSG3_UTILS_MINGW -DSPTD
+OS_FLAGS = -DSG3_UTILS_WIN32 -DSG3_UTILS_MINGW
+LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+EXTRA_FLAGS = $(OS_FLAGS) $(LARGE_FILE_FLAGS)
+
+# CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS)
+CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS)
+# CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS)
+
+LDFLAGS =
+
+all: $(EXECS)
+
+clean:
+ rm *.o $(EXE_S)
+
+.c.o:
+ $(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) -c -o $@ $<
+
+hxascdmp: hxascdmp.o
+ $(LD) -o $@ $(LDFLAGS) $@.o
+
diff --git a/utils/README b/utils/README
new file mode 100644
index 00000000..34bb2603
--- /dev/null
+++ b/utils/README
@@ -0,0 +1,20 @@
+This directory contains these utilities:
+ - hxascdmp: takes a binary stream and converts it to hexadecimal ASCII
+ which is sent to stdout. The incoming binary stream can either be
+ from a file or, in the absence of a file name, from stdin. Similar to
+ the Unix "od" command. By default, it decodes 16 bytes per line with
+ an ASCII interpretation to the right of each line.
+ - sg_chk_asc: utility decodes the SCSI additional sense code table
+ found at http://www.t10.org/lists/asc-num.txt and checks it
+ against the table found in sg_lib.c in the main directory.
+ It is designed to keep the table in sg_lib.c in "sync" with the
+ table at the t10.org web site.
+
+
+These utilities can be built for Linux or FreeBSD. To build sg_chk_asc
+in FreeBSD the sg_lib.o file must be present (i.e. compiled) in the
+main directory. The hxascdmp utility can be built in a Windows
+MinGW/MSYS environment.
+
+Doug Gilbert
+21st January 2007
diff --git a/utils/sg_lib.h b/utils/sg_lib.h
deleted file mode 120000
index f6ce0761..00000000
--- a/utils/sg_lib.h
+++ /dev/null
@@ -1 +0,0 @@
-../sg_lib.h \ No newline at end of file
diff --git a/utils/sg_lib.hh b/utils/sg_lib.hh
new file mode 100644
index 00000000..c650c885
--- /dev/null
+++ b/utils/sg_lib.hh
@@ -0,0 +1,307 @@
+#ifndef SG_LIB_H
+#define SG_LIB_H
+
+/*
+ * Copyright (c) 2004-2007 Douglas Gilbert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/* Version 1.32 [20070129]
+ *
+ * On 5th October 2004 a FreeBSD license was added to this file.
+ * The intention is to keep this file and the related sg_lib.c file
+ * as open source and encourage their unencumbered use.
+ */
+
+
+/*
+ * This header file contains defines and function declarations that may
+ * be useful to applications that communicate with devices that use a
+ * SCSI command set. These command sets have names like SPC-4, SBC-3,
+ * SSC-3, SES-2 and draft standards defining them can be found at
+ * http://www.t10.org . Virtually all devices in the Linux SCSI subsystem
+ * utilize SCSI command sets. Many devices in other Linux device subsystems
+ * utilize SCSI command sets either natively or via emulation (e.g. a
+ * parallel ATA disk in a USB enclosure).
+ */
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SAM_STAT_GOOD
+/* The SCSI status codes as found in SAM-4 at www.t10.org */
+#define SAM_STAT_GOOD 0x0
+#define SAM_STAT_CHECK_CONDITION 0x2
+#define SAM_STAT_CONDITION_MET 0x4
+#define SAM_STAT_BUSY 0x8
+#define SAM_STAT_INTERMEDIATE 0x10 /* obsolete in SAM-4 */
+#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14 /* obsolete in SAM-4 */
+#define SAM_STAT_RESERVATION_CONFLICT 0x18
+#define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */
+#define SAM_STAT_TASK_SET_FULL 0x28
+#define SAM_STAT_ACA_ACTIVE 0x30
+#define SAM_STAT_TASK_ABORTED 0x40
+#endif
+
+/* The SCSI sense key codes as found in SPC-4 at www.t10.org */
+#define SPC_SK_NO_SENSE 0x0
+#define SPC_SK_RECOVERED_ERROR 0x1
+#define SPC_SK_NOT_READY 0x2
+#define SPC_SK_MEDIUM_ERROR 0x3
+#define SPC_SK_HARDWARE_ERROR 0x4
+#define SPC_SK_ILLEGAL_REQUEST 0x5
+#define SPC_SK_UNIT_ATTENTION 0x6
+#define SPC_SK_DATA_PROTECT 0x7
+#define SPC_SK_BLANK_CHECK 0x8
+#define SPC_SK_COPY_ABORTED 0xa
+#define SPC_SK_ABORTED_COMMAND 0xb
+#define SPC_SK_VOLUME_OVERFLOW 0xd
+#define SPC_SK_MISCOMPARE 0xe
+
+
+/* Returns length of SCSI command given the opcode (first byte).
+ Yields the wrong answer for variable length commands (opcode=0x7f)
+ and potentially some vendor specific commands. */
+extern int sg_get_command_size(unsigned char cdb_byte0);
+
+/* Command name given pointer to the cdb. Certain command names
+ depend on peripheral type (give 0 if unknown). Places command
+ name into buff and will write no more than buff_len bytes. */
+extern void sg_get_command_name(const unsigned char * cdbp, int peri_type,
+ int buff_len, char * buff);
+
+/* Command name given only the first byte (byte 0) of a cdb and
+ * peripheral type. */
+extern void sg_get_opcode_name(unsigned char cdb_byte0, int peri_type,
+ int buff_len, char * buff);
+
+/* Command name given opcode (byte 0), service action and peripheral type.
+ If no service action give 0, if unknown peripheral type give 0. */
+extern void sg_get_opcode_sa_name(unsigned char cdb_byte0, int service_action,
+ int peri_type, int buff_len, char * buff);
+
+/* Fetch scsi status string. */
+extern void sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff);
+
+/* This is a slightly stretched SCSI sense "descriptor" format header.
+ The addition is to allow the 0x70 and 0x71 response codes. The idea
+ is to place the salient data of both "fixed" and "descriptor" sense
+ format into one structure to ease application processing.
+ The original sense buffer should be kept around for those cases
+ in which more information is required (e.g. the LBA of a MEDIUM ERROR). */
+struct sg_scsi_sense_hdr {
+ unsigned char response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
+ unsigned char sense_key;
+ unsigned char asc;
+ unsigned char ascq;
+ unsigned char byte4;
+ unsigned char byte5;
+ unsigned char byte6;
+ unsigned char additional_length;
+};
+
+/* Maps the salient data from a sense buffer which is in either fixed or
+ descriptor format into a structure mimicking a descriptor format
+ header (i.e. the first 8 bytes of sense descriptor format).
+ If zero response code returns 0. Otherwise returns 1 and if 'sshp' is
+ non-NULL then zero all fields and then set the appropriate fields in
+ that structure. sshp::additional_length is always 0 for response
+ codes 0x70 and 0x71 (fixed format). */
+extern int sg_scsi_normalize_sense(const unsigned char * sensep,
+ int sense_len,
+ struct sg_scsi_sense_hdr * sshp);
+
+/* Attempt to find the first SCSI sense data descriptor that matches the
+ given 'desc_type'. If found return pointer to start of sense data
+ descriptor; otherwise (including fixed format sense data) returns NULL. */
+extern const unsigned char * sg_scsi_sense_desc_find(
+ const unsigned char * sensep, int sense_len, int desc_type);
+
+/* Yield string associated with sense_key value. Returns 'buff'. */
+extern char * sg_get_sense_key_str(int sense_key, int buff_len, char * buff);
+
+/* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
+extern char * sg_get_asc_ascq_str(int asc, int ascq, int buff_len,
+ char * buff);
+
+/* Returns 1 if valid bit set, 0 if valid bit clear. Irrespective the
+ information field is written out via 'info_outp' (except when it is
+ NULL). Handles both fixed and descriptor sense formats. */
+extern int sg_get_sense_info_fld(const unsigned char * sensep, int sb_len,
+ unsigned long long * info_outp);
+
+/* Returns 1 if sense key is NO_SENSE or NOT_READY and SKSV is set. Places
+ progress field from sense data where progress_outp points. If progress
+ field is not available returns 0. Handles both fixed and descriptor
+ sense formats. N.B. App should multiply by 100 and divide by 65536
+ to get percentage completion from given value. */
+extern int sg_get_sense_progress_fld(const unsigned char * sensep,
+ int sb_len, int * progress_outp);
+
+/* Closely related to sg_print_sense(). Puts decode sense data in 'buff'.
+ Usually multiline with multiple '\n' including one trailing. If
+ 'raw_sinfo' set appends sense buffer in hex. */
+extern void sg_get_sense_str(const char * leadin,
+ const unsigned char * sense_buffer, int sb_len,
+ int raw_sinfo, int buff_len, char * buff);
+
+/* Yield string associated with peripheral device type (pdt). Returns
+ 'buff'. If 'pdt' out of range yields "bad pdt" string. */
+extern char * sg_get_pdt_str(int pdt, int buff_len, char * buff);
+
+extern FILE * sg_warnings_strm;
+
+extern void sg_set_warnings_strm(FILE * warnings_strm);
+
+/* The following "print" functions send ACSII to 'sg_warnings_strm' file
+ descriptor (default value is stderr) */
+extern void sg_print_command(const unsigned char * command);
+extern void sg_print_sense(const char * leadin,
+ const unsigned char * sense_buffer, int sb_len,
+ int raw_info);
+extern void sg_print_scsi_status(int scsi_status);
+
+/* Utilities can use these process status values for syntax errors and
+ file (device node) problems (e.g. not found or permissions). */
+#define SG_LIB_SYNTAX_ERROR 1
+#define SG_LIB_FILE_ERROR 15
+
+/* The sg_err_category_sense() function returns one of the following.
+ These may be used as process status values (on exit). Notice that
+ some of the lower values correspond to SCSI sense key values. */
+#define SG_LIB_CAT_CLEAN 0 /* No errors or other information */
+/* Value 1 left unused for utilities to use SG_LIB_SYNTAX_ERROR */
+#define SG_LIB_CAT_NOT_READY 2 /* interpreted from sense buffer */
+ /* [sk,asc,ascq: 0x2,*,*] */
+#define SG_LIB_CAT_MEDIUM_HARD 3 /* medium or hardware error, blank check */
+ /* [sk,asc,ascq: 0x3/0x4/0x8,*,*] */
+#define SG_LIB_CAT_ILLEGAL_REQ 5 /* Illegal request (other than invalid */
+ /* opcode): [sk,asc,ascq: 0x5,*,*] */
+#define SG_LIB_CAT_UNIT_ATTENTION 6 /* interpreted from sense buffer */
+ /* [sk,asc,ascq: 0x6,*,*] */
+ /* was SG_LIB_CAT_MEDIA_CHANGED earlier [sk,asc,ascq: 0x6,0x28,*] */
+#define SG_LIB_CAT_INVALID_OP 9 /* (Illegal request,) Invalid opcode: */
+ /* [sk,asc,ascq: 0x5,0x20,0x0] */
+#define SG_LIB_CAT_ABORTED_COMMAND 11 /* interpreted from sense buffer */
+ /* [sk,asc,ascq: 0xb,*,*] */
+#define SG_LIB_CAT_NO_SENSE 20 /* sense data with key of "no sense" */
+ /* [sk,asc,ascq: 0x0,*,*] */
+#define SG_LIB_CAT_RECOVERED 21 /* Successful command after recovered err */
+ /* [sk,asc,ascq: 0x1,*,*] */
+#define SG_LIB_CAT_MALFORMED 97 /* Response to SCSI command malformed */
+#define SG_LIB_CAT_SENSE 98 /* Something else is in the sense buffer */
+#define SG_LIB_CAT_OTHER 99 /* Some other error/warning has occurred
+ (e.g. a transport or driver error) */
+
+extern int sg_err_category_sense(const unsigned char * sense_buffer,
+ int sb_len);
+
+/* Iterates to next designation descriptor in the device identification
+ VPD page. The 'initial_desig_desc' should point to start of first
+ descriptor with 'page_len' being the number of valid bytes in that
+ and following descriptors. To start, 'off' should point to a negative
+ value, thereafter it should point to the value yielded by the previous
+ call. If 0 returned then 'initial_desig_desc + *off' should be a valid
+ descriptor; returns -1 if normal end condition and -2 for an abnormal
+ termination. Matches association, designator_type and/or code_set when
+ any of those values are greater than or equal to zero. */
+extern int sg_vpd_dev_id_iter(const unsigned char * initial_desig_desc,
+ int page_len, int * off, int m_assoc,
+ int m_desig_type, int m_code_set);
+
+
+/* <<< General purpose (i.e. not SCSI specific) utility functions >>> */
+
+/* Always returns valid string even if errnum is wild (or library problem).
+ If errnum is negative, flip its sign. */
+extern char * safe_strerror(int errnum);
+
+
+/* Print (to stdout) 'str' of bytes in hex, 16 bytes per line optionally
+ followed at the right hand side of the line with an ASCII interpretation.
+ Each line is prefixed with an address, starting at 0 for str[0]..str[15].
+ All output numbers are in hex. 'no_ascii' allows for 3 output types:
+ > 0 each line has address then up to 16 ASCII-hex bytes
+ = 0 in addition, the bytes are listed in ASCII to the right
+ < 0 only the ASCII-hex bytes are listed (i.e. without address)
+*/
+extern void dStrHex(const char* str, int len, int no_ascii);
+
+/* Returns 1 when executed on big endian machine; else returns 0.
+ Useful for displaying ATA identify words (which need swapping on a
+ big endian machine).
+*/
+extern int sg_is_big_endian();
+
+/* Extract character sequence from ATA words as in the model string
+ in a IDENTIFY DEVICE response. Returns number of characters
+ written to 'ochars' before 0 character is found or 'num' words
+ are processed. */
+extern int sg_ata_get_chars(const unsigned short * word_arr, int start_word,
+ int num_words, int is_big_endian, char * ochars);
+
+/* Print (to stdout) 16 bit 'words' in hex, 8 words per line optionally
+ followed at the right hand side of the line with an ASCII interpretation
+ (pairs of ASCII characters in big endian order (upper first)).
+ Each line is prefixed with an address, starting at 0.
+ All output numbers are in hex. 'no_ascii' allows for 3 output types:
+ > 0 each line has address then up to 8 ASCII-hex words
+ = 0 in addition, the words are listed in ASCII pairs to the right
+ = -1 only the ASCII-hex words are listed (i.e. without address)
+ = -2 only the ASCII-hex words, formatted for "hdparm --Istdin"
+ < -2 same as -1
+ If 'swapb' non-zero then bytes in each word swapped. Needs to be set
+ for ATA IDENTIFY DEVICE response on big-endian machines.
+*/
+extern void dWordHex(const unsigned short* words, int num, int no_ascii,
+ int swapb);
+
+/* If the number in 'buf' can not be decoded or the multiplier is unknown
+ then -1 is returned. Accepts a hex prefix (0x or 0X) or a 'h' (or 'H')
+ suffix. Otherwise a decimal multiplier suffix may be given. Recognised
+ multipliers: c C *1; w W *2; b B *512; k K KiB *1,024;
+ KB *1,000; m M MiB *1,048,576; MB *1,000,000; g G GiB *1,073,741,824;
+ GB *1,000,000,000 and <n>x<m> which multiplies <n> by <m> . */
+extern int sg_get_num(const char * buf);
+
+/* If the number in 'buf' can not be decoded or the multiplier is unknown
+ then -1LL is returned. Accepts a hex prefix (0x or 0X) or a 'h' (or 'H')
+ suffix. Otherwise a decimal multiplier suffix may be given. In addition
+ to supporting the multipliers of sg_get_num(), this function supports:
+ t T TiB *(2**40); TB *(10**12); p P PiB *(2**50); PB *(10**15) . */
+extern long long sg_get_llnum(const char * buf);
+
+extern const char * sg_lib_version();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif