aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG19
-rw-r--r--COPYING29
-rw-r--r--COVERAGE64
-rw-r--r--Makefile9
-rw-r--r--Makefile.asroot9
-rw-r--r--README25
-rw-r--r--debian/changelog6
-rw-r--r--debian/control1
-rw-r--r--debian/copyright24
-rw-r--r--debian/docs8
-rw-r--r--doc/sg_dd.html520
-rw-r--r--doc/sg_io.html1555
-rw-r--r--doc/u_index.html111
-rw-r--r--lib_no_lib/Makefile.no_lib8
-rw-r--r--lib_no_lib/sg3_utils.spec.no_lib10
-rw-r--r--sg3_utils.spec8
-rw-r--r--sg_cmds.c119
-rw-r--r--sg_cmds.h4
-rw-r--r--sg_dd.8145
-rw-r--r--sg_dd.c441
-rw-r--r--sg_format.c59
-rw-r--r--sg_get_config.c46
-rw-r--r--sg_inq.814
-rw-r--r--sg_inq.c76
-rw-r--r--sg_lib.c60
-rw-r--r--sg_lib.h16
-rw-r--r--sg_logs.c7
-rw-r--r--sg_luns.c19
-rw-r--r--sg_map26.8159
-rw-r--r--sg_map26.c1144
-rw-r--r--sg_modes.c7
-rw-r--r--sg_opcodes.c46
-rw-r--r--sg_persist.c46
-rw-r--r--sg_rbuf.c11
-rw-r--r--sg_read.c4
-rw-r--r--sg_read_long.c4
-rw-r--r--sg_readcap.c6
-rw-r--r--sg_reassign.c6
-rw-r--r--sg_requests.c2
-rw-r--r--sg_ses.818
-rw-r--r--sg_ses.c123
-rw-r--r--sg_start.84
-rw-r--r--sg_turs.811
-rw-r--r--sg_turs.c94
-rw-r--r--sg_verify.c6
-rw-r--r--sg_write_long.814
-rw-r--r--sg_write_long.c27
-rw-r--r--sginfo.c90
-rw-r--r--sgm_dd.c10
49 files changed, 4289 insertions, 955 deletions
diff --git a/CHANGELOG b/CHANGELOG
index d5da92c7..860d0352 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,25 @@ 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.
+Changelog for sg3_utils-1.18 [20051118]
+ - sg_map26: new utility to map sg devices in lk 2.6
+ - sg_luns: luns > 16,384 (sam-4 rev 4)
+ - sg_ses: bump fan speed field to 11 bits
+ - SAS connector names (ses2r13)
+ - sg_inq: add '-rr' option for "hdparm --Istdin"
+ - sg_get_config: tracking mmc-5
+ - sg_write_long: add support for COR_DIS bit
+ - sg_cmds: add sg_ll_test_unit_ready_progress()
+ - sg_turs: '-p' option shows progress
+ - sg_dd: add 'iflag=' and 'oflag=' options
+ - remove output of mode page info when verbose > 0
+ - add control of DPO bit via iflag/oflag
+ - sg_lib: add sg_get_pdt_str()
+ - update asc/ascq strings
+ - sg_modes + sginfo: add SAS(2) SSP shared mode subpage
+ - doc: rename "html" directory to "doc"
+ - Makefile: add 'libtool --finish' to install
+
Changelog for sg3_utils-1.17 [20050922]
- sg_inq: add '-a' option for ATA information VPD page
- add '-b' option for Block limits VPD page (SBC)
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..4fc6be3b
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,29 @@
+
+Upstream Authors: Douglas Gilbert <dgilbert at interlog dot com>,
+ Bruce Allen <ballen at gravity dot phys dot uwm dot edu>,
+ Peter Allworth <linsol at zeta dot org dot au>,
+ James Bottomley <jejb at parisc-linux dot org>,
+ Lars Marowsky-Bree <lmb at suse dot de>,
+ Kurt Garloff <garloff at suse dot de>,
+ Grant Grundler <grundler at parisc-linux dot org>,
+ Christophe Varoqui <christophe dot varoqui at free dot fr>,
+ Michael Weller <eowmob at exp-math dot uni-essen dot de>,
+ Eric Youngdale <eric at andante dot org>
+
+Copyright:
+
+This software is copyright(c) 1994-2005 by the authors
+
+You are free to distribute this software under the terms of
+the GNU General Public License.
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL file.
+
+Some parts of this package are covered by the BSD license.
+These include central error processing code (sg_lib.[hc]),
+common command code (sg_cmds.[hc]) and later utilities. They
+are Copyright: Douglas Gilbert.
+The author's intention is that the BSD licensed code can be used
+freely by others. On Debian systems, the complete text of the
+BSD License can be found in `/usr/share/common-licenses/BSD'.
+
diff --git a/COVERAGE b/COVERAGE
index 8f0efd50..ac067d60 100644
--- a/COVERAGE
+++ b/COVERAGE
@@ -4,55 +4,57 @@ The following table lists SCSI commands in alphabetical order on the
left and the sg3_utils utilities that implement invocations of them
on the right. The second table lists supported ATA commands.
-SCSI command sg3_utils ** utilities that use this SCSI command
+SCSI command sg3_utils utilities that use this SCSI command
------------ -------------------------------------------------
GET CONFIGURATION sg_get_config
-INQUIRY sdparm, sg_dd, sg_format, sg_inq, sginfo, sg_logs,
- sg_map('-i'), sg_modes, sg_opcodes, sg_persist,
- sg_scan, sg_ses
+INQUIRY sg_dd, sg_format, sg_inq, sginfo,
+ sg_logs, sg_map('-i'), sg_modes, sg_opcodes,
+ sg_persist, sg_scan, sg_ses, ++
FORMAT UNIT sg_format
-LOG SELECT sg_logs('-r')
-LOG SENSE sg_logs
-MODE SELECT(6) sdparm, sg_wr_mode, sginfo, sg_format, sg_emc_trespass
-MODE SELECT(10) sdparm, sg_wr_mode, sginfo, sg_format, sg_emc_trespass
-MODE SENSE(6) sdparm, sg_modes, sg_wr_mode, sginfo, sg_format, sg_dd,
- sg_senddiag('-e')
-MODE SENSE(10) sdparm, sg_modes, sg_wr_mode, sginfo, sg_format, sg_dd,
- sg_senddiag('-e')
+LOG SELECT sg_logs('-r'), ++
+LOG SENSE sg_logs, ++
+MODE SELECT(6) sg_wr_mode, sginfo, sg_format,
+ sg_emc_trespass, ++
+MODE SELECT(10) sg_wr_mode, sginfo, sg_format,
+ sg_emc_trespass, ++
+MODE SENSE(6) sg_modes, sg_wr_mode, sginfo, sg_format,
+ sg_senddiag('-e'), ++
+MODE SENSE(10) sg_modes, sg_wr_mode, sginfo, sg_format,
+ sg_senddiag('-e'), ++
PERSISTENT IN sg_persist
PERSISTENT OUT sg_persist
-PREVENT ALLOW MEDIUM REMOVAL sg_prevent
+PREVENT ALLOW MEDIUM REMOVAL sg_prevent, ++
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 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
+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, ++
READ DEFECT(12) sginfo
-READ LONG sg_read_long, sg_dd
-READ MEDIA SERIAL NUMBER sg_rmsn
+READ LONG (10) sg_read_long, sg_dd
+READ MEDIA SERIAL NUMBER sg_rmsn, ++
REASSIGN BLOCKS sg_reassign
-RECEIVE DIAGNOSTIC sg_senddiag, sg_ses
-REPORT DEVICE IDENTIFIER sg_ident
-REPORT LUNS sg_luns
+RECEIVE DIAGNOSTIC sg_senddiag, sg_ses, ++
+REPORT DEVICE IDENTIFIER sg_ident, ++
+REPORT LUNS sg_luns, ++
REPORT SUPPORTED OPERATION CODES sg_opcodes
REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS sg_opcodes
-REPORT TARGET PORT GROUPS sg_rtpg
-REQUEST SENSE sg_requests
-SEND DIAGNOSTIC sg_senddiag, sg_ses
-SET DEVICE IDENTIFIER sg_ident
-START STOP sg_start
-SYNCHRONIZE CACHE sg_sync, sg_dd, sgm_dd, sgp_dd
-TEST UNIT READY sg_turs, sg_format
+REPORT TARGET PORT GROUPS sg_rtpg, ++
+REQUEST SENSE sg_requests, ++
+SEND DIAGNOSTIC sg_senddiag, sg_ses, ++
+SET DEVICE IDENTIFIER sg_ident, ++
+START STOP sg_start, ++
+SYNCHRONIZE CACHE(10) sg_sync, sg_dd, sgm_dd, sgp_dd, ++
+TEST UNIT READY sg_turs, sg_format, ++
VERIFY(10) sg_verify
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 LONG sg_write_long
+WRITE LONG (10) sg_write_long
ATA command sg3_utils utilities that use this SCSI command
@@ -61,7 +63,7 @@ IDENTIFY DEVICE sg_inq, sg_scan
IDENTIFY PACKET DEVICE sg_inq
-** sdparm is now in its own package called sdparm (rather than sg3_utils)
+++ command wrapper found in sg_cmds.c for this command
Doug Gilbert
-19th September 2005
+14th November 2005
diff --git a/Makefile b/Makefile
index 535d5ce6..1b5bc08f 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ 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_rmsn sg_ident sg_map26
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 \
@@ -23,7 +23,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_opcodes.8 sg_persist.8 sg_write_long.8 sg_read_long.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_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
+ sg_map26.8
MAN_PREF = man8
HEADERS = sg_lib.h sg_cmds.h
@@ -178,10 +179,14 @@ sg_rmsn: sg_rmsn.o libsgutils.la
sg_ident: sg_ident.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+sg_map26: sg_map26.o
+ libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
install -d $(LIBDIR)
libtool --mode=install install -c libsgutils.la $(LIBDIR)/libsgutils.la
+ libtool --finish $(LIBDIR)
for name in $^; \
do libtool --mode=install install -m 755 \
$$name $(INSTDIR); \
diff --git a/Makefile.asroot b/Makefile.asroot
index c005950e..234b490e 100644
--- a/Makefile.asroot
+++ b/Makefile.asroot
@@ -15,7 +15,7 @@ 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_rmsn sg_ident sg_map26
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 \
@@ -23,7 +23,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_opcodes.8 sg_persist.8 sg_write_long.8 sg_read_long.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_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
+ sg_map26.8
MAN_PREF = man8
HEADERS = sg_lib.h sg_cmds.h
@@ -178,10 +179,14 @@ sg_rmsn: sg_rmsn.o libsgutils.la
sg_ident: sg_ident.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+sg_map26: sg_map26.o
+ libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
install -d $(LIBDIR)
libtool --mode=install install -c libsgutils.la $(LIBDIR)/libsgutils.la
+ libtool --finish $(LIBDIR)
for name in $^; \
do libtool --mode=install install -s -o root -g root -m 755 \
$$name $(INSTDIR); \
diff --git a/README b/README
index 390a05dc..5cd07d81 100644
--- a/README
+++ b/README
@@ -25,7 +25,7 @@ found at http://www.torque.net/sg . The most recent release version
of sg3_utils and the most recent beta is on that page. There is also
a page describing the utilities in the sg3_utils and sg_utils packages:
http://www.torque.net/sg/u_index.html . A copy of the "u_index.html"
-file is in the "html" subdirectory.
+file is in the "doc" subdirectory.
In the Linux 2.4 kernel series these utilities need to use the SCSI generic
(sg) driver to access SCSI devices. The name of this package (i.e.
@@ -137,11 +137,11 @@ Utilities
Here is list in alphabetical order of utilities found in the main directory
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_modes,
- sg_opcodes, sg_persist, sg_prevent, sg_rbuf, 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_write_long, sg_wr_mode
+ 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_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_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
@@ -150,8 +150,8 @@ Makefile's in the subdirectories. Each utility in the main directory has a
distributions of the sg3_utils package (e.g. "rpm" and debian packages)
typically contains the shared library, the utilities in the main directory,
their associated man pages and some documentation files (e.g. README, INSTALL,
-CREDITS and COVERAGE). See the INSTALL file for instructions about building
-and installing from a "tarball".
+CREDITS, COPYING and COVERAGE). See the INSTALL file for instructions about
+building and installing from a "tarball".
Man pages can be read (without building and installing the package) by
going to the main directory and executing something like this:
@@ -179,11 +179,14 @@ The "utils" subdirectory contains source and a Makefile to build
command line) and outputs an ASCII-HEX and ASCII representation of
it. It is similar to the Unix od command.
-The "html" subdirectory contains copies of web pages relevant to
+The "doc" subdirectory contains copies of web pages relevant to
the sg3_utils package. Currently it contains:
- - u_index.html : a description of the sg3_utils package contents
- sg_dd.html : describes the sg_dd utility and compares it with the
Unix dd command
+ - sg_io.html : describes the SG_IO ioctl used by sg3_utils. Looks
+ at differences between the lk 2.4 and 2.6 series;
+ including its use with block devices
+ - u_index.html : a description of the sg3_utils package contents
Notes for utilities without man pages
@@ -280,4 +283,4 @@ user). It is available for Linux and other operating systems.
See http://members.aol.com/plscsi .
Doug Gilbert
-22nd September 2005
+18th November 2005
diff --git a/debian/changelog b/debian/changelog
index 9e9ac7ab..246c2d73 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+sg3-utils (1.18-0.1) unstable; urgency=low
+
+ * New upstream version
+
+ -- Doug Gilbert <dgilbert@interlog.com> Fri, 18 Nov 2005 13:00:00 +1000
+
sg3-utils (1.17-0.1) unstable; urgency=low
* New upstream version
diff --git a/debian/control b/debian/control
index e3e4b5fb..11c483be 100644
--- a/debian/control
+++ b/debian/control
@@ -28,6 +28,7 @@ Description: Collection of Linux utilities for devices that use the
* sg_logs - prints out log sense pages
* sg_luns - prints out REPORT LUNS response
* sg_map - shows the mapping between SCSI devices and sg devices
+ * sg_map26 - map primary device node and generic node (lk 2.6 only)
* sgm_dd - like sg_dd, but uses mmap()'d IO
* sg_modes - prints out mode sense pages
* sg_opcodes - reports supported opcodes and task management fcns
diff --git a/debian/copyright b/debian/copyright
index 3f924ace..c9df7714 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -3,13 +3,31 @@ Wed, 14 Nov 2001 17:05:56 -0700.
It was downloaded from <URL:http://www.torque.net/sg/>
-Upstream Authors: Andries Brouwer, Remy Card, Douglas Gilbert <dgilbert@interlog.com>, P. Allworth, Eric Youngdale, Kurt Garloff <garloff@suse.de>, Michael Weller <eowmob@exp-math.uni-essen.de>
+Upstream Authors: Douglas Gilbert <dgilbert at interlog dot com>,
+ Bruce Allen <ballen at gravity dot phys dot uwm dot edu>,
+ Peter Allworth <linsol at zeta dot org dot au>,
+ James Bottomley <jejb at parisc-linux dot org>,
+ Lars Marowsky-Bree <lmb at suse dot de>,
+ Kurt Garloff <garloff at suse dot de>,
+ Grant Grundler <grundler at parisc-linux dot org>,
+ Christophe Varoqui <christophe dot varoqui at free dot fr>,
+ Michael Weller <eowmob at exp-math dot uni-essen dot de>,
+ Eric Youngdale <eric at andante dot org>,
Copyright:
-This software is copyright(c) 1994-2001 by the authors
+This software is copyright(c) 1994-2005 by the authors
You are free to distribute this software under the terms of
the GNU General Public License.
On Debian systems, the complete text of the GNU General Public
-License can be found in /usr/share/common-licenses/GPL file. \ No newline at end of file
+License can be found in /usr/share/common-licenses/GPL file.
+
+Some parts of this package are covered by the BSD license.
+These include central error processing code (sg_lib.[hc]),
+common command code (sg_cmds.[hc]) and later utilities. They
+are Copyright: Douglas Gilbert.
+The author's intention is that this code can be used freely
+by others. On Debian systems, the complete text of the BSD
+License can be found in /usr/share/common-licenses/BSD.
+
diff --git a/debian/docs b/debian/docs
index f458d89e..e9c2decf 100644
--- a/debian/docs
+++ b/debian/docs
@@ -1,4 +1,8 @@
+CHANGELOG
+COVERAGE
+CREDITS
+INSTALL
README
README.sg_start
-CREDITS
-COVERAGE
+doc/u_index.html
+doc/sg_dd.html
diff --git a/doc/sg_dd.html b/doc/sg_dd.html
index 93a2cac8..996206cc 100644
--- a/doc/sg_dd.html
+++ b/doc/sg_dd.html
@@ -1,28 +1,36 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
+ <title>Linux sg_dd utility (a dd variant)</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<meta name="keywords" content="Linux, SCSI, sg_dd, dd variant">
<meta name="GENERATOR"
content="Mozilla/4.79 [en] (X11; U; Linux 2.5.31 i686) [Netscape]">
- <title>Linux sg_dd utility (a dd variant)</title>
</head>
<body alink="#ff0000" background="paper.jpg" bgcolor="#ffffff"
link="#0000ff" text="#000000" vlink="#000080">
<center>
-<h1> The&nbsp; Linux sg_dd utility<br>
+<h1><a class="mozTocH1" name="mozTocId228087"></a> The&nbsp; Linux
+sg_dd utility<br>
</h1>
</center>
-<a href="#Introduction">Introduction</a> <br>
-<a href="#dd_like_features">dd like features</a> <br>
-<a href="#sg_dd_extras">sg_dd extras</a><br>
-<a href="#coe">Continue on error (coe)</a> <br>
-<a href="#Recovered_errors">Recovered errors</a> <br>
-<a href="#Verbose">Verbose</a><br>
-<a href="#Conclusion">Conclusion</a><br>
-&nbsp;
-<h2><a name="Introduction"></a>Introduction</h2>
+<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>
+ <ol>
+ <li><a href="#mozTocId370866">Introduction</a></li>
+ <li><a href="#mozTocId352668">&nbsp;dd like features</a></li>
+ <li><a href="#mozTocId703997">sg_dd extras</a></li>
+ <li><a href="#mozTocId437677">Continue on error (coe)</a></li>
+ <li><a href="#mozTocId566094">Recovered errors</a></li>
+ <li><a href="#mozTocId899152">Verbose</a></li>
+ <li><a href="#mozTocId157981">Conclusion</a></li>
+ </ol>
+ </li>
+</ol>
+<h2><a class="mozTocH2" name="mozTocId370866"></a>Introduction</h2>
The <span style="font-weight: bold;">sg_dd</span> utility is a variant
of the standard Unix command <span style="font-weight: bold;">dd</span>
which
@@ -48,46 +56,89 @@ It is becoming common for non-SCSI devices (e.g. ATA disks) to appear
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 uses.
-However, advanced options (e.g. using the 'cdbsz' and 'fua') most
+exactly the same SCSI commands that the normal block layer would use.
+However, advanced options (e.g. using the 'cdbsz' 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
-transport is ATAPI (i.e. the ATA packet interface) is irrelevant, to
+transport for CD/DVD drives is ATAPI (i.e. the ATA packet interface) is
+irrelevant to
the
-sg_dd utility they are SCSI devices.<br>
+sg_dd utility; they are SCSI devices.<br>
<br>
-This page outlines the features of the sg_dd utility version 5.42 found
-in the <a href="u_index.html">sg3_utils</a> version 1.16 package. This
-was released on the 9th August 2005.<br>
-<h2><a name="dd_like_features"></a> dd like features</h2>
+This page outlines the features of the sg_dd utility version 5.44 found
+in the <a href="u_index.html">sg3_utils</a> version 1.18 package. This
+was released on the 30th October 2005.<br>
+<h2><a class="mozTocH2" name="mozTocId352668"></a>&nbsp;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 semantic of the sg_dd
+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.
The recent GNU implementation of the dd command is used as a reference
point.<br>
<br>
The main options of dd are:<br>
-<ul>
- <li>if=&lt;input_file&gt;</li>
- <li>of=&lt;output_file&gt;</li>
- <li>bs=&lt;block_size&gt;</li>
- <li>count=&lt;count_of_blocks&gt;</li>
-</ul>
+<br>
+<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
+ cellspacing="2">
+ <tbody>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Standard
+dd options</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Default</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Brief
+description</span><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">bs=&lt;block_size&gt;<br>
+ </td>
+ <td style="vertical-align: top;">512<br>
+ </td>
+ <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>
+ <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;">stdin<br>
+ </td>
+ <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;">stdout<br>
+ </td>
+ <td style="vertical-align: top;">file (or device) to write to.
+Doesn't bother writing anything if &lt;output_file&gt; is /dev/null or
+. (period).<br>
+ </td>
+ </tr>
+ </tbody>
+</table>
+<br>
+<br>
Both dd and sg_dd given these options with suitable arguments will copy
-(bs * count) bytes from the beginning of &lt;input_file&gt; to the
+(&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
-of both devices. In both dd and sg_dd if the if=&lt;input_file&gt;
-option is not given then stdin is assumed. In both dd and sg_dd if
-of=&lt;output_file&gt; is not given then stdout is assumed.<br>
+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
@@ -95,7 +146,11 @@ interpreted as stdout while an &lt;output_file&gt; 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
-directory and will not accept it.]<br>
+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
+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
the remaining blocks in the file, device or partition. If the input
@@ -114,26 +169,102 @@ remaining length of the input and output files are done and the sg_dd
will attempt to copy that number of blocks. A 'count=0' option is valid
and all the normal preparations are made including files being opened
but no copy takes place. Hence the 'count=0' option can be used to
-check the syntax is in order and the files are present (see the
-"Verbose" section below).<br>
+check the syntax is in order and that the files are present (see the
+"<a href="#mozTocId899152">Verbose</a>" section below).<br>
<br>
Other dd options supported by sg_dd:<br>
-<ul>
- <li>seek=&lt;n_blocks_of&gt;</li>
- <li>skip=&lt;n_blocks_if&gt;</li>
- <li>ibs=&lt;block_size&gt;</li>
- <li>obs=&lt;block_size&gt;</li>
-</ul>
+<br>
+<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
+ cellspacing="2">
+ <tbody>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Standard
+dd options</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Default</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Brief
+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>
+ <td style="vertical-align: top;">number of bytes in each block of
+&lt;input_file&gt;<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">iflag=&lt;flags&gt;<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">[new in sg3_utils 1.18] 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>
+ <td style="vertical-align: top;">number of bytes in each block of
+&lt;output_file&gt;</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">oflag=&lt;flags&gt;<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">[new in sg3_utils 1.18] 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;">0<br>
+ </td>
+ <td style="vertical-align: top;">block number (origin 0) in
+&lt;output_file&gt; to commence writing<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">seek=&lt;n_blocks_of&gt;</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>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">--help<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">print usage message then exit<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">--version<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">print version number and its
+date then exit<br>
+ </td>
+ </tr>
+ </tbody>
+</table>
+<br>
If ibs and obs are given to sg_dd then they must be the same as bs
-(i.e. they are essentially dummies). Both seek and skip are origin zero
-and default to zero (i.e the start of the output and input files
-respectively). The 'skip' option cannot be used on an input stream
+(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. stdout).<br>
<br>
All numeric arguments can take a multiplier suffix. From sg3_utils
version 1.13 sg_dd's multiplier prefixes have been brought into line
-with those of GNU's dd (in coreutils post a change on&nbsp; 2001-12-18):<br>
+with those of GNU's dd. GNU's dd is found in coreutils and its
+changelog notes the change to this suffix pattern on&nbsp; 2001-12-18:<br>
<br>
<table style="width: 50%; text-align: left;" border="1" cellpadding="2"
cellspacing="2">
@@ -228,6 +359,134 @@ both be in hex and have a suffix multiplier. Hence "0x9" is interpreted
as hexadecimal 9 [not (0 * 9)==0]. This is valid "2x4x0xa" and yields
80 (but it isn't very clear).<br>
<br>
+The "&lt;flags&gt;" 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"
+ cellspacing="2">
+ <tbody>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">flag</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">sg
+device</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">block
+device</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">regular
+file</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">comments</span><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">append<br>
+ </td>
+ <td style="vertical-align: top;">ignored<br>
+ </td>
+ <td style="vertical-align: top;">applied on &lt;ofile&gt;<br>
+ </td>
+ <td style="vertical-align: top;">applied on &lt;ofile&gt;<br>
+ </td>
+ <td style="vertical-align: top;">use O_APPEND open flag.
+Conflicts with 'seek=&lt;n&gt;'.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">coe<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied if using SG_IO ioctl</td>
+ <td style="vertical-align: top;">ignored<br>
+ </td>
+ <td style="vertical-align: top;">continue on error; best effort
+recovery then continue<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">direct<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">use O_DIRECT open flag, no
+effect with sg devices<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">dpo<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied if using SG_IO ioctl</td>
+ <td style="vertical-align: top;">ignored</td>
+ <td style="vertical-align: top;">"disable page out" set for READ
+and/or WRITE SCSI commands</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">dsync<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">use O_SYNC open flag, no effect
+with sg devices<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">excl<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">Use O_EXCL open flag<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">fua<br>
+ </td>
+ <td style="vertical-align: top;">applied<br>
+ </td>
+ <td style="vertical-align: top;">applied if using SG_IO ioctl<br>
+ </td>
+ <td style="vertical-align: top;">ignored<br>
+ </td>
+ <td style="vertical-align: top;">"force unit access" set for READ
+and/or WRITE SCSI commands<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">sgio<br>
+ </td>
+ <td style="vertical-align: top;">ignored<br>
+ </td>
+ <td style="vertical-align: top;">use SG_IO ioctl<br>
+ </td>
+ <td style="vertical-align: top;">ignored<br>
+ </td>
+ <td style="vertical-align: top;">access block device via SG_IO
+ioctl (only supported in lk 2.6 series)<br>
+ </td>
+ </tr>
+ </tbody>
+</table>
+<br>
+Recent versions of GNU's dd command have these flags with similar
+semantics:&nbsp; 'append', 'direct' and 'sync' (which is called 'dsync'
+in sg_dd). So 'coe', 'dpo', 'excl', 'fua' and 'sgio' are sg_dd
+extensions.<br>
+<br>
The following dd options are <span style="font-weight: bold;">not</span>
supported by sg_dd:<br>
<ul>
@@ -237,7 +496,7 @@ supported by sg_dd:<br>
Basically sg_dd does not supported the conversion features of dd. If a
conversion is really needed then sg_dd could be piped through dd (or
vice versa).<br>
-<h2><a name="sg_dd_extras"></a>sg_dd extras</h2>
+<h2><a class="mozTocH2" name="mozTocId703997"></a>sg_dd extras</h2>
The extra options of sg_dd (not found in GNU's dd) are:<br>
<br>
<ul>
@@ -261,7 +520,7 @@ description</span><br>
<td style="vertical-align: top;">0<br>
</td>
<td style="vertical-align: top;">append to output file (rather
-than overwrite)<br>
+than overwrite). Better to use 'iflag=append' and/or 'oflag=append'.<br>
</td>
</tr>
<tr>
@@ -270,7 +529,8 @@ than overwrite)<br>
<td style="vertical-align: top;">0<br>
</td>
<td style="vertical-align: top;">when set access devices via SCSI
-commands (SG_IO ioctl)<br>
+commands (SG_IO ioctl). May use 'iflag=sgio' and/or 'oflag=sgio'
+instead.<br>
</td>
</tr>
<tr>
@@ -280,7 +540,9 @@ commands (SG_IO ioctl)<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<br>
+is 32. For block devices (bpt * bs) is constrained by <span
+ style="font-family: monospace;">/sys/block/&lt;device&gt;/queue/max_sectors_kb</span>
+.<br>
</td>
</tr>
<tr>
@@ -289,7 +551,8 @@ is 32<br>
<td style="vertical-align: top;">10 or 16<br>
</td>
<td style="vertical-align: top;">cdb size of SCSI READ and/or
-WRITE commands<br>
+WRITE commands. Only applicable to sg devices or when the SG_IO ioctl
+is being used (e.g. when blk_sgio=1)<br>
</td>
</tr>
<tr>
@@ -297,8 +560,10 @@ WRITE commands<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
- <td style="vertical-align: top;">continue_on_error when set<br>
- </td>
+ <td style="vertical-align: top;">when set, continue_on_error for
+sg devices and block devices using the SG_IO ioctl. May use 'iflag=coe'
+and/or 'oflag=coe'
+instead. </td>
</tr>
<tr>
<td style="vertical-align: top;">dio=0|1<br>
@@ -315,24 +580,24 @@ nodes)<br>
<td style="vertical-align: top;">0<br>
</td>
<td style="vertical-align: top;">force_unit_access, 1-&gt;if,
-2-&gt;of, 3-&gt;if+of<br>
- </td>
+2-&gt;of, 3-&gt;if+of . Better to use 'iflag=fua' and/or 'oflag=fua'. </td>
</tr>
<tr>
<td style="vertical-align: top;">odir=0|1<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
- <td style="vertical-align: top;">O_DIRECT flag on open() when set<br>
- </td>
+ <td style="vertical-align: top;">O_DIRECT flag on open() when
+set. Better to use 'iflag=direct' and/or 'oflag=direct'. </td>
</tr>
<tr>
<td style="vertical-align: top;">sync=0|1<br>
</td>
<td style="vertical-align: top;">0<br>
</td>
- <td style="vertical-align: top;">SYNCHRONIZE CACHE SCSI command
-after transfer when set<br>
+ <td style="vertical-align: top;">when set, sends SYNCHRONIZE
+CACHE SCSI command to &lt;ofile&gt; if it is a sg device or accessed
+via the SG_IO ioctl.<br>
</td>
</tr>
<tr>
@@ -353,23 +618,15 @@ throughput after copy<br>
the debug output<br>
</td>
</tr>
- <tr>
- <td style="vertical-align: top;">--version<br>
- </td>
- <td style="vertical-align: top;"><br>
- </td>
- <td style="vertical-align: top;">print the version number and
-release date of
-sg_dd then exit<br>
- </td>
- </tr>
</tbody>
</table>
<br>
<br>
The sg_dd utility examines the files it is given and treats them
-differently depending on the category and, in some case,s the command
-line options given:<br>
+differently depending on their file type. Depending on
+'iflag=&lt;flags&gt;' and 'oflag=&lt;flags&gt;' settings: O_DIRECT,
+O_SYNC, O_APPEND and O_EXCL flags may be added to the relevant open()
+command.<br>
<br>
<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
cellspacing="2">
@@ -397,12 +654,11 @@ method</span><br>
<br>
</td>
<td style="vertical-align: top;">O_WRONLY | O_CREAT<br>
-[add O_APPEND if 'append=1']<br>
</td>
<td style="vertical-align: top;">Unix read() write()<br>
</td>
- <td style="vertical-align: top;">Add O_DIRECT if<br>
-'odir=1'<br>
+ <td style="vertical-align: top;">N.B. A normal output file is
+overwritten (not truncated).<br>
</td>
</tr>
<tr>
@@ -414,18 +670,20 @@ method</span><br>
</td>
<td style="vertical-align: top;">Unix read() write()<br>
</td>
- <td style="vertical-align: top;"><br>
+ <td style="vertical-align: top;">hence open() flags have no
+effect (e.g. 'oflag=direct')<br>
</td>
</tr>
<tr>
- <td style="vertical-align: top;">/dev/null<br>
+ <td style="vertical-align: top;">/dev/null or . (period)<br>
</td>
<td style="vertical-align: top;">O_RDONLY</td>
<td style="vertical-align: top;">[do nothing]<br>
</td>
<td style="vertical-align: top;">Unix read() if input<br>
</td>
- <td style="vertical-align: top;">if output then no IO<br>
+ <td style="vertical-align: top;">if output file then nothing is
+written<br>
</td>
</tr>
<tr>
@@ -433,20 +691,20 @@ method</span><br>
</td>
<td style="vertical-align: top;">O_RDONLY</td>
<td style="vertical-align: top;">O_WRONLY | O_CREAT<br>
-[add O_APPEND if 'append=1']</td>
+ </td>
<td style="vertical-align: top;">Unix read() write()</td>
- <td style="vertical-align: top;">Add O_DIRECT if<br>
-'odir=1'</td>
+ <td style="vertical-align: top;"><br>
+ </td>
</tr>
<tr>
- <td style="vertical-align: top;">block device [blk_sgio=1]<br>
+ <td style="vertical-align: top;">block device [sgio flag given]<br>
</td>
<td style="vertical-align: top;">O_RDWR or O_RDONLY</td>
<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 <br>
-if O_RDWR fails. Adds <br>
-O_DIRECT if 'odir=1' </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'. Partition ignored. </td>
</tr>
<tr>
<td style="vertical-align: top;">sg device<br>
@@ -457,8 +715,8 @@ O_DIRECT if 'odir=1' </td>
</td>
<td style="vertical-align: top;">SCSI commands<br>
</td>
- <td style="vertical-align: top;">Opens input O_RDONLY<br>
-if O_RDWR fails</td>
+ <td style="vertical-align: top;">Opens input O_RDONLY if O_RDWR
+fails</td>
</tr>
<tr>
<td style="vertical-align: top;">raw device<br>
@@ -468,7 +726,8 @@ if O_RDWR fails</td>
</td>
<td style="vertical-align: top;">Unix read() write()<br>
</td>
- <td style="vertical-align: top;"><br>
+ <td style="vertical-align: top;">O_DIRECT open flag in lk 2.6
+series is a replacement for raw devices<br>
</td>
</tr>
<tr>
@@ -493,11 +752,12 @@ 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
-kilobytes in the i386 architecture. This memory alignment is a
-technical requirement of both raw devices and normal block devices that
+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 is only valid in the lk 2.6 series. This option
+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
@@ -581,7 +841,8 @@ 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
sg_dd utility which has the 'time' option set the elapsed time and the
throughput of the copy to that point is output and the copy continues.<br>
-<h2><a name="coe"></a>Continue on error (coe)</h2>
+<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
last resort" from failing media. Read errors on an input file
taking SCSI commands are "tolerated" when the 'coe' option is set.
@@ -617,7 +878,8 @@ zeroes is substituted for them.<br>
<br>
There still remains blocks after the "bad" block in the initial
transfer to be fetched. Further bad blocks may be detected and if so
-the algorithm in the last two paragraph is repeated. The result of this
+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
is given two addition counters are output on completion:<br>
@@ -631,7 +893,7 @@ 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>
-<h2><a name="Recovered_errors"></a>Recovered errors</h2>
+<h2><a class="mozTocH2" name="mozTocId566094"></a>Recovered errors</h2>
Often errors are recovered using ECC data or by the device retrying
(usually re-reading) the media. Also at the first sign of trouble,
recoverable errors lead to the block in question being reassigned to
@@ -642,8 +904,8 @@ reaching the end of its useful life. Error counters are maintained in
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 add a new entry to the "grown"
-defect list which cal be viewed with 'sginfo -G' (also found in the
+automatically or manually re-assigned adds a new entry to the "grown"
+defect list which can be viewed with 'sginfo -G' (also found in the
sg3_utils package).<br>
<br>
A disk can be instructed to report RECOVERED ERRORs by setting the PER
@@ -665,7 +927,7 @@ via a RECOVERED ERROR sense key (see the MRIE field in the
Informational Exceptions mode page). Such alerts have additional sense
codes like "Failure prediction threshold exceeded" and those that
contain "impending failure".<br>
-<h2><a name="Verbose"></a>Verbose</h2>
+<h2><a class="mozTocH2" name="mozTocId899152"></a>Verbose</h2>
In the Unix style, sg_dd doesn't output anything (to stderr) during
large IO transfers. To get a progress report the SIGUSR1 signal can be
sent to the sg_dd process. In the Unix dd command style, sg_dd outputs
@@ -680,8 +942,8 @@ this option has the following actions:<br>
<ol>
<li>show categorization and INQUIRY data (where applicable) for the
input and output files. For files, other than streams, the file/device
-size (and device block size) are output. For SCSI devices mode data
-relevant to error recovery and caching is output.</li>
+size (and device block size) are output.<br>
+ </li>
<li>same output as 1 plus data for Unix and SCSI commands (cdbs) that
are not repeated (i.e. other than Unix read/write and SCSI READ/WRITE
commands). Increased error reporting for all SCSI commands</li>
@@ -699,23 +961,9 @@ 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
-standard response data (e.g. "SEAGATE ..." line) followed by the
-setting of various mode pages relevant to error processing and caching.
+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. As an example a AWRE bit of 1 means that the disk
-will automatically reallocate a logical block address (to another
-sector)
-if a recoverable error is detected on a WRITE operation. RECOVERED
-ERRORs are only report on read and write operations when the PER [Post
-Error] bit is set. The values shown in brackets are:<br>
-<ul>
- <li>whether the field is changeable (i.e. "cha: y" for yes it is
-changeable)</li>
- <li>its default value (i.e. "def:") which is supplied by the vendor</li>
- <li>the saved value (i.e. "sav:") which will become current <span
- style="font-style: italic;">after</span> the next device power cycle
-or reset</li>
-</ul>
+for more information.<br>
<br>
<span style="font-family: monospace;">$ sg_dd if=/dev/sda of=. bs=512
verbose=1 count=0 blk_sgio=0</span><br style="font-family: monospace;">
@@ -743,43 +991,8 @@ open input(sg_io), flags=0x2</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; /dev/sda:
SEAGATE&nbsp;&nbsp;
ST39173LC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1234&nbsp;
-[pdt=0]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp; Read write error recovery
-mode page:</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-AWRE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; [cha: y, def: 1,
-sav: 1]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-ARRE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; [cha: y, def: 1,
-sav: 1]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-RC:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; [cha: y,
-def: 0, sav: 0]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-EER:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; [cha: y, def:
-0, sav: 1]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-PER:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; [cha: y, def:
-0, sav: 1]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-DTE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; [cha: y, def:
-0, sav: 0]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-DCR:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; [cha: y, def:
-0, sav: 0]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp; Caching mode page:</span><br
- style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-WRE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; [cha: y, def:
-1, sav: 1]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-RCD:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; [cha: y, def:
-0, sav: 0]</span><br style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp; Control mode page:</span><br
+[pdt=0]</span><span style="font-family: monospace;"></span><br
style="font-family: monospace;">
-<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
-SWP:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; [cha: n, def:
-0, sav: 0]</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&gt;&gt; Output file type:
null device</span><br style="font-family: monospace;">
<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@@ -794,16 +1007,17 @@ relates to the input file.<br>
<br>
Mode page settings can be examined and changed with a utility like <a
href="sdparm.html">sdparm</a> .<br>
-<h2><a name="Conclusion"></a>Conclusion</h2>
+<h2><a class="mozTocH2" name="mozTocId157981"></a>Conclusion</h2>
The sg_dd utility maintains syntactic and semantic compatibility with
-the Unix dd command while allowing precise control over SCSI devices
-such as SCSI disks and CD/DVD drives. Amongst other uses it can copy
-data from failing media, continuing as best it can when medium errors
-are encountered.<br>
+the Unix/GNU dd command while allowing precise control over SCSI
+devices
+such as SCSI disks and CD/DVD drives. Amongst other uses, it can copy
+data from failing media, continuing as best it can in the presence of
+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: 8th August 2005<br>
+<p>Last updated: 18th November 2005<br>
<br>
</p>
</center>
diff --git a/doc/sg_io.html b/doc/sg_io.html
new file mode 100644
index 00000000..2af17047
--- /dev/null
+++ b/doc/sg_io.html
@@ -0,0 +1,1555 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Linux SG_IO ioctl in the 2.6 series</title>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <meta name="keywords" content="Linux, SCSI, SG_IO, ioctl">
+ <meta name="GENERATOR"
+ content="Mozilla/4.79 [en] (X11; U; Linux 2.5.31 i686) [Netscape]">
+</head>
+<body alink="#ff0000" background="paper.jpg" bgcolor="#ffffff"
+ link="#0000ff" text="#000000" vlink="#000080">
+<center>
+<h1><a class="mozTocH1" name="mozTocId288504"></a> The&nbsp; Linux
+SG_IO ioctl in the 2.6 series<br>
+</h1>
+</center>
+<a href="#Conclusion"></a>
+<ol id="mozToc">
+<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6--><li><a href="#mozTocId288504">
+The&nbsp; Linux SG_IO ioctl in the 2.6 series </a>
+ <ol>
+ <li><a href="#mozTocId857690">Introduction</a></li>
+ <li><a href="#mozTocId844428">SCSI and related
+command sets </a></li>
+ <li><a href="#mozTocId568229">SG_IO ioctl overview</a></li>
+ <li><a href="#mozTocId575826">SG_IO ioctl in the sg
+driver </a></li>
+ <li><a href="#mozTocId104192">SG_IO ioctl differences </a></li>
+ <li><a href="#mozTocId830340">open() considerations</a></li>
+ <li><a href="#mozTocId645134">SCSI command permissions</a></li>
+ <li><a href="#mozTocId267334">Conclusion</a></li>
+ </ol>
+ </li>
+</ol>
+<h2><a class="mozTocH2" name="mozTocId857690"></a>Introduction</h2>
+The <span style="font-weight: bold;">SG_IO</span> ioctl permits user
+applications to send SCSI commands to a device. In the linux 2.4 series
+this ioctl was only available via the SCSI generic (sg) driver. In the
+linux 2.6 series the SG_IO ioctl is additionally available for block
+devices
+and SCSI tape (st) devices.&nbsp; So there are multiple implementations
+of this ioctl within the kernel with slightly different characteristics
+and describing these is the purpose of this document.<br>
+<br>
+The information in this page is valid for linux kernel 2.6.14 .<br>
+<h2><a class="mozTocH2" name="mozTocId844428"></a>SCSI and related
+command sets<br>
+</h2>
+All SCSI devices should respond to an INQUIRY command and part of their
+response is the so-called peripheral device type. This is used by the
+linux kernel to decide which upper level driver controls the device.
+There are also devices that belong to other (i.e. not considered SCSI)
+transports that use SCSI command sets, the primary examples of this are
+(S-)ATAPI CD and DVD drives. Not all peripheral device types map to
+upper level drivers and devices of these types are usually accessed via
+the SCSI generic (sg) driver.<br>
+<br>
+SCSI (draft) standards are found at <a href="http://www.t10.org/">www.t10.org</a>
+. SCSI commands common to all
+SCSI devices are found in SPC-4 while those specific to block devices
+are found in SBC-2, those for CD/DVD drives are found in MMC-5 and
+those for SCSI tape drives are found in SSC-3.<br>
+<br>
+The major non-SCSI command set in the storage area is for ATA
+<span style="font-style: italic;">non-packet</span> devices which are
+typically disks. ATA <span style="font-style: italic;">packet</span>
+devices use ATAPI which in
+the vast majority of cases carry a SCSI command set. The most recent
+draft ATA command set standard is ATA8-ACS and can be found at <a
+ href="http://www.t13.org/">www.t13.org</a> . To complicate things
+(non-packet) ATA devices may have their native command set translated
+into SCSI. This can happen in the kernel (e.g. libata in linux) or in
+an intermediate device (e.g. in a USB external disk enclosure). Yet
+another possibility are disks
+whose firmware can be changed to allow them to use either the SCSI or
+ATA command set, this may happen in the SAS/SATA area since the
+physical (cabling) and phy (electrical signalling) levels are so
+similar.<br>
+<h2><a class="mozTocH2" name="mozTocId568229"></a>SG_IO ioctl overview</h2>
+The third argument given to the SG_IO ioctl is a pointer to an instance
+of the sg_io_hdr structure which is defined in the &lt;scsi/sg.h&gt;
+header file. The execution of the SG_IO ioctl can viewed as going
+through three phases:<br>
+<ol>
+ <li>do sanity checks on the metadata in the sg_io_hdr instance; read
+the input fields and the data pointed to by some of those fields; build
+a SCSI command and issue it to the device</li>
+ <li>wait for either a response from the device, the command to
+timeout or
+the user to terminate the process (or thread) that invoked the SG_IO
+ioctl</li>
+ <li>write the output fields and in some cases write data to locations
+pointed to by some fields, then return</li>
+</ol>
+Only phase 1 returns an ioctl error (i.e. a return value of -1 and a
+value
+set in errno). In phase 2, command timeouts should be used sparingly as
+the device (and some others on the same interconnect) may end up being
+reset. If the user terminates the process or thread that invoked the
+SG_IO ioctl then obviously phase 3 never occurs but the command
+execution runs to completion (or timeout) and the kernel "throws away"
+the results. If the command yields a SCSI status of CHECK
+CONDITION (in field "status") then sense data is written out in
+phase 3 .<br>
+<br>
+Now we will assume that the SCSI command involves user data being
+transferred to or from the device. The SCSI subsystem does not support
+true bidirectional data transfers to a device. All data DMA transfers
+(assuming the hardware supports DMA) occur in phase 2. However, if
+indirect IO is being used (i.e. neither direct IO nor mmap-ed
+transfers) then either:<br>
+<ul>
+ <li>data is read from the user space in phase 1 into kernel buffers
+and DMA-ed to the device in phase 2, or</li>
+ <li>data is read from the device into kernel buffers in phase 2 and
+written into the user space in phase 3</li>
+</ul>
+When direct IO or mmap-ed transfers are being used then all user data
+is moved in phase 2 . If a process is terminated during such a data
+transfer then the kernel gracefully handles this (by pinning the
+associated memory pages until the transfer is complete).<br>
+<br>
+The sg_io_hdr structure has 22 fields (members) but typically only a
+small number of them need to be set. The following code fragment shows
+the setup for a simple TEST UNIT READY SCSI command which has no
+associated data transfers:<br>
+&nbsp;&nbsp;&nbsp; <br>
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; unsigned char
+sense_b[32];</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; unsigned char
+turCmbBlk[] = {TUR_CMD, 0, 0, 0, 0, 0};<br>
+&nbsp;&nbsp;&nbsp; struct sg_io_hdr io_hdr;<br
+ style="font-family: monospace;">
+</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
+memset(&amp;io_hdr, 0, sizeof(struct sg_io_hdr));</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
+io_hdr.interface_id = 'S';</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; io_hdr.cmd_len
+= sizeof(turCmbBlk);</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
+io_hdr.mx_sb_len = sizeof(sense_b);</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;
+io_hdr.dxfer_direction = SG_DXFER_NONE;</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; io_hdr.cmdp =
+turCmbBlk;</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; io_hdr.sbp =
+sense_b;</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; io_hdr.timeout
+= DEF_TIMEOUT;</span><br style="font-family: monospace;">
+<br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; if (ioctl(fd,
+SG_IO, &amp;io_hdr) &lt; 0) {</span><br>
+<br>
+The memset() call is pretty important, setting unused input fields to
+safe values. Setting the timeout field to zero is not a good idea;
+30,000 (for 30 seconds) is a reasonable default for most SCSI commands.
+As always, good error
+processing consumes a lot more code. This is especially the case with
+SCSI commands that yield "sense data" when something goes wrong. For
+example, if there is a medium error during a disk read, the sense data
+will contain the logical block address (lba) of the failure. Another
+error processing example is a SCSI command that the device considers an
+"illegal
+request", the sense data may show the byte and bit position of the
+field in the command block (usually referred to as a "cdb") that it
+objects to. For examples on error processing please refer to the
+sg3_utils package, its "examples" directory and its library components:
+sg_lib.c (SCSI error processing and tables) and sg_cmds.c (common SCSI
+commands).<br>
+<br>
+Below is a grouping of important sg_io_hdr structure fields with brief
+summaries:<br>
+Command block (historically referred to as the "cdb"):<br>
+<ul>
+ <li>cmdp - pointer to cdb (the SCSI command block)</li>
+ <li>cmd_len - length (in bytes) of cdb</li>
+</ul>
+Data transfer:<br>
+<ul>
+ <li>dxferp - pointer to user data to start reading from or start
+writing to</li>
+ <li>dxfer_len - number of bytes to transfer</li>
+ <li>dxfer_direction - whether to read from device (into user memory)
+or write to device (from user memory) or transfer no data:
+DXFER_FROM_DEV, DXFER_TO_DEV or DXFER_NONE respectively<br>
+ </li>
+ <li>resid - requested number of bytes to transfer (i.e. dxfer_len)
+less the actual number transferred</li>
+</ul>
+Error indication:<br>
+<ul>
+ <li>status - SCSI status returned from the device</li>
+ <li>host_status - error from Host Bus Adapter including initiator
+(port)<br>
+ </li>
+ <li>driver_status - driver (mid level or low level driver) error and
+suggestion mask</li>
+</ul>
+Sense data (only used when 'status' is CHECK CONDITION or
+(driver_status &amp; DRIVER_SENSE) is true):<br>
+<ul>
+ <li>sbp - pointer to start writing sense data to<br>
+ </li>
+ <li>mx_sb_len - maximum number of bytes to write to sbp</li>
+ <li>sb_len_wr - actual number of bytes written to sbp</li>
+</ul>
+The fields in the sg_io_hdr structure are defined in more detail in the
+<a href="http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/index.html">SCSI-Generic-HOWTO</a>
+document.<br>
+<h2><a class="mozTocH2" name="mozTocId575826"></a>SG_IO ioctl in the sg
+driver<br>
+</h2>
+Linux kernel 2.4.0 was the first production kernel in which the SG_IO
+ioctl appeared in the SCSI generic (sg) driver. The sg driver itself
+has been in linux since around 1993.
+An instance of the sg_io_hdr structure in the sg driver can either be:<br>
+<ul>
+ <li>pointed to by the third argument of the SG_IO ioctl</li>
+ <li>pointed to by the second argument of UNIX write() or read()
+system
+calls which have a file descriptor of a sg device node as their first
+argument<br>
+ </li>
+</ul>
+The <a href="http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/index.html">SCSI-Generic-HOWTO</a>
+document describes the sg driver in the lk 2.4 series including its use
+of the SG_IO ioctl. Prior to the lk 2.4 series the sg driver only had
+the sg_header structure. It was used as an asynchronous
+command interface in which command, metadata and optionally user data
+was sent via a Unix write() system call. The corresponding response
+which included
+error information (e.g. sense data) or optionally user data was
+received via a Unix read() system call. Two major additions were made
+to the sg
+driver at the beginning of the lk 2.4 series:<br>
+<ul>
+ <li>a new metadata structure (sg_io_hdr) as an alternative to the
+original mixed metadata and data structure (sg_header)</li>
+ <li>the SG_IO ioctl that used the new metadata structure and was
+synchronous: it sent a SCSI command and waited for its reply</li>
+</ul>
+The sg_io_hdr only contains metadata in the sense that it contains
+pointers to locations of where data will come from (command or data in)
+or go to (sense data or data out). These pointers have caused problems
+in mixed 32/64 bit environments, especially when the user application
+(e.g. cdrecord) is built for 32 bits and the kernel is 64 bits. The lk
+2.6 series has a compatibility layer to cope with this via code
+specialized for the SG_IO ioctl. Unfortunately this problem was not
+foreseen when the sg_io_hdr structure was designed.<br>
+<br>
+A significant feature of the SG_IO ioctl in the sg driver is that it
+is user interruptible. This means between issuing a command (e.g. a
+long duration command like a disk format) and its response arriving a
+user could hit control-C on the associated application. The kernel
+would remain stable and resources would be cleared up at the
+appropriate time. The sg driver does not attempt to abort such a
+command that is "in flight", it simply throws away the response and
+cleans up. Naturally the user has no direct way of finding out whether
+an interrupted command succeeded or not, by there may be indirect ways.<br>
+<br>
+A warning may also be in order here: a long duration command such as
+format would typically be given a long timeout value. If the user
+interrupted the application that sent the format command then the
+device may remain
+busy doing the format (especially if the IMMED bit is not set). So if
+the user then sent a short duration command such as TEST UNIT READY or
+REQUEST SENSE to see what the device was doing, these commands may
+timeout. This would invoke the SCSI subsystem error handler which would
+most likely
+send a device reset, thus aborting the format, to get the device's
+attention. This is probably not what the user had in mind!<br>
+<br>
+<h2><a class="mozTocH2" name="mozTocId104192"></a>SG_IO ioctl
+differences<br>
+</h2>
+In the following table,
+sg_io_hdr structure fields are listed in the order they appear in that
+structure. Basically the "in" fields appear at the top of the structure
+and are read in phase 1. The latter fields are termed as "out" and are
+written by the SG_IO implementation in phase 3.<br>
+&nbsp;<br>
+<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
+ cellspacing="2">
+ <caption><span style="font-weight: bold;">Table 1. sg_io_hdr
+structure&nbsp; summary and implementation differences</span><br>
+ </caption> <tbody>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">sg_io_hdr
+field</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">in
+or out</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">type</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">different</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">brief
+description including differences between implementations</span><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">interface_id<br>
+ </td>
+ <td style="vertical-align: top;">in<br>
+ </td>
+ <td style="vertical-align: top;">int<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">guard field. Current
+implementations only accept " (int)'S' ". If not set, the sg driver
+sets errno to ENOSYS
+while the block layer sets it to EINVAL<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">dxfer_direction<br>
+ </td>
+ <td style="vertical-align: top;">in<br>
+ </td>
+ <td style="vertical-align: top;">(-ve) int<br>
+ </td>
+ <td style="vertical-align: top;">minor<br>
+ </td>
+ <td style="vertical-align: top;">direction of data transfer.
+SG_DXFER_NONE and friends are defined as negative integers so the sg
+driver can discriminate between sg_io_hdr instances and those of
+sg_header. This nuance is irrelevant to non-sg driver usage of SG_IO.
+See below.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">cmd_len<br>
+ </td>
+ <td style="vertical-align: top;">in<br>
+ </td>
+ <td style="vertical-align: top;">unsigned char<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">limits command length to 255
+bytes. No SCSI commands (even variable length ones in OSD) are this
+long (yet)<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">max_sb_len<br>
+ </td>
+ <td style="vertical-align: top;">in<br>
+ </td>
+ <td style="vertical-align: top;">unsigned char<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">maximum number of bytes of sense
+data that the driver can output via the sbp pointer<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">iovec_count<br>
+ </td>
+ <td style="vertical-align: top;">in<br>
+ </td>
+ <td style="vertical-align: top;">unsigned short<br>
+ </td>
+ <td style="vertical-align: top;">yes<br>
+ </td>
+ <td style="vertical-align: top;">if not sg driver and greater
+than zero then the SG_IO ioctl fails with errno set to EOPNOTSUPP; sg
+driver treats dxferp as a pointer to an array struct sg_iovec when this
+field is greater than zero<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">dxfer_len<br>
+ </td>
+ <td style="vertical-align: top;">in<br>
+ <br>
+ </td>
+ <td style="vertical-align: top;">unsigned int<br>
+ </td>
+ <td style="vertical-align: top;">minor<br>
+ </td>
+ <td style="vertical-align: top;">number of bytes of data to
+transfer to or from the device. Upper limit for block devices related
+to <span style="font-family: monospace;">/sys/block/&lt;device&gt;/queue/max_sectors_kb</span><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">dxferp </td>
+ <td style="vertical-align: top;">in [*in or *out]<br>
+ </td>
+ <td style="vertical-align: top;">void *<br>
+ </td>
+ <td style="vertical-align: top;">minor<br>
+ </td>
+ <td style="vertical-align: top;">pointer to (user space) data to
+transfer to (if reading from device) or transfer from (if writing to
+device). Further level of indirection in the sg driver when iovec_count
+is greater than 0 .<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">cmdp </td>
+ <td style="vertical-align: top;">in [*in]<br>
+ </td>
+ <td style="vertical-align: top;">unsigned char *<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">pointer to SCSI command. The
+SG_IO ioctl in the sg drive fails with errno set to&nbsp; EMSGSIZE if
+cmdp is NULL and EFAULT if it is invalid; the block layer sets errno to
+EFAULT&nbsp; in both cases.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">sbp<br>
+ </td>
+ <td style="vertical-align: top;">in [*out]<br>
+ </td>
+ <td style="vertical-align: top;">unsigned char *<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">pointer to user data area where
+no more than max_sb_len bytes of sense data from the device will be
+written if the SCSI status is CHECK CONDITION. <br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">timeout<br>
+ </td>
+ <td style="vertical-align: top;">in<br>
+ </td>
+ <td style="vertical-align: top;">unsigned int<br>
+ </td>
+ <td style="vertical-align: top;">yes <br>
+(if = 0)<br>
+ </td>
+ <td style="vertical-align: top;">time in milliseconds that the
+SCSI mid-level will wait for a response. If that timer expires
+before the command finishes, then the command may be aborted, the
+device (and maybe others on the same interconnect) may be reset
+depending on error
+handler settings. Dangerous stuff, the SG_IO ioctl has no control
+(through this interface) of exactly what happens. In the sg driver a
+timeout value of 0 means 0 milliseconds, in the block layer (currently)
+it means 60 seconds.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">flags<br>
+ </td>
+ <td style="vertical-align: top;">in<br>
+ </td>
+ <td style="vertical-align: top;">unsigned int<br>
+ </td>
+ <td style="vertical-align: top;">yes<br>
+ </td>
+ <td style="vertical-align: top;">Block layer SG_IO ioctl ignores
+this field; the sg driver uses it to request special services like
+direct IO or mmap-ed transfers. It is a bit mask.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">pack_id<br>
+ </td>
+ <td style="vertical-align: top;">in -&gt; out<br>
+ </td>
+ <td style="vertical-align: top;">int<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">unused (for user space program
+tag)<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">usr_ptr<br>
+ </td>
+ <td style="vertical-align: top;">in -&gt; out<br>
+ </td>
+ <td style="vertical-align: top;">void *<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">unused (for user space pointer
+tag)<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">status<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">unsigned char<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">SCSI command status, zero
+implies GOOD<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">masked_status<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">unsigned char<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">Logically: masked_status ==
+((status &amp; 0x3e) &gt;&gt; 1). Old linux SCSI subsystem usage,
+deprecated. </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">msg_status<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">unsigned char<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">SCSI parallel interface (SPI)
+message status (very
+old, deprecated)<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">sb_len_wr<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">unsigned char<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">actual length of sense data (in
+bytes) output via sbp pointer.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">host_status<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">unsigned short<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">error reported by the initiator
+(port). These are the "DID_*" error codes in scsi.h<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">driver_status<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">unsigned short<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">bit mask: error and suggestion
+reported by the low level driver (LLD). These are the "DRIVER_*" error
+codes in scsi.h</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">resid<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">int<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">(dxfer_len -
+number_of_bytes_actually_transferred). Typically only set when there is
+a shortened DMA transfer from the device.&nbsp; Not necessarily an
+error. Older LLDs always yield zero.</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">duration<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">unsigned int<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">number of milliseconds that
+elapsed between when the command was injected into the SCSI mid level
+and the corresponding "done" callback was invoked. Roughly the duration
+of the SCSI command in milliseconds.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">info<br>
+ </td>
+ <td style="vertical-align: top;">out<br>
+ </td>
+ <td style="vertical-align: top;">unsigned int<br>
+ </td>
+ <td style="vertical-align: top;">minor<br>
+ </td>
+ <td style="vertical-align: top;">bit mask indicating what was
+done (or not) and whether any error was detected. Block layer SG_IO
+ioctl only sets SG_INFO_CHECK if an error was detected<br>
+ </td>
+ </tr>
+ </tbody>
+</table>
+<br>
+The DID_* and DRIVER_* error and suggestion codes (associated with
+host_status and driver_status) are discussed in more detail in the
+<a href="http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/index.html">SCSI-Generic-HOWTO</a>
+document.
+<h2><a class="mozTocH2" name="mozTocId830340"></a>open() considerations</h2>
+Various drivers have different characteristics when a device node is
+opened. One problem with the ioctl system call is that a user only
+needs read permissions to execute it but may, with the ioctls like
+SG_IO, write to a device (e.g. format it).&nbsp; Command (operation
+code) sniffing logic is used to overcome this security problem. Also
+users of the SG_IO ioctl need to be aware when they "share" a device
+with sd, st or a cdrom driver that state machines within those drivers
+may be tricked. This may be unavoidable but the users of the SG_IO
+ioctl should take appropriate care.<br>
+<br>
+Opening a file in linux with flags of zero implies the O_RDONLY flag
+and hence read only access. All open() system calls can yield ENOENT
+(no such file or directory); ENODEV (no such device) if the file exists
+but there is no attached device and EACCES (permission denied) if the
+user doesn't have appropriate permissions.<br>
+<br>
+A user with CAP_SYS_RAWIO capability (normally associated with the
+"root" user) bypasses all command sniffing and other access controls
+that would otherwise lead to EACCES or EPERM errors. With the sg driver
+such a user may still need to open() a device node with O_RDWR (rather
+than O_RDONLY) to use all SCSI commands.<br>
+<br>
+<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
+ cellspacing="2">
+ <caption><span style="font-weight: bold;">Table 2. open() flags for
+SG_IO ioctl usage</span><br>
+ </caption> <tbody>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">open()
+flags</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">sg<br>
+notes<br>
+ </span> </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">sd<br>
+notes<br>
+ </span> </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">st<br>
+notes<br>
+ </span> </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">cdrom<br>
+notes<br>
+ </span> </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Comments</span><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">&lt;none&gt; or<br>
+O_RDONLY<br>
+ </td>
+ <td style="vertical-align: top;">1, 2<br>
+ </td>
+ <td style="vertical-align: top;">3,4<br>
+ </td>
+ <td style="vertical-align: top;">3,5<br>
+ </td>
+ <td style="vertical-align: top;">3,6<br>
+ </td>
+ <td style="vertical-align: top;">best to add O_NONBLOCK. For a
+device with removable media (e.g. tape drive) that depends on whether
+the drive or its media is being accessed.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">O_RDONLY | O_NONBLOCK<br>
+ </td>
+ <td style="vertical-align: top;">1,7<br>
+ </td>
+ <td style="vertical-align: top;">3<br>
+ </td>
+ <td style="vertical-align: top;">3,13<br>
+ </td>
+ <td style="vertical-align: top;">3<br>
+ </td>
+ <td style="vertical-align: top;">recommended when SCSI commands
+are recognized as reading information from the device<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">O_RDWR<br>
+ </td>
+ <td style="vertical-align: top;">2<br>
+ </td>
+ <td style="vertical-align: top;">4,8,9<br>
+ </td>
+ <td style="vertical-align: top;">5,8,9<br>
+ </td>
+ <td style="vertical-align: top;">6,8,9<br>
+ </td>
+ <td style="vertical-align: top;">again, could be better to add
+O_NONBLOCK</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">O_RDWR | O_NONBLOCK<br>
+ </td>
+ <td style="vertical-align: top;">7<br>
+ </td>
+ <td style="vertical-align: top;">8,9<br>
+ </td>
+ <td style="vertical-align: top;">8,9,13<br>
+ </td>
+ <td style="vertical-align: top;">8,9<br>
+ </td>
+ <td style="vertical-align: top;">recommended when arbitrary
+(including vendor specific) SCSI commands are to be sent<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">&lt;&lt; interaction with
+O_EXCL&gt;&gt;<br>
+ </td>
+ <td style="vertical-align: top;">10<br>
+ </td>
+ <td style="vertical-align: top;">11<br>
+ </td>
+ <td style="vertical-align: top;">12<br>
+ </td>
+ <td style="vertical-align: top;">11<br>
+ </td>
+ <td style="vertical-align: top;">only use when sure that no other
+application may want to access the device (or partition). A surprising
+number of applications do "poke around" devices.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">&lt;&lt; interaction with
+O_DIRECT&gt;&gt;<br>
+ </td>
+ <td style="vertical-align: top;">-<br>
+ </td>
+ <td style="vertical-align: top;">--&gt;<br>
+ </td>
+ <td style="vertical-align: top;">-<br>
+ </td>
+ <td style="vertical-align: top;">--&gt;<br>
+ </td>
+ <td style="vertical-align: top;">requires sector alignment on
+data transfers (ignored by sg and st)<br>
+ </td>
+ </tr>
+ </tbody>
+</table>
+<br>
+<span style="font-weight: bold;">Notes</span>:<br>
+<ol>
+ <li>on subsequent SG_IO ioctl calls, the sg driver will only allow
+SCSI commands in its allow_ops array, others result in EPERM (operation
+not permitted) in errno. See <a href="#SCSI_command_permissions">below</a>
+.<br>
+ </li>
+ <li>if previous open() of this sg device node still holds O_EXCL then
+this open() waits until it clears.</li>
+ <li>on subsequent SG_IO ioctl calls, the block layer will only allow
+SCSI commands listed as "safe_for_read" in the verify_command()
+function in the drivers/block/scsi_ioctl.c file; others result in EPERM
+(operation not permitted) in errno. See <a
+ href="#SCSI_command_permissions">below</a> .<br>
+ </li>
+ <li>if removable media and it is not present then yields ENOMEDIUM
+(no medium found)</li>
+ <li>if a tape is not present in drive then yields EIO (input/output
+error), if tape is "in use" then yields EBUSY (resource busy). Only one
+open file descriptor is allowed per st device node at a time (although
+dup() can be used).<br>
+ </li>
+ <li>if tray closed and media is not present then yields ENOMEDIUM (no
+medium found); if tray open then tries to close it and if no media
+present then yields ENOMEDIUM</li>
+ <li>if previous open() of this sg device node still holds O_EXCL then
+yields EBUSY (resource busy).<br>
+ </li>
+ <li>on subsequent SG_IO ioctl calls, the block layer will allow SCSI
+commands listed as either "safe_for_read" or "safe_for_write". For
+other SCSI commands the user requires the CAP_SYS_RAWIO capability
+(usually associated with the "root" user); if not yields EPERM
+(operation
+not permitted). The first instance of other SCSI commands since boot,
+sends an annoying "scsi: unknown opcode" message to the log.<br>
+ </li>
+ <li>if the media or drive is marked as not writable then yields EROFS
+(read-only file system).</li>
+ <li>if sg device node already has exclusive lock then a subsequent
+attempt to open(O_EXCL) will wait unless O_NONBLOCK is given in which
+case it yields EBUSY (resource busy)<br>
+ </li>
+ <li>implemented at block device level (which knows about partitions
+within devices). If a previous open(O_EXCL) is active then a subsequent
+open(O_EXCL) yields EBUSY (resource busy). Mounted file systems
+typically open a device/partition with O_EXCL; as long as an
+application using the SG_IO ioctl does not also try and use the O_EXCL
+flag then it will be allowed access to the device.</li>
+ <li>the st driver does not support (i.e. ignores) the O_EXCL flag.
+However the fact that it only permits one active open() per tape device
+is similar functionality.<br>
+ </li>
+ <li>if tape is "in use" then yields EBUSY (resource busy). Only one
+open file descriptor is allowed per st device node at a time.</li>
+</ol>
+The O_EXCL flag has a different effect in the sg driver and the block
+layer. In the sg driver, once O_EXCL is held on a device, all
+subsequent open() attempts will either wait or yield EBUSY
+(irrespective of whether they attempt to use the O_EXCL flag). Once a
+partition/device is opened successfully in the block layer (with the sd
+or cdrom driver) only subsequent open() attempts that also use the
+O_EXCL flag are rejected (with EBUSY). A O_EXCL lock held on a device
+in the block layer has no effect on accessing the same device via the
+sg driver (and vice versa).<br>
+<br>
+The first successful open on a sd or a cdrom device node that has
+removable media will send a PREVENT ALLOW MEDIUM REMOVAL (prevent) SCSI
+command to the device. If successful, this will inhibit a subsequent
+START STOP UNIT (eject) SCSI command and de-activate the eject button
+on the drive. In emergencies, the SG_IO ioctl can be used to defeat
+this action, an example of this is the <a href="sdparm.html">sdparm</a>
+utility, specifically "sdparm --command=unlock".<br>
+<br>
+The open() flag O_NDELAY has the same value and meaning as O_NONBLOCK.
+Other flags such as O_DIRECT, O_TRUNC and O_APPEND have no effect on
+the SG_IO ioctl.<br>
+<h2><a class="mozTocH2" name="mozTocId645134"></a>SCSI command
+permissions</h2>
+In linux a user only needs read permissions on a file descriptor to
+execute an ioctl() system command. In the case of the SG_IO ioctl, a
+SCSI command could be sent that obviously changes the state of a device
+(e.g. WRITE to a disk). So both implementations of the SG_IO ioctl
+require more than read permissions for some commands, especially those
+that are known to change the state of a device or those that have some
+unknown action (e.g. vendor specific commands).<br>
+<br>
+Here is a table of SCSI commands that don't need the user to have write
+permissions (or in some cases CAP_SYS_RAWIO capability which usually
+equates to "root" user):<br>
+<table style="width: 100%; text-align: left;" border="1" cellpadding="2"
+ cellspacing="2">
+ <caption><span style="font-weight: bold;">Table 3. SCSI command
+minimum permission requirements</span><br>
+ </caption> <tbody>
+ <tr>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">SCSI
+command</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">(draft)
+standard</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">sg
+driver requires</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">block
+layer SG_IO<br>
+requires (except st)</span><br>
+ </td>
+ <td style="vertical-align: top;"><span style="font-weight: bold;">Comments</span><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">BLANK<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">CLOSE TRACK/SESSION<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">ERASE<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">FLUSH CACHE<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">Really SYNCHRONIZE CACHE command<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">FORMAT UNIT<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">default command timeout may not
+be long enough<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">GET CONFIGURATION<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">reads CD/DVD metadata<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">GET EVENT STATUS NOTIFICATION<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">GET PERFORMANCE<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">INQUIRY<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY<br>
+ </td>
+ <td style="vertical-align: top;">All SCSI devices should respond
+to this command<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">LOAD UNLOAD MEDIUM<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">MEDIUM may be replaced by CD,
+DVD or nothing<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">LOG SELECT<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">used to change logging or clear
+logged data<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">LOG SENSE<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">used to fetch logged data<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">MAINTENANCE COMMAND IN<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY<br>
+ </td>
+ <td style="vertical-align: top;">CAP_SYS_RAW_IO<br>
+ <br>
+ </td>
+ <td style="vertical-align: top;">various "REPORT ..." commands
+such as REPORT SUPPORTED OPERATION CODES in here<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">MODE SELECT (6+10)<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">Used to change SCSI device
+metadata<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">MODE SENSE (6+10)<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY </td>
+ <td style="vertical-align: top;">O_RDONLY </td>
+ <td style="vertical-align: top;">Used to read SCSI device metadata<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">PAUSE RESUME</td>
+ <td style="vertical-align: top;">MMC-4</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">PLAY AUDIO (10)<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">PLAY AUDIO MSF<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">PLAY AUDIO TI<br>
+ </td>
+ <td style="vertical-align: top;">??<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">opcode 0x48, unassigned to&nbsp;
+any spec in SPC-4<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">PLAY CD</td>
+ <td style="vertical-align: top;">MMC-2<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">old, now SPARE IN in SPC-4<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">PREVENT ALLOW MEDIUM REMOVAL<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">sd, st and cdrom drivers use
+this internally<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ (6+10+12+16)<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ BUFFER<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ BUFFER CAPACITY<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ CAPACITY(10)<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ CAPACITY(16)<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3,<br>
+MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY<br>
+ </td>
+ <td style="vertical-align: top;">CAP_SYS_RAW_IO<br>
+ </td>
+ <td style="vertical-align: top;">within SERVICE ACTION IN
+command. Needed for RAIDs larger than 2 TB<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ CD<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ CD MSF<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ CDVD CAPACITY<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">Strange (old ?) name from
+cdrom.h . Actually is READ CAPACITY.<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ DEFECT (10)<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ DISC INFO<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ DVD STRUCTURE<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ FORMAT CAPACITIES<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ HEADER<br>
+ </td>
+ <td style="vertical-align: top;">MMC-2<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ LONG (10)<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">but not READ LONG (16)<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ SUB-CHANNEL<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ TOC/PMA/ATIP<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">READ TRACK (RZONE) INFO<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">In MMC-4 called READ TRACK INFO<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">RECEIVE DIAGNOSTIC<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">CAP_SYS_RAW_IO</td>
+ <td style="vertical-align: top;">the SES command set uses this
+command a lot. An SES device is only accessible via an sg device node<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">REPAIR (RZONE) TRACK<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">REPORT KEY<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">REPORT LUNS<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">CAP_SYS_RAW_IO</td>
+ <td style="vertical-align: top;">mandatory since SPC-3<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">REQUEST SENSE<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">has uses other than those
+displaced by autosense<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">RESERVE (RZONE) TRACK<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SCAN<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SEEK<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SEND CUE SHEET<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SEND DVD STRUCTURE<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">[SEND EVENT]<br>
+ </td>
+ <td style="vertical-align: top;">MMC-2<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">cdrom.h associates opcode 0xa2
+but MMC-2 uses opcode 0x5d ??<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SEND KEY<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SEND OPC INFORMATION<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SERVICE ACTION IN<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4, SBC-3<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">CAP_SYS_RAW_IO</td>
+ <td style="vertical-align: top;">READ CAPACITY (16) service
+action in here<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SET CD SPEED<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">cdrom.h calls this SET SPEED<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SET STREAMING<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">START STOP UNIT<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">hmm<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">STOP PLAY/SCAN<br>
+ </td>
+ <td style="vertical-align: top;">MMC-4</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">SYNCHRONIZE CACHE</td>
+ <td style="vertical-align: top;">SBC-3, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">cdrom.h calls this FLUSH CACHE<br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">TEST UNIT READY<br>
+ </td>
+ <td style="vertical-align: top;">SPC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;">All SCSI devices should respond
+to this command</td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">VERIFY (10+16)<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDONLY</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">WRITE (6+10+12+16)</td>
+ <td style="vertical-align: top;">SBC-3<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">WRITE LONG (10+16)<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">WRITE VERIFY (10+16)<br>
+ </td>
+ <td style="vertical-align: top;">SBC-3, MMC-4<br>
+ </td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">O_RDWR</td>
+ <td style="vertical-align: top;">only WRITE VERIFY(10) is in MMC-4<br>
+ </td>
+ </tr>
+ </tbody>
+</table>
+<br>
+Any other SCSI command (opcode) not mentioned for the sg driver needs
+O_RDWR. Any other SCSI command (opcode) not mentioned for the block
+layer SG_IO ioctl needs a user with CAP_SYS_RAW_IO capability. All
+"block" SG_IO ioctl calls on st device nodes need a user with
+CAP_SYS_RAW_IO capability. If a
+user does not have sufficient permissions to execute a SCSI command via
+the SG_IO ioctl then the system calls fails (i.e. no SCSI command is
+sent) and errno is set to EPERM (operation not permitted).<br>
+<br>
+Both the sg driver and the block layer SG_IO code use internal tables
+to enforce the permissions shown in the above table (allow_ops and
+cmd_type [safe_for_read and safe_for_write] respectively). This
+technique doesn't scale well, since more advanced command sets (e.g.
+OSD) use service actions (and one opcode: 0x7f in the case of OSD).
+There may also be overlap in opcode usage between command sets, for
+example between SBC, MMC and SSC.<br>
+<br>
+<h2><a class="mozTocH2" name="mozTocId267334"></a>Conclusion</h2>
+In some situations, sending commands via the SG_IO ioctl may interfere
+with a higher level driver's use of a device. Users of the SG_IO ioctl
+should be aware that they are using a powerful, but low level facility,
+and write code accordingly. An example of this would be a utility to
+perform self tests on a disk: "background" self tests should be
+preferred over "foreground" self tests if there is a chance the
+computer may be using a file system on that disk at the time. Even a
+short foreground self test may take up to two minutes which is a long
+time to lock out a file system.<br>
+<br>
+<p>Return to <a href="index.html">main</a> page. </p>
+<center>
+<p>Last updated: 2nd November 2005<br>
+<br>
+</p>
+</center>
+</body>
+</html>
diff --git a/doc/u_index.html b/doc/u_index.html
index ed4554cb..d742fa99 100644
--- a/doc/u_index.html
+++ b/doc/u_index.html
@@ -1,26 +1,53 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
+ <title>Linux sg3_utils package</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
+ <meta name="keywords" content="sg3_utils, SCSI utilities, linux">
<meta name="GENERATOR"
content="Mozilla/4.79 [en] (X11; U; Linux 2.5.31 i686) [Netscape]">
- <title>Linux sg3_utils package</title>
</head>
<body alink="#ff0000" background="paper.jpg" bgcolor="#ffffff"
link="#0000ff" text="#000000" vlink="#000080">
<center>
-<h1> The&nbsp; Linux sg3_utils package</h1>
+<h1><a class="mozTocH1" name="mozTocId697451"></a> The&nbsp; Linux
+sg3_utils package</h1>
</center>
-<a href="#intro">Introduction</a> <br>
-<a href="#contents">Contents</a><br>
-<a href="#Changing_mode_page_settings">Changing mode page settings</a><br>
-<a href="#Examples"><span style="text-decoration: underline;">Examples</span></a><br>
-<a href="#notes">Notes</a> <br>
-<a href="#download">Download</a> <br>
-<a href="#others">Programs from other sources</a> <br>
-&nbsp;
-<h2> <a name="intro"></a>Introduction</h2>
+<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 sg3_utils package</a>
+ <ol>
+ <li><a href="#mozTocId746876"> Introduction</a></li>
+ <li><a href="#mozTocId764860"> Contents of sg3_utils</a></li>
+ <li><a href="#mozTocId143590">Changing mode page
+settings</a></li>
+ <li><a href="#mozTocId301018">Examples</a></li>
+ <li><a href="#mozTocId585558"> Notes</a></li>
+ <li><a href="#mozTocId479511"> Download</a></li>
+ <li><a href="#mozTocId185822"> Programs from other sources</a>
+ <ol>
+ <li><a href="#mozTocId348388"> scu</a></li>
+ <li><a href="#mozTocId668788"> dt</a></li>
+ <li><a href="#mozTocId673853">scsiinfo</a></li>
+ <li><a href="#mozTocId550034"> scsidev</a></li>
+ <li><a href="#mozTocId212850"> ddrescue</a></li>
+ <li><a href="#mozTocId380766"> mapscsi</a></li>
+ <li><a href="#mozTocId108175"> scsimap</a></li>
+ <li><a href="#mozTocId143073"> smartsuite</a></li>
+ <li><a href="#mozTocId535090">smartmontools</a></li>
+ <li><a href="#mozTocId974127">scsirastools</a></li>
+ <li><a href="#mozTocId783871">SeaTools</a></li>
+ <li><a href="#mozTocId264328"> devlabel</a></li>
+ <li><a href="#mozTocId295637">plscsi</a></li>
+ <li><a href="#mozTocId325127">safte-monitor</a></li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+</ol>
+<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 Linux devices. As well as devices on SCSI
@@ -41,7 +68,7 @@ targeted the&nbsp; 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>&nbsp;
for further information about sg_utils.&nbsp; This
document describes
-<span style="font-weight: bold;">version 1.16</span> of <span
+<span style="font-weight: bold;">version 1.18</span> of <span
style="font-weight: bold;">sg3_utils</span> . <br>
<br>
In the linux kernel 2.4 series most these utilities must be
@@ -61,7 +88,7 @@ state machines.<br>
<p>SCSI utility programs for Linux from other sources are listed and
briefly described in
the final section. </p>
-<h2> <a name="contents"></a>Contents of sg3_utils</h2>
+<h2><a class="mozTocH2" name="mozTocId764860"></a> Contents of sg3_utils</h2>
Here is a listing in alphabetical order of the utilities in the
sg3_utils package:<br>
<br>
@@ -246,7 +273,7 @@ cd/dvd drive and/or its current media<br>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">default is to report (fetch) the
-device identifier. With the '--set' option a new identifier can be sent
+device identifier. With the '--set' option a new identifier is sent
to the device.<br>
</td>
</tr>
@@ -258,7 +285,8 @@ to the device.<br>
<td style="vertical-align: top;"><br>
</td>
<td style="vertical-align: top;">fetch standard response, VPD
-pages (including device identification) or version descriptors<br>
+pages (including device identification) or version descriptors. Also
+can perform IDENTIFY (PACKET) DEVICE ATA command.<br>
</td>
</tr>
<tr>
@@ -296,6 +324,18 @@ and primary device node (if any). In lk 2.6 see <a
</td>
</tr>
<tr>
+ <td style="vertical-align: top;">sg_map26<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">maps between single 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>
+ </tr>
+ <tr>
<td style="vertical-align: top;">sg_modes<br>
</td>
<td style="vertical-align: top;">MODE SENSE<br>
@@ -621,7 +661,7 @@ 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
file
systems on it is going to cause damage.<br>
-<h2><a name="Changing_mode_page_settings"></a>Changing mode page
+<h2><a class="mozTocH2" name="mozTocId143590"></a>Changing mode page
settings</h2>
SCSI devices store settings (metadata) that could possibly be changed
by the user (called the "application client" in SCSI jargon) in mode
@@ -680,7 +720,7 @@ this particular feature)).<br>
The author's recommendation is to use <a href="sdparm.html">sdparm</a>
unless the features of
another utility better suit your needs.<br>
-<h2><a name="Examples"></a>Examples</h2>
+<h2><a class="mozTocH2" name="mozTocId301018"></a>Examples</h2>
The fundamental SCSI command whose support is mandatory for all SCSI
devices is INQUIRY. All devices should respond to a "standard" (i.e.
when no Vital Product Pages are requested) INQUIRY.<br>
@@ -856,7 +896,7 @@ 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
still needed to "talk" to devices such as enclosures which have no
specialized driver in linux.<br>
-<h2> <a name="notes"></a>Notes</h2>
+<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
@@ -883,7 +923,7 @@ 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 name="download"></a>Download</h2>
+<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 <span
style="text-decoration: underline;">table 2</span> on the main
@@ -891,8 +931,9 @@ page (link at the bottom of this page). There are also source,
i386 binary rpm and deb packages available. Both sg3_utils and the
older sg_utils packages can
be found on http://freshmeat.net .
-<h2> <a name="others"></a>Programs from other sources</h2>
-<h3> scu</h3>
+<h2><a class="mozTocH2" name="mozTocId185822"></a> Programs from other
+sources</h2>
+<h3><a class="mozTocH3" name="mozTocId348388"></a> scu</h3>
The SCSI Command Utility (SCU) implements various SCSI commands
necessary for normal maintenance and diagnostics of SCSI
peripherals. Some of its features include: formatting, scanning for
@@ -904,7 +945,7 @@ in binary form. See&nbsp;<a class="moz-txt-link-freetext"
style="font-family: monospace;"> </span>www.scsifaq.org/RMiller_Tools/index.html</a>
or&nbsp; <a href="http://www.scsifaq.org/RMiller_Tools/index.html">http://www.scsifaq.org/RMiller_Tools/index.html</a>
for more details.
-<h3> dt</h3>
+<h3><a class="mozTocH3" name="mozTocId668788"></a> dt</h3>
The Data Test (DT) program is modelled on dd's syntax but <b>dt </b>can
do a lot more than sequential copies. It is a comprehensive data test
program for SCSI devices such as disks, tapes and cdrom/dvds. It is
@@ -915,7 +956,7 @@ See&nbsp;<a class="moz-txt-link-freetext"
style="font-family: monospace;"></span>www.scsifaq.org/RMiller_Tools/index.html</a>&nbsp;for
more details. Both <b>scu</b> and <b>dt </b>are written by Robin
T. Miller &lt;Robin.Miller at hp dot com&gt;<br>
-<h3>scsiinfo</h3>
+<h3><a class="mozTocH3" name="mozTocId673853"></a>scsiinfo</h3>
Older package that includes the <span style="font-weight: bold;">scsiinfo</span>
and <span style="font-weight: bold;">scsiformat</span> utilities plus
tcl/tk GUI interfaces for those utilities. The last update of the <span
@@ -929,7 +970,7 @@ standards (e.g. extra and extended mode pages) are reflected in <span
style="font-weight: bold;">sg_format</span> utility can be thought of
as a modern replacement for the <span style="font-weight: bold;">scsiformat</span>
utility.<br>
-<h3> scsidev</h3>
+<h3><a class="mozTocH3" name="mozTocId550034"></a> scsidev</h3>
Kurt Garloff &lt;garloff@suse.de&gt; describes this utility thus: "This
program scans the SCSI bus and creates device nodes in /dev/scsi/,
which have a naming corresponding to their SCSI IDs and LUNs, just
@@ -943,13 +984,13 @@ more information see: <a
href="http://www.garloff.de/kurt/linux/scsidev">www.garloff.de/kurt/linux/scsidev</a>
. He also has the useful <b>rescan-scsi-bus.sh</b> script at the same
location.
-<h3> ddrescue</h3>
+<h3><a class="mozTocH3" name="mozTocId212850"></a> ddrescue</h3>
This is another utility from&nbsp; Kurt Garloff &lt;garloff@suse.de&gt;
for rescuing damaged media. It is a variant of dd that will continue
passed errors on the input file. It is applicable to any device that
can be read by dd (e.g. IDE and SCSI disks, cds and tapes). For more
information see: <a href="http://www.garloff.de/kurt/linux/ddrescue">www.garloff.de/kurt/linux/ddrescue</a>
-<h3> mapscsi</h3>
+<h3><a class="mozTocH3" name="mozTocId380766"></a> mapscsi</h3>
Michael Clark &lt;michael@metaparadigm.com&gt; describes his utility
thus: "mapscsi is a small utility that creates a consistent mapping
to Linux scsi devices. mapscsi achieves this by creating symbolic
@@ -961,7 +1002,7 @@ using this information plus a mapping rules file containing device
templates to dynamically create link names". For more information see: <a
href="http://gort.metaparadigm.com/mapscsi">http://gort.metaparadigm.com/mapscsi</a>
.
-<h3> scsimap</h3>
+<h3><a class="mozTocH3" name="mozTocId108175"></a> scsimap</h3>
Steve Cameron &lt;smcameron@yahoo.com&gt; has the following description
at his site:
<p>This is a utility to create and maintain symbolic links mapping a
@@ -979,7 +1020,7 @@ handles later generation Compaq array controllers (those which use
the cciss driver.) </p>
<p>See: <a href="http://www.geocities.com/smcameron">www.geocities.com/smcameron</a>
. </p>
-<h3> smartsuite</h3>
+<h3><a class="mozTocH3" name="mozTocId143073"></a> smartsuite</h3>
This is a package that supports S.M.A.R.T. capabilities built into
modern IDE and SCSI-3 disks. Self-Monitoring, Analysis and Reporting
Technology (S.M.A.R.T.) is described at <a
@@ -987,14 +1028,14 @@ Technology (S.M.A.R.T.) is described at <a
For smartsuite see <a href="http://sourceforge.net/projects/smartsuite">sourceforge.net/projects/smartsuite</a>
. <br>
<br>
-<h3>smartmontools</h3>
+<h3><a class="mozTocH3" name="mozTocId535090"></a>smartmontools</h3>
This project has taken over from the aforementioned
smartsuite which is currently not actively maintained. See <a
href="http://smartmontools.sourceforge.net">http://smartmontools.sourceforge.net</a>
. The author is a maintainer of the SCSI component of this project.
[The lead maintainer is Bruce Allen.]<br>
<br>
-<h3>scsirastools</h3>
+<h3><a class="mozTocH3" name="mozTocId974127"></a>scsirastools</h3>
"This project includes changes that enhance the Reliability,
Availability and Serviceability (RAS) of the drivers that are
commonly used in a Linux software RAID-1 configuration. Other
@@ -1006,7 +1047,7 @@ to load disk firmware, <b>sgmode</b> to get and set mode pages, <b>sgdefects</b>
to read primary and grown defect lists and <b>sgdiag</b> to perform
format and other test functions.<br>
&nbsp;<br>
-<h3>SeaTools</h3>
+<h3><a class="mozTocH3" name="mozTocId783871"></a>SeaTools</h3>
SeaTools is a freely available (binary, not source) utility for disk
diagnostics from Seagate which is a disk manufacturer. It can be found
at <a href="http://www.seagate.com">http://www.seagate.com</a> under
@@ -1014,7 +1055,7 @@ the support tab. They have both a command line and a graphical utility.
&nbsp;Some of the facilities will work on any SCSI disks while others
are Seagate specific. Self tests, mode page settings and formats (to
different block sizes) are amongst the facilities available.<br>
-<h3> devlabel</h3>
+<h3><a class="mozTocH3" name="mozTocId264328"></a> devlabel</h3>
Devlabel is "a small userspace app which maps symlinks to underlying
disk names. It uses [INQUIRY VPD] Page83/Page80 data to track the
true locations of disks even if their hd/sd name changes and simply
@@ -1023,11 +1064,11 @@ lk 2.6 series and support for multi-path configurations is on the
author's "to do" list. See <a href="http://www.lerhaupt.com/linux.html">http://www.lerhaupt.com/linux.html</a>
.<br>
<br>
-<h3>plscsi</h3>
+<h3><a class="mozTocH3" name="mozTocId295637"></a>plscsi</h3>
This utility allows arbitrary SCSI commands to be sent to a device. See
<a href="http://members.aol.com/plscsi">http://members.aol.com/plscsi</a>
. It is similar to FreeBSD's camcontrol command.<br>
-<h3>safte-monitor</h3>
+<h3><a class="mozTocH3" name="mozTocId325127"></a>safte-monitor</h3>
SAF-TE (SCSI Attached Fault-Tolerant Enclosure) is a SCSI command set
for monitoring and controlling enclosures and RAIDs. SAF-TE devices
report "processor" peripheral device type (0x3) in their INQUIRY
@@ -1038,7 +1079,7 @@ monitoring tool for linux see: <a
<br>
<p>Return to <a href="index.html">main</a> page. </p>
<center>
-<p>Last updated: 5th August 2005<br>
+<p>Last updated: 15th November 2005<br>
<br>
</p>
</center>
diff --git a/lib_no_lib/Makefile.no_lib b/lib_no_lib/Makefile.no_lib
index 1ff83f14..642e9f1a 100644
--- a/lib_no_lib/Makefile.no_lib
+++ b/lib_no_lib/Makefile.no_lib
@@ -15,7 +15,7 @@ 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_rmsn sg_ident sg_map26
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 \
@@ -23,7 +23,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_opcodes.8 sg_persist.8 sg_write_long.8 sg_read_long.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_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
+ sg_map26.8
MAN_PREF = man8
LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
@@ -156,6 +157,9 @@ sg_rmsn: sg_rmsn.o sg_lib.o sg_cmds.o
sg_ident: sg_ident.o sg_lib.o sg_cmds.o
$(LD) -o $@ $(LDFLAGS) $^
+sg_map26: sg_map26.o
+ $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
for name in $^; \
diff --git a/lib_no_lib/sg3_utils.spec.no_lib b/lib_no_lib/sg3_utils.spec.no_lib
index 79d5179b..22165375 100644
--- a/lib_no_lib/sg3_utils.spec.no_lib
+++ b/lib_no_lib/sg3_utils.spec.no_lib
@@ -1,6 +1,6 @@
Summary: Utilities for SCSI devices in Linux
Name: sg3_utils
-Version: 1.17
+Version: 1.18
Release: 1
Packager: Douglas Gilbert <dgilbert at interlog dot com>
License: GPL/FreeBSD
@@ -47,7 +47,7 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%attr(-,root,root) %doc CREDITS README README.sg_start
-%attr(-,root,root) %doc CHANGELOG INSTALL COVERAGE
+%attr(-,root,root) %doc CHANGELOG INSTALL COVERAGE COPYING
%attr(755,root,root) %{_bindir}/sg_dd
%attr(755,root,root) %{_bindir}/sg_inq
%attr(755,root,root) %{_bindir}/sg_scan
@@ -83,6 +83,7 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root) %{_bindir}/sg_format
%attr(755,root,root) %{_bindir}/sg_rmsn
%attr(755,root,root) %{_bindir}/sg_ident
+%attr(755,root,root) %{_bindir}/sg_map26
# 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*
@@ -119,9 +120,14 @@ rm -rf $RPM_BUILD_ROOT
%attr(-,root,root) %doc %{_mandir}/man8/sg_format.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg_rmsn.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg_ident.8*
+%attr(-,root,root) %doc %{_mandir}/man8/sg_map26.8*
%changelog
+* 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
* sg3_utils-1.17
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 604ee014..81cb0bf5 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -1,5 +1,5 @@
%define name sg3_utils
-%define version 1.17
+%define version 1.18
%define release 1
%define major 1
@@ -80,7 +80,7 @@ make install \
%files
%defattr(-,root,root)
-%doc CHANGELOG COVERAGE CREDITS INSTALL README README.sg_start
+%doc CHANGELOG COPYING COVERAGE CREDITS INSTALL README README.sg_start
%attr(0755,root,root) %{_bindir}/*
%{_mandir}/man8/*
@@ -96,6 +96,10 @@ make install \
%{_libdir}/*.la
%changelog
+* 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
diff --git a/sg_cmds.c b/sg_cmds.c
index 318cf09d..134a479a 100644
--- a/sg_cmds.c
+++ b/sg_cmds.c
@@ -54,7 +54,7 @@
#include "sg_lib.h"
#include "sg_cmds.h"
-static char * version_str = "1.20 20050904";
+static char * version_str = "1.21 20051027";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -180,7 +180,7 @@ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Inquiry", &io_hdr, verbose);
+ sg_chk_n_print3("Inquiry", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
got = io_hdr.dxfer_len - io_hdr.resid;
@@ -206,7 +206,7 @@ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op,
pg_op);
else
snprintf(ebuff, EBUFF_SZ, "Inquiry error, [standard]");
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -2;
}
@@ -263,7 +263,7 @@ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Inquiry", &io_hdr, verbose);
+ sg_chk_n_print3("Inquiry", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
got = io_hdr.dxfer_len - io_hdr.resid;
@@ -295,7 +295,7 @@ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "Inquiry error ");
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -2;
}
@@ -303,8 +303,11 @@ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
/* Invokes a SCSI TEST UNIT READY command.
* 'pack_id' is just for diagnostics, safe to set to 0.
+ * Looks for progress indicator if 'progress' non-NULL;
+ * if found writes value [0..65535] else write -1.
* Return of 0 -> success, -1 -> failure */
-int sg_ll_test_unit_ready(int sg_fd, int pack_id, int noisy, int verbose)
+int sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress,
+ int noisy, int verbose)
{
int res, k;
unsigned char turCmbBlk[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0};
@@ -345,12 +348,26 @@ int sg_ll_test_unit_ready(int sg_fd, int pack_id, int noisy, int verbose)
case SG_LIB_CAT_CLEAN:
return 0;
default:
+ if (progress) {
+ if (! sg_get_sense_progress_fld(sense_b, sizeof(sense_b),
+ progress))
+ *progress = -1;
+ }
if (noisy || verbose)
- sg_chk_n_print3("test unit ready", &io_hdr, verbose);
+ sg_chk_n_print3("test unit ready", &io_hdr, (verbose > 1));
return -1;
}
}
+/* Invokes a SCSI TEST UNIT READY command.
+ * 'pack_id' is just for diagnostics, safe to set to 0.
+ * Return of 0 -> success, -1 -> failure */
+int sg_ll_test_unit_ready(int sg_fd, int pack_id, int noisy, int verbose)
+{
+ return sg_ll_test_unit_ready_progress(sg_fd, pack_id, NULL, noisy,
+ verbose);
+}
+
/* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success,
* -1 -> failure, SG_LIB_CAT_MEDIA_CHANGED -> repeat, SG_LIB_CAT_INVALID_OP
* -> cdb not supported, SG_LIB_CAT_IlLEGAL_REQ -> bad field in cdb */
@@ -420,7 +437,7 @@ int sg_ll_sync_cache_10(int sg_fd, int sync_nv, int immed, int group,
return res;
default:
if (noisy || verbose)
- sg_chk_n_print3("synchronize cache", &io_hdr, verbose);
+ sg_chk_n_print3("synchronize cache", &io_hdr, (verbose > 1));
return -1;
}
return 0;
@@ -488,7 +505,7 @@ int sg_ll_readcap_16(int sg_fd, int pmi, unsigned long long llba,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (verbose)
- sg_chk_n_print3("Read capacity (16)", &io_hdr, 1);
+ sg_chk_n_print3("Read capacity (16)", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -505,7 +522,7 @@ int sg_ll_readcap_16(int sg_fd, int pmi, unsigned long long llba,
default:
if (noisy || verbose)
sg_chk_n_print3("READ CAPACITY 16 command error", &io_hdr,
- verbose);
+ (verbose > 1));
return -1;
}
}
@@ -562,7 +579,7 @@ int sg_ll_readcap_10(int sg_fd, int pmi, unsigned int lba,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (verbose)
- sg_chk_n_print3("Read capacity (10)", &io_hdr, 1);
+ sg_chk_n_print3("Read capacity (10)", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -579,7 +596,7 @@ int sg_ll_readcap_10(int sg_fd, int pmi, unsigned int lba,
default:
if (noisy || verbose)
sg_chk_n_print3("READ CAPACITY 10 command error", &io_hdr,
- verbose);
+ (verbose > 1));
return -1;
}
}
@@ -637,7 +654,7 @@ int sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Mode sense (6)", &io_hdr, verbose);
+ sg_chk_n_print3("Mode sense (6)", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -665,7 +682,7 @@ int sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
snprintf(ebuff, EBUFF_SZ, "Mode sense (6) error, dbd=%d "
"pc=%d page_code=%x sub_page_code=%x\n ", dbd,
pc, pg_code, sub_pg_code);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -726,7 +743,7 @@ int sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Mode sense (10)", &io_hdr, verbose);
+ sg_chk_n_print3("Mode sense (10)", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -754,7 +771,7 @@ int sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code,
snprintf(ebuff, EBUFF_SZ, "Mode sense (10) error, dbd=%d "
"pc=%d page_code=%x sub_page_code=%x\n ", dbd,
pc, pg_code, sub_pg_code);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -815,7 +832,7 @@ int sg_ll_mode_select6(int sg_fd, int pf, int sp, void * paramp,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Mode select (6)", &io_hdr, verbose);
+ sg_chk_n_print3("Mode select (6)", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -830,7 +847,7 @@ int sg_ll_mode_select6(int sg_fd, int pf, int sp, void * paramp,
snprintf(ebuff, EBUFF_SZ, "Mode select (6) error, pf=%d "
"sp=%d\n ", pf, sp);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -892,7 +909,7 @@ int sg_ll_mode_select10(int sg_fd, int pf, int sp, void * paramp,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Mode select (10)", &io_hdr, verbose);
+ sg_chk_n_print3("Mode select (10)", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -907,7 +924,7 @@ int sg_ll_mode_select10(int sg_fd, int pf, int sp, void * paramp,
snprintf(ebuff, EBUFF_SZ, "Mode select (10) error, pf=%d "
"sp=%d\n ", pf, sp);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -1128,7 +1145,7 @@ int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (verbose)
- sg_chk_n_print3("Request sense", &io_hdr, 1);
+ sg_chk_n_print3("Request sense", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if ((mx_resp_len >= 8) && (io_hdr.resid > (mx_resp_len - 8))) {
@@ -1149,7 +1166,7 @@ int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len,
default:
if (noisy || verbose)
sg_chk_n_print3("REQUEST SENSE command problem", &io_hdr,
- verbose);
+ (verbose > 1));
return -1;
}
}
@@ -1203,7 +1220,7 @@ int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Report luns", &io_hdr, verbose);
+ sg_chk_n_print3("Report luns", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -1220,7 +1237,8 @@ int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
return 2;
default:
if (noisy || verbose)
- sg_chk_n_print3("REPORT LUNS command error", &io_hdr, verbose);
+ sg_chk_n_print3("REPORT LUNS command error", &io_hdr,
+ (verbose > 1));
return -1;
}
}
@@ -1281,7 +1299,7 @@ int sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Log sense", &io_hdr, verbose);
+ sg_chk_n_print3("Log sense", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -1300,7 +1318,7 @@ int sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code,
snprintf(ebuff, EBUFF_SZ, "log_sense: ppc=%d, sp=%d, "
"pc=%d, page_code=%x, paramp=%x\n ", ppc, sp, pc,
pg_code, paramp);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -1365,7 +1383,7 @@ int sg_ll_log_select(int sg_fd, int pcr, int sp, int pc,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Log select", &io_hdr, verbose);
+ sg_chk_n_print3("Log select", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -1379,7 +1397,7 @@ int sg_ll_log_select(int sg_fd, int pcr, int sp, int pc,
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "log_select: pcr=%d, sp=%d, "
"pc=%d\n ", pcr, sp, pc);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -1434,7 +1452,8 @@ int sg_ll_report_tgt_prt_grp(int sg_fd, void * resp,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Report target port groups", &io_hdr, verbose);
+ sg_chk_n_print3("Report target port groups", &io_hdr,
+ (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -1450,7 +1469,7 @@ int sg_ll_report_tgt_prt_grp(int sg_fd, void * resp,
default:
if (noisy || verbose)
sg_chk_n_print3("REPORT TARGET PORT GROUPS command error",
- &io_hdr, verbose);
+ &io_hdr, (verbose > 1));
return -1;
}
}
@@ -1512,7 +1531,8 @@ int sg_ll_send_diag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Send diagnostic, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("Send diagnostic, continuing", &io_hdr,
+ (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -1526,7 +1546,7 @@ int sg_ll_send_diag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "Send diagnostic error, sf_code=0x%x, "
"pf_bit=%d, sf_bit=%d ", sf_code, pf_bit, sf_bit);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -1582,7 +1602,7 @@ int sg_ll_receive_diag(int sg_fd, int pcv, int pg_code, void * resp,
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
sg_chk_n_print3("Receive diagnostics results, continuing",
- &io_hdr, verbose);
+ &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -1596,7 +1616,7 @@ int sg_ll_receive_diag(int sg_fd, int pcv, int pg_code, void * resp,
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "Receive diagnostics results error, "
"pcv=%d, page_code=%x ", pcv, pg_code);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -1656,7 +1676,7 @@ int sg_ll_read_defect10(int sg_fd, int req_plist, int req_glist,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Read defect (10)", &io_hdr, verbose);
+ sg_chk_n_print3("Read defect (10)", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -1684,7 +1704,7 @@ int sg_ll_read_defect10(int sg_fd, int req_plist, int req_glist,
snprintf(ebuff, EBUFF_SZ, "Read defect (10) error, req_plist=%d "
"req_glist=%d dl_format=%x\n ", req_plist, req_glist,
dl_format);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, (verbose > 1));
}
return -1;
}
@@ -1739,7 +1759,8 @@ int sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Read media serial number", &io_hdr, verbose);
+ sg_chk_n_print3("Read media serial number", &io_hdr,
+ (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -1763,7 +1784,7 @@ int sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len,
default:
if (noisy || verbose)
sg_chk_n_print3("READ MEDIA SERIAL NUMBER command error",
- &io_hdr, verbose);
+ &io_hdr, (verbose > 1));
return -1;
}
}
@@ -1789,8 +1810,8 @@ int sg_ll_start_stop_unit(int sg_fd, int immed, int power_cond,
if (verbose) {
fprintf(sg_warnings_str, " Start stop unit command:");
for (k = 0; k < (int)sizeof(ssuBlk); ++k)
- fprintf (stderr, " %02x", ssuBlk[k]);
- fprintf(stderr, "\n");
+ fprintf (sg_warnings_str, " %02x", ssuBlk[k]);
+ fprintf(sg_warnings_str, "\n");
}
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(ssuBlk);
@@ -1814,7 +1835,7 @@ int sg_ll_start_stop_unit(int sg_fd, int immed, int power_cond,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (verbose)
- sg_chk_n_print3("Start stop unit", &io_hdr, verbose);
+ sg_chk_n_print3("Start stop unit", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -1826,7 +1847,7 @@ int sg_ll_start_stop_unit(int sg_fd, int immed, int power_cond,
default:
if (noisy || verbose)
sg_chk_n_print3("START STOP UNIT command error", &io_hdr,
- verbose);
+ (verbose > 1));
return -1;
}
}
@@ -1880,7 +1901,8 @@ int sg_ll_prevent_allow(int sg_fd, int prevent, int noisy, int verbose)
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (verbose)
- sg_chk_n_print3("Prevent allow medium removal", &io_hdr, verbose);
+ sg_chk_n_print3("Prevent allow medium removal", &io_hdr,
+ (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -1893,7 +1915,7 @@ int sg_ll_prevent_allow(int sg_fd, int prevent, int noisy, int verbose)
default:
if (noisy || verbose)
sg_chk_n_print3("Prevent allow medium removal command problem",
- &io_hdr, verbose);
+ &io_hdr, (verbose > 1));
return -1;
}
}
@@ -1947,7 +1969,8 @@ int sg_ll_report_dev_id(int sg_fd, void * resp, int mx_resp_len,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Report device identifier", &io_hdr, verbose);
+ sg_chk_n_print3("Report device identifier", &io_hdr,
+ (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -1971,7 +1994,7 @@ int sg_ll_report_dev_id(int sg_fd, void * resp, int mx_resp_len,
default:
if (noisy || verbose)
sg_chk_n_print3("REPORT DEVICE IDENTIFIER command error",
- &io_hdr, verbose);
+ &io_hdr, (verbose > 1));
return -1;
}
}
@@ -2030,7 +2053,7 @@ int sg_ll_set_dev_id(int sg_fd, void * paramp, int param_len,
switch (res) {
case SG_LIB_CAT_RECOVERED:
if (noisy || verbose)
- sg_chk_n_print3("Set device identifier", &io_hdr, verbose);
+ sg_chk_n_print3("Set device identifier", &io_hdr, (verbose > 1));
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -2042,7 +2065,7 @@ int sg_ll_set_dev_id(int sg_fd, void * paramp, int param_len,
default:
if (noisy || verbose)
sg_chk_n_print3("SET DEVICE IDENTIFIER command error",
- &io_hdr, verbose);
+ &io_hdr, (verbose > 1));
return -1;
}
}
diff --git a/sg_cmds.h b/sg_cmds.h
index e8340394..fc6e1a1c 100644
--- a/sg_cmds.h
+++ b/sg_cmds.h
@@ -70,6 +70,10 @@ extern int sg_ll_sync_cache_10(int sg_fd, int sync_nv, int immed, int group,
extern int sg_ll_test_unit_ready(int sg_fd, int pack_id, int noisy,
int verbose);
+extern int sg_ll_test_unit_ready_progress(int sg_fd, int pack_id,
+ int * progress, int noisy,
+ int verbose);
+
extern int sg_ll_start_stop_unit(int sg_fd, int immed, int power_cond,
int loej, int start, int noisy, int verbose);
diff --git a/sg_dd.8 b/sg_dd.8
index 3e7888f7..4f83180e 100644
--- a/sg_dd.8
+++ b/sg_dd.8
@@ -1,14 +1,17 @@
-.TH SG_DD "8" "August 2005" "sg3_utils-1.16" SG3_UTILS
+.TH SG_DD "8" "November 2005" "sg3_utils-1.18" 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
-[\fIappend=0|1\fR] [\fIblk_sgio=0|1\fR] [\fIbpt=<n>\fR] [\fIbs=<n>\fR]
-[\fIcdbsz=6|10|12|16\fR] [\fIcoe=0|1\fR] [\fIcount=<n>\fR] [\fIdio=0|1\fR]
-[\fIfua=0|1|2|3\fR] [\fIibs=<n>\fR] [\fIif=<ifile>\fR] [\fIobs=<n>\fR]
-[\fIodir=0|1\fR] [\fIof=<ofile>\fR] [\fIseek=<n>\fR] [\fIskip=<n>\fR]
-[\fIsync=0|1\fR] [\fItime=0|1\fR] [\fIverbose=<n>\fR] [\fI--version\fR]
+[\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]
+.PP
+[\fIblk_sgio=0|1\fR] [\fIbpt=<n>\fR] [\fIcdbsz=6|10|12|16\fR]
+[\fIcoe=0|1\fR] [\fIdio=0|1\fR] [\fIodir=0|1\fR] [\fIsync=0|1\fR]
+[\fItime=0|1\fR] [\fIverbose=<n>\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -19,14 +22,6 @@ series). Similar syntax and semantics to
.B dd(1)
but does not perform any conversions.
.TP
-append=0 | 1
-when set to 1 the output will be appended to the normal file given
-to the "of=<name>" argument. Appending only takes place to normal files:
-not to pipes nor raw files nor sg devices nor block devices. Error
-message produced if append=1 and seek=<n> where <n> > 0. Default is 0
-which starts output at the beginning of a normal file (or at some other
-offset if the "seek=" argument is given).
-.TP
blk_sgio=0 | 1
when set to 0, block devices (e.g. /dev/sda) are treated like normal
files (i.e.
@@ -40,7 +35,7 @@ the SCSI command set but ATA disks do not (unless there is a protocol
conversion as often occurs in the USB mass storage class). If the input
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.
+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
@@ -51,7 +46,7 @@ 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. The block layer when the blk_sgio=1 option
is used has relatively low upper limits for transfer sizes (compared
-to sg device nodes).
+to sg device nodes, see /sys/block/<dev/queue/max_sectors_kb ).
.TP
bs=BYTES
this
@@ -66,18 +61,16 @@ IO operation is 'bs * bpt' bytes.
.TP
cdbsz=6 | 10 | 12 | 16
size of SCSI READ and/or WRITE commands issued on sg device
-names (or block devices when "blk_sgio=1" is given).
+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, in which case it defaults
to 16 byte SCSI commands).
.TP
coe=0 | 1
-set to 1 for continue on error: if reading assume zeros read, if writing
-then ignore and continue. Only applies to errors on sg devices (e.g.
-errors on normal files will stop sg_dd). Error messages are still sent to
-stderr. Similar to "conv=noerror" in the
-.B dd(1)
-utility. Default is 0 which implies stop on error.
+set to 1 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
@@ -97,12 +90,6 @@ 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
-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. 6 byte SCSI READ and WRITE commands (cdbsz=6) do not support the
-fua bit. Only active for sg device file names
-.TP
ibs=BYTES
if given must be the same as bs
.TP
@@ -110,12 +97,18 @@ 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.
.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.
+.TP
obs=BYTES
if given must be the same as bs
.TP
odir=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
@@ -126,7 +119,12 @@ 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 "append=1" or "seek" is given.
+overwritten from the start of FILE unless "oflag=append" or "seek" 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.
.TP
seek=BLOCKS
start writing BLOCKS bs-sized blocks from the start of the output file.
@@ -153,14 +151,88 @@ A value of 1 reports extra information that is not repetitive. A value
(i.e. other that READ and WRITE). Error processing is not considered
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.
-Non-zero verbose settings result in some caching mode page and read write
-error recovery mode page information being output prior to the copy.
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
+.TP
--version
outputs version number information and exits
-.PP
+.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
+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.
+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>.
+.TP
+coe
+continue on error. Only active for sg devices and block devices that
+have the "sgio" flag set. A medium or hardware error while reading
+will re-read blocks prior to the bad block, then use READ LONG on
+the bad block, supplying zeroes if that fails, and finally reread
+the blocks after the bad block. A medium error while writing is
+noted and ignored. SCSI disks may automatically try and remap
+faulty sectors (see the AWRE and ARRE in the read write error
+recoevry mode page (perhaps with the sdparm utility)).
+Errors on other files will stop sg_dd. Error messages are sent to
+stderr. Similar to "conv=noerror" in the
+.B dd(1)
+utility.
+.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.
+.TP
+dpo
+set the DPO bit (disable page out) in READ and WRITE SCSI 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).
+.TP
+excl
+causes the O_EXCL flag to be added to the open of <ifile> and/or <ofile>.
+.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 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.
+.TP
+sgio
+causes block devices to be accessed via the SG_IO ioctl rather than
+standard UNIX read() and write() commands. When the SG_IO ioctl is
+used the SCSI READ and WRITE commands are used directly to move
+data. sg devices always use the SG_IO ioctl. This flag offers finer
+grain control compared to the otherwise identical 'blk_sgio=1' option.
+.SH RETIRED OPTIONS
+Here are some retired options that are still present:
+.TP
+append=0 | 1
+when set, equivalent to "oflag=append". When clear the action is
+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.
+.SH NOTES
The exit status of the sg_dd utility is 0 when successful, 1 for
total failure (i.e. failed before copying data) and 2 when some
data has been copied (prior to some problem).
@@ -282,13 +354,16 @@ A POSIX threads version of this utility called
is in the sg3_utils package. Another version from that package is called
.B sgm_dd
and it uses memory mapped IO to speed transfers from sg devices.
+.PP
The lmbench package contains
.B lmdd
which is also interesting. For moving data to and from tapes see
.B dt
which is found at http://www.scsifaq.org/RMiller_Tools/index.html
-To change mode parameters that effect SCSI devices caching and error
+.PP
+To change mode parameters that effect a SCSI device's caching and error
recovery see
.B sdparm
+.PP
See also
.B raw(8), dd(1)
diff --git a/sg_dd.c b/sg_dd.c
index 94f061a0..cc0c57b4 100644
--- a/sg_dd.c
+++ b/sg_dd.c
@@ -49,7 +49,7 @@
This version is designed for the linux kernel 2.4 and 2.6 series.
*/
-static char * version_str = "5.42 20050909";
+static char * version_str = "5.44 20051118";
#define ME "sg_dd: "
@@ -110,7 +110,6 @@ static int recovered_errs = 0;
static int unrecovered_errs = 0;
static int read_longs = 0;
-static int do_coe = 0;
static int do_time = 0;
static int verbose = 0;
static int start_tm_valid = 0;
@@ -119,6 +118,20 @@ static int blk_sz = 0;
static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio";
+struct flags_t {
+ int append;
+ int coe;
+ int direct;
+ int dpo;
+ int dsync;
+ int excl;
+ int fua;
+ int sgio;
+};
+
+static struct flags_t iflag;
+static struct flags_t oflag;
+
static void calc_duration_throughput();
static void install_handler (int sig_num, void (*sig_handler) (int sig))
@@ -144,7 +157,7 @@ static void print_stats(const char * str)
out_partial);
if (recovered_errs > 0)
fprintf(stderr, "%s%d recovered errors\n", str, recovered_errs);
- if (do_coe) {
+ if (iflag.coe || oflag.coe) {
fprintf(stderr, "%s%d unrecovered errors\n", str, unrecovered_errs);
fprintf(stderr, "%s%d read_longs fetched part of unrecovered "
"read errors\n", str, read_longs);
@@ -223,14 +236,16 @@ static char * dd_filetype_str(int ft, char * buff)
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_dd [if=<infile>] [skip=<n>] [of=<ofile>] [seek=<n> | "
- "append=0|1]\n"
- " [bs=<num>] [bpt=<num>] [count=<n>] [time=0|1]"
- " [dio=0|1]\n"
- " [sync=0|1] [cdbsz=6|10|12|16] [fua=0|1|2|3]"
- " [coe=0|1]\n"
- " [odir=0|1] [blk_sgio=0|1] [verbose=<n>]"
- " [--version]\n"
+ "sg_dd [bs=<n>] [count=<n>] [ibs=<n>] [if=<infile>]"
+ " [iflag=<flags>]\n"
+ " [obs=<n>] [of=<ofile>] [oflag=<flags>]"
+ "[seek=<n>] [skip=<n>]\n"
+ " [--help] [--version]\n\n"
+ " [append=0|1] [bpt=<n>] [blk_sgio=0|1]"
+ " [cdbsz=6|10|12|16]\n"
+ " [coe=0|1] [dio=0|1] [fua=0|1|2|3] [odir=0|1]"
+ " [sync=0|1]\n"
+ " [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"
@@ -241,23 +256,29 @@ static void usage()
" 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), try read_long on unrecovered read block\n"
- " dio is direct IO, 1->attempt, 0->indirect IO (def)\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 to\n");
+ "translated\n");
fprintf(stderr,
- " /dev/null\n"
+ " to /dev/null\n"
+ " oflag comma separated list from: [append,coe,direct,dpo,"
+ "dsync,excl,\n"
+ " fua,sgio]\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"
+ " 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");
}
@@ -441,7 +462,7 @@ static int sg_ll_read_long10(int sg_fd, int correct, unsigned long lba,
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("READ LONG(10), continuing", &io_hdr, vverbose);
+ sg_chk_n_print3("READ LONG(10), continuing", &io_hdr, vverbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -566,14 +587,15 @@ static int sg_build_scsi_cdb(unsigned char * cdbp, int cdb_sz,
-1 -> other SCSI error */
static int sg_read_low(int sg_fd, unsigned char * buff, int blocks,
long long from_block, int bs, int cdbsz, int fua,
- int pdt, int * diop, unsigned long long * io_addrp)
+ int dpo, int pdt, int * diop,
+ unsigned long long * io_addrp)
{
unsigned char rdCmd[MAX_SCSI_CDBSZ];
unsigned char senseBuff[SENSE_BUFF_LEN];
struct sg_io_hdr io_hdr;
int res, k, info_valid;
- if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, 0)) {
+ if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, dpo)) {
fprintf(stderr, ME "bad rd cdb build, from_block=%lld, blocks=%d\n",
from_block, blocks);
return -2;
@@ -624,7 +646,7 @@ static int sg_read_low(int sg_fd, unsigned char * buff, int blocks,
} else {
fprintf(stderr, "Recovered error: [no info] reading from "
"block=0x%llx, num=%d\n", from_block, blocks);
- sg_chk_n_print3("reading", &io_hdr, verbose);
+ sg_chk_n_print3("reading", &io_hdr, verbose > 1);
}
break;
case SG_LIB_CAT_MEDIA_CHANGED:
@@ -647,7 +669,7 @@ static int sg_read_low(int sg_fd, unsigned char * buff, int blocks,
break;
default:
++unrecovered_errs;
- sg_chk_n_print3("reading", &io_hdr, verbose);
+ sg_chk_n_print3("reading", &io_hdr, verbose > 1);
return -1;
}
if (diop && *diop &&
@@ -661,7 +683,7 @@ static int sg_read_low(int sg_fd, unsigned char * buff, int blocks,
-2 -> recoverable (ENOMEM) */
static int sg_read(int sg_fd, unsigned char * buff, int blocks,
long long from_block, int bs, int cdbsz, int fua,
- int * diop, int pdt)
+ int dpo, int * diop, int pdt)
{
unsigned long long io_addr;
long long lba;
@@ -672,7 +694,7 @@ static int sg_read(int sg_fd, unsigned char * buff, int blocks,
blks > 0; blks = blocks - xferred) {
io_addr = 0;
cont = 0;
- res = sg_read_low(sg_fd, bp, blks, lba, bs, cdbsz, fua, pdt,
+ res = sg_read_low(sg_fd, bp, blks, lba, bs, cdbsz, fua, dpo, pdt,
diop, &io_addr);
switch (res) {
case 0:
@@ -687,7 +709,7 @@ static int sg_read(int sg_fd, unsigned char * buff, int blocks,
case -1:
goto err_out;
case -2:
- do_coe = 0;
+ iflag.coe = 0;
goto err_out;
case 3:
break; /* unrecovered read error at lba=io_addr */
@@ -708,7 +730,7 @@ static int sg_read(int sg_fd, unsigned char * buff, int blocks,
}
blks = (int)(io_addr - (unsigned long long)lba);
if (blks > 0) {
- res = sg_read_low(sg_fd, bp, blks, lba, bs, cdbsz, fua,
+ res = sg_read_low(sg_fd, bp, blks, lba, bs, cdbsz, fua, dpo,
pdt, diop, &io_addr);
switch (res) {
case 0:
@@ -721,7 +743,7 @@ static int sg_read(int sg_fd, unsigned char * buff, int blocks,
"Unit attention, media changed, unexpected (r)\n");
return -1;
case -2:
- do_coe = 0;
+ iflag.coe = 0;
goto err_out;
case -1: case 3:
goto err_out;
@@ -732,7 +754,7 @@ static int sg_read(int sg_fd, unsigned char * buff, int blocks,
}
}
xferred += blks;
- if (! do_coe)
+ if (! iflag.coe)
return xferred; /* give up at block before problem unless 'coe' */
if (bs < 32) {
fprintf(stderr, ">> bs=%d too small for read_long\n", bs);
@@ -806,7 +828,7 @@ static int sg_read(int sg_fd, unsigned char * buff, int blocks,
return xferred;
err_out:
- if (do_coe) {
+ if (iflag.coe) {
memset(bp, 0, bs * blks);
fprintf(stderr, ">> unable to read at blk=%lld for "
"%d bytes, use zeros\n", lba, bs * blks);
@@ -818,7 +840,7 @@ err_out:
/* 0 -> successful, -1 -> unrecoverable error, -2 -> recoverable (ENOMEM),
-3 -> try again (media changed unit attention) */
static int sg_write(int sg_fd, unsigned char * buff, int blocks,
- long long to_block, int bs, int cdbsz, int fua,
+ long long to_block, int bs, int cdbsz, int fua, int dpo,
int * diop)
{
unsigned char wrCmd[MAX_SCSI_CDBSZ];
@@ -827,7 +849,7 @@ static int sg_write(int sg_fd, unsigned char * buff, int blocks,
int res, k, info_valid;
unsigned long long io_addr = 0;
- if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, 0)) {
+ if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, dpo)) {
fprintf(stderr, ME "bad wr cdb build, to_block=%lld, blocks=%d\n",
to_block, blocks);
return -1;
@@ -879,7 +901,7 @@ static int sg_write(int sg_fd, unsigned char * buff, int blocks,
} else {
fprintf(stderr, "Recovered error: [no info] writing to "
"block=0x%llx, num=%d\n", to_block, blocks);
- sg_chk_n_print3("writing", &io_hdr, verbose);
+ sg_chk_n_print3("writing", &io_hdr, verbose > 1);
}
break;
case SG_LIB_CAT_MEDIA_CHANGED:
@@ -887,8 +909,8 @@ static int sg_write(int sg_fd, unsigned char * buff, int blocks,
sg_chk_n_print3("writing", &io_hdr, 1);
return -3;
default:
- sg_chk_n_print3("writing", &io_hdr, verbose);
- if (do_coe) {
+ sg_chk_n_print3("writing", &io_hdr, verbose > 1);
+ if (oflag.coe) {
fprintf(stderr, ">> ignored errors for out blk=%lld for "
"%d bytes\n", to_block, bs * blocks);
return 0; /* fudge success */
@@ -927,121 +949,46 @@ static void calc_duration_throughput()
}
}
-static void print_mp_bit(const char * pre, int smask, int byte_off,
- int bit_mask, const unsigned char * cur_mp,
- const unsigned char * cha_mp, const unsigned char * def_mp,
- const unsigned char * sav_mp)
+static int process_flags(const char * arg, struct flags_t * fp)
{
- int sep = 0;
-
- fprintf(stderr, "%s%d", pre, !!(cur_mp[byte_off] & bit_mask));
- if (smask & 0xe) {
- fprintf(stderr, " [");
- if (smask & 2) {
- fprintf(stderr, "cha: %s",
- (cha_mp[byte_off] & bit_mask) ? "y" : "n");
- sep = 1;
- }
- if (smask & 4) {
- fprintf(stderr, "%sdef: %d", (sep ? ", " : " "),
- !!(def_mp[2] & bit_mask));
- sep = 1;
- }
- if (smask & 8)
- fprintf(stderr, "%ssav: %d", (sep ? ", " : " "),
- !!(sav_mp[2] & bit_mask));
- fprintf(stderr, "]\n");
- } else
- fprintf(stderr, "\n");
-}
-
-static void print_scsi_dev_info(int sg_fd, int pdt)
-{
- int res, verb, smask;
- unsigned char cur_mp[DEF_MODE_RESP_LEN];
- unsigned char cha_mp[DEF_MODE_RESP_LEN];
- unsigned char def_mp[DEF_MODE_RESP_LEN];
- unsigned char sav_mp[DEF_MODE_RESP_LEN];
- int mode6;
- void * pc_arr[4];
-
- mode6 = (6 == DEF_MODE_CDB_SZ) ? 1 : 0;
- verb = (verbose > 0) ? verbose - 1 : 0;
- pc_arr[0] = cur_mp;
- pc_arr[1] = cha_mp;
- pc_arr[2] = def_mp;
- pc_arr[3] = sav_mp;
- res = sg_get_mode_page_controls(sg_fd, mode6, RW_ERR_RECOVERY_MP,
- 0 /* subpage */, 0 /*dbd */,
- 1 /* flexible */, DEF_MODE_RESP_LEN,
- &smask, pc_arr, NULL /* rep_len */, verb);
- if (SG_LIB_CAT_INVALID_OP == res) {
- mode6 = !mode6; /* flip between mode sense(10) and (6) */
- res = sg_get_mode_page_controls(sg_fd, mode6, RW_ERR_RECOVERY_MP,
- 0 /* subpage */, 0 /* dbd */,
- 1 /* flexible */, DEF_MODE_RESP_LEN,
- &smask, pc_arr, NULL /* rep_len */,
- verb);
- }
- if (0 == (smask & 1)) {
- if (verbose > 1)
- fprintf(stderr, " Read write error recovery mode page not "
- "supported, res=%d\n", res);
- } else if (cur_mp[1] < 0xa)
- fprintf(stderr, " Read write error recovery mode page too "
- "short, page len=%d\n", cur_mp[1]);
- else {
- fprintf(stderr, " Read write error recovery mode page:\n");
- print_mp_bit(" AWRE: ", smask, 2, 0x80, cur_mp, cha_mp,
- def_mp, sav_mp);
- print_mp_bit(" ARRE: ", smask, 2, 0x40, cur_mp, cha_mp,
- def_mp, sav_mp);
- print_mp_bit(" RC: ", smask, 2, 0x10, cur_mp, cha_mp,
- def_mp, sav_mp);
- if (0 == pdt)
- print_mp_bit(" EER: ", smask, 2, 0x8, cur_mp, cha_mp,
- def_mp, sav_mp);
- print_mp_bit(" PER: ", smask, 2, 0x4, cur_mp, cha_mp,
- def_mp, sav_mp);
- print_mp_bit(" DTE: ", smask, 2, 0x2, cur_mp, cha_mp,
- def_mp, sav_mp);
- print_mp_bit(" DCR: ", smask, 2, 0x1, cur_mp, cha_mp,
- def_mp, sav_mp);
- }
- res = sg_get_mode_page_controls(sg_fd, mode6, CACHING_MP, 0 /* subpage */,
- 0 /* dbd */, 1 /* flexible */,
- DEF_MODE_RESP_LEN, &smask, pc_arr,
- NULL /* rep_len */, verb);
- if (0 == (smask & 1)) {
- if (verbose > 1)
- fprintf(stderr, " Caching mode page not "
- "supported, res=%d\n", res);
- } else if (cur_mp[1] < 0xa)
- fprintf(stderr, " Caching mode page too "
- "short, page len=%d\n", cur_mp[1]);
- else {
- fprintf(stderr, " Caching mode page:\n");
- print_mp_bit(" WCE: ", smask, 2, 0x4, cur_mp, cha_mp,
- def_mp, sav_mp);
- print_mp_bit(" RCD: ", smask, 2, 0x1, cur_mp, cha_mp,
- def_mp, sav_mp);
- }
- res = sg_get_mode_page_controls(sg_fd, mode6, CONTROL_MP, 0 /* subpage */,
- 0 /* dbd */, 1 /* flexible */,
- DEF_MODE_RESP_LEN, &smask, pc_arr,
- NULL /* rep_len */, verb);
- if (0 == (smask & 1)) {
- if (verbose > 1)
- fprintf(stderr, " Control mode page not "
- "supported, res=%d\n", res);
- } else if (cur_mp[1] < 0xa)
- fprintf(stderr, " Control mode page too "
- "short, page len=%d\n", cur_mp[1]);
- else {
- fprintf(stderr, " Control mode page:\n");
- print_mp_bit(" SWP: ", smask, 4, 0x8, cur_mp, cha_mp,
- def_mp, sav_mp);
+ char buff[256];
+ char * cp;
+ char * np;
+
+ strncpy(buff, arg, sizeof(buff));
+ buff[sizeof(buff) - 1] = '\0';
+ if ('\0' == buff[0]) {
+ fprintf(stderr, "no flag found\n");
+ return 1;
}
+ cp = buff;
+ do {
+ np = strchr(cp, ',');
+ if (np)
+ *np++ = '\0';
+ if (0 == strcmp(cp, "append"))
+ fp->append = 1;
+ else if (0 == strcmp(cp, "coe"))
+ fp->coe = 1;
+ else if (0 == strcmp(cp, "direct"))
+ fp->direct = 1;
+ else if (0 == strcmp(cp, "dpo"))
+ fp->dpo = 1;
+ else if (0 == strcmp(cp, "dsync"))
+ fp->dsync = 1;
+ else if (0 == strcmp(cp, "excl"))
+ fp->excl = 1;
+ else if (0 == strcmp(cp, "fua"))
+ fp->fua = 1;
+ else if (0 == strcmp(cp, "sgio"))
+ fp->sgio = 1;
+ else {
+ fprintf(stderr, "unrecognised flag: %s\n", cp);
+ return 1;
+ }
+ cp = np;
+ } while (cp);
+ return 0;
}
@@ -1062,15 +1009,11 @@ int main(int argc, char * argv[])
int out_type = FT_OTHER;
int dio = 0;
int dio_incomplete = 0;
- int do_odir = 0;
int scsi_cdbsz_in = DEF_SCSI_CDBSZ;
int scsi_cdbsz_out = DEF_SCSI_CDBSZ;
- int fua_mode = 0;
int do_sync = 0;
- int do_blk_sgio = 0;
- int do_append = 0;
int verb = 0;
- int res, k, t, buf_sz, dio_tmp, flags;
+ int res, k, t, buf_sz, dio_tmp, flags, fl;
int infd, outfd, blocks, in_pdt, out_pdt;
unsigned char * wrkBuff;
unsigned char * wrkPos;
@@ -1086,7 +1029,7 @@ int main(int argc, char * argv[])
if (argc < 2) {
fprintf(stderr,
"Can't have both 'if' as stdin _and_ 'of' as stdout\n");
- usage();
+ fprintf(stderr, "For more information use '--help'\n");
return 1;
}
@@ -1101,81 +1044,100 @@ int main(int argc, char * argv[])
buf++;
if (*buf)
*buf++ = '\0';
- if (strcmp(key,"if") == 0) {
+ if (0 == strncmp(key, "app", 3)) {
+ iflag.append = sg_get_num(buf);
+ oflag.append = iflag.append;
+ } else if (0 == strcmp(key, "blk_sgio")) {
+ iflag.sgio = sg_get_num(buf);
+ oflag.sgio = iflag.sgio;
+ } else if (0 == strcmp(key, "bpt")) {
+ bpt = sg_get_num(buf);
+ if (-1 == bpt) {
+ fprintf(stderr, ME "bad argument to 'bpt'\n");
+ return 1;
+ }
+ 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");
+ return 1;
+ }
+ } else if (0 == strcmp(key, "cdbsz")) {
+ scsi_cdbsz_in = sg_get_num(buf);
+ scsi_cdbsz_out = scsi_cdbsz_in;
+ } else if (0 == strcmp(key, "coe")) {
+ iflag.coe = sg_get_num(buf);
+ oflag.coe = iflag.coe;
+ } else if (0 == strcmp(key, "count")) {
+ dd_count = sg_get_llnum(buf);
+ if (-1LL == dd_count) {
+ fprintf(stderr, ME "bad argument to 'count'\n");
+ return 1;
+ }
+ } else if (0 == strcmp(key, "dio"))
+ dio = sg_get_num(buf);
+ else if (0 == strcmp(key, "fua")) {
+ t = sg_get_num(buf);
+ oflag.fua = (t & 1) ? 1 : 0;
+ iflag.fua = (t & 2) ? 1 : 0;
+ } else if (0 == strcmp(key, "ibs"))
+ ibs = sg_get_num(buf);
+ else if (strcmp(key, "if") == 0) {
if ('\0' != inf[0]) {
fprintf(stderr, "Second 'if=' argument??\n");
return 1;
} else
strncpy(inf, buf, INOUTF_SZ);
- } else if (strcmp(key,"of") == 0) {
+ } else if (0 == strcmp(key, "iflag")) {
+ if (process_flags(buf, &iflag)) {
+ fprintf(stderr, ME "bad argument to 'iflag'\n");
+ return 1;
+ }
+ } else if (0 == strcmp(key, "obs"))
+ obs = sg_get_num(buf);
+ else if (0 == strcmp(key, "odir")) {
+ iflag.direct = sg_get_num(buf);
+ oflag.direct = iflag.direct;
+ } else if (strcmp(key, "of") == 0) {
if ('\0' != outf[0]) {
fprintf(stderr, "Second 'of=' argument??\n");
return 1;
} else
strncpy(outf, buf, INOUTF_SZ);
- } else if (0 == strcmp(key,"ibs"))
- ibs = sg_get_num(buf);
- else if (0 == strcmp(key,"obs"))
- obs = sg_get_num(buf);
- else if (0 == strcmp(key,"bs")) {
- blk_sz = sg_get_num(buf);
- if (-1 == blk_sz) {
- fprintf(stderr, ME "bad argument to 'bs'\n");
+ } else if (0 == strcmp(key, "oflag")) {
+ if (process_flags(buf, &oflag)) {
+ fprintf(stderr, ME "bad argument to 'oflag'\n");
return 1;
}
- } else if (0 == strcmp(key,"bpt")) {
- bpt = sg_get_num(buf);
- if (-1 == bpt) {
- fprintf(stderr, ME "bad argument to 'bpt'\n");
- return 1;
- }
- bpt_given = 1;
- } else if (0 == strcmp(key,"skip")) {
- skip = sg_get_llnum(buf);
- if (-1LL == skip) {
- fprintf(stderr, ME "bad argument to 'skip'\n");
- return 1;
- }
- } else if (0 == strcmp(key,"seek")) {
+ } else if (0 == strcmp(key, "seek")) {
seek = sg_get_llnum(buf);
if (-1LL == seek) {
fprintf(stderr, ME "bad argument to 'seek'\n");
return 1;
}
- } else if (0 == strcmp(key,"count")) {
- dd_count = sg_get_llnum(buf);
- if (-1LL == dd_count) {
- fprintf(stderr, ME "bad argument to 'count'\n");
+ } else if (0 == strcmp(key, "skip")) {
+ skip = sg_get_llnum(buf);
+ if (-1LL == skip) {
+ fprintf(stderr, ME "bad argument to 'skip'\n");
return 1;
}
- } else if (0 == strcmp(key,"dio"))
- dio = sg_get_num(buf);
- else if (0 == strcmp(key,"coe"))
- do_coe = sg_get_num(buf);
- else if (0 == strcmp(key,"time"))
- do_time = sg_get_num(buf);
- else if (0 == strcmp(key,"cdbsz")) {
- scsi_cdbsz_in = sg_get_num(buf);
- scsi_cdbsz_out = scsi_cdbsz_in;
- } else if (0 == strcmp(key,"fua"))
- fua_mode = sg_get_num(buf);
- else if (0 == strcmp(key,"sync"))
+ } else if (0 == strcmp(key, "sync"))
do_sync = sg_get_num(buf);
- else if (0 == strcmp(key,"odir"))
- do_odir = sg_get_num(buf);
- else if (0 == strcmp(key,"blk_sgio"))
- do_blk_sgio = sg_get_num(buf);
- else if (0 == strncmp(key,"app", 3))
- do_append = sg_get_num(buf);
+ else if (0 == strcmp(key, "time"))
+ do_time = sg_get_num(buf);
else if (0 == strncmp(key, "verb", 4)) {
verbose = sg_get_num(buf);
verb = (verbose ? verbose - 1: 0);
+ } else if (0 == strncmp(key, "--help", 7)) {
+ usage();
+ return 0;
} else if (0 == strncmp(key, "--vers", 6)) {
fprintf(stderr, ME "%s\n", version_str);
return 0;
} else {
- fprintf(stderr, "Unrecognized argument '%s'\n", key);
- usage();
+ fprintf(stderr, "Unrecognized option '%s'\n", key);
+ fprintf(stderr, "For more information use '--help'\n");
return 1;
}
}
@@ -1186,14 +1148,14 @@ int main(int argc, char * argv[])
}
if ((ibs && (ibs != blk_sz)) || (obs && (obs != blk_sz))) {
fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n");
- usage();
+ fprintf(stderr, "For more information use '--help'\n");
return 1;
}
if ((skip < 0) || (seek < 0)) {
fprintf(stderr, "skip and seek cannot be negative\n");
return 1;
}
- if ((do_append > 0) && (seek > 0)) {
+ if ((oflag.append > 0) && (seek > 0)) {
fprintf(stderr, "Can't use both append and seek switches\n");
return 1;
}
@@ -1225,22 +1187,24 @@ int main(int argc, char * argv[])
fprintf(stderr, " >> Input file type: %s\n",
dd_filetype_str(in_type, ebuff));
- if ((FT_BLOCK & in_type) && do_blk_sgio)
+ if ((FT_BLOCK & in_type) && iflag.sgio)
in_type |= FT_SG;
if (FT_ST & in_type) {
fprintf(stderr, ME "unable to use scsi tape device %s\n", inf);
return 1;
- }
- else if (FT_SG & in_type) {
- flags = O_RDWR | O_NONBLOCK;
- if ((do_odir && (FT_BLOCK & in_type)))
+ } else if (FT_SG & in_type) {
+ flags = O_NONBLOCK;
+ if (iflag.direct)
flags |= O_DIRECT;
- if ((infd = open(inf, flags)) < 0) {
- flags = O_RDONLY | O_NONBLOCK;
- if ((do_odir && (FT_BLOCK & in_type)))
- flags |= O_DIRECT;
- if ((infd = open(inf, flags)) < 0) {
+ if (iflag.excl)
+ flags |= O_EXCL;
+ if (iflag.dsync)
+ flags |= O_SYNC;
+ fl = O_RDONLY;
+ if ((infd = open(inf, fl | flags)) < 0) {
+ fl = O_RDWR;
+ if ((infd = open(inf, fl | flags)) < 0) {
snprintf(ebuff, EBUFF_SZ,
ME "could not open %s for sg reading", inf);
perror(ebuff);
@@ -1249,7 +1213,7 @@ int main(int argc, char * argv[])
}
if (verbose)
fprintf(stderr, " open input(sg_io), flags=0x%x\n",
- flags);
+ fl | flags);
if (sg_simple_inquiry(infd, &sir, 0, verb)) {
fprintf(stderr, "INQUIRY failed on %s\n", inf);
return -1;
@@ -1273,13 +1237,15 @@ int main(int argc, char * argv[])
return 1;
}
}
- if (verbose)
- print_scsi_dev_info(infd, in_pdt);
}
else {
flags = O_RDONLY;
- if (do_odir && (FT_BLOCK & in_type))
+ if (iflag.direct)
flags |= O_DIRECT;
+ if (iflag.excl)
+ flags |= O_EXCL;
+ if (iflag.dsync)
+ flags |= O_SYNC;
infd = open(inf, flags);
if (infd < 0) {
snprintf(ebuff, EBUFF_SZ,
@@ -1315,7 +1281,7 @@ int main(int argc, char * argv[])
fprintf(stderr, " >> Output file type: %s\n",
dd_filetype_str(out_type, ebuff));
- if ((FT_BLOCK & out_type) && do_blk_sgio)
+ if ((FT_BLOCK & out_type) && oflag.sgio)
out_type |= FT_SG;
if (FT_ST & out_type) {
@@ -1324,8 +1290,12 @@ int main(int argc, char * argv[])
}
else if (FT_SG & out_type) {
flags = O_RDWR | O_NONBLOCK;
- if ((do_odir && (FT_BLOCK & out_type)))
+ if (oflag.direct)
flags |= O_DIRECT;
+ if (oflag.excl)
+ flags |= O_EXCL;
+ if (oflag.dsync)
+ flags |= O_SYNC;
if ((outfd = open(outf, flags)) < 0) {
snprintf(ebuff, EBUFF_SZ,
ME "could not open %s for sg writing", outf);
@@ -1354,17 +1324,19 @@ int main(int argc, char * argv[])
return 1;
}
}
- if (verbose)
- print_scsi_dev_info(outfd, out_pdt);
}
else if (FT_DEV_NULL & out_type)
outfd = -1; /* don't bother opening */
else {
if (! (FT_RAW & out_type)) {
flags = O_WRONLY | O_CREAT;
- if (do_odir && (FT_BLOCK & out_type) && (! (FT_SG & out_type)))
+ if (oflag.direct)
flags |= O_DIRECT;
- else if (do_append && (! (FT_BLOCK & out_type)))
+ if (oflag.excl)
+ flags |= O_EXCL;
+ if (oflag.dsync)
+ flags |= O_SYNC;
+ if (oflag.append)
flags |= O_APPEND;
if ((outfd = open(outf, flags, 0666)) < 0) {
snprintf(ebuff, EBUFF_SZ,
@@ -1375,6 +1347,12 @@ int main(int argc, char * argv[])
}
else {
flags = O_WRONLY;
+ if (oflag.direct)
+ flags |= O_DIRECT;
+ if (oflag.excl)
+ flags |= O_EXCL;
+ if (oflag.dsync)
+ flags |= O_SYNC;
if ((outfd = open(outf, flags)) < 0) {
snprintf(ebuff, EBUFF_SZ,
ME "could not open %s for raw writing", outf);
@@ -1403,6 +1381,7 @@ int main(int argc, char * argv[])
if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) {
fprintf(stderr,
"Can't have both 'if' as stdin _and_ 'of' as stdout\n");
+ fprintf(stderr, "For more information use '--help'\n");
return 1;
}
@@ -1510,7 +1489,8 @@ int main(int argc, char * argv[])
scsi_cdbsz_out = MAX_SCSI_CDBSZ;
}
- if (dio || do_odir || (FT_RAW & in_type) || (FT_RAW & out_type)) {
+ if (dio || iflag.direct || oflag.direct || (FT_RAW & in_type) ||
+ (FT_RAW & out_type)) {
size_t psz = getpagesize();
wrkBuff = malloc(blk_sz * bpt + psz);
if (0 == wrkBuff) {
@@ -1546,11 +1526,9 @@ int main(int argc, char * argv[])
while (dd_count > 0) {
blocks = (dd_count > blocks_per) ? blocks_per : dd_count;
if (FT_SG & in_type) {
- int fua = fua_mode & 2;
-
dio_tmp = dio;
res = sg_read(infd, wrkPos, blocks, skip, blk_sz, scsi_cdbsz_in,
- fua, &dio_tmp, in_pdt);
+ iflag.fua, iflag.dpo, &dio_tmp, in_pdt);
if (-2 == res) { /* ENOMEM, find what's available+try that */
if (ioctl(infd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) {
perror("RESERVED_SIZE ioctls failed");
@@ -1562,7 +1540,8 @@ int main(int argc, char * argv[])
fprintf(stderr, "Reducing read to %d blocks per "
"loop\n", blocks_per);
res = sg_read(infd, wrkPos, blocks, skip, blk_sz,
- scsi_cdbsz_in, fua, &dio_tmp, in_pdt);
+ scsi_cdbsz_in, iflag.fua, iflag.dpo,
+ &dio_tmp, in_pdt);
}
}
if (res < 0) {
@@ -1607,11 +1586,9 @@ int main(int argc, char * argv[])
break; /* nothing read so leave loop */
if (FT_SG & out_type) {
- int fua = fua_mode & 1;
-
dio_tmp = dio;
res = sg_write(outfd, wrkPos, blocks, seek, blk_sz,
- scsi_cdbsz_out, fua, &dio_tmp);
+ scsi_cdbsz_out, oflag.fua, oflag.dpo, &dio_tmp);
if (-2 == res) { /* ENOMEM, find what's available+try that */
if (ioctl(outfd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) {
perror("RESERVED_SIZE ioctls failed");
@@ -1623,14 +1600,16 @@ int main(int argc, char * argv[])
fprintf(stderr,
"Reducing write to %d blocks per loop\n", blocks);
res = sg_write(outfd, wrkPos, blocks, seek, blk_sz,
- scsi_cdbsz_out, fua, &dio_tmp);
+ scsi_cdbsz_out, oflag.fua, oflag.dpo,
+ &dio_tmp);
}
}
else if (-3 == res) {
fprintf(stderr,
"Unit attention, media changed, continuing (w)\n");
res = sg_write(outfd, wrkPos, blocks, seek, blk_sz,
- scsi_cdbsz_out, fua, &dio_tmp);
+ scsi_cdbsz_out, oflag.fua, oflag.dpo,
+ &dio_tmp);
}
if (res < 0) {
fprintf(stderr, "sg_write failed,%s seek=%lld\n",
diff --git a/sg_format.c b/sg_format.c
index dcc6bae4..30cdc3fa 100644
--- a/sg_format.c
+++ b/sg_format.c
@@ -68,7 +68,7 @@ static unsigned char sbuff[MAX_SENSE_SZ];
#define MAX_BUFF_SZ 252
static unsigned char dbuff[MAX_BUFF_SZ];
-static char * version_str = "1.05 20050908";
+static char * version_str = "1.06 20051025";
static struct option long_options[] = {
{"count", 1, 0, 'c'},
@@ -178,7 +178,7 @@ scsi_format(int fd, int pinfo, int rto_req, int immed, int early, int verbose)
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Format, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("Format, continuing", &io_hdr, verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
break;
@@ -210,56 +210,15 @@ scsi_format(int fd, int pinfo, int rto_req, int immed, int early, int verbose)
for(;;) {
int progress;
- struct sg_scsi_sense_hdr sshdr;
sleep(POLL_DURATION_SECS);
- cdb[0] = TEST_UNIT_READY; /* draft say REQUEST SENSE */
- cdb[1] = 0;
- cdb[2] = 0;
- cdb[3] = 0;
- cdb[4] = 0;
- cdb[5] = 0;
-
- memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
- memset(sbuff, 0, MAX_SENSE_SZ);
-
- io_hdr.interface_id = 'S';
- io_hdr.dxfer_direction = SG_DXFER_NONE;
- io_hdr.cmd_len = CDB_SIZE;
- io_hdr.mx_sb_len = MAX_SENSE_SZ;
- io_hdr.iovec_count = 0; /* no scatter gather */
- io_hdr.dxfer_len = 0;
- io_hdr.dxferp = NULL;
- io_hdr.cmdp = cdb;
- io_hdr.sbp = sbuff;
- io_hdr.timeout = SHORT_TIMEOUT;
-
- if (verbose) {
- fprintf(stderr, " test unit ready cdb: ");
- for (k = 0; k < 6; ++k)
- fprintf(stderr, "%02x ", cdb[k]);
- fprintf(stderr, "\n");
- }
-
- if (ioctl(fd, SG_IO, &io_hdr) < 0) {
- perror("Test Unit Ready SG_IO ioctl error");
- return -1;
- }
- if (sg_normalize_sense(&io_hdr, &sshdr)) {
- if (sg_get_sense_progress_fld(sbuff,
- io_hdr.sb_len_wr, &progress)) {
- printf("Format in progress, %d%% done\n",
- progress * 100 / 65536);
- if (verbose > 1)
- sg_print_sense("tur", sbuff,
- io_hdr.sb_len_wr, 1);
- continue;
- } else {
- sg_print_sense("tur: unexpected sense", sbuff,
- io_hdr.sb_len_wr, verbose);
- continue;
- }
- } else
+ progress = -1;
+ res = sg_ll_test_unit_ready_progress(fd, 0, &progress, 0,
+ verbose);
+ if (progress >= 0)
+ printf("Format in progress, %d%% done\n",
+ (progress * 100) / 65536);
+ else
break;
}
printf("FORMAT Complete\n");
diff --git a/sg_get_config.c b/sg_get_config.c
index 971e1dc3..55416292 100644
--- a/sg_get_config.c
+++ b/sg_get_config.c
@@ -49,7 +49,7 @@
*/
-static char * version_str = "0.19 20050806";
+static char * version_str = "0.20 20051025";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -137,7 +137,7 @@ static int sg_ll_get_config(int sg_fd, int rt, int starting, void * resp,
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Get config, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("Get config, continuing", &io_hdr, verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
if (verbose && io_hdr.resid)
@@ -152,7 +152,7 @@ static int sg_ll_get_config(int sg_fd, int rt, int starting, void * resp,
if (verbose | noisy) {
snprintf(ebuff, EBUFF_SZ, "get config error, rt=%d, "
"starting=0x%x ", rt, starting);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
}
return -1;
}
@@ -189,39 +189,6 @@ static void usage()
"Get configuration information for MMC drive and/or media\n");
}
-static const char * scsi_ptype_strs[] = {
- /* 0 */ "disk",
- "tape",
- "printer",
- "processor",
- "write once optical disk",
- /* 5 */ "cd/dvd",
- "scanner",
- "optical memory device",
- "medium changer",
- "communications",
- /* 0xa */ "graphics [0xa]",
- "graphics [0xb]",
- "storage array controller",
- "enclosure services device",
- "simplified direct access device",
- "optical card reader/writer device",
- /* 0x10 */ "bridge controller commands",
- "object based storage",
- "automation/driver interface",
- "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
- "0x19", "0x1a", "0x1b", "0x1c", "0x1d",
- "well known logical unit",
- "no physical device on this lu",
-};
-
-static const char * get_ptype_str(int scsi_ptype)
-{
- int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]);
-
- return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : "";
-}
-
struct code_desc {
int code;
const char * desc;
@@ -309,6 +276,9 @@ static struct code_desc feature_desc_arr[] = {
{0x3b, "DVD+R double layer"},
{0x40, "BD read"},
{0x41, "BD write"},
+ {0x42, "TSR"},
+ {0x50, "HD DVD read"},
+ {0x51, "HD DVD write"},
{0x100, "Power management"},
{0x101, "SMART"},
{0x102, "Embedded changer"},
@@ -322,6 +292,7 @@ static struct code_desc feature_desc_arr[] = {
{0x10a, "Disc control blocks"},
{0x10b, "DVD CPRM"},
{0x10c, "Firmware information"},
+ {0x10d, "AACS"},
{0x110, "VCPS"},
{0x120, "BD CPS"},
};
@@ -914,6 +885,7 @@ int main(int argc, char * argv[])
int starting = 0;
int verbose = 0;
char device_name[256];
+ char buff[64];
const char * cp;
struct sg_simple_inquiry_resp inq_resp;
int ret = 1;
@@ -1007,7 +979,7 @@ int main(int argc, char * argv[])
printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product,
inq_resp.revision);
peri_type = inq_resp.peripheral_type;
- cp = get_ptype_str(peri_type);
+ cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
if (strlen(cp) > 0)
printf(" Peripheral device type: %s\n", cp);
else
diff --git a/sg_inq.8 b/sg_inq.8
index 94154326..4732e678 100644
--- a/sg_inq.8
+++ b/sg_inq.8
@@ -1,4 +1,4 @@
-.TH SG_INQ "8" "September 2005" "sg3_utils-1.17" SG3_UTILS
+.TH SG_INQ "8" "November 2005" "sg3_utils-1.18" SG3_UTILS
.SH NAME
sg_inq \- outputs data retrieved from the SCSI INQUIRY or
ATA IDENTIFY (PACKET) DEVICE command
@@ -153,7 +153,10 @@ 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.
+process binary data. Can be used twice 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
@@ -234,6 +237,11 @@ 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").
+.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 has
+been added to use with either the '-A' or '-a' option to produce a
+format acceptable to "hdparm --Istdin". See hdparm.
.SH AUTHOR
Written by Doug Gilbert
.SH "REPORTING BUGS"
@@ -245,4 +253,4 @@ 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)
+.B sg_logs(sg3_utils), hdparm(hdparm)
diff --git a/sg_inq.c b/sg_inq.c
index 8599721b..ae3d18fe 100644
--- a/sg_inq.c
+++ b/sg_inq.c
@@ -58,7 +58,7 @@
* added in the future.
*/
-static char * version_str = "0.55 20050922"; /* spc-4 rev02 */
+static char * version_str = "0.55 20051113"; /* spc-4 rev02 */
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -140,39 +140,6 @@ static void dStrRaw(const char* str, int len)
printf("%c", str[k]);
}
-static const char * scsi_ptype_strs[] = {
- /* 0 */ "disk",
- "tape",
- "printer",
- "processor", /* often SAF-TE (seldom scanner) device */
- "write once optical disk",
- /* 5 */ "cd/dvd",
- "scanner",
- "optical memory device",
- "medium changer",
- "communications",
- /* 0xa */ "graphics",
- "graphics",
- "storage array controller",
- "enclosure services device",
- "simplified direct access device",
- "optical card reader/writer device",
- /* 0x10 */ "bridge controller commands",
- "object based storage",
- "automation/driver interface",
- "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
- "0x19", "0x1a", "0x1b", "0x1c", "0x1d",
- "well known logical unit",
- "no physical device on this lu",
-};
-
-static const char * get_ptype_str(int scsi_ptype)
-{
- int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]);
-
- return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : "";
-}
-
struct vpd_name {
int number;
int peri_type;
@@ -786,12 +753,14 @@ static void decode_x_inq_vpd(unsigned char * buff, int len, int do_hex)
dStrHex((const char *)buff, len, 0);
return;
}
- printf(" RTO=%d GRD_CHK=%d APP_CHK=%d REF_CHK=%d\n", !!(buff[4] & 0x8),
- !!(buff[4] & 0x4), !!(buff[4] & 0x2), !!(buff[4] & 0x1));
+ printf(" SPT=%d GRD_CHK=%d APP_CHK=%d REF_CHK=%d\n",
+ ((buff[4] >> 3) & 0x7), !!(buff[4] & 0x4), !!(buff[4] & 0x2),
+ !!(buff[4] & 0x1));
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(" NV_SUP=%d V_SUP=%d\n", !!(buff[6] & 0x2), !!(buff[6] & 0x1));
+ printf(" CORR_D_SUP=%d NV_SUP=%d V_SUP=%d\n", !!(buff[6] & 0x80),
+ !!(buff[6] & 0x2), !!(buff[6] & 0x1));
}
static void decode_ata_info_vpd(unsigned char * buff, int len, int do_hex)
@@ -1028,7 +997,7 @@ static int process_std_inq(int sg_fd, const char * file_name, int do_36,
int res, len, act_len, pqual, peri_type, ansi_version, ret, k, j;
const char * cp;
int vdesc_arr[8];
- char buff[32];
+ char buff[48];
memset(vdesc_arr, 0, sizeof(vdesc_arr));
res = sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, 36, 0, do_verbose);
@@ -1092,7 +1061,7 @@ static int process_std_inq(int sg_fd, const char * file_name, int do_36,
printf("MultiP=1 (VS=%d) ", !!(rsp_buff[6] & 0x20));
else
printf("MultiP=0 ");
- printf("MChngr=%d [ACKREQQ=%d] Addr16=%d\n [RelAdr=%d] ",
+ printf("[MChngr=%d] [ACKREQQ=%d] Addr16=%d\n [RelAdr=%d] ",
!!(rsp_buff[6] & 0x08), !!(rsp_buff[6] & 0x04),
!!(rsp_buff[6] & 0x01), !!(rsp_buff[7] & 0x80));
printf("WBus16=%d Sync=%d Linked=%d [TranDis=%d] ",
@@ -1110,7 +1079,7 @@ static int process_std_inq(int sg_fd, const char * file_name, int do_36,
len, len);
if ((ansi_version >= 2) && (len < 36))
printf(" [for SCSI>=2, len>=36 is expected]");
- cp = get_ptype_str(peri_type);
+ cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
if (strlen(cp) > 0)
printf(" Peripheral device type: %s\n", cp);
@@ -1145,7 +1114,7 @@ static int process_std_inq(int sg_fd, const char * file_name, int do_36,
}
}
}
- if (! (do_raw || do_hex)) {
+ if (! (do_raw || do_hex || do_36)) {
if (0 == fetch_unit_serial_num(sg_fd, xtra_buff,
sizeof(xtra_buff), do_verbose))
printf(" Unit serial number: %s\n", xtra_buff);
@@ -1301,6 +1270,7 @@ static int process_evpd(int sg_fd, int num_opcode, int do_hex,
{
int ret, len, num, k, peri_type, vpd;
const char * cp;
+ char buff[48];
if (!do_raw)
printf("VPD INQUIRY, page code=0x%.2x:\n", num_opcode);
@@ -1332,7 +1302,7 @@ static int process_evpd(int sg_fd, int num_opcode, int do_hex,
peri_type = rsp_buff[0] & 0x1f;
printf(" [PQual=%d Peripheral device type: %s]\n",
(rsp_buff[0] & 0xe0) >> 5,
- get_ptype_str(peri_type));
+ sg_get_pdt_str(peri_type, sizeof(buff), buff));
printf(" Supported VPD pages:\n");
num = rsp_buff[3];
for (k = 0; k < num; ++k) {
@@ -1492,9 +1462,13 @@ static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
1, do_verbose))
return 1;
}
- if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
- else
+ if (do_raw) {
+ if (2 == do_raw)
+ dWordHex((const unsigned short *)(rsp_buff + 60),
+ 256, -2, sg_is_big_endian());
+ else
+ dStrRaw((const char *)rsp_buff, len);
+ } else
decode_ata_info_vpd(rsp_buff, len, do_hex);
return 0;
}
@@ -1674,7 +1648,7 @@ int main(int argc, char * argv[])
++do_vpd_decode;
break;
case 'r':
- do_raw = 1;
+ ++do_raw;
break;
case 's':
num_opcode = SCSI_PORTS_VPD;
@@ -1973,9 +1947,13 @@ static int try_ata_identify(int ata_fd, int do_hex, int do_raw,
#endif
if (res)
return res;
- if (do_raw)
- dStrRaw((const char *)&ata_ident, 512);
- else {
+ if (do_raw) {
+ if (2 == do_raw)
+ dWordHex((const unsigned short *)&ata_ident, 256, -2,
+ sg_is_big_endian());
+ else
+ dStrRaw((const char *)&ata_ident, 512);
+ } else {
if (do_hex) {
if (atapi)
printf("ATA IDENTIFY PACKET DEVICE response ");
diff --git a/sg_lib.c b/sg_lib.c
index 059e824c..36d593e5 100644
--- a/sg_lib.c
+++ b/sg_lib.c
@@ -68,7 +68,7 @@
#include "sg_include.h"
#include "sg_lib.h"
-static char * version_str = "1.13 20050906"; /* spc-4 rev 01a */
+static char * version_str = "1.15 20051113"; /* spc-4 rev 02 */
FILE * sg_warnings_str = NULL; /* would like to default to stderr */
@@ -592,6 +592,7 @@ static struct error_info additional[] =
{0x11,0x11,"Read error - loss of streaming"},
{0x11,0x12,"Auxiliary memory read error"},
{0x11,0x13,"Read error - failed retransmission request"},
+ {0x11,0x14,"Read error - LBA marked bad by application client"},
{0x12,0x00,"Address mark not found for id field"},
{0x13,0x00,"Address mark not found for data field"},
{0x14,0x00,"Recorded entity not found"},
@@ -724,6 +725,7 @@ static struct error_info additional[] =
{0x2D,0x00,"Overwrite error on update in place"},
{0x2E,0x00,"Insufficient time for operation"},
{0x2F,0x00,"Commands cleared by another initiator"},
+ {0x2F,0x01,"Commands cleared by power loss notification"},
{0x30,0x00,"Incompatible medium installed"},
{0x30,0x01,"Cannot read medium - unknown format"},
{0x30,0x02,"Cannot read medium - incompatible format"},
@@ -1153,6 +1155,8 @@ int sg_get_sense_info_fld(const unsigned char * sensep, int sb_len,
const unsigned char * ucp;
unsigned long long ull;
+ if (info_outp)
+ *info_outp = 0;
if (sb_len < 7)
return 0;
switch (sensep[0] & 0x7f) {
@@ -1174,7 +1178,7 @@ int sg_get_sense_info_fld(const unsigned char * sensep, int sb_len,
}
if (info_outp)
*info_outp = ull;
- return !!(ucp[2] & 0x80);
+ return !!(ucp[2] & 0x80); /* since spc3r23 should be set */
} else
return 0;
default:
@@ -1219,6 +1223,41 @@ int sg_get_sense_progress_fld(const unsigned char * sensep,
}
}
+static const char * scsi_pdt_strs[] = {
+ /* 0 */ "disk",
+ "tape",
+ "printer",
+ "processor", /* often SAF-TE (seldom scanner) device */
+ "write once optical disk",
+ /* 5 */ "cd/dvd",
+ "scanner",
+ "optical memory device",
+ "medium changer",
+ "communications",
+ /* 0xa */ "graphics [0xa]",
+ "graphics [0xb]",
+ "storage array controller",
+ "enclosure services device",
+ "simplified direct access device",
+ "optical card reader/writer device",
+ /* 0x10 */ "bridge controller commands",
+ "object based storage",
+ "automation/driver interface",
+ "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
+ "0x19", "0x1a", "0x1b", "0x1c", "0x1d",
+ "well known logical unit",
+ "no physical device on this lu",
+};
+
+char * sg_get_pdt_str(int pdt, int buff_len, char * buff)
+{
+ if ((pdt < 0) || (pdt > 31))
+ snprintf(buff, buff_len, "bad pdt");
+ else
+ snprintf(buff, buff_len, "%s", scsi_pdt_strs[pdt]);
+ return buff;
+}
+
/* Print descriptor format sense descriptors (assumes sense buffer is
in descriptor format) */
static void sg_print_sense_descriptors(const unsigned char * sense_buffer,
@@ -2151,7 +2190,9 @@ static unsigned short swapb_ushort(unsigned short u)
'no_ascii' allows for 3 output types:
> 0 each line has address then up to 8 ASCII-hex 16 bit words
= 0 in addition, the ASCI bytes pairs are listed to the right
- < 0 only the ASCII-hex words are listed (i.e. without address)
+ = -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. */
void dWordHex(const unsigned short* words, int num, int no_ascii,
@@ -2181,13 +2222,20 @@ void dWordHex(const unsigned short* words, int num, int no_ascii,
sprintf(&buff[bpos], "%.4x", (unsigned int)c);
buff[bpos + 4] = ' ';
if ((k > 0) && (0 == ((k + 1) % 8))) {
- printf("%.60s\n", buff);
+ if (-2 == no_ascii)
+ printf("%.39s\n", buff +8);
+ else
+ printf("%.47s\n", buff);
bpos = bpstart;
memset(buff, ' ', 80);
}
}
- if (bpos > bpstart)
- printf("%.60s\n", buff);
+ if (bpos > bpstart) {
+ if (-2 == no_ascii)
+ printf("%.39s\n", buff +8);
+ else
+ printf("%.47s\n", buff);
+ }
return;
}
/* no_ascii>=0, start each line with address (offset) */
diff --git a/sg_lib.h b/sg_lib.h
index 7b50c4a0..f3acdedf 100644
--- a/sg_lib.h
+++ b/sg_lib.h
@@ -30,7 +30,7 @@
*
*/
-/* Version 1.13 [20050906]
+/* Version 1.15 [20051113]
*
* 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
@@ -130,7 +130,7 @@ 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);
+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,
@@ -150,6 +150,10 @@ extern int sg_get_sense_info_fld(const unsigned char * sensep, int sb_len,
extern int sg_get_sense_progress_fld(const unsigned char * sensep,
int sb_len, int * progress_outp);
+/* 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);
+
/* <<< General purpose (i.e. not SCSI specific) utility functions >>> */
@@ -180,7 +184,9 @@ extern int sg_is_big_endian();
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
- < 0 only the ASCII-hex words are listed (i.e. without address)
+ = -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.
*/
@@ -191,8 +197,8 @@ extern void dWordHex(const unsigned short* words, int num, int no_ascii,
then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
multiplier suffix (not both). 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 x<m>
- which multiplies the leading number by <n> . */
+ 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
diff --git a/sg_logs.c b/sg_logs.c
index 924fe307..101bcab6 100644
--- a/sg_logs.c
+++ b/sg_logs.c
@@ -23,7 +23,7 @@
*/
-static char * version_str = "0.44 20050916";
+static char * version_str = "0.44 20051104";
#define ME "sg_logs: "
@@ -764,8 +764,9 @@ static int show_protocol_specific_page(unsigned char * resp, int len,
break;
case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state");
break;
- case 8: snprintf(s, sz, "phy enabled; 1.5Gbps"); break;
- case 9: snprintf(s, sz, "phy enabled; 3.0Gbps"); break;
+ case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
+ case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
+ 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);
diff --git a/sg_luns.c b/sg_luns.c
index 033db57a..1b2acaa8 100644
--- a/sg_luns.c
+++ b/sg_luns.c
@@ -47,7 +47,7 @@
* This program issues the SCSI command REPORT LUNS to the given SCSI device.
*/
-static char * version_str = "1.03 20050808";
+static char * version_str = "1.04 20051116";
#define REPORT_LUNS_BUFF_LEN 1024
@@ -84,9 +84,9 @@ static void usage()
}
-/* Decoded according to SAM-3 rev 14. Note that one draft: BCC rev 0,
- * defines its own "bridge addressing method" in place of the
- * SAM-3 "logical addressing method". */
+/* Decoded according to SAM-4 rev 4. Note that one draft: BCC rev 0,
+ * defines its own "bridge addressing method" in place of the SAM-3
+ * "logical addressing method". */
static void decode_lun(const char * leadin, unsigned char * lunp)
{
int k, j, x, a_method, bus_id, target, lun, len, e_a_method, next_level;
@@ -154,12 +154,19 @@ static void decode_lun(const char * leadin, unsigned char * lunp)
printf("%swell known logical unit %d\n", l_leadin, x);
break;
}
- } else {
+ } else if ((1 == len) && (2 == e_a_method)) {
+ x = (lunp[1] << 16) + (lunp[2] << 8) + lunp[3];
+ printf("%sExtended flat space logical unit addressing: "
+ "value=0x%x\n", l_leadin, x);
+ } else if ((3 == len) && (0xf == e_a_method))
+ printf("%sLogical unit _not_ specified addressing\n",
+ l_leadin);
+ else {
if (len < 2) {
if (1 == len)
x = (lunp[1] << 16) + (lunp[2] << 8) + lunp[3];
printf("%sExtended logical unit addressing: length=%d, "
- "e. a. method=%d, value=0x%x\n", l_leadin, len,
+ "e.a. method=%d, value=0x%x\n", l_leadin, len,
e_a_method, x);
} else {
ull = 0;
diff --git a/sg_map26.8 b/sg_map26.8
new file mode 100644
index 00000000..78a11de2
--- /dev/null
+++ b/sg_map26.8
@@ -0,0 +1,159 @@
+.TH SG_MAP26 "8" "October 2005" "sg3_utils-1.18" SG3_UTILS
+.SH NAME
+sg_map26 \- maps a special file to a SCSI generic (sg) device (or vv)
+.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
+.SH DESCRIPTION
+.\" Add any additional description here
+.PP
+Maps a special file (block or char) associated with a SCSI device
+to the corresponding SCSI generic (sg) device, or vice versa.
+Can also be given a sysfs file, for example '/sys/block/sda'
+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'.
+This feature works on ATA devices (e.g. 'dev/hdc') as well
+as SCSI devices.
+.PP
+In this utility, "mapped" refers to finding the relationship between
+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).
+.PP
+In this utility, "matching" refers to different representations of
+the same device accessed via the same driver. For example, '/dev/hdc'
+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'.
+.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.
+.TP
+--given_is=0|1 | -g 0|1
+specifies the given <device> 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>.
+.TP
+--help | -h
+output the usage message then exit.
+.TP
+--result=0|1|2|3 | -r 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
+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
+special file in the same directory.
+.TP
+--verbose | -v
+increase the level of verbosity, (i.e. debug output).
+.TP
+--version | -V
+print the version string and then exit.
+.PP
+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
+matching. In the absence of any other information, device special
+files are assumed to be in the '/dev' directory while sysfs is
+assumed to be mounted at '/sys'. Device names in sysfs are
+predictable, given the corresponding major and minor number of
+the device. However, due to udev rules, the name of device
+special files can be anything the user desires (e.g. '/dev/sda'
+could be named '/dev/my_boot_disk'). When trying to
+find a resultant device special file, this utility uses the major
+and minor numbers (and whether a block or char device is sought)
+to search the device directory.
+.PP
+This utility only shows one relationship at a time. To get an
+overview of all SCSI devices, with special file names and optionally
+the "mapped" sg device name, see the lsscsi utility.
+.PP
+When this utility succeeds its process exits with a status of 0;
+if problems are encountered the process status is 1 .
+.SH EXAMPLES
+Assume sg2 maps to sdb while dvd, cdrom and hdc are all matching.
+.PP
+ # sg_map26 /dev/sg2
+.br
+ /dev/sdb
+.PP
+ # sg_map26 /dev/sdb
+.br
+ /dev/sg2
+.PP
+ # sg_map26 --result=0 /dev/sdb
+.br
+ /dev/sg2
+.PP
+ # sg_map26 --result=3 /dev/sdb
+.br
+ /sys/block/sda
+.PP
+ # sg_map26 --result=1 /dev/sdb
+.br
+ /sys/class/scsi_generic/sg0
+.PP
+Now look at '/dev/hdc' and friends
+.PP
+ # sg_map26 /dev/hdc
+.br
+ <error: a hd device does not map to a sg device>
+.PP
+ # sg_map26 --result=3 /dev/hdc
+.br
+ /sys/block/hdc
+.PP
+ # sg_map26 --result=2 /dev/hdc
+.br
+ /dev/hdc
+.PP
+ # sg_map26 --result=2 --symlink /dev/hdc
+.br
+ /dev/cdrom
+.br
+ /dev/dvd
+.br
+ /dev/hdc
+.PP
+ # sg_map26 --result=2 --symlink /sys/block/hdc
+.br
+ /dev/cdrom
+.br
+ /dev/dvd
+.br
+ /dev/hdc
+.SH AUTHORS
+Written by Douglas Gilbert.
+.SH "REPORTING BUGS"
+Report bugs to <dgilbert at interlog dot com>.
+.SH COPYRIGHT
+Copyright \(co 2005 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 udev(8), udevinfo(8), lsscsi(lsscsi)
diff --git a/sg_map26.c b/sg_map26.c
new file mode 100644
index 00000000..b9847ac9
--- /dev/null
+++ b/sg_map26.c
@@ -0,0 +1,1144 @@
+/*
+ * Copyright (c) 2005 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.
+ *
+ */
+
+/* A utility program for the Linux OS SCSI subsystem.
+ *
+ *
+ * This program maps a primary SCSI device node name to the corresponding
+ * SCSI generic device node name (or vice versa). Targets linux
+ * kernel 2.6 series. Sysfs device names can also be mapped.
+ */
+
+/* #define _XOPEN_SOURCE 500 */
+/* needed to see DT_REG and friends when compiled with: c99 pedantic */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <linux/major.h>
+
+static char * version_str = "1.01 20051026";
+
+#define ME "sg_map26: "
+
+#define NT_NO_MATCH 0
+#define NT_SD 1
+#define NT_SR 2
+#define NT_HD 3
+#define NT_ST 4
+#define NT_OSST 5
+#define NT_SG 6
+#define NT_CH 7
+#define NT_REG 8
+#define NT_DIR 9
+
+#define NAME_LEN_MAX 260
+#define D_NAME_LEN_MAX 516
+
+#ifndef SCSI_CHANGER_MAJOR
+#define SCSI_CHANGER_MAJOR 86
+#endif
+#ifndef OSST_MAJOR
+#define OSST_MAJOR 206
+#endif
+
+/* scandir() and stat() categories */
+#define FT_OTHER 0
+#define FT_REGULAR 1
+#define FT_BLOCK 2
+#define FT_CHAR 3
+#define FT_DIR 4
+
+/* older major.h headers may not have these */
+#ifndef SCSI_DISK8_MAJOR
+#define SCSI_DISK8_MAJOR 128
+#define SCSI_DISK9_MAJOR 129
+#define SCSI_DISK10_MAJOR 130
+#define SCSI_DISK11_MAJOR 131
+#define SCSI_DISK12_MAJOR 132
+#define SCSI_DISK13_MAJOR 133
+#define SCSI_DISK14_MAJOR 134
+#define SCSI_DISK15_MAJOR 135
+#endif
+
+static const char * sys_sg_dir = "/sys/class/scsi_generic/";
+static const char * sys_sd_dir = "/sys/block/";
+static const char * sys_sr_dir = "/sys/block/";
+static const char * sys_hd_dir = "/sys/block/";
+static const char * sys_st_dir = "/sys/class/scsi_tape/";
+static const char * sys_sch_dir = "/sys/class/scsi_changer/";
+static const char * sys_osst_dir = "/sys/class/onstream_tape/";
+static const char * def_dev_dir = "/dev";
+
+
+static struct option long_options[] = {
+ {"dev_dir", 1, 0, 'd'},
+ {"given_is", 1, 0, 'g'},
+ {"help", 0, 0, 'h'},
+ {"result", 1, 0, 'r'},
+ {"symlink", 0, 0, 's'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+static const char * nt_names[] = {
+ "No matching",
+ "disk",
+ "cd/dvd",
+ "hd",
+ "tape",
+ "tape (osst)",
+ "generic (sg)",
+ "changer",
+ "regular file",
+ "directory",
+};
+
+static void usage()
+{
+ fprintf(stderr, "Usage: "
+ "sg_map26 [--dev_dir=<dir>] [--given_is=<n>] [--help] "
+ "[--result=<n>]\n"
+ " [--symlink] [--verbose] [--version] "
+ "<device>\n"
+ " where:\n"
+ " --dev_dir=<dir>|-d <dir> search in <dir> for "
+ "resulting special\n"
+ " (def: directory of <device> "
+ "or '/dev')\n"
+ " --given_is=<n>|-g <n> variety of given "
+ "<device>\n"
+ " 0->block or char special "
+ "(or symlink to)\n"
+ " 1->sysfs device, 'dev' or "
+ "parent\n"
+ " --help|-h print out usage message\n"
+ " --result=<n>|-r <n> variety of file(s) to "
+ "find\n"
+ " 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"
+ " --symlink|-s symlinks to special included in "
+ "result\n"
+ " --verbose|-v set device identifier\n"
+ " --version|-V print version string and exit\n\n"
+ "Maps SCSI device node to corresponding generic node (and "
+ "vv)\n"
+ );
+}
+
+
+/* ssafe_strerror() contributed by Clayton Weaver <cgweav at email dot com>
+ Allows for situation in which strerror() is given a wild value (or the
+ C library is incomplete) and returns NULL. Still not thread safe.
+ */
+
+static char safe_errbuf[64] = {'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ',
+ 'e', 'r', 'r', 'n', 'o', ':', ' ', 0};
+
+static char * ssafe_strerror(int errnum)
+{
+ size_t len;
+ char * errstr;
+
+ errstr = strerror(errnum);
+ if (NULL == errstr) {
+ len = strlen(safe_errbuf);
+ snprintf(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i",
+ errnum);
+ safe_errbuf[sizeof(safe_errbuf) - 1] = '\0'; /* bombproof */
+ return safe_errbuf;
+ }
+ return errstr;
+}
+
+static int nt_typ_from_filename(const char * filename, int * majj, int * minn)
+{
+ struct stat st;
+ int ma, mi;
+
+ if (stat(filename, &st) < 0)
+ return -errno;
+ ma = major(st.st_rdev);
+ mi = minor(st.st_rdev);
+ if (majj)
+ *majj = ma;
+ if (minn)
+ *minn = mi;
+ if (S_ISCHR(st.st_mode)) {
+ switch(ma) {
+ case OSST_MAJOR:
+ return NT_OSST;
+ case SCSI_GENERIC_MAJOR:
+ return NT_SG;
+ case SCSI_TAPE_MAJOR:
+ return NT_ST;
+ case SCSI_CHANGER_MAJOR:
+ return NT_CH;
+ default:
+ return NT_NO_MATCH;
+ }
+ } else if (S_ISBLK(st.st_mode)) {
+ switch(ma) {
+ case SCSI_DISK0_MAJOR: case SCSI_DISK1_MAJOR:
+ case SCSI_DISK2_MAJOR: case SCSI_DISK3_MAJOR:
+ case SCSI_DISK4_MAJOR: case SCSI_DISK5_MAJOR:
+ case SCSI_DISK6_MAJOR: case SCSI_DISK7_MAJOR:
+ case SCSI_DISK8_MAJOR: case SCSI_DISK9_MAJOR:
+ case SCSI_DISK10_MAJOR: case SCSI_DISK11_MAJOR:
+ case SCSI_DISK12_MAJOR: case SCSI_DISK13_MAJOR:
+ case SCSI_DISK14_MAJOR: case SCSI_DISK15_MAJOR:
+ return NT_SD;
+ case SCSI_CDROM_MAJOR:
+ return NT_SR;
+ case IDE0_MAJOR: case IDE1_MAJOR:
+ case IDE2_MAJOR: case IDE3_MAJOR:
+ case IDE4_MAJOR: case IDE5_MAJOR:
+ case IDE6_MAJOR: case IDE7_MAJOR:
+ case IDE8_MAJOR: case IDE9_MAJOR:
+ return NT_HD;
+ default:
+ return NT_NO_MATCH;
+ }
+ } else if (S_ISREG(st.st_mode))
+ return NT_REG;
+ else if (S_ISDIR(st.st_mode))
+ return NT_DIR;
+ return NT_NO_MATCH;
+}
+
+static int nt_typ_from_major(int ma)
+{
+ switch(ma) {
+ case SCSI_DISK0_MAJOR: case SCSI_DISK1_MAJOR:
+ case SCSI_DISK2_MAJOR: case SCSI_DISK3_MAJOR:
+ case SCSI_DISK4_MAJOR: case SCSI_DISK5_MAJOR:
+ case SCSI_DISK6_MAJOR: case SCSI_DISK7_MAJOR:
+ case SCSI_DISK8_MAJOR: case SCSI_DISK9_MAJOR:
+ case SCSI_DISK10_MAJOR: case SCSI_DISK11_MAJOR:
+ case SCSI_DISK12_MAJOR: case SCSI_DISK13_MAJOR:
+ case SCSI_DISK14_MAJOR: case SCSI_DISK15_MAJOR:
+ return NT_SD;
+ case SCSI_CDROM_MAJOR:
+ return NT_SR;
+ case IDE0_MAJOR: case IDE1_MAJOR:
+ case IDE2_MAJOR: case IDE3_MAJOR:
+ case IDE4_MAJOR: case IDE5_MAJOR:
+ case IDE6_MAJOR: case IDE7_MAJOR:
+ case IDE8_MAJOR: case IDE9_MAJOR:
+ return NT_HD;
+ case OSST_MAJOR:
+ return NT_OSST;
+ case SCSI_GENERIC_MAJOR:
+ return NT_SG;
+ case SCSI_TAPE_MAJOR:
+ return NT_ST;
+ case SCSI_CHANGER_MAJOR:
+ return NT_CH;
+ default:
+ return NT_NO_MATCH;
+ }
+ return NT_NO_MATCH;
+}
+
+
+struct node_match_item {
+ const char * dir_name;
+ int file_type;
+ int majj;
+ int minn;
+ int follow_symlink;
+};
+
+static struct node_match_item nd_match;
+
+static int nd_match_scandir_select(const struct dirent * s)
+{
+ struct stat st;
+ char name[D_NAME_LEN_MAX];
+ int symlnk = 0;
+
+ switch (s->d_type) {
+ case DT_BLK:
+ if (FT_BLOCK != nd_match.file_type)
+ return 0;
+ break;
+ case DT_CHR:
+ if (FT_CHAR != nd_match.file_type)
+ return 0;
+ break;
+ case DT_DIR:
+ return (FT_DIR == nd_match.file_type) ? 1 : 0;
+ case DT_REG:
+ return (FT_REGULAR == nd_match.file_type) ? 1 : 0;
+ case DT_LNK: /* follow symlinks */
+ if (! nd_match.follow_symlink)
+ return 0;
+ symlnk = 1;
+ break;
+ default:
+ return 0;
+ }
+ if ((! symlnk) && (-1 == nd_match.majj) && (-1 == nd_match.minn))
+ return 1;
+ strncpy(name, nd_match.dir_name, NAME_LEN_MAX);
+ strcat(name, "/");
+ strncat(name, s->d_name, NAME_LEN_MAX);
+ memset(&st, 0, sizeof(st));
+ if (stat(name, &st) < 0)
+ return 0;
+ if (symlnk) {
+ if (S_ISCHR(st.st_mode)) {
+ if (FT_CHAR != nd_match.file_type)
+ return 0;
+ } else if (S_ISBLK(st.st_mode)) {
+ if (FT_BLOCK != nd_match.file_type)
+ return 0;
+ } else
+ return 0;
+ }
+ return (((-1 == nd_match.majj) ||
+ (major(st.st_rdev) == (unsigned)nd_match.majj)) &&
+ ((-1 == nd_match.minn) ||
+ (minor(st.st_rdev) == (unsigned)nd_match.minn)))
+ ? 1 : 0;
+}
+
+static int list_matching_nodes(const char * dir_name, int file_type,
+ int majj, int minn, int follow_symlink,
+ int verbose)
+{
+ struct dirent ** namelist;
+ int num, k;
+
+ nd_match.dir_name = dir_name;
+ nd_match.file_type = file_type;
+ nd_match.majj = majj;
+ nd_match.minn = minn;
+ nd_match.follow_symlink = follow_symlink;
+ num = scandir(dir_name, &namelist, nd_match_scandir_select, NULL);
+ if (num < 0) {
+ if (verbose)
+ fprintf(stderr, "scandir: %s %s\n", dir_name,
+ ssafe_strerror(errno));
+ return -errno;
+ }
+ for (k = 0; k < num; ++k) {
+ printf("%s/%s\n", dir_name, namelist[k]->d_name);
+ free(namelist[k]);
+ }
+ free(namelist);
+ return num;
+}
+
+struct from_sg_item {
+ char name[NAME_LEN_MAX];
+ int ft;
+ int nt;
+};
+
+static struct from_sg_item from_sg;
+
+static int from_sg_scandir_select(const struct dirent * s)
+{
+ if (FT_OTHER != from_sg.ft)
+ return 0;
+ if (DT_LNK != s->d_type)
+ return 0;
+ if (0 == strncmp("scsi_changer", s->d_name, 12)) {
+ strncpy(from_sg.name, s->d_name, NAME_LEN_MAX);
+ from_sg.ft = FT_CHAR;
+ from_sg.nt = NT_CH;
+ return 1;
+ } else if (0 == strcmp("block", s->d_name)) {
+ strcpy(from_sg.name, s->d_name);
+ from_sg.ft = FT_BLOCK;
+ return 1;
+ } else if (0 == strcmp("tape", s->d_name)) {
+ strcpy(from_sg.name, s->d_name);
+ from_sg.ft = FT_CHAR;
+ from_sg.nt = NT_ST;
+ return 1;
+ } else if (0 == strncmp("onstream_tape:os", s->d_name, 16)) {
+ strcpy(from_sg.name, s->d_name);
+ from_sg.ft = FT_CHAR;
+ from_sg.nt = NT_OSST;
+ return 1;
+ } else
+ return 0;
+}
+
+static int from_sg_scan(const char * dir_name, int verbose)
+{
+ struct dirent ** namelist;
+ int num, k;
+
+ from_sg.ft = FT_OTHER;
+ from_sg.nt = NT_NO_MATCH;
+ num = scandir(dir_name, &namelist, from_sg_scandir_select, NULL);
+ if (num < 0) {
+ if (verbose)
+ fprintf(stderr, "scandir: %s %s\n", dir_name,
+ ssafe_strerror(errno));
+ return -errno;
+ }
+ if (verbose) {
+ for (k = 0; k < num; ++k)
+ fprintf(stderr, " %s/%s\n", dir_name,
+ namelist[k]->d_name);
+ }
+ for (k = 0; k < num; ++k)
+ free(namelist[k]);
+ free(namelist);
+ return num;
+}
+
+/* Return 1 if directory, else 0 */
+static int if_directory_chdir(const char * dir_name, const char * base_name)
+{
+ char buff[D_NAME_LEN_MAX];
+ struct stat a_stat;
+
+ strcpy(buff, dir_name);
+ strcat(buff, "/");
+ strcat(buff, base_name);
+ if (stat(buff, &a_stat) < 0)
+ return 0;
+ if (S_ISDIR(a_stat.st_mode)) {
+ if (chdir(buff) < 0)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+/* Return 1 if found, else 0 if problems */
+static int get_value(const char * dir_name, const char * base_name,
+ char * value, int max_value_len)
+{
+ char buff[D_NAME_LEN_MAX];
+ FILE * f;
+ int len;
+
+ if ((NULL == dir_name) && (NULL == base_name))
+ return 0;
+ if (dir_name) {
+ strcpy(buff, dir_name);
+ if (base_name && (strlen(base_name) > 0)) {
+ strcat(buff, "/");
+ strcat(buff, base_name);
+ }
+ } else
+ strcpy(buff, base_name);
+ if (NULL == (f = fopen(buff, "r"))) {
+ return 0;
+ }
+ if (NULL == fgets(value, max_value_len, f)) {
+ fclose(f);
+ return 0;
+ }
+ len = strlen(value);
+ if ((len > 0) && (value[len - 1] == '\n'))
+ value[len - 1] = '\0';
+ fclose(f);
+ return 1;
+}
+
+static int map_hd(const char * device_dir, int ma, int mi, int result,
+ int follow_symlink, int verbose)
+{
+ char c, num;
+
+ if (2 == result) {
+ num = list_matching_nodes(device_dir, FT_BLOCK,
+ ma, mi, follow_symlink,
+ verbose);
+ return (num > 0) ? 0 : 1;
+ }
+ switch (ma) {
+ case IDE0_MAJOR: c = 'a'; break;
+ case IDE1_MAJOR: c = 'c'; break;
+ case IDE2_MAJOR: c = 'e'; break;
+ case IDE3_MAJOR: c = 'g'; break;
+ case IDE4_MAJOR: c = 'i'; break;
+ case IDE5_MAJOR: c = 'k'; break;
+ case IDE6_MAJOR: c = 'm'; break;
+ case IDE7_MAJOR: c = 'o'; break;
+ case IDE8_MAJOR: c = 'q'; break;
+ case IDE9_MAJOR: c = 's'; break;
+ default: c = '?'; break;
+ }
+ if (mi > 63)
+ ++c;
+ printf("%shd%c\n", sys_hd_dir, c);
+ return 0;
+}
+
+static int map_sd(const char * device_name, const char * device_dir,
+ int ma, int mi, int result, int follow_symlink,
+ int verbose)
+{
+ int index, m_mi, m_ma, num;
+ char value[D_NAME_LEN_MAX];
+ char name[D_NAME_LEN_MAX];
+
+ if (2 == result) {
+ num = list_matching_nodes(device_dir, FT_BLOCK, ma, mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ }
+ if (SCSI_DISK0_MAJOR == ma)
+ index = mi / 16;
+ else if (ma >= SCSI_DISK8_MAJOR)
+ index = (mi / 16) + 128 +
+ ((ma - SCSI_DISK8_MAJOR) * 16);
+ else
+ index = (mi / 16) + 16 +
+ ((ma - SCSI_DISK1_MAJOR) * 16);
+ if (index < 26)
+ snprintf(name, sizeof(name), "%ssd%c",
+ sys_sd_dir, 'a' + index % 26);
+ else if (index < (26 + 1) * 26)
+ snprintf(name, sizeof(name), "%ssd%c%c",
+ sys_sd_dir,
+ 'a' + index / 26 - 1,'a' + index % 26);
+ else {
+ const unsigned int m1 = (index / 26 - 1) / 26 - 1;
+ const unsigned int m2 = (index / 26 - 1) % 26;
+ const unsigned int m3 = index % 26;
+
+ snprintf(name, sizeof(name), "%ssd%c%c%c",
+ sys_sd_dir, 'a' + m1, 'a' + m2, 'a' + m3);
+ }
+ if (3 == result) {
+ printf("%s\n", name);
+ return 0;
+ }
+ if (! get_value(name, "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs match for "
+ "device: %s\n", device_name);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "sysfs sd dev: %s\n", value);
+ if (! if_directory_chdir(name, "device")) {
+ fprintf(stderr, "sysfs problem with device: %s\n",
+ device_name);
+ return 1;
+ }
+ if (if_directory_chdir(".", "generic")) {
+ if (1 == result) {
+ if (NULL == getcwd(value, sizeof(value)))
+ value[0] = '\0';
+ printf("%s\n", value);
+ return 0;
+ }
+ if (! get_value(".", "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs generic"
+ "dev\n");
+ return 1;
+ }
+ if (verbose)
+ printf("matching dev: %s\n", value);
+ if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) {
+ fprintf(stderr, "Couldn't decode mapped "
+ "dev\n");
+ return 1;
+ }
+ num = list_matching_nodes(device_dir, FT_CHAR, m_ma, m_mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ } else {
+ fprintf(stderr, "sd device: %s does not match any "
+ "SCSI generic device\n", device_name);
+ fprintf(stderr, " perhaps sg module is not "
+ "loaded\n");
+ return 1;
+ }
+}
+
+static int map_sr(const char * device_name, const char * device_dir, int ma,
+ int mi, int result, int follow_symlink, int verbose)
+{
+ int m_mi, m_ma, num;
+ char value[D_NAME_LEN_MAX];
+ char name[D_NAME_LEN_MAX];
+
+ if (2 == result) {
+ num = list_matching_nodes(device_dir, FT_BLOCK, ma, mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ }
+ snprintf(name, sizeof(name), "%ssr%d", sys_sr_dir, mi);
+ if (3 == result) {
+ printf("%s\n", name);
+ return 0;
+ }
+ if (! get_value(name, "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs match for "
+ "device: %s\n", device_name);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "sysfs sr dev: %s\n", value);
+ if (! if_directory_chdir(name, "device")) {
+ fprintf(stderr, "sysfs problem with device: %s\n",
+ device_name);
+ return 1;
+ }
+ if (if_directory_chdir(".", "generic")) {
+ if (1 == result) {
+ if (NULL == getcwd(value, sizeof(value)))
+ value[0] = '\0';
+ printf("%s\n", value);
+ return 0;
+ }
+ if (! get_value(".", "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs generic"
+ "dev\n");
+ return 1;
+ }
+ if (verbose)
+ printf("matching dev: %s\n", value);
+ if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) {
+ fprintf(stderr, "Couldn't decode mapped "
+ "dev\n");
+ return 1;
+ }
+ num = list_matching_nodes(device_dir, FT_BLOCK, m_ma, m_mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ } else {
+ fprintf(stderr, "sr device: %s does not match any "
+ "SCSI generic device\n", device_name);
+ fprintf(stderr, " perhaps sg module is not "
+ "loaded\n");
+ return 1;
+ }
+}
+
+static int map_st(const char * device_name, const char * device_dir, int ma,
+ int mi, int result, int follow_symlink, int verbose)
+{
+ int m_mi, m_ma, num;
+ char value[D_NAME_LEN_MAX];
+ char name[D_NAME_LEN_MAX];
+
+ if (2 == result) {
+ num = list_matching_nodes(device_dir, FT_CHAR, ma, mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ }
+ snprintf(name, sizeof(name), "%sst%d", sys_st_dir,
+ (mi & 0x1f));
+ if (3 == result) {
+ printf("%s\n", name);
+ return 0;
+ }
+ if (! get_value(name, "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs match for "
+ "device: %s\n", device_name);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "sysfs st dev: %s\n", value);
+ if (! if_directory_chdir(name, "device")) {
+ fprintf(stderr, "sysfs problem with device: %s\n",
+ device_name);
+ return 1;
+ }
+ if (if_directory_chdir(".", "generic")) {
+ if (1 == result) {
+ if (NULL == getcwd(value, sizeof(value)))
+ value[0] = '\0';
+ printf("%s\n", value);
+ return 0;
+ }
+ if (! get_value(".", "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs generic"
+ "dev\n");
+ return 1;
+ }
+ if (verbose)
+ printf("matching dev: %s\n", value);
+ if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) {
+ fprintf(stderr, "Couldn't decode mapped "
+ "dev\n");
+ return 1;
+ }
+ num = list_matching_nodes(device_dir, FT_CHAR, m_ma, m_mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ } else {
+ fprintf(stderr, "st device: %s does not match any "
+ "SCSI generic device\n", device_name);
+ fprintf(stderr, " perhaps sg module is not "
+ "loaded\n");
+ return 1;
+ }
+}
+
+static int map_osst(const char * device_name, const char * device_dir, int ma,
+ int mi, int result, int follow_symlink, int verbose)
+{
+ int m_mi, m_ma, num;
+ char value[D_NAME_LEN_MAX];
+ char name[D_NAME_LEN_MAX];
+
+ if (2 == result) {
+ num = list_matching_nodes(device_dir, FT_CHAR, ma, mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ }
+ snprintf(name, sizeof(name), "%sosst%d", sys_osst_dir,
+ (mi & 0x1f));
+ if (3 == result) {
+ printf("%s\n", name);
+ return 0;
+ }
+ if (! get_value(name, "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs match for "
+ "device: %s\n", device_name);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "sysfs osst dev: %s\n", value);
+ if (! if_directory_chdir(name, "device")) {
+ fprintf(stderr, "sysfs problem with device: %s\n",
+ device_name);
+ return 1;
+ }
+ if (if_directory_chdir(".", "generic")) {
+ if (1 == result) {
+ if (NULL == getcwd(value, sizeof(value)))
+ value[0] = '\0';
+ printf("%s\n", value);
+ return 0;
+ }
+ if (! get_value(".", "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs generic"
+ "dev\n");
+ return 1;
+ }
+ if (verbose)
+ printf("matching dev: %s\n", value);
+ if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) {
+ fprintf(stderr, "Couldn't decode mapped "
+ "dev\n");
+ return 1;
+ }
+ num = list_matching_nodes(device_dir, FT_CHAR, m_ma, m_mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ } else {
+ fprintf(stderr, "osst device: %s does not match any "
+ "SCSI generic device\n", device_name);
+ fprintf(stderr, " perhaps sg module is not "
+ "loaded\n");
+ return 1;
+ }
+}
+
+static int map_ch(const char * device_name, const char * device_dir, int ma,
+ int mi, int result, int follow_symlink, int verbose)
+{
+ int m_mi, m_ma, num;
+ char value[D_NAME_LEN_MAX];
+ char name[D_NAME_LEN_MAX];
+
+ if (2 == result) {
+ num = list_matching_nodes(device_dir, FT_CHAR, ma, mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ }
+ snprintf(name, sizeof(name), "%ssch%d", sys_sch_dir, mi);
+ if (3 == result) {
+ printf("%s\n", name);
+ return 0;
+ }
+ if (! get_value(name, "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs match for "
+ "device: %s\n", device_name);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "sysfs sch dev: %s\n", value);
+ if (! if_directory_chdir(name, "device")) {
+ fprintf(stderr, "sysfs problem with device: %s\n",
+ device_name);
+ return 1;
+ }
+ if (if_directory_chdir(".", "generic")) {
+ if (1 == result) {
+ if (NULL == getcwd(value, sizeof(value)))
+ value[0] = '\0';
+ printf("%s\n", value);
+ return 0;
+ }
+ if (! get_value(".", "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs generic"
+ "dev\n");
+ return 1;
+ }
+ if (verbose)
+ printf("matching dev: %s\n", value);
+ if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) {
+ fprintf(stderr, "Couldn't decode mapped "
+ "dev\n");
+ return 1;
+ }
+ num = list_matching_nodes(device_dir, FT_CHAR, m_ma, m_mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ } else {
+ fprintf(stderr, "sch device: %s does not match any "
+ "SCSI generic device\n", device_name);
+ fprintf(stderr, " perhaps sg module is not "
+ "loaded\n");
+ return 1;
+ }
+}
+
+static int map_sg(const char * device_name, const char * device_dir, int ma,
+ int mi, int result, int follow_symlink, int verbose)
+{
+ int m_mi, m_ma, num;
+ char value[D_NAME_LEN_MAX];
+ char name[D_NAME_LEN_MAX];
+
+ if (2 == result) {
+ num = list_matching_nodes(device_dir, FT_CHAR, ma, mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ }
+ snprintf(name, sizeof(name), "%ssg%d", sys_sg_dir, mi);
+ if (3 == result) {
+ printf("%s\n", name);
+ return 0;
+ }
+ if (! get_value(name, "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs match for "
+ "device: %s\n", device_name);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "sysfs sg dev: %s\n", value);
+ if (! if_directory_chdir(name, "device")) {
+ fprintf(stderr, "sysfs problem with device: %s\n",
+ device_name);
+ return 1;
+ }
+ if ((1 == from_sg_scan(".", verbose)) &&
+ (if_directory_chdir(".", from_sg.name))) {
+ if (1 == result) {
+ if (NULL == getcwd(value, sizeof(value)))
+ value[0] = '\0';
+ printf("%s\n", value);
+ return 0;
+ }
+ if (! get_value(".", "dev", value, sizeof(value))) {
+ fprintf(stderr, "Couldn't find sysfs block "
+ "dev\n");
+ return 1;
+ }
+ if (verbose)
+ printf("matching dev: %s\n", value);
+ if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) {
+ fprintf(stderr, "Couldn't decode mapped "
+ "dev\n");
+ return 1;
+ }
+ num = list_matching_nodes(device_dir, from_sg.ft, m_ma, m_mi,
+ follow_symlink, verbose);
+ return (num > 0) ? 0 : 1;
+ } else {
+ fprintf(stderr, "sg device: %s does not match any "
+ "other SCSI device\n", device_name);
+ return 1;
+ }
+}
+
+
+int main(int argc, char * argv[])
+{
+ int c, num, res, tt, cont;
+ int do_dev_dir = 0;
+ int given_is = -1;
+ int result = 0;
+ int follow_symlink = 0;
+ int verbose = 0;
+ char device_name[D_NAME_LEN_MAX];
+ char device_dir[D_NAME_LEN_MAX];
+ char value[D_NAME_LEN_MAX];
+ int ret = 1;
+ int ma, mi;
+
+ memset(device_name, 0, sizeof(device_name));
+ memset(device_dir, 0, sizeof(device_dir));
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "d:hg:r:svV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'd':
+ strncpy(device_dir, optarg, sizeof(device_dir));
+ do_dev_dir = 1;
+ break;
+ case 'g':
+ num = sscanf(optarg, "%d", &res);
+ if ((1 == num) && ((0 == res) || (1 == res)))
+ given_is = res;
+ else {
+ fprintf(stderr, "value for '--given_to=' "
+ "must be 0 or 1\n");
+ return 1;
+ }
+ break;
+ case 'h':
+ case '?':
+ usage();
+ return 0;
+ case 'r':
+ num = sscanf(optarg, "%d", &res);
+ if ((1 == num) && (res >= 0) && (res < 4))
+ result = res;
+ else {
+ fprintf(stderr, "value for '--result=' "
+ "must be 0..3\n");
+ return 1;
+ }
+ break;
+ case 's':
+ follow_symlink = 1;
+ 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 1;
+ }
+ }
+ 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 1;
+ }
+ }
+
+ if (0 == device_name[0]) {
+ fprintf(stderr, "missing device name!\n");
+ usage();
+ return 1;
+ }
+
+ ma = 0;
+ mi = 0;
+ if (do_dev_dir) {
+ if (if_directory_chdir(".", device_dir)) {
+ if (getcwd(device_dir, sizeof(device_dir)))
+ device_dir[sizeof(device_dir) - 1] = '\0';
+ else
+ device_dir[0] = '\0';
+ if (verbose > 1)
+ fprintf(stderr, "Absolute path to "
+ "dev_dir: %s\n", device_dir);
+ } else {
+ fprintf(stderr, "dev_dir: %s invalid\n", device_dir);
+ return 1;
+ }
+ } else {
+ strcpy(device_dir, device_name);
+ dirname(device_dir);
+ if (0 == strcmp(device_dir, device_name)) {
+ if (NULL == getcwd(device_dir, sizeof(device_dir)))
+ device_dir[0] = '\0';
+ }
+ }
+ ret = nt_typ_from_filename(device_name, &ma, &mi);
+ if (ret < 0) {
+ fprintf(stderr, "stat failed on %s: %s\n", device_name,
+ ssafe_strerror(-ret));
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, " %s: %s device [maj=%d, min=%d]\n",
+ device_name, nt_names[ret], ma, mi);
+ res = 0;
+ switch (ret) {
+ case NT_SD:
+ case NT_SR:
+ case NT_HD:
+ if (given_is > 0) {
+ fprintf(stderr, "block special but '--given_is=' "
+ "suggested sysfs device\n");
+ return 1;
+ }
+ break;
+ case NT_ST:
+ case NT_OSST:
+ case NT_CH:
+ case NT_SG:
+ if (given_is > 0) {
+ fprintf(stderr, "character special but '--given_is=' "
+ "suggested sysfs device\n");
+ return 1;
+ }
+ break;
+ case NT_REG:
+ if (0 == given_is) {
+ fprintf(stderr, "regular file but '--given_is=' "
+ "suggested block or char special\n");
+ return 1;
+ }
+ strcpy(device_dir, def_dev_dir);
+ break;
+ case NT_DIR:
+ if (0 == given_is) {
+ fprintf(stderr, "directory but '--given_is=' "
+ "suggested block or char special\n");
+ return 1;
+ }
+ strcpy(device_dir, def_dev_dir);
+ break;
+ default:
+ break;
+ }
+
+ tt = NT_NO_MATCH;
+ do {
+ cont = 0;
+ switch (ret) {
+ case NT_NO_MATCH:
+ res = 1;
+ break;
+ case NT_SD:
+ res = map_sd(device_name, device_dir, ma, mi, result,
+ follow_symlink, verbose);
+ break;
+ case NT_SR:
+ res = map_sr(device_name, device_dir, ma, mi, result,
+ follow_symlink, verbose);
+ break;
+ case NT_HD:
+ if (result < 2) {
+ fprintf(stderr, "a hd device does not map "
+ "to a sg device\n");
+ return 1;
+ }
+ res = map_hd(device_dir, ma, mi, result,
+ follow_symlink, verbose);
+ break;
+ case NT_ST:
+ res = map_st(device_name, device_dir, ma, mi, result,
+ follow_symlink, verbose);
+ break;
+ case NT_OSST:
+ res = map_osst(device_name, device_dir, ma, mi,
+ result, follow_symlink, verbose);
+ break;
+ case NT_CH:
+ res = map_ch(device_name, device_dir, ma, mi, result,
+ follow_symlink, verbose);
+ break;
+ case NT_SG:
+ res = map_sg(device_name, device_dir, ma, mi, result,
+ follow_symlink, verbose);
+ break;
+ case NT_REG:
+ if (! get_value(NULL, device_name, value,
+ sizeof(value))) {
+ fprintf(stderr, "Couldn't fetch value "
+ "from: %s\n", device_name);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "value: %s\n", value);
+ if (2 != sscanf(value, "%d:%d", &ma, &mi)) {
+ fprintf(stderr, "Couldn't decode value\n");
+ return 1;
+ }
+ tt = nt_typ_from_major(ma);
+ cont = 1;
+ break;
+ case NT_DIR:
+ if (! get_value(device_name, "dev", value,
+ sizeof(value))) {
+ fprintf(stderr, "Couldn't fetch value from: "
+ "%s/dev\n", device_name);
+ return 1;
+ }
+ if (verbose)
+ fprintf(stderr, "value: %s\n", value);
+ if (2 != sscanf(value, "%d:%d", &ma, &mi)) {
+ fprintf(stderr, "Couldn't decode value\n");
+ return 1;
+ }
+ tt = nt_typ_from_major(ma);
+ cont = 1;
+ break;
+ default:
+ break;
+ }
+ ret = tt;
+ } while (cont);
+ return res;
+}
diff --git a/sg_modes.c b/sg_modes.c
index 8d42e67e..c72c3d73 100644
--- a/sg_modes.c
+++ b/sg_modes.c
@@ -24,7 +24,7 @@
*/
-static char * version_str = "1.10 20050904";
+static char * version_str = "1.11 20051113";
#define ME "sg_modes: "
@@ -236,6 +236,7 @@ static struct page_code_desc pc_desc_t_sas[] = {
{0x18, 0x0, "LU SSP, short format"},
{0x19, 0x0, "Port SSP, short format"},
{0x19, 0x1, "Port SSP, phy control and discover"},
+ {0x19, 0x2, "Port SSP, shared"},
};
static struct page_code_desc pc_desc_t_adt[] = {
@@ -706,7 +707,7 @@ int main(int argc, char * argv[])
fprintf(stderr, ">>>>>> try again without the '-6' "
"switch for a 10 byte MODE SENSE command\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "bad field in cdb (perhaps subpages "
+ fprintf(stderr, "invalid field in cdb (perhaps subpages "
"or page control (PC) not supported)\n");
} else {
res = sg_ll_mode_sense10(sg_fd, do_llbaa, do_dbd, pc, pg_code,
@@ -716,7 +717,7 @@ int main(int argc, char * argv[])
fprintf(stderr, ">>>>>> try again with a '-6' "
"switch for a 6 byte MODE SENSE command\n");
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "bad field in cdb (perhaps subpages "
+ fprintf(stderr, "invalid field in cdb (perhaps subpages "
"or page control (PC) not supported)\n");
}
if (0 == res) {
diff --git a/sg_opcodes.c b/sg_opcodes.c
index 0f3cdac4..15a84835 100644
--- a/sg_opcodes.c
+++ b/sg_opcodes.c
@@ -24,7 +24,7 @@
*/
-static char * version_str = "0.21 20050904";
+static char * version_str = "0.22 20051025";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -143,7 +143,7 @@ static int do_rsoc(int sg_fd, int rep_opts, int rq_opcode, int rq_servact,
switch (res) {
case SG_LIB_CAT_RECOVERED:
sg_chk_n_print3("Report supported operation codes", &io_hdr,
- verbose);
+ verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -159,7 +159,7 @@ static int do_rsoc(int sg_fd, int rep_opts, int rq_opcode, int rq_servact,
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);
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
}
return -1;
}
@@ -208,7 +208,7 @@ static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
switch (res) {
case SG_LIB_CAT_RECOVERED:
sg_chk_n_print3("Report supported task management fns", &io_hdr,
- verbose);
+ verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -216,7 +216,7 @@ static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
if (noisy | verbose) {
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "RSTMF error ");
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
}
return -1;
}
@@ -241,39 +241,6 @@ static void usage()
"management\nfunctions) SCSI command\n");
}
-static const char * scsi_ptype_strs[] = {
- /* 0 */ "disk",
- "tape",
- "printer",
- "processor",
- "write once optical disk",
- /* 5 */ "cd/dvd",
- "scanner",
- "optical memory device",
- "medium changer",
- "communications",
- /* 0xa */ "graphics [0xa]",
- "graphics [0xb]",
- "storage array controller",
- "enclosure services device",
- "simplified direct access device",
- "optical card reader/writer device",
- /* 0x10 */ "bridge controller commands",
- "object based storage",
- "automation/driver interface",
- "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
- "0x19", "0x1a", "0x1b", "0x1c", "0x1d",
- "well known logical unit",
- "no physical device on this lu",
-};
-
-static const char * get_ptype_str(int scsi_ptype)
-{
- int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]);
-
- return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : "";
-}
-
/* returns -1 when left < right, 0 when left == right, else returns 1 */
int opcode_num_compare(const void * left, const void * right)
{
@@ -407,6 +374,7 @@ int main(int argc, char * argv[])
int rep_opts = 0;
int ret = 0;
const char * cp;
+ char buff[48];
struct sg_simple_inquiry_resp inq_resp;
for (k = 1; k < argc; ++k) {
@@ -503,7 +471,7 @@ int main(int argc, char * argv[])
printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product,
inq_resp.revision);
peri_type = inq_resp.peripheral_type;
- cp = get_ptype_str(peri_type);
+ cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
if (strlen(cp) > 0)
printf(" Peripheral device type: %s\n", cp);
else
diff --git a/sg_persist.c b/sg_persist.c
index ffd8eed8..4b040663 100644
--- a/sg_persist.c
+++ b/sg_persist.c
@@ -24,7 +24,7 @@
*/
-static char * version_str = "0.23 20050808";
+static char * version_str = "0.23 20051025";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -153,7 +153,7 @@ static int do_prin(int sg_fd, int rq_servact, void * resp, int mx_resp_len,
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("PRIN, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("PRIN, continuing", &io_hdr, verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -163,7 +163,7 @@ static int do_prin(int sg_fd, int rq_servact, void * resp, int mx_resp_len,
snprintf(ebuff, EBUFF_SZ, "PRIN error, service_action: %s",
((rq_servact < num_prin_sa_strs) ?
prin_sa_strs[rq_servact] : "??"));
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
}
return -1;
}
@@ -216,7 +216,7 @@ static int do_prout(int sg_fd, int rq_servact, int rq_scope,
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("PROUT, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("PROUT, continuing", &io_hdr, verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -226,7 +226,7 @@ static int do_prout(int sg_fd, int rq_servact, int rq_scope,
snprintf(ebuff, EBUFF_SZ, "PROUT error, service_action: %s",
((rq_servact < num_prout_sa_strs) ?
prout_sa_strs[rq_servact] : "??"));
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
}
return -1;
}
@@ -280,39 +280,6 @@ static void usage()
"Performs a PERSISTENT RESERVATION (IN or OUT) SCSI command\n");
}
-static const char * scsi_ptype_strs[] = {
- /* 0 */ "disk",
- "tape",
- "printer",
- "processor",
- "write once optical disk",
- /* 5 */ "cd/dvd",
- "scanner",
- "optical memory device",
- "medium changer",
- "communications",
- /* 0xa */ "graphics",
- "graphics",
- "storage array controller",
- "enclosure services device",
- "simplified direct access device",
- "optical card reader/writer device",
- /* 0x10 */ "bridging expander",
- "object based storage",
- "automation/driver interface",
- "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
- "0x19", "0x1a", "0x1b", "0x1c", "0x1d",
- "well known logical unit",
- "no physical device on this lu",
-};
-
-static const char * get_ptype_str(int scsi_ptype)
-{
- int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]);
-
- return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : "";
-}
-
static const char * pr_type_strs[] = {
"obsolete [0]",
"Write Exclusive",
@@ -814,6 +781,7 @@ int main(int argc, char * argv[])
unsigned int param_rtp = 0;
char device_name[256];
char ebuff[EBUFF_SZ];
+ char buff[48];
int num_prin_sa = 0;
int num_prout_sa = 0;
int num_prout_param = 0;
@@ -1074,7 +1042,7 @@ int main(int argc, char * argv[])
printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product,
inq_resp.revision);
peri_type = inq_resp.peripheral_type;
- cp = get_ptype_str(peri_type);
+ cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
if (strlen(cp) > 0)
printf(" Peripheral device type: %s\n", cp);
else
diff --git a/sg_rbuf.c b/sg_rbuf.c
index d2192e36..cf85ad38 100644
--- a/sg_rbuf.c
+++ b/sg_rbuf.c
@@ -45,7 +45,7 @@
#define ME "sg_rbuf: "
-static char * version_str = "4.83 20050808";
+static char * version_str = "4.83 20051025";
static void usage()
{
@@ -217,12 +217,12 @@ int main(int argc, char * argv[])
switch (sg_err_category3(&io_hdr)) {
case SG_LIB_CAT_RECOVERED:
sg_chk_n_print3("READ BUFFER descriptor, continuing", &io_hdr,
- verbose);
+ 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);
+ sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr, verbose > 1);
if (rawp) free(rawp);
return 1;
}
@@ -338,10 +338,11 @@ int main(int argc, char * argv[])
case SG_LIB_CAT_CLEAN:
break;
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("READ BUFFER data, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("READ BUFFER data, continuing", &io_hdr,
+ verbose > 1);
break;
default: /* won't bother decoding other categories */
- sg_chk_n_print3("READ BUFFER data error", &io_hdr, verbose);
+ sg_chk_n_print3("READ BUFFER data error", &io_hdr, verbose > 1);
if (rawp) free(rawp);
return 1;
}
diff --git a/sg_read.c b/sg_read.c
index a224272e..1746ed08 100644
--- a/sg_read.c
+++ b/sg_read.c
@@ -40,7 +40,7 @@
*/
-static const char * version_str = "1.06 20050806";
+static const char * version_str = "1.06 20051025";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -299,7 +299,7 @@ int sg_bread(int sg_fd, unsigned char * buff, int blocks, int from_block,
case SG_LIB_CAT_MEDIA_CHANGED:
return 2;
default:
- sg_chk_n_print3("reading", &io_hdr, verbose);
+ sg_chk_n_print3("reading", &io_hdr, verbose > 1);
return -1;
}
if (diop && *diop &&
diff --git a/sg_read_long.c b/sg_read_long.c
index 49cb1848..c385083a 100644
--- a/sg_read_long.c
+++ b/sg_read_long.c
@@ -25,7 +25,7 @@
the sector data and the ECC bytes.
*/
-static char * version_str = "1.06 20050808";
+static char * version_str = "1.06 20051025";
#define READ_LONG_OPCODE 0x3E
#define READ_LONG_CMD_LEN 10
@@ -163,7 +163,7 @@ static int sg_ll_read_long10(int sg_fd, int correct, unsigned long lba,
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("READ LONG(10), continuing", &io_hdr, verbose);
+ sg_chk_n_print3("READ LONG(10), continuing", &io_hdr, verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
diff --git a/sg_readcap.c b/sg_readcap.c
index cce6ba98..9272be79 100644
--- a/sg_readcap.c
+++ b/sg_readcap.c
@@ -27,7 +27,7 @@
*/
-static char * version_str = "3.74 20050808";
+static char * version_str = "3.75 20051114";
#define ME "sg_readcap: "
@@ -238,8 +238,8 @@ int main(int argc, char * argv[])
goto good;
}
printf("Read Capacity results:\n");
- printf(" Protection: prot_en=%d, rto_en=%d\n",
- !!(resp_buff[12] & 0x1), !!(resp_buff[12] & 0x2));
+ 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 block before "
"delay=0x%llx\n", llba, llast_blk_addr);
diff --git a/sg_reassign.c b/sg_reassign.c
index 08d6b87e..ac2a4a03 100644
--- a/sg_reassign.c
+++ b/sg_reassign.c
@@ -50,7 +50,7 @@
* vendor specific data is written.
*/
-static char * version_str = "1.03 20050808";
+static char * version_str = "1.03 20051025";
#define ME "sg_reassign: "
@@ -164,7 +164,7 @@ int sg_ll_reassign_blocks(int sg_fd, int dummy, int longlba, int longlist,
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Reassign blocks, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("Reassign blocks, continuing", &io_hdr, verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -179,7 +179,7 @@ int sg_ll_reassign_blocks(int sg_fd, int dummy, int longlba, int longlist,
snprintf(ebuff, EBUFF_SZ, "Reassign blocks error, longlba=%d "
"longlist=%d\n ", longlba, longlist);
- sg_chk_n_print3(ebuff, &io_hdr, verbose);
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
}
return -1;
}
diff --git a/sg_requests.c b/sg_requests.c
index 78d5c503..eb94a582 100644
--- a/sg_requests.c
+++ b/sg_requests.c
@@ -149,7 +149,7 @@ int main(int argc, char * argv[])
if (0 == res) {
resp_len = requestSenseBuff[7] + 8;
fprintf(stderr, "Decode response as sense data:\n");
- sg_print_sense(NULL, requestSenseBuff, resp_len, verbose);
+ sg_print_sense(NULL, requestSenseBuff, resp_len, 0);
if (verbose) {
fprintf(stderr, "\nOutput response in hex\n");
dStrHex((const char *)requestSenseBuff, resp_len, 1);
diff --git a/sg_ses.8 b/sg_ses.8
index 4e5230cc..750af4b3 100644
--- a/sg_ses.8
+++ b/sg_ses.8
@@ -1,4 +1,4 @@
-.TH SG_SES "8" "July 2005" "sg3_utils-1.16" SG3_UTILS
+.TH SG_SES "8" "October 2005" "sg3_utils-1.18" SG3_UTILS
.SH NAME
sg_ses \- send controls and fetch status from a SCSI Enclosure
Services (SES) device
@@ -96,8 +96,20 @@ be sent to a device with the sg_senddiag utility.
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 reponse. See safte-monitor on the internet.
-.SH EXAMPLE
+INQUIRY response. See safte-monitor on the internet.
+.SH EXAMPLES
+To view the supported pages:
+.PP
+ sg_ses /dev/sda
+.PP
+To view the configuration page:
+.PP
+ sg_ses --page=1 /dev/sda
+.PP
+To view the status page:
+.PP
+ 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
diff --git a/sg_ses.c b/sg_ses.c
index 6aa436c7..64ae6214 100644
--- a/sg_ses.c
+++ b/sg_ses.c
@@ -47,7 +47,7 @@
*commands tailored for SES (enclosure) devices.
*/
-static char * version_str = "1.18 20050808";
+static char * version_str = "1.21 20051113"; /* ses2r13 */
#define MX_ALLOC_LEN 4096
#define MX_ELEM_HDR 512
@@ -120,39 +120,6 @@ static int do_senddiag(int sg_fd, int pf_bit, void * outgoing_pg,
noisy, verbose);
}
-static const char * scsi_ptype_strs[] = {
- /* 0 */ "disk",
- "tape",
- "printer",
- "processor",
- "write once optical disk",
- /* 5 */ "cd/dvd",
- "scanner",
- "optical memory device",
- "medium changer",
- "communications",
- /* 0xa */ "graphics",
- "graphics",
- "storage array controller",
- "enclosure services device",
- "simplified direct access device",
- "optical card reader/writer device",
- /* 0x10 */ "bridge controller commands",
- "object based storage",
- "automation/driver interface",
- "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
- "0x19", "0x1a", "0x1b", "0x1c", "0x1d",
- "well known logical unit",
- "no physical device on this lu",
-};
-
-static const char * get_ptype_str(int scsi_ptype)
-{
- int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]);
-
- return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : "";
-}
-
struct page_code_desc {
int page_code;
const char * desc;
@@ -178,6 +145,27 @@ static struct page_code_desc pc_desc_arr[] = {
{0x40, "Translate address (SBC)"},
{0x41, "Device status (SBC)"},
};
+static struct page_code_desc in_pc_desc_arr[] = {
+ {0x0, "Supported diagnostic pages"},
+ {0x1, "Configuration (SES)"},
+ {0x2, "Enclosure status (SES)"},
+ {0x3, "Help text (SES)"},
+ {0x4, "String In (SES)"},
+ {0x5, "Threshold In (SES)"},
+ {0x6, "Array Status (SES, obsolete)"},
+ {0x7, "Element descriptor (SES)"},
+ {0x8, "Short enclosure status (SES)"},
+ {0x9, "Enclosure busy (SES-2)"},
+ {0xa, "Additional (device) element status (SES-2)"},
+ {0xb, "Subenclosure help text (SES-2)"},
+ {0xc, "Subenclosure string In (SES-2)"},
+ {0xd, "Supported SES diagnostic pages (SES-2)"},
+ {0xe, "Download microcode (SES-2)"},
+ {0xf, "Subenclosure nickname (SES-2)"},
+ {0x3f, "Protocol specific SAS (SAS-1)"},
+ {0x40, "Translate address (SBC)"},
+ {0x41, "Device status (SBC)"},
+};
static const char * find_page_code_desc(int page_num)
{
@@ -194,6 +182,21 @@ static const char * find_page_code_desc(int page_num)
return NULL;
}
+static const char * find_in_page_code_desc(int page_num)
+{
+ int k;
+ int num = sizeof(in_pc_desc_arr) / sizeof(in_pc_desc_arr[0]);
+ const struct page_code_desc * pcdp = &in_pc_desc_arr[0];
+
+ for (k = 0; k < num; ++k, ++pcdp) {
+ if (page_num == pcdp->page_code)
+ return pcdp->desc;
+ else if (page_num < pcdp->page_code)
+ return NULL;
+ }
+ return NULL;
+}
+
struct element_desc {
int type_code;
const char * desc;
@@ -400,30 +403,29 @@ static char * find_sas_connector_type(int conn_type, char * buff,
snprintf(buff, buff_len, "No information");
break;
case 0x1:
- snprintf(buff, buff_len, "SAS external receptacle (SFF-8470) "
+ snprintf(buff, buff_len, "SAS 4x receptacle (SFF-8470) "
"[max 4 phys]");
break;
case 0x2:
- snprintf(buff, buff_len, "SAS external compact receptacle "
- "(SFF-8088) [max 4 phys]");
+ snprintf(buff, buff_len, "Mini SAS 4x receptacle (SFF-8088) "
+ "[max 4 phys]");
break;
case 0x10:
- snprintf(buff, buff_len, "SAS internal wide plug (SFF-8484) "
- "[max 4 phys]");
+ snprintf(buff, buff_len, "SAS 4i plug (SFF-8484) [max 4 phys]");
break;
case 0x11:
- snprintf(buff, buff_len, "SAS internal compact wide plug "
- "(SFF-8087) [max 4 phys]");
+ snprintf(buff, buff_len, "Mini SAS 4i receptacle (SFF-8087) "
+ "[max 4 phys]");
break;
case 0x20:
- snprintf(buff, buff_len, "SAS backplane receptacle (SFF-8482) "
+ snprintf(buff, buff_len, "SAS Drive backplane receptacle (SFF-8482) "
"[max 2 phys]");
break;
case 0x21:
- snprintf(buff, buff_len, "SATA style host plug [max 1 phy]");
+ snprintf(buff, buff_len, "SATA host plug [max 1 phy]");
break;
case 0x22:
- snprintf(buff, buff_len, "SAS plug (SFF-8482) [max 2 phys]");
+ snprintf(buff, buff_len, "SAS Drive plug (SFF-8482) [max 2 phys]");
break;
case 0x23:
snprintf(buff, buff_len, "SATA device plug [max 1 phy]");
@@ -444,7 +446,7 @@ static char * find_sas_connector_type(int conn_type, char * buff,
else if (conn_type < 0x80)
snprintf(buff, buff_len, "vendor specific connector type: 0x%x",
conn_type);
- else /* conn_type comes from a 7 bit field, so this is imposs */
+ else /* conn_type is a 7 bit field, so this is impossible */
snprintf(buff, buff_len, "unexpected connector type: 0x%x",
conn_type);
break;
@@ -531,7 +533,7 @@ static void print_element_status(const char * pad,
!!(statp[1] & 0x80), !!(statp[3] & 0x40),
!!(statp[3] & 0x20), !!(statp[3] & 0x10));
printf("%sActual speed=%d rpm, Fan %s\n", pad,
- (((3 & statp[1]) << 8) + statp[2]) * 10,
+ (((0x7 & statp[1]) << 8) + statp[2]) * 10, /* 05-372r0 */
actual_speed_desc[7 & statp[3]]);
break;
case 4: /* temperature sensor */
@@ -996,20 +998,20 @@ static char * sas_device_type[] = {
static void ses_transport_proto(const unsigned char * ucp, int len,
int elem_num)
{
- int ports, phys, j, m, desc_type, eip_off;
+ int ports, phys, j, m, desc_type, eip_offset;
const unsigned char * per_ucp;
- eip_off = (0x10 & ucp[0]) ? 2 : 0;
+ eip_offset = (0x10 & ucp[0]) ? 2 : 0;
switch (0xf & ucp[0]) {
case 0: /* FCP */
- ports = ucp[2 + eip_off];
+ ports = ucp[2 + eip_offset];
printf(" [%d] Transport protocol: FCP, number of ports: %d\n",
elem_num + 1, ports);
printf(" node_name: ");
for (m = 0; m < 8; ++m)
- printf("%02x", ucp[6 + eip_off + m]);
+ printf("%02x", ucp[6 + eip_offset + m]);
printf("\n");
- per_ucp = ucp + 14 + eip_off;
+ per_ucp = ucp + 14 + eip_offset;
for (j = 0; j < ports; ++j, per_ucp += 16) {
printf(" [%d] port loop position: %d, port requested hard "
"address: %d\n", j + 1, per_ucp[0], per_ucp[4]);
@@ -1022,14 +1024,14 @@ static void ses_transport_proto(const unsigned char * ucp, int len,
}
break;
case 6: /* SAS */
- desc_type = (ucp[3 + eip_off] >> 6) & 0x3;
+ desc_type = (ucp[3 + eip_offset] >> 6) & 0x3;
printf(" [%d] Transport protocol: SAS, ", elem_num + 1);
if (0 == desc_type) {
- phys = ucp[2 + eip_off];
+ phys = ucp[2 + eip_offset];
printf("SAS and SATA device descriptor type [%d]\n", desc_type);
printf(" number of phys: %d, not all phys: %d\n", phys,
- ucp[3 + eip_off] & 1);
- per_ucp = ucp + 4 + eip_off + eip_off;
+ ucp[3 + eip_offset] & 1);
+ per_ucp = ucp + 4 + eip_offset + eip_offset;
for (j = 0; j < phys; ++j, per_ucp += 28) {
printf(" [%d] device type: %s\n", phys + 1,
sas_device_type[(0x70 & per_ucp[0]) >> 4]);
@@ -1052,14 +1054,14 @@ static void ses_transport_proto(const unsigned char * ucp, int len,
printf("\n phy identifier: 0x%x\n", per_ucp[20]);
}
} else if (1 == desc_type) {
- phys = ucp[2 + eip_off];
+ phys = ucp[2 + eip_offset];
printf("expander descriptor type [%d]\n", desc_type);
printf(" number of phys: %d\n", phys);
printf(" SAS address: ");
for (m = 0; m < 8; ++m)
- printf("%02x", ucp[6 + eip_off + m]);
+ printf("%02x", ucp[6 + eip_offset + m]);
printf("\n");
- per_ucp = ucp + 14 + eip_off;
+ per_ucp = ucp + 14 + eip_offset;
for (j = 0; j < phys; ++j, per_ucp += 2) {
printf(" [%d] ", phys + 1);
if (0xff == per_ucp[0])
@@ -1380,7 +1382,7 @@ static void ses_process_status(int sg_fd, int page_code, int do_raw,
const char * cp;
memset(rsp_buff, 0, rsp_buff_size);
- cp = find_page_code_desc(page_code);
+ cp = find_in_page_code_desc(page_code);
if (0 == sg_ll_receive_diag(sg_fd, 1, page_code, rsp_buff,
rsp_buff_size, 1, verbose)) {
rsp_len = (rsp_buff[2] << 8) + rsp_buff[3] + 4;
@@ -1524,6 +1526,7 @@ int main(int argc, char * argv[])
int inner_hex = 0;
int byte1 = 0;
char device_name[256];
+ char buff[48];
unsigned char data_arr[1024];
int arr_len = 0;
int pd_type = 0;
@@ -1667,7 +1670,7 @@ int main(int argc, char * argv[])
printf(" %.8s %.16s %.4s\n", inq_resp.vendor,
inq_resp.product, inq_resp.revision);
pd_type = inq_resp.peripheral_type;
- cp = get_ptype_str(pd_type);
+ cp = sg_get_pdt_str(pd_type, sizeof(buff), buff);
if (0xd == pd_type)
printf(" enclosure services device\n");
else if (0x40 & inq_resp.byte_6)
diff --git a/sg_start.8 b/sg_start.8
index 2796103f..d0484948 100644
--- a/sg_start.8
+++ b/sg_start.8
@@ -1,4 +1,4 @@
-.TH SG_START "8" "August 2005" "sg3_utils-1.16" SG3_UTILS
+.TH SG_START "8" "October 2005" "sg3_utils-1.18" SG3_UTILS
.SH NAME
sg_start \- starts (spins-up) or stops (spins down) SCSI device, load or
eject medium
@@ -38,7 +38,7 @@ already started (or is in the process of starting).
.TP
-eject
stop the medium and eject it from the drive. Only appropriate for a
-removable medium.
+device with removable medium. Might be ignored (prevented), see below.
.TP
-imm=0|1
when the immediate bit is 1 then this utility returns immediately after
diff --git a/sg_turs.8 b/sg_turs.8
index 3349517c..754c9d02 100644
--- a/sg_turs.8
+++ b/sg_turs.8
@@ -1,11 +1,11 @@
-.TH SG_TURS "8" "April 2005" "sg3_utils-1.14" SG3_UTILS
+.TH SG_TURS "8" "October 2005" "sg3_utils-1.18" SG3_UTILS
.SH NAME
sg_turs \- executes a user specified number of TEST UNIT READY commands on
the given device
.SH SYNOPSIS
.B sg_turs
-[\fI-n=<number of commands to send>\fR] [\fI-t] [\fI-v] [\fI-V]
-<\fIscsi_device\fR>
+[\fI-n=<number of commands to send>\fR] [\fI-p\fR] [\fI-t\fR] [\fI-v\fR]
+[\fI-V\fR] <\fIscsi_device\fR>
.SH DESCRIPTION
.\" Add any additional description here
.PP
@@ -22,6 +22,11 @@ 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.
.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.
+.TP
-t
after completing the requested number of TEST UNIT READY commands, outputs
the total duration and the average number of commands executed per second.
diff --git a/sg_turs.c b/sg_turs.c
index 8220743a..b0881f27 100644
--- a/sg_turs.c
+++ b/sg_turs.c
@@ -26,16 +26,19 @@
*/
-static char * version_str = "3.17 20050808";
+static char * version_str = "3.18 20051012";
#define EBUFF_SZ 256
static void usage()
{
- printf("Usage: 'sg_turs [-n=<num_of_test_unit_readys>] [-t] "
- "[-v] [-V] <scsi_device>'\n"
+ printf("Usage: 'sg_turs [-n=<num_of_test_unit_readys>] [-p] [-t] "
+ "[-v] [-V]\n"
+ " <scsi_device>'\n"
" where '-n=<num>' number of test_unit_ready commands "
"(def: 1)\n"
+ " '-p' outputs progress indication (percentage) "
+ "if available\n"
" '-t' outputs total duration and commands per "
"second\n"
" '-v' increase verbosity\n"
@@ -50,6 +53,8 @@ int main(int argc, char * argv[])
const char * cp;
char ebuff[EBUFF_SZ];
int num_turs = 1;
+ int do_progress = 0;
+ int progress;
int num_errs = 0;
int do_time = 0;
int verbose = 0;
@@ -64,6 +69,9 @@ int main(int argc, char * argv[])
if ('-' == *cp) {
for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
switch (*cp) {
+ case 'p':
+ do_progress = 1;
+ break;
case 't':
do_time = 1;
break;
@@ -118,40 +126,58 @@ int main(int argc, char * argv[])
perror(ebuff);
return 1;
}
- if (do_time) {
- start_tm.tv_sec = 0;
- start_tm.tv_usec = 0;
- gettimeofday(&start_tm, NULL);
- }
- for (k = 0; k < num_turs; ++k) {
- if (sg_ll_test_unit_ready(sg_fd, k, ((1 == num_turs) ? 1 : 0),
- verbose))
- ++num_errs;
- }
- if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
- struct timeval res_tm;
- double a, b;
+ if (do_progress) {
+ for (k = 0; k < num_turs; ++k) {
+ if (k > 0)
+ sleep(30);
+ progress = -1;
+ sg_ll_test_unit_ready_progress(sg_fd, k, &progress,
+ ((1 == num_turs) ? 1 : 0), verbose);
+ if (progress < 0)
+ break;
+ else
+ printf("Progress indication: %d%% done\n",
+ (progress * 100) / 65536);
+ }
+ if (num_turs > 1)
+ printf("Completed %d Test Unit Ready commands\n",
+ ((k < num_turs) ? k + 1 : k));
+ } else {
+ if (do_time) {
+ start_tm.tv_sec = 0;
+ start_tm.tv_usec = 0;
+ gettimeofday(&start_tm, NULL);
+ }
+ for (k = 0; k < num_turs; ++k) {
+ if (sg_ll_test_unit_ready(sg_fd, k, ((1 == num_turs) ? 1 : 0),
+ verbose))
+ ++num_errs;
+ }
+ if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
+ struct timeval res_tm;
+ double a, b;
- 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;
- if (res_tm.tv_usec < 0) {
- --res_tm.tv_sec;
- res_tm.tv_usec += 1000000;
+ 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;
+ if (res_tm.tv_usec < 0) {
+ --res_tm.tv_sec;
+ res_tm.tv_usec += 1000000;
+ }
+ a = res_tm.tv_sec;
+ a += (0.000001 * res_tm.tv_usec);
+ b = (double)num_turs;
+ printf("time to perform commands was %d.%06d secs",
+ (int)res_tm.tv_sec, (int)res_tm.tv_usec);
+ if (a > 0.00001)
+ printf("; %.2f operations/sec\n", b / a);
+ else
+ printf("\n");
}
- a = res_tm.tv_sec;
- a += (0.000001 * res_tm.tv_usec);
- b = (double)num_turs;
- printf("time to perform commands was %d.%06d secs",
- (int)res_tm.tv_sec, (int)res_tm.tv_usec);
- if (a > 0.00001)
- printf("; %.2f operations/sec\n", b / a);
- else
- printf("\n");
- }
- printf("Completed %d Test Unit Ready commands with %d errors\n",
- num_turs, num_errs);
+ printf("Completed %d Test Unit Ready commands with %d errors\n",
+ num_turs, num_errs);
+ }
close(sg_fd);
return num_errs ? 1 : 0;
}
diff --git a/sg_verify.c b/sg_verify.c
index 0ee2fc59..77a48b94 100644
--- a/sg_verify.c
+++ b/sg_verify.c
@@ -45,7 +45,7 @@
* This program issues the SCSI VERIFY command to the given SCSI block device.
*/
-static char * version_str = "1.04 20050808";
+static char * version_str = "1.04 20051025";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
#define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
@@ -149,7 +149,7 @@ int sg_ll_verify10(int sg_fd, int dpo, int bytechk, unsigned long lba,
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("VERIFY(10), continuing", &io_hdr, verbose);
+ sg_chk_n_print3("VERIFY(10), continuing", &io_hdr, verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
return 0;
@@ -159,7 +159,7 @@ int sg_ll_verify10(int sg_fd, int dpo, int bytechk, unsigned long lba,
sg_chk_n_print3("VERIFY(10) command problem", &io_hdr, 1);
return res;
default:
- sg_chk_n_print3("VERIFY(10) command problem", &io_hdr, verbose);
+ sg_chk_n_print3("VERIFY(10) command problem", &io_hdr, verbose > 1);
return -1;
}
}
diff --git a/sg_write_long.8 b/sg_write_long.8
index 02359b0d..0a1fc2e8 100644
--- a/sg_write_long.8
+++ b/sg_write_long.8
@@ -1,14 +1,15 @@
-.TH SG_WRITE_LONG "8" "February 2005" "sg3_utils-1.13" SG3_UTILS
+.TH SG_WRITE_LONG "8" "October 2005" "sg3_utils-1.18" SG3_UTILS
.SH NAME
sg_write_long \- send the SCSI command write long
.SH SYNOPSIS
.B sg_write_long
-[\fI--help\fR] [\fI--in=<name>\fR] [\fI--lba=<num>\fR] [\fI--verbose\fR]
-[\fI--version\fR] [\fI--xfer_len=<num>\fR] \fI<scsi_device>\fR
+[\fI--cor_dis\fR] [\fI--help\fR] [\fI--in=<name>\fR] [\fI--lba=<num>\fR]
+[\fI--verbose\fR] [\fI--version\fR] [\fI--xfer_len=<num>\fR]
+\fI<scsi_device>\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send WRITE LONG command to a Linux SCSI device. The
+Send WRITE LONG (10) command to a Linux SCSI device. The
buffer to be written to the device is filled with
.B 0xff
bytes or read from the given file. This buffer includes the sector data
@@ -26,6 +27,11 @@ contents of the logical block address with
.B sg_read_long
utility prior to testing and restore it with this utility after testing.
.TP
+--cor_dis | -c
+sets the correction disabled bit. This inhibits various other
+mechanisms such as automatic block reallocation, error recovery
+and various informational exception conditions being triggered.
+.TP
--help | -h
output the usage message then exit.
.TP
diff --git a/sg_write_long.c b/sg_write_long.c
index e1496ee9..ae91ac95 100644
--- a/sg_write_long.c
+++ b/sg_write_long.c
@@ -27,7 +27,7 @@
This code was contributed by Saeed Bishara
*/
-static char * version_str = "1.06 20050808";
+static char * version_str = "1.08 20051113";
#define WRITE_LONG_OPCODE 0x3F
#define WRITE_LONG_CMD_LEN 10
@@ -42,6 +42,7 @@ static char * version_str = "1.06 20050808";
#define EBUFF_SZ 256
static struct option long_options[] = {
+ {"cor_dis", 0, 0, 'c'},
{"help", 0, 0, 'h'},
{"in", 1, 0, 'i'},
{"lba", 1, 0, 'l'},
@@ -54,9 +55,11 @@ static struct option long_options[] = {
static void usage()
{
fprintf(stderr, "Usage: "
- "sg_write_long [--help] [--in=<name>] [--lba=<num>] [--verbose]\n"
- " [--version] [--xfer_len=<num>] <scsi_device>\n"
- " where: --help print out usage message\n"
+ "sg_write_long [--cor_dis] [--help] [--in=<name>] [--lba=<num>]\n"
+ " [--verbose] [--version] [--xfer_len=<num>] "
+ "<scsi_device>\n"
+ " where: --cor_dis set correction disabled bit\n"
+ " --help print out usage message\n"
" --in=<name> input from file <name> (default write "
"0xff bytes)\n"
" --lba=<num>|-l <num> logical block address (default 0)\n"
@@ -70,7 +73,7 @@ static void usage()
" To write to a defected sector use:\n"
" sg_dd of=<scsi_device> seek=<lba> if=/dev/zero bs=512 "
"count=1\n\n"
- "Performs a WRITE LONG SCSI command\n"
+ "Performs a WRITE LONG (10) SCSI command\n"
);
}
@@ -121,6 +124,7 @@ int main(int argc, char * argv[])
void * rawp = NULL;
unsigned char sense_buffer[SENSE_BUFF_LEN];
int xfer_len = 520;
+ int cor_dis = 0;
unsigned int lba = 0;
int verbose = 0;
int got_stdin;
@@ -136,11 +140,15 @@ int main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "hi:l:vVx:", long_options, &option_index);
+ c = getopt_long(argc, argv, "chi:l:vVx:", long_options,
+ &option_index);
if (c == -1)
break;
switch (c) {
+ case 'c':
+ cor_dis = 1;
+ break;
case 'h':
case '?':
usage();
@@ -252,6 +260,9 @@ int main(int argc, char * argv[])
/*size*/
writeLongCmdBlk[7] = (xfer_len & 0x0000ff00) >> 8;
writeLongCmdBlk[8] = (xfer_len & 0x000000ff);
+
+ if (cor_dis)
+ writeLongCmdBlk[1] |= 0x80;
fprintf(stderr, ME "issue write long to device %s\n\t\txfer_len= %d "
"(0x%x), lba=%d (0x%x)\n", device_name, xfer_len, xfer_len,
@@ -284,7 +295,7 @@ int main(int argc, char * argv[])
/* now for the error processing */
switch (sg_err_category3(&io_hdr)) {
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("WRITE LONG, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("WRITE LONG, continuing", &io_hdr, verbose > 1);
/* fall through */
case SG_LIB_CAT_CLEAN:
break;
@@ -302,7 +313,7 @@ int main(int argc, char * argv[])
"expected but not found]\n");
goto err_out;
}
- sg_chk_n_print3("WRITE LONG problem error", &io_hdr, verbose);
+ sg_chk_n_print3("WRITE LONG problem error", &io_hdr, verbose > 1);
goto err_out;
}
diff --git a/sginfo.c b/sginfo.c
index 28be4db7..e84c096e 100644
--- a/sginfo.c
+++ b/sginfo.c
@@ -110,7 +110,7 @@
#define _XOPEN_SOURCE 500
#define _GNU_SOURCE
-static const char * sginfo_version_str = "sginfo version 2.18 [20050906]";
+static const char * version_str = "2.20 [20051114]";
#include <stdio.h>
#include <string.h>
@@ -180,6 +180,8 @@ static int common_proto_spec_port(struct mpage_info * mpi,
const char * prefix);
static int common_proto_spec_port_sp1(struct mpage_info * mpi,
const char * prefix);
+static int common_proto_spec_port_sp2(struct mpage_info * mpi,
+ const char * prefix);
static int common_power_condition(struct mpage_info * mpi,
const char * prefix);
static int common_informational(struct mpage_info * mpi, const char * prefix);
@@ -237,8 +239,10 @@ static struct mpage_name_func mpage_common[] =
{ 0x19, 0, PC_COMMON, "Protocol specific port", common_proto_spec_port},
{ 0x19, 1, PC_COMMON, "Protocol specific port, subpage 1 overload",
common_proto_spec_port_sp1},
- { 0x19, 2, PC_COMMON, "SPI-4 Saved Training configuration",
- spi4_training_config},
+ { 0x19, 2, PC_COMMON, "Protocol specific port, subpage 2 overload",
+ common_proto_spec_port_sp2},
+/* { 0x19, 2, PC_COMMON, "SPI-4 Saved Training configuration",
+ spi4_training_config}, */
{ 0x19, 3, PC_COMMON, "SPI-4 Negotiated Settings", spi4_negotiated},
{ 0x19, 4, PC_COMMON, "SPI-4 Report transfer capabilities",
spi4_report_xfer},
@@ -1100,24 +1104,26 @@ int setup_mode_page(struct mpage_info * mpi, int nparam,
return 0;
}
-static int get_protocol_id(int port1_or_lu0, unsigned char * buff,
+static int get_protocol_id(int port_not_lu, unsigned char * buff,
int * proto_idp, int * offp)
{
- int status, off, proto_id;
+ int status, off, proto_id, spf;
struct mpage_info mp_i;
memset(&mp_i, 0, sizeof(mp_i));
- mp_i.page = (port1_or_lu0 ? 0x19 : 0x18);
+ mp_i.page = (port_not_lu ? 0x19 : 0x18);
+ /* N.B. getting port or lu specific mode page (not subpage) */
status = get_mode_page(&mp_i, 0, buff);
if (status)
return status;
off = modePageOffset(buff, mp_i.resp_len, mode6byte);
if (off < 0)
return off;
- proto_id = buff[off + 2] & 0xf;
+ spf = (buff[off] & 0x40) ? 1 : 0; /* subpages won't happen here */
+ proto_id = buff[off + (spf ? 5 : 2)] & 0xf;
if (trace_cmd > 0)
printf("Protocol specific %s, protocol_id=%s\n",
- (port1_or_lu0 ? "port" : "lu"),
+ (port_not_lu ? "port" : "lu"),
transport_proto_arr[proto_id]);
if (proto_idp)
*proto_idp = proto_id;
@@ -2642,8 +2648,8 @@ static int sas_phy_control_discover(struct mpage_info * mpi,
if (prefix[0])
printf("%s", prefix);
if (!x_interface && !replace) {
- printf("%s mode subpage (0x%x,0x%x)\n", "SAS Phy Control and Discover",
- mpi->page, mpi->subpage);
+ printf("%s mode subpage (0x%x,0x%x)\n", "SAS Phy Control and "
+ "Discover", mpi->page, mpi->subpage);
printf("--------------------------------------------\n");
}
intfield(pagestart + 7, 1, "Number of phys");
@@ -2701,8 +2707,8 @@ static int spi4_training_config(struct mpage_info * mpi, const char * prefix)
if (prefix[0])
printf("%s", prefix);
if (!x_interface && !replace) {
- printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page,
- mpi->subpage);
+ printf("%s mode subpage (0x%x,0x%x)\n", "training configuration",
+ mpi->page, mpi->subpage);
printf("----------------------------------------------------------\n");
}
hexdatafield(pagestart + 10, 4, "DB(0) value");
@@ -2740,6 +2746,48 @@ static int spi4_training_config(struct mpage_info * mpi, const char * prefix)
return 0;
}
+/* SAS(2) SSP, shared protocol specific port mode subpage (subpage 2) */
+static int sas_shared_spec_port(struct mpage_info * mpi, const char * prefix)
+{
+ int status;
+ unsigned char *pagestart;
+
+ status = setup_mode_page(mpi, 1, cbuffer, &pagestart);
+ if (status)
+ return status;
+
+ if (prefix[0])
+ printf("%s", prefix);
+ if (!x_interface && !replace) {
+ printf("%s mode subpage (0x%x,0x%x)\n", "SAS SSP shared protocol "
+ "specific port", mpi->page, mpi->subpage);
+ printf("-----------------------------------------------------\n");
+ }
+ intfield(pagestart + 6, 2, "Power loss timeout(ms)");
+
+ if (x_interface && replace)
+ return put_mode_page(mpi, cbuffer);
+ else
+ printf("\n");
+ return 0;
+}
+
+static int common_proto_spec_port_sp2(struct mpage_info * mpi,
+ const char * prefix)
+{
+ int status, proto_id;
+
+ status = get_protocol_id(1, cbuffer, &proto_id, NULL);
+ if (status)
+ return status;
+ if (1 == proto_id)
+ return spi4_training_config(mpi, prefix);
+ else if (6 == proto_id)
+ return sas_shared_spec_port(mpi, prefix);
+ else
+ return DECODE_FAILED_TRY_HEX;
+}
+
static int spi4_negotiated(struct mpage_info * mpi, const char * prefix)
{
int status;
@@ -2974,8 +3022,8 @@ static int do_inquiry(int * peri_type, int * resp_byte6,
}
if (!x_interface && !replace) {
- printf("INQUIRY reponse (cmd: 0x12)\n");
- printf("---------------------------\n");
+ printf("INQUIRY response (cmd: 0x12)\n");
+ printf("----------------------------\n");
};
bitfield(pagestart + 0, "Device Type", 0x1f, 0);
if (2 == inquiry_verbosity) {
@@ -3463,8 +3511,8 @@ static void usage(char *errtext)
"\t-R Replace parameters - best used with -X (expert use only)\n"
"\t [replacement parameters placed after device on command line]\n\n",
stdout);
- printf("\t %s; See man page for further details.\n",
- sginfo_version_str);
+ printf("\t sginfo version: %s; See man page for further details.\n",
+ version_str);
exit(2);
}
@@ -3474,6 +3522,7 @@ int main(int argc, char *argv[])
unsigned int unum, unum2;
int decode_in_hex = 0;
char c;
+ char * cp;
int status = 0;
long tmp;
struct mpage_info mp_i;
@@ -3604,7 +3653,12 @@ int main(int argc, char *argv[])
unum2 = 0;
j = sscanf(optarg, "0x%x,0x%x", &unum, &unum2);
mp_i.page = unum;
- mp_i.subpage = unum2;
+ if (1 == j) {
+ cp = strchr(optarg, ',');
+ if (cp && (1 == sscanf(cp, ",%d", &mp_i.subpage)))
+ j = 2;
+ } else
+ mp_i.subpage = unum2;
} else
j = sscanf(optarg, "%d,%d", &mp_i.page, &mp_i.subpage);
if (1 == j)
@@ -3619,7 +3673,7 @@ int main(int argc, char *argv[])
found = 1;
break;
case 'v':
- fprintf(stdout, " %s\n", sginfo_version_str);
+ fprintf(stdout, "sginfo version: %s\n", version_str);
return 0;
case 'V':
mp_i.page = 0x7;
diff --git a/sgm_dd.c b/sgm_dd.c
index cd781ad7..ef85ad5c 100644
--- a/sgm_dd.c
+++ b/sgm_dd.c
@@ -54,7 +54,7 @@
This version is designed for the linux kernel 2.4 and 2.6 series.
*/
-static char * version_str = "1.21 20050909";
+static char * version_str = "1.21 20051025";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -469,12 +469,12 @@ int sg_read(int sg_fd, unsigned char * buff, int blocks, long long from_block,
case SG_LIB_CAT_CLEAN:
break;
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Reading, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("Reading, continuing", &io_hdr, verbose > 1);
break;
case SG_LIB_CAT_MEDIA_CHANGED:
return 2;
default:
- sg_chk_n_print3("reading", &io_hdr, verbose);
+ sg_chk_n_print3("reading", &io_hdr, verbose > 1);
return -1;
}
sum_of_resids += io_hdr.resid;
@@ -553,12 +553,12 @@ int sg_write(int sg_fd, unsigned char * buff, int blocks, long long to_block,
case SG_LIB_CAT_CLEAN:
break;
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Writing, continuing", &io_hdr, verbose);
+ sg_chk_n_print3("Writing, continuing", &io_hdr, verbose > 1);
break;
case SG_LIB_CAT_MEDIA_CHANGED:
return 2;
default:
- sg_chk_n_print3("writing", &io_hdr, verbose);
+ sg_chk_n_print3("writing", &io_hdr, verbose > 1);
return -1;
}
if (diop && *diop &&