aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2007-06-27 03:14:21 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2007-06-27 03:14:21 +0000
commitc83e58b4d5d0afd71b0742dd9f008fc33c317d0c (patch)
tree6ddb55ad3c304fd6eafa9125723170a1eed1618c
parentfa84ae0fc95b560c5afa0577f6bfabf58028d63a (diff)
downloadsg3_utils-c83e58b4d5d0afd71b0742dd9f008fc33c317d0c.tar.gz
Load sg3_utils-1.17 into trunk/.
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@59 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--CHANGELOG18
-rw-r--r--COVERAGE5
-rw-r--r--INSTALL19
-rw-r--r--README20
-rw-r--r--debian/changelog6
-rw-r--r--debian/control1
-rw-r--r--lib_no_lib/sg3_utils.spec.no_lib6
-rw-r--r--sg3_utils.spec6
-rw-r--r--sg_cmds.c13
-rw-r--r--sg_dd.c6
-rw-r--r--sg_format.87
-rw-r--r--sg_format.c5
-rw-r--r--sg_inq.8164
-rw-r--r--sg_inq.c837
-rw-r--r--sg_lib.c125
-rw-r--r--sg_lib.h22
-rw-r--r--sg_logs.c9
-rw-r--r--sg_modes.c3
-rw-r--r--sg_opcodes.86
-rw-r--r--sg_opcodes.c6
-rw-r--r--sg_scan.c5
-rw-r--r--sginfo.821
-rw-r--r--sginfo.c45
-rw-r--r--sgm_dd.834
-rw-r--r--sgm_dd.c136
25 files changed, 1094 insertions, 431 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 9450dd60..d5da92c7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,24 @@ 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.17 [20050922]
+ - sg_inq: add '-a' option for ATA information VPD page
+ - add '-b' option for Block limits VPD page (SBC)
+ - add '-A' option for probing ATA or ATAPI device
+ - increase raw ('-r') and verbose ('-v') output for
+ ATA(PI) devices to 512 bytes (was 256 bytes)
+ - output hex ('-H') and verbose response for ATA(PI)
+ devices in 16 bit words (corrected for endianness)
+ - output bytes if '-HH' option given
+ - sync with spc4 rev 02
+ - sg_lib: add dWordHex() and sg_is_big_endian()
+ - sync asc/ascq with spc4 rev 02
+ - sg_cmds: defensive prefill for inquiry commands
+ - sg_opcodes: sync with spc4 rev 02 (add tmf I_T nexus reset)
+ - sginfo: add EBACKERR in Informational exception mode page
+ - add Background control mode page (SBC-3)
+ - sgm_dd: add 'verbose=<n>' option
+
Changelog for sg3_utils-1.16 [20050810]
- sg_ident: new utility to report+set device identifier
- sg_map: increase MAX_SG_DEVS from 256 to 2048
diff --git a/COVERAGE b/COVERAGE
index 0ddb24da..8f0efd50 100644
--- a/COVERAGE
+++ b/COVERAGE
@@ -57,10 +57,11 @@ WRITE LONG sg_write_long
ATA command sg3_utils utilities that use this SCSI command
----------- ----------------------------------------------
-IDENTIFY sg_inq, sg_scan
+IDENTIFY DEVICE sg_inq, sg_scan
+IDENTIFY PACKET DEVICE sg_inq
** sdparm is now in its own package called sdparm (rather than sg3_utils)
Doug Gilbert
-5th August 2005
+19th September 2005
diff --git a/INSTALL b/INSTALL
index 365734c7..34ae152e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -8,10 +8,10 @@ in the /usr/local/bin directory, LIBDIR places libraries in the
/usr/local/include/scsi directory.
Other Makefile targets that might be useful:
-make clean # remove .o, executables, core and .depend file
-make depend # generate dependency hierarchy in .depend file
-make dep # same as 'make depend'
-make sg_inq # build a specific executable (e.g. 'sg_inq')
+make clean # remove .o, executables, core and .depend file
+make depend # generate dependency hierarchy in .depend file
+make dep # same as 'make depend'
+make sg_inq # build a specific executable (e.g. 'sg_inq')
make uninstall # removes executables, libraries and build remnants
make -f lib_no_lib/Makefile.no_lib # build without a library
@@ -53,11 +53,16 @@ files.
Binary rpms (at least in the RedHat distribution) tend to install
executables in /usr/bin and libraries in /usr/lib .
+To build debian "deb" (binary) packages, first untar the tarball, then
+change directory to the top level within the sg3_utils source. Then:
+ # chmod +x debian/rules
+ # dpkg-buildpackage -b -rfakeroot
+The binary deb packages will be placed in the parent directory (of
+the sg3_utils source directory) if all goes well.
+
If the shared object (library) is troublesome or unwanted then
a "no_lib" version of the Makefile and the sg3_utils.spec file
can be found in the "lib_no_lib" subdirectory.
-There is also infrastructure in the debian subdirectory to build
-deb packages.
-8th June 2005
+28th August 2005
diff --git a/README b/README
index 319b56e1..390a05dc 100644
--- a/README
+++ b/README
@@ -217,6 +217,24 @@ scsi device. This is only supported for lk >= 2.4.15 and for adapter
drivers that indicate that they have 16 byte CDB capability (otherwise
DID_ABORT will appear in the host_status).
+Command line processing
+=======================
+These utilities can be divided into 3 groups when their handling of
+command line arguments is considered:
+ - ad hoc, typically in a short form only, sometimes longer (e.g.
+ "sg_start -stop /dev/sdc")
+ - inspired by the dd Unix command (e.g. sg_dd, sgm_dd, sgp_dd, sg_read)
+ - recent utilities use "getopt_long" (see "man getopt_long")
+ type command lines. These have short form (starting with "-")
+ and corresponding longer form (starting with "--") options.
+
+The recent utilities that use "getopt_long" are, in alphabetical
+order:
+ - sg_format sg_get_config sg_ident sg_luns sg_persist sg_prevent
+ sg_read_long sg_reassign sg_requests sg_rmsn sg_rtpg sg_ses
+ sg_sync sg_test_rwbuf sg_verify sg_write_long sg_wr_mode
+
+
Header file problems
====================
These utilities include 2 special Linux header files:
@@ -262,4 +280,4 @@ user). It is available for Linux and other operating systems.
See http://members.aol.com/plscsi .
Doug Gilbert
-10th August 2005
+22nd September 2005
diff --git a/debian/changelog b/debian/changelog
index 677cf259..9e9ac7ab 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+sg3-utils (1.17-0.1) unstable; urgency=low
+
+ * New upstream version
+
+ -- Doug Gilbert <dgilbert@interlog.com> Thu, 22 Sep 2005 17:00:00 +1000
+
sg3-utils (1.16-0.1) unstable; urgency=low
* New upstream version
diff --git a/debian/control b/debian/control
index 5f901398..e3e4b5fb 100644
--- a/debian/control
+++ b/debian/control
@@ -22,6 +22,7 @@ Description: Collection of Linux utilities for devices that use the
* sg_emc_trespass - vendor specific for Clariion hardware
* sg_format - format SCSI disks
* sg_get_config - get features and profiles of MMC devices
+ * sg_ident - report and set device identifiers
* sginfo - a re-porting of the 'scsiinfo' program, updated
* sg_inq - a utility for poking around with the SCSI INQUIRY command
* sg_logs - prints out log sense pages
diff --git a/lib_no_lib/sg3_utils.spec.no_lib b/lib_no_lib/sg3_utils.spec.no_lib
index 6785e45e..79d5179b 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.16
+Version: 1.17
Release: 1
Packager: Douglas Gilbert <dgilbert at interlog dot com>
License: GPL/FreeBSD
@@ -122,6 +122,10 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Thu Sep 22 2005 - dgilbert at interlog dot com
+- add ATA information VPD page
+ * sg3_utils-1.17
+
* Wed Aug 10 2005 - dgilbert at interlog dot com
- add sg_ident, sg_inq VPD page extensions
* sg3_utils-1.16
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 47e937f4..604ee014 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -1,5 +1,5 @@
%define name sg3_utils
-%define version 1.16
+%define version 1.17
%define release 1
%define major 1
@@ -96,6 +96,10 @@ make install \
%{_libdir}/*.la
%changelog
+* Thu Sep 22 2005 - dgilbert at interlog dot com
+- add ATA information VPD page to sg_inq
+ * sg3_utils-1.17
+
* Wed Aug 10 2005 - dgilbert at interlog dot com
- add sg_ident, sg_inq VPD page extensions
* sg3_utils-1.16
diff --git a/sg_cmds.c b/sg_cmds.c
index a82156a1..318cf09d 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.18 20050809";
+static char * version_str = "1.20 20050904";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -132,6 +132,7 @@ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op,
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
struct sg_io_hdr io_hdr;
+ unsigned char * up;
if (cmddt)
inqCmdBlk[1] |= 2;
@@ -149,6 +150,12 @@ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op,
fprintf(sg_warnings_str, "%02x ", inqCmdBlk[k]);
fprintf(sg_warnings_str, "\n");
}
+ if (resp && (mx_resp_len > 0)) {
+ up = resp;
+ up[0] = 0x7f; /* defensive prefill */
+ if (mx_resp_len > 4)
+ up[4] = 0;
+ }
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
@@ -230,6 +237,8 @@ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
fprintf(sg_warnings_str, "%02x ", inqCmdBlk[k]);
fprintf(sg_warnings_str, "\n");
}
+ memset(inq_resp, 0, sizeof(inq_resp));
+ inq_resp[0] = 0x7f; /* defensive prefill */
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
@@ -1865,6 +1874,8 @@ int sg_ll_prevent_allow(int sg_fd, int prevent, int noisy, int verbose)
"error: %s\n", safe_strerror(errno));
return -1;
}
+ if (verbose > 2)
+ fprintf(sg_warnings_str, " duration=%u ms\n", io_hdr.duration);
res = sg_err_category3(&io_hdr);
switch (res) {
case SG_LIB_CAT_RECOVERED:
diff --git a/sg_dd.c b/sg_dd.c
index 1773f3db..94f061a0 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 20050807";
+static char * version_str = "5.42 20050909";
#define ME "sg_dd: "
@@ -1221,10 +1221,10 @@ int main(int argc, char * argv[])
out_pdt = -1;
if (inf[0] && ('-' != inf[0])) {
in_type = dd_filetype(inf);
-
if (verbose)
fprintf(stderr, " >> Input file type: %s\n",
dd_filetype_str(in_type, ebuff));
+
if ((FT_BLOCK & in_type) && do_blk_sgio)
in_type |= FT_SG;
@@ -1311,10 +1311,10 @@ int main(int argc, char * argv[])
if (outf[0] && ('-' != outf[0])) {
out_type = dd_filetype(outf);
-
if (verbose)
fprintf(stderr, " >> Output file type: %s\n",
dd_filetype_str(out_type, ebuff));
+
if ((FT_BLOCK & out_type) && do_blk_sgio)
out_type |= FT_SG;
diff --git a/sg_format.8 b/sg_format.8
index 0d81332d..cfa6d4ff 100644
--- a/sg_format.8
+++ b/sg_format.8
@@ -1,4 +1,4 @@
-.TH SG_FORMAT "8" "July 2005" "sg3_utils-1.16" SG3_UTILS
+.TH SG_FORMAT "8" "September 2005" "sg3_utils-1.17" SG3_UTILS
.SH NAME
sg_format \- format or resize a SCSI disk (perhaps change its block size)
.SH SYNOPSIS
@@ -141,6 +141,9 @@ from the current value then a MODE SELECT command is used to change it
prior to the FORMAT command being started (as recommended in the draft
standard). Recent SCSI disks usually have 512 byte sectors by default
and allow up to 16 bytes extra in a sector (i.e. 528 byte sectors).
+If the given size in unacceptable to the disk, most likely an "Invalid
+field in parameter list" message will appear in sense data (requires the
+use of '-v' to decode sense data).
.TP
--verbose | -v
increase the level of verbosity, (i.e. debug output). "-vvv" gives
@@ -287,4 +290,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 sg_turs, sg_requests, sg_inq, sg_modes, sginfo, sg_wr_mode
-.B (all in sg3_utils), sdparm, scsiformat
+.B (all in sg3_utils), sdparm, scsiformat, setblocksize
diff --git a/sg_format.c b/sg_format.c
index 7e3761d2..dcc6bae4 100644
--- a/sg_format.c
+++ b/sg_format.c
@@ -1,5 +1,6 @@
/*
-** sg_format : format a SCSI disk (potentially with a different block size)
+** sg_format : format a SCSI disk
+** potentially with a different number of blocks and block size
**
** formerly called blk512-linux.c (v0.4)
**
@@ -67,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 20050808";
+static char * version_str = "1.05 20050908";
static struct option long_options[] = {
{"count", 1, 0, 'c'},
diff --git a/sg_inq.8 b/sg_inq.8
index e2bda356..94154326 100644
--- a/sg_inq.8
+++ b/sg_inq.8
@@ -1,34 +1,68 @@
-.TH SG_INQ "8" "August 2005" "sg3_utils-1.16" SG3_UTILS
+.TH SG_INQ "8" "September 2005" "sg3_utils-1.17" SG3_UTILS
.SH NAME
-sg_inq \- outputs data retrieved from the SCSI INQUIRY command
+sg_inq \- outputs data retrieved from the SCSI INQUIRY or
+ATA IDENTIFY (PACKET) DEVICE command
.SH SYNOPSIS
.B sg_inq
-[\fI-c\fR] [\fI-cl\fR] [\fI-d\fR] [\fI-e\fR] [\fI-h\fR] [\fI-H\fR]
-[\fI-i\fR] [\fI-m\fR] [\fI-m\fR] [\fI-o=<opcode_page>\fR]
-[\fI-p=<vpd_page>\fR] [\fI-P\fR] [\fI-r\fR] [\fI-s\fR] [\fI-v\fR]
-[\fI-V\fR] [\fI-x\fR] [\fI-36\fR] [\fI-?\fR] \fI<scsi_device>\fR
+[\fI-a\fR] [\fI-A\fR] [\fI-b\fR] [\fI-c\fR] [\fI-cl\fR] [\fI-d\fR]
+[\fI-e\fR] [\fI-h\fR] [\fI-H\fR] [\fI-i\fR] [\fI-m\fR] [\fI-m\fR]
+[\fI-o=<opcode_page>\fR] [\fI-p=<vpd_page>\fR] [\fI-P\fR] [\fI-r\fR]
+[\fI-s\fR] [\fI-v\fR] [\fI-V\fR] [\fI-x\fR] [\fI-36\fR] [\fI-?\fR]
+\fI<device>\fR
.SH DESCRIPTION
.\" Add any additional description here
.PP
-This utility sends an INQUIRY SCSI command to the given device and then
-outputs the response. All SCSI devices are meant to respond to
-a "standard" INQUIRY command with at least a 36 byte response (in SCSI 2
-and higher). An INQUIRY is termed as "standard" when both the EVPD and
-CmdDt bits are clear.
+This utility by default sends an INQUIRY SCSI command to the given
+device and then outputs the response. All SCSI devices are meant
+to respond to a "standard" INQUIRY command with at least a 36 byte
+response (in SCSI 2 and higher). An INQUIRY is termed as "standard"
+when both the EVPD and CmdDt bits are clear.
.PP
An important "non-standard" INQUIRY page is the Device Identification
-Vital Product Data (VPD) page (page number: 0x83). In recent SPC-3
-drafts support for this page has been flagged as mandatory. The '-i'
+Vital Product Data (VPD) page (page number: 0x83). Since SPC-3,
+support for this page has been flagged as mandatory. The '-i'
option decodes this page.
.PP
-If <scsi_device> exists and the SCSI INQUIRY fails (because the SG_IO
-ioctl is unknown) then an ATA IDENTIFY is tried. If it succeeds then
-device identification strings are output. If the "-r" option is given
-then the 256 byte IDENTIFY block is output in binary.
+If <device> exists and the SCSI INQUIRY fails (because the SG_IO
+ioctl is unknown) then an ATA IDENTIFY (PACKET) DEVICE is tried. If it
+succeeds then device identification strings are output. If the "-r" option
+is given then the 512 byte IDENTIFY response is output in binary. If
+the "-H" (or "-h") option is given then the 512 byte response is
+output in ASCII hex, grouped as 256 16 bit words, 8 words per line.
+If the "-A" option is given then the SCSI INQUIRY is not performed
+and the device is assumed to be ATA (or ATAPI). This allows ATAPI
+transport information to be found for ATAPI cd/dvd drives; since
+without this option such drives respond to a SCSI INQUIRY command.
.PP
-The reference document used for interpreting an INQUIRY is T10/1416-D
-Revision 23 (SPC-3, 4th May 2005) found at http://www.t10.org . Obsolete
-items in the standard INQUIRY response are displayed in brackets.
+The reference document used for interpreting an INQUIRY is T10/1713-D
+Revision 2 (SPC-4, 15 September 2005) found at http://www.t10.org .
+Obsolete items in the standard INQUIRY response are displayed in
+brackets. The reference document for the ATA IDENTIFY (PACKET) DEVICE
+command is ATA8-ACS found at http://www.t13.org .
+.PP
+ATA or ATAPI devices that use a SCSI to ATA Translation layer (see
+SAT at www.t10.org) may support the ATA Information VPD page. This
+returns the IDENTIFY (PACKET) DEVICE response amongst other things.
+See the '-a' option.
+.TP
+-a
+decodes the ATA Information Vital Product Data (VPD) page [0x89].
+If '-H' is given then the whole page as ASCII hex bytes; with '-HH'
+the IDENTIFY (PACKET) DEVICE response is output in ASCII hex bytes;
+and without either the IDENTIFY (PACKET) DEVICE response is output
+in 16 bit ASCII hex words. This page is defined in SAT (revision 5)
+at www.t10.org .
+.TP
+-A
+Assume given <device> is an ATA or ATAPI device which can receive
+ATA passthrough commands from the host operating system. Skip
+the SCSI INQUIRY command and use either the ATA IDENTIFY DEVICE
+command (for nonpacket devices) or the ATA IDENTIFY PACKET DEVICE
+command.
+.TP
+-b
+decodes the Block Limits Vital Product Data (VPD) page [0xb0].
+This page is defined in SBC-2 (revision 16) at www.t10.org .
.TP
-c
set the Command Support Data (CmdDt) bit (defaults to clear(0)). Used
@@ -57,36 +91,37 @@ enable (i.e. sets) the Vital Product Data (EVPD) bit (defaults to clear(0)).
Used in conjunction with the '-p=<vpd_page>' option to specify the VPD page
to fetch. If '-p' is not given then VPD page 0 (list supported VPD pages)
is assumed. Support for VPD page 0 and page 0x83 (device identification)
-have been made mandatory in recent SPC-3 drafts.
+have been made mandatory in SPC-3 .
.TP
-h
outputs INQUIRY response in hex rather than trying to decode it. When
used with '-i' outputs partially decoded device identification descriptors
-with the identifier itself output in hex.
+with the identifier itself output in hex. When selected, ATA IDENTIFY
+responses are output in 16 bit words if '-h' is given; they are output in
+bytes when '-hh' (or '-HH') is given. The '-hh' option has a similar effect
+on the ATA information VPD page decoding (i.e. when the '-a' option is given).
.TP
-H
same action as "-h". For compatibility with many other sg3_utils programs
in which "-H" is for hex output.
.TP
-i
-outputs the Device Identification Vital Product Data (VPD) page [0x83].
-If '-r' is not given then attempts to decode the response which can be made
-up of several "identification descriptors". If '-h' is given then each
-descriptor header is decoded and the identifier itself is output in hex.
-To see the whole VPD 0x83 page response in hex use '-p=83 -h'. Recent SPC-3
-drafts have made support of the device identification VPD page mandatory.
+decodes the Device Identification Vital Product Data (VPD) page [0x83].
+This page is made up of several "identification descriptors". If '-h' is
+given then each descriptor header is decoded and the identifier itself
+is output in hex. To see the whole VPD 0x83 page response in hex
+use '-p=83 -h'. Since SPC-3, support for the device identification VPD
+page is mandatory.
.TP
-m
-outputs the Management network addresses Vital Product Data (VPD)
-page [0x85]. If '-r' is not given then attempts to decode the response
-which can be made up of several "network service descriptors". If '-h' is
-given then each descriptor payload is output in hex.
+decodes the Management network addresses Vital Product Data (VPD)
+page [0x85]. This page is made up of several "network service descriptors".
+If '-h' is given then each descriptor payload is output in hex.
.TP
-M
-outputs the Mode page policy Vital Product Data (VPD) page [0x87].
-If '-r' is not given then attempts to decode the response which can be
-made up of several "mode page policy descriptors". If '-h' is given
-then each descriptor payload is output in hex.
+decodes the Mode page policy Vital Product Data (VPD) page [0x87].
+This page is made up of several "mode page policy descriptors".
+If '-h' is given then each descriptor payload is output in hex.
.TP
-o=<opcode_page>
used in conjunction with the '-e' or '-c' option. If neither given then
@@ -109,19 +144,19 @@ hexadecimal and is expected to be in the range 0 to ff inclusive.
Defaults to 0 so if '-e' is given without '-p=' then VPD page 0 is output.
.TP
-P
-outputs the Unit Path Report Vital Product Data (VPD) page [0xc0],
+decodes the Unit Path Report Vital Product Data (VPD) page [0xc0],
which is specific to selected EMC devices. To see the whole VPD 0xc0
-page response in hex use '-o=c0 -h'.
+page response in hex use '-p=c0 -h'.
.TP
-r
outputs the INQUIRY response in binary. If the SCSI INQUIRY has failed
-and an ATA IDENTIFY succeeds then the 256 byte IDENTIFY response is
-output in hex. Standard output should be redirected
-to a file or some other program that can process binary data.
+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.
.TP
-s
-outputs the SCSI Ports Vital Product Data (VPD) page [0x88].
-If '-r' is not given then attempts to decode the response. The response
+decodes the SCSI Ports Vital Product Data (VPD) page [0x88]. The response
contains information about the target (or rarely the initiator) ports
associated with the addressed device server (i.e. the target). In practice
this is a way to find all target port addresses of a dual ported disk.
@@ -130,21 +165,22 @@ in hex. To see the whole VPD 0x88 page response in hex use '-p=88 -h'.
.TP
-v
verbose: print out cdb of issued commands prior to execution. '-vv'
-and '-vvv' are also accepted yielding greater verbosity.
+and '-vvv' are also accepted yielding greater verbosity. For ATA disks
+the identity response (256 16 bit words) is output when this option
+is given.
.TP
-V
print out version string
.TP
-x
-outputs the Extended INQUIRY data Vital Product Data (VPD) [0x86] page.
-If '-r' is not given then attempts to decode the response.
+decodes the Extended INQUIRY data Vital Product Data (VPD) [0x86] page.
If '-h' is given then prints out VPD page in hex which is similar to
using '-p=86 -h'.
.TP
-36
-only requires 36 bytes of response data for an INQUIRY. Furthermore even
+only requests 36 bytes of response data for an INQUIRY. Furthermore even
if the device indicates in its response it can supply more data, a
-second (longer) INQUIRY is not performed.
+second (longer) INQUIRY is not performed. This is a paranoid setting.
.TP
-?
output usage message and exit. Ignore all other parameters.
@@ -155,7 +191,8 @@ that they don't expect). Such devices need to be treated carefully,
hence the '-36' option. Without this option this utility will issue
an initial standard INQUIRY requesting 36 bytes of response data. If
the device indicates it could have supplied more data then a second
-INQUIRY is issued to fetch the longer response.
+INQUIRY is issued to fetch the longer response. That second command may
+lock up faulty devices.
.PP
In the INQUIRY standard response there is a 'MultiP' flag which is set
when the device has 2 or more ports. Some vendors use the preceding
@@ -169,9 +206,34 @@ available ports on the device.
.PP
In the 2.4 series of Linux kernels the given device must be
a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example "sg_inq /dev/sda"
+and ATAPI DVDs) can also be specified. For example "sg_inq /dev/sda"
will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char"
device names may be used as well (e.g. "/dev/st0m").
+.SH ATA DEVICES
+There are two major types of ATA devices: non-packet devices (e.g. ATA
+disks) and packet devices (ATAPI). The majority of ATAPI devices are
+CD/DVD drives in which the ATAPI transport carries the MMC set (i.e.
+a SCSI command set). Further, both types of ATA devices can be connected
+to a host computer via a "SCSI" (or some other) transport. When an
+ATA disk is controlled via a SCSI (or non-ATA) transport then two
+approaches are commonly used: tunnelling (e.g. STP in Serial Attached
+SCSI (SAS)) or by emulating a SCSI device (typically via a SCSI to
+ATA translation layer, see SAT at www.t10.org ). Even when the
+physical transport to the host computer is ATA (especially in the
+case of SATA) the linux operating system may choose to put a SAT
+layer in the driver "stack" (e.g. libata).
+.PP
+The main identifying command for any SCSI device is an INQUIRY. The
+corresponding command for an ATA non-packet device is IDENTIFY DEVICE
+while for an ATA packet device it is IDENTIFY PACKET DEVICE.
+.PP
+When this utility is invoked for an ATAPI device (e.g. a CD/DVD
+drive with "sg_inq /dev/hdc") then a SCSI INQUIRY is sent to the
+device and if it responds then the response to decoded and output and
+this utility exits. To see the response for an ATA IDENTIFY PACKET
+DEVICE command add the '-A' option (e.g. "sg_inq -A /dev/hdc) and to
+see the response in hex add the "-H" option as
+well (e.g. "sg_inq -A -H /dev/hdc").
.SH AUTHOR
Written by Doug Gilbert
.SH "REPORTING BUGS"
@@ -183,4 +245,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), blktool(internet)
+.B sg_logs(sg3_utils)
diff --git a/sg_inq.c b/sg_inq.c
index 4680d47d..8599721b 100644
--- a/sg_inq.c
+++ b/sg_inq.c
@@ -8,6 +8,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <linux/hdreg.h>
#include "sg_include.h"
#include "sg_lib.h"
#include "sg_cmds.h"
@@ -20,7 +21,7 @@
* any later version.
This program outputs information provided by a SCSI INQUIRY command.
- It is mainly based on the SCSI SPC-3 document at http://www.t10.org .
+ It is mainly based on the SCSI SPC-4 document at http://www.t10.org .
Acknowledgment:
- Martin Schwenke <martin at meltin dot net> added the raw switch and
@@ -57,7 +58,7 @@
* added in the future.
*/
-static char * version_str = "0.52 20050808";
+static char * version_str = "0.55 20050922"; /* spc-4 rev02 */
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -73,10 +74,13 @@ static char * version_str = "0.52 20050808";
#define X_INQ_VPD 0x86
#define MODE_PG_POLICY_VPD 0x87
#define SCSI_PORTS_VPD 0x88
+#define ATA_INFO_VPD 0x89
+#define BLOCK_LIMITS_VPD 0xb0
#define UPR_EMC_VPD 0xc0
#define DEF_ALLOC_LEN 252
#define MX_ALLOC_LEN (0xc000 + 0x80)
+#define ATA_INFO_VPD_LEN 572
#define EBUFF_SZ 256
@@ -84,7 +88,8 @@ static char * version_str = "0.52 20050808";
static unsigned char rsp_buff[MX_ALLOC_LEN + 1];
static char xtra_buff[MX_ALLOC_LEN + 1];
-static int try_ata_identity(int ata_fd, int do_raw);
+static int try_ata_identify(int ata_fd, int do_hex, int do_raw,
+ int do_verbose);
static const char * find_version_descriptor_str(int value);
static void decode_dev_ids(const char * leadin, unsigned char * buff,
int len, int do_hex);
@@ -95,12 +100,15 @@ static void decode_transport_id(const char * leadin, unsigned char * ucp,
static void usage()
{
fprintf(stderr,
- "Usage: sg_inq [-c] [-cl] [-d] [-e] [-h] [-H] [-i] [-m] "
- "[-o=<opcode_page>]\n"
- " [-p=<vpd_page>] [-P] [-r] [-s] [-v] [-V] [-x] "
- "[-36] [-?]\n"
- " <scsi_device>\n"
- " where -c set CmdDt mode (use -o for opcode) [obsolete]\n"
+ "Usage: sg_inq [-a] [-A] [-b] [-c] [-cl] [-d] [-e] [-h] [-H] "
+ "[-i] [-m]\n"
+ " [-o=<opcode_page>] [-p=<vpd_page>] [-P] [-r] "
+ "[-s] [-v]\n"
+ " [-V] [-x] [-36] [-?] <device>\n"
+ " where -a decode ATA information VPD page (0x89)\n"
+ " -A treat <device> as (directly attached) ATA device\n"
+ " -b decode Block limits VPD page (0xb0) (SBC)\n"
+ " -c set CmdDt mode (use -o for opcode) [obsolete]\n"
" -cl list supported commands using CmdDt mode [obsolete]\n"
" -d list version descriptors\n"
" -e set VPD mode (use -p for page code)\n"
@@ -120,8 +128,7 @@ static void usage()
" -x decode extented INQUIRY data VPD page (0x86)\n"
" -36 perform standard INQUIRY with a 36 byte response\n"
" -? output this usage message\n"
- " If no optional switches given then does"
- " a standard SCSI INQUIRY\n");
+ " If no options given then does a standard SCSI INQUIRY\n");
}
@@ -175,7 +182,7 @@ struct vpd_name {
static struct vpd_name vpd_name_arr[] = {
{SUPPORTED_VPDS_VPD, 0, "Supported VPD pages"},
{UNIT_SERIAL_NUM_VPD, 0, "Unit serial number"},
- {0x81, 0, "Implemented operating definitions"},
+ {0x81, 0, "Implemented operating definitions (obsolete)"},
{0x82, 0, "ASCII implemented operating definition (obsolete)"},
{DEV_ID_VPD, 0, "Device identification"},
{0x84, 0, "Software interface identification"},
@@ -183,8 +190,8 @@ static struct vpd_name vpd_name_arr[] = {
{X_INQ_VPD, 0, "Extended INQUIRY data"},
{MODE_PG_POLICY_VPD, 0, "Mode page policy"},
{SCSI_PORTS_VPD, 0, "SCSI ports"},
- {0x89, 0, "ATA information"},
- {0xb0, 0, "Block limits (sbc2)"},
+ {ATA_INFO_VPD, 0, "ATA information"},
+ {BLOCK_LIMITS_VPD, 0, "Block limits (sbc2)"},
{0xb0, 0x1, "SSC device capabilities (ssc3)"},
{0xb0, 0x11, "OSD information (osd)"},
{0xb1, 0x11, "Security token (osd)"},
@@ -244,7 +251,7 @@ static void decode_id_vpd(unsigned char * buff, int len, int do_hex)
static const char * assoc_arr[] =
{
"addressed logical unit",
- "target port that received request",
+ "target port", /* that received request; unless SCSI ports VPD */
"target device that contains addressed lu",
"reserved [0x3]",
};
@@ -375,7 +382,7 @@ static void decode_scsi_ports_vpd(unsigned char * buff, int len, int do_hex)
return;
}
if (tpd_len > 0) {
- printf(" Target ports:\n");
+ printf(" Target port descriptor(s):\n");
if (do_hex)
dStrHex((const char *)(ucp + bump + 4), tpd_len, 1);
else
@@ -442,10 +449,10 @@ static void decode_dev_ids(const char * leadin, unsigned char * buff,
for (k = 0, j = 1; k < len; k += id_len, ucp += id_len, ++j) {
i_len = ucp[3];
id_len = i_len + 4;
- printf(" Descriptor number %d, "
+ printf(" Designation descriptor number %d, "
"descriptor length: %d\n", j, id_len);
if ((k + id_len) > len) {
- fprintf(stderr, "%s VPD page error: descriptor length longer "
+ fprintf(stderr, "%s VPD page error: designator length longer "
"than\n remaining response length=%d\n", leadin,
(len - k));
return;
@@ -462,9 +469,9 @@ static void decode_dev_ids(const char * leadin, unsigned char * buff,
code_set_arr[c_set]);
printf(" associated with the %s\n", assoc_arr[assoc]);
if (do_hex) {
- printf(" descriptor header(hex): %.2x %.2x %.2x %.2x\n",
+ printf(" designator header(hex): %.2x %.2x %.2x %.2x\n",
ucp[0], ucp[1], ucp[2], ucp[3]);
- printf(" identifier:\n");
+ printf(" designator:\n");
dStrHex((const char *)ip, i_len, 0);
continue;
}
@@ -787,6 +794,74 @@ static void decode_x_inq_vpd(unsigned char * buff, int len, int do_hex)
printf(" NV_SUP=%d V_SUP=%d\n", !!(buff[6] & 0x2), !!(buff[6] & 0x1));
}
+static void decode_ata_info_vpd(unsigned char * buff, int len, int do_hex)
+{
+ char b[32];
+
+ if (len < 36) {
+ fprintf(stderr, "ATA information VPD page length too "
+ "short=%d\n", len);
+ return;
+ }
+ if (do_hex && (2 != do_hex)) {
+ dStrHex((const char *)buff, len, 0);
+ return;
+ }
+ memcpy(b, buff + 8, 8);
+ b[8] = '\0';
+ printf(" SAT Vendor identification: %s\n", b);
+ memcpy(b, buff + 16, 16);
+ b[16] = '\0';
+ printf(" SAT Product identification: %s\n", b);
+ memcpy(b, buff + 32, 4);
+ b[4] = '\0';
+ printf(" SAT Product revision level: %s\n", b);
+ if (len < 56)
+ return;
+ printf(" Signature (20 bytes):\n");
+ dStrHex((const char *)buff + 36, 20, 0);
+ if (len < 60)
+ return;
+ if (0xec == buff[56])
+ printf(" ATA command IDENTIFY DEVICE got following response:\n");
+ else if (0xa1 == buff[56])
+ printf(" ATA command IDENTIFY PACKET DEVICE got following "
+ "response:\n");
+ else
+ printf(" ATA command 0x%x got following response:\n",
+ (unsigned int)buff[56]);
+ if (len < 572)
+ return;
+ if (2 == do_hex)
+ dStrHex((const char *)(buff + 60), 512, 0);
+ else
+ dWordHex((const unsigned short *)(buff + 60), 256, 0,
+ sg_is_big_endian());
+}
+
+static void decode_block_limits_vpd(unsigned char * buff, int len, int do_hex)
+{
+ unsigned int u;
+
+ if (len < 16) {
+ fprintf(stderr, "Block limits VPD page length too "
+ "short=%d\n", len);
+ return;
+ }
+ if (do_hex) {
+ dStrHex((const char *)buff, len, 0);
+ return;
+ }
+ u = (buff[6] << 8) | buff[7];
+ printf(" Optimal transfer length granularity: %u blocks\n", u);
+ u = (buff[8] << 24) | (buff[9] << 16) | (buff[10] << 8) |
+ buff[11];
+ printf(" Maximum transfer length: %u blocks\n", u);
+ u = (buff[12] << 24) | (buff[13] << 16) | (buff[14] << 8) |
+ buff[15];
+ printf(" Optimal transfer length: %u blocks\n", u);
+}
+
static const char * lun_state_arr[] =
{
"LUN not bound or LUN_Z report",
@@ -1094,12 +1169,12 @@ static int process_std_inq(int sg_fd, const char * file_name, int do_36,
}
}
else if (-1 == res) { /* could be an ATA device */
- /* Try an ATA Identity command */
- res = try_ata_identity(sg_fd, do_raw);
+ /* Try an ATA Identify Device command */
+ res = try_ata_identify(sg_fd, do_hex, do_raw, do_verbose);
if (0 != res) {
- fprintf(stderr, "Both SCSI INQUIRY and ATA IDENTIFY failed "
- "on %s with this error:\n\t%s\n", file_name,
- safe_strerror(res));
+ fprintf(stderr, "Both SCSI INQUIRY and ATA IDENTIFY DEVICE "
+ "failed on %s\n\t the latter with this error:\n\t%s\n",
+ file_name, safe_strerror(res));
return 1;
}
} else { /* SCSI device not supporting 36 byte INQUIRY?? */
@@ -1282,31 +1357,257 @@ static int process_evpd(int sg_fd, int num_opcode, int do_hex,
return 0;
}
+/* Returns 0 if successful */
+static int decode_vpd(int sg_fd, int num_opcode, int do_hex,
+ int do_raw, int do_verbose)
+{
+ int len;
+
+ switch(num_opcode) {
+ case DEV_ID_VPD:
+ if (!do_raw)
+ printf("VPD INQUIRY: Device Identification page\n");
+ if (0 == sg_ll_inquiry(sg_fd, 0, 1, DEV_ID_VPD, rsp_buff,
+ DEF_ALLOC_LEN, 1, do_verbose)) {
+ len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
+ if (DEV_ID_VPD != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably a STANDARD "
+ "INQUIRY response\n");
+ return 1;
+ }
+ if (len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", len,
+ MX_ALLOC_LEN);
+ return 1;
+ } else if (len > DEF_ALLOC_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, DEV_ID_VPD, rsp_buff, len,
+ 1, do_verbose))
+ return 1;
+ }
+ if (do_raw)
+ dStrRaw((const char *)rsp_buff, len);
+ else
+ decode_id_vpd(rsp_buff, len, do_hex);
+ return 0;
+ }
+ break;
+ case MAN_NET_ADDR_VPD:
+ if (!do_raw)
+ printf("VPD INQUIRY: Management network addresses page\n");
+ if (0 == sg_ll_inquiry(sg_fd, 0, 1, MAN_NET_ADDR_VPD, rsp_buff,
+ DEF_ALLOC_LEN, 1, do_verbose)) {
+ len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
+ if (MAN_NET_ADDR_VPD != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably a STANDARD "
+ "INQUIRY response\n");
+ return 1;
+ }
+ if (len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", len,
+ MX_ALLOC_LEN);
+ return 1;
+ } else if (len > DEF_ALLOC_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, MAN_NET_ADDR_VPD, rsp_buff,
+ len, 1, do_verbose))
+ return 1;
+ }
+ if (do_raw)
+ dStrRaw((const char *)rsp_buff, len);
+ else
+ decode_net_man_vpd(rsp_buff, len, do_hex);
+ return 0;
+ }
+ break;
+ case MODE_PG_POLICY_VPD:
+ if (!do_raw)
+ printf("VPD INQUIRY: Mode page policy\n");
+ if (0 == sg_ll_inquiry(sg_fd, 0, 1, MODE_PG_POLICY_VPD, rsp_buff,
+ DEF_ALLOC_LEN, 1, do_verbose)) {
+ len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
+ if (MODE_PG_POLICY_VPD != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably a STANDARD "
+ "INQUIRY response\n");
+ return 1;
+ }
+ if (len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", len,
+ MX_ALLOC_LEN);
+ return 1;
+ } else if (len > DEF_ALLOC_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, MODE_PG_POLICY_VPD, rsp_buff,
+ len, 1, do_verbose))
+ return 1;
+ }
+ if (do_raw)
+ dStrRaw((const char *)rsp_buff, len);
+ else
+ decode_mode_policy_vpd(rsp_buff, len, do_hex);
+ return 0;
+ }
+ break;
+ case X_INQ_VPD:
+ if (!do_raw)
+ printf("VPD INQUIRY: extended INQUIRY data page\n");
+ if (0 == sg_ll_inquiry(sg_fd, 0, 1, X_INQ_VPD, rsp_buff,
+ DEF_ALLOC_LEN, 1, do_verbose)) {
+ len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
+ if (X_INQ_VPD != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably a STANDARD "
+ "INQUIRY response\n");
+ return 1;
+ }
+ if (len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", len,
+ MX_ALLOC_LEN);
+ return 1;
+ } else if (len > DEF_ALLOC_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, X_INQ_VPD, rsp_buff, len,
+ 1, do_verbose))
+ return 1;
+ }
+ if (do_raw)
+ dStrRaw((const char *)rsp_buff, len);
+ else
+ decode_x_inq_vpd(rsp_buff, len, do_hex);
+ return 0;
+ }
+ break;
+ case ATA_INFO_VPD:
+ if (!do_raw)
+ printf("VPD INQUIRY: ATA information page\n");
+ if (0 == sg_ll_inquiry(sg_fd, 0, 1, ATA_INFO_VPD, rsp_buff,
+ ATA_INFO_VPD_LEN, 1, do_verbose)) {
+ len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
+ if (ATA_INFO_VPD != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably a STANDARD "
+ "INQUIRY response\n");
+ return 1;
+ }
+ if (len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", len,
+ MX_ALLOC_LEN);
+ return 1;
+ } else if (len > ATA_INFO_VPD_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, ATA_INFO_VPD, rsp_buff, len,
+ 1, do_verbose))
+ return 1;
+ }
+ if (do_raw)
+ dStrRaw((const char *)rsp_buff, len);
+ else
+ decode_ata_info_vpd(rsp_buff, len, do_hex);
+ return 0;
+ }
+ break;
+ case BLOCK_LIMITS_VPD:
+ if (!do_raw)
+ printf("VPD INQUIRY: Block limits page (SBC)\n");
+ if (0 == sg_ll_inquiry(sg_fd, 0, 1, BLOCK_LIMITS_VPD, rsp_buff,
+ DEF_ALLOC_LEN, 1, do_verbose)) {
+ len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
+ if (BLOCK_LIMITS_VPD != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably a STANDARD "
+ "INQUIRY response\n");
+ return 1;
+ }
+ if (len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", len,
+ MX_ALLOC_LEN);
+ return 1;
+ } else if (len > DEF_ALLOC_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, BLOCK_LIMITS_VPD, rsp_buff,
+ len, 1, do_verbose))
+ return 1;
+ }
+ if (do_raw)
+ dStrRaw((const char *)rsp_buff, len);
+ else
+ decode_block_limits_vpd(rsp_buff, len, do_hex);
+ return 0;
+ }
+ break;
+ case UPR_EMC_VPD:
+ if (!do_raw)
+ printf("VPD INQUIRY: Unit Path Report Page (EMC)\n");
+ if (0 == sg_ll_inquiry(sg_fd, 0, 1, UPR_EMC_VPD, rsp_buff,
+ DEF_ALLOC_LEN, 1, do_verbose)) {
+ len = rsp_buff[3] + 3;
+ if (UPR_EMC_VPD != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably not "
+ "supported\n");
+ return 1;
+ }
+ if (len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", len,
+ MX_ALLOC_LEN);
+ return 1;
+ } else if (len > DEF_ALLOC_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, UPR_EMC_VPD, rsp_buff, len, 1,
+ do_verbose))
+ return 1;
+ }
+ if (do_raw)
+ dStrRaw((const char *)rsp_buff, len);
+ else if (do_hex)
+ dStrHex((const char *)rsp_buff, len, 1);
+ else
+ decode_upr_vpd_c0_emc(rsp_buff, len);
+ return 0;
+ }
+ break;
+ case SCSI_PORTS_VPD:
+ if (!do_raw)
+ printf("VPD INQUIRY: SCSI Ports page\n");
+ if (0 == sg_ll_inquiry(sg_fd, 0, 1, SCSI_PORTS_VPD, rsp_buff,
+ DEF_ALLOC_LEN, 1, do_verbose)) {
+ len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
+ if (SCSI_PORTS_VPD != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably a STANDARD "
+ "INQUIRY response\n");
+ return 1;
+ }
+ if (len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", len,
+ MX_ALLOC_LEN);
+ return 1;
+ } else if (len > DEF_ALLOC_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, SCSI_PORTS_VPD, rsp_buff, len,
+ 1, do_verbose))
+ return 1;
+ }
+ if (do_raw)
+ dStrRaw((const char *)rsp_buff, len);
+ else
+ decode_scsi_ports_vpd(rsp_buff, len, do_hex);
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
int main(int argc, char * argv[])
{
- int sg_fd, k, num, len, plen, jmp_out;
+ int sg_fd, k, num, plen, res, jmp_out;
const char * file_name = 0;
const char * cp;
char ebuff[EBUFF_SZ];
unsigned int num_opcode = 0; /* SUPPORTED_VPDS_VPD == 0 */
int num_opcode_given = 0;
int p_switch_given = 0;
+ int do_ata_device = 0;
int do_evpd = 0;
int do_cmddt = 0;
int do_cmdlst = 0;
- int do_di_vpd = 0;
int do_hex = 0;
- int do_man_net_vpd = 0;
- int do_mode_policy_vpd = 0;
int do_raw = 0;
- int do_scsi_ports_vpd = 0;
- int do_xtended = 0;
- int do_upr_c0_emc = 0;
int do_36 = 0;
int do_vdescriptors = 0;
int do_verbose = 0;
- int decode = 0;
+ int do_vpd_decode = 0;
int oflags = O_RDONLY | O_NONBLOCK;
int ret = 0;
@@ -1327,6 +1628,17 @@ int main(int argc, char * argv[])
} else
jmp_out = 1;
break;
+ case 'a':
+ num_opcode = ATA_INFO_VPD;
+ ++do_vpd_decode;
+ break;
+ case 'A':
+ do_ata_device = 1;
+ break;
+ case 'b':
+ num_opcode = BLOCK_LIMITS_VPD;
+ ++do_vpd_decode;
+ break;
case 'c':
do_cmddt = 1;
if ('l' == *(cp + 1)) {
@@ -1343,25 +1655,30 @@ int main(int argc, char * argv[])
break;
case 'h':
case 'H':
- do_hex = 1;
+ ++do_hex;
break;
case 'i':
- do_di_vpd = 1;
+ num_opcode = DEV_ID_VPD;
+ ++do_vpd_decode;
break;
case 'm':
- do_man_net_vpd = 1;
+ num_opcode = MAN_NET_ADDR_VPD;
+ ++do_vpd_decode;
break;
case 'M':
- do_mode_policy_vpd = 1;
+ num_opcode = MODE_PG_POLICY_VPD;
+ ++do_vpd_decode;
break;
case 'P':
- do_upr_c0_emc = 1;
+ num_opcode = UPR_EMC_VPD;
+ ++do_vpd_decode;
break;
case 'r':
do_raw = 1;
break;
case 's':
- do_scsi_ports_vpd = 1;
+ num_opcode = SCSI_PORTS_VPD;
+ ++do_vpd_decode;
break;
case 'v':
++do_verbose;
@@ -1370,7 +1687,8 @@ int main(int argc, char * argv[])
fprintf(stderr, "Version string: %s\n", version_str);
exit(0);
case 'x':
- do_xtended = 1;
+ num_opcode = X_INQ_VPD;
+ ++do_vpd_decode;
break;
case '?':
usage();
@@ -1415,30 +1733,36 @@ int main(int argc, char * argv[])
return 1;
}
}
-
- decode = do_di_vpd + do_xtended + do_upr_c0_emc + do_scsi_ports_vpd +
- do_man_net_vpd + do_mode_policy_vpd;
+
if (do_raw && do_hex) {
fprintf(stderr, "Can't do hex and raw at the same time\n");
usage();
return 1;
}
- if (decode > 1) {
- fprintf(stderr, "Can only have one of '-i', '-P', '-s' or '-x'\n");
- usage();
- return 1;
- } else if (decode && (do_cmddt || do_evpd || num_opcode_given)) {
- fprintf(stderr, "Can't use '-i', '-P', '-s' or '-x' with other VPD "
- "or CmdDt flags\n");
+ if (do_vpd_decode > 1) {
+ fprintf(stderr, "Can only decode one VPD page at a time\n");
usage();
return 1;
+ } else if (do_vpd_decode) {
+ if (do_cmddt || num_opcode_given) {
+ fprintf(stderr, "Can't use '-a', '-b', '-i', '-m', '-M', '-P', "
+ "'-s' or '-x'\n with other '-p=', '-o=' or CmdDt "
+ "flags\n");
+ usage();
+ return 1;
+ } else if (do_ata_device) {
+ fprintf(stderr, "Can't use '-A' with an explicit decode VPD "
+ "page option\n");
+ usage();
+ return 1;
+ }
}
if (0 == file_name) {
- fprintf(stderr, "No <scsi_device> argument given\n");
+ fprintf(stderr, "No <device> argument given\n");
usage();
return 1;
}
- if ((! (decode || do_cmddt || do_evpd)) &&
+ if ((! (do_vpd_decode || do_cmddt || do_evpd)) &&
num_opcode_given) {
do_evpd = 1; /* '-o' implies '-e' unless explicitly overridden */
if (! (do_raw || p_switch_given))
@@ -1462,183 +1786,34 @@ int main(int argc, char * argv[])
}
memset(rsp_buff, 0, MX_ALLOC_LEN + 1);
- if (! (do_cmddt || do_evpd || decode)) {
- /* So it's a Standard INQUIRY */
+ if (do_ata_device) {
+ res = try_ata_identify(sg_fd, do_hex, do_raw, do_verbose);
+ if (0 != res) {
+ fprintf(stderr, "ATA IDENTIFY DEVICE failed on %s with this "
+ "error:\n\t%s\n", file_name, safe_strerror(res));
+ ret = 1;
+ } else
+ ret = 0;
+ goto err_out;
+ }
+ ret = 1;
+ if (! (do_cmddt || do_evpd || do_vpd_decode)) {
+ /* So it's a Standard INQUIRY, try ATA IDENTIFY if that fails */
if (process_std_inq(sg_fd, file_name, do_36, do_vdescriptors,
do_hex, do_raw, do_verbose))
- return 1;
+ goto err_out;
} else if (do_cmddt) {
if (process_cmddt(sg_fd, do_cmdlst, num_opcode, do_hex, do_raw,
do_verbose))
- return 1;
+ goto err_out;
+ } else if (do_vpd_decode) {
+ if (decode_vpd(sg_fd, num_opcode, do_hex, do_raw, do_verbose))
+ goto err_out;
} else if (do_evpd) {
if (process_evpd(sg_fd, num_opcode, do_hex, do_raw, do_verbose))
- return 1;
- } else if (do_di_vpd) {
- if (!do_raw)
- printf("VPD INQUIRY: Device Identification page\n");
- if (0 == sg_ll_inquiry(sg_fd, 0, 1, DEV_ID_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, do_verbose)) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- ret = 3;
- if (DEV_ID_VPD != rsp_buff[1]) {
- fprintf(stderr, "invalid VPD response; probably a STANDARD "
- "INQUIRY response\n");
- goto err_out;
- }
- if (len > MX_ALLOC_LEN) {
- fprintf(stderr, "response length too long: %d > %d\n", len,
- MX_ALLOC_LEN);
- goto err_out;
- } else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, DEV_ID_VPD, rsp_buff, len,
- 1, do_verbose))
- goto err_out;
- }
- ret = 0;
- if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
- else
- decode_id_vpd(rsp_buff, len, do_hex);
- }
- } else if (do_man_net_vpd) {
- if (!do_raw)
- printf("VPD INQUIRY: Management network addresses page\n");
- if (0 == sg_ll_inquiry(sg_fd, 0, 1, MAN_NET_ADDR_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, do_verbose)) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- ret = 3;
- if (MAN_NET_ADDR_VPD != rsp_buff[1]) {
- fprintf(stderr, "invalid VPD response; probably a STANDARD "
- "INQUIRY response\n");
- goto err_out;
- }
- if (len > MX_ALLOC_LEN) {
- fprintf(stderr, "response length too long: %d > %d\n", len,
- MX_ALLOC_LEN);
- goto err_out;
- } else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, MAN_NET_ADDR_VPD, rsp_buff,
- len, 1, do_verbose))
- goto err_out;
- }
- ret = 0;
- if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
- else
- decode_net_man_vpd(rsp_buff, len, do_hex);
- }
- } else if (do_mode_policy_vpd) {
- if (!do_raw)
- printf("VPD INQUIRY: Mode page policy\n");
- if (0 == sg_ll_inquiry(sg_fd, 0, 1, MODE_PG_POLICY_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, do_verbose)) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- ret = 3;
- if (MODE_PG_POLICY_VPD != rsp_buff[1]) {
- fprintf(stderr, "invalid VPD response; probably a STANDARD "
- "INQUIRY response\n");
- goto err_out;
- }
- if (len > MX_ALLOC_LEN) {
- fprintf(stderr, "response length too long: %d > %d\n", len,
- MX_ALLOC_LEN);
- goto err_out;
- } else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, MODE_PG_POLICY_VPD, rsp_buff,
- len, 1, do_verbose))
- goto err_out;
- }
- ret = 0;
- if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
- else
- decode_mode_policy_vpd(rsp_buff, len, do_hex);
- }
- } else if (do_xtended) {
- if (!do_raw)
- printf("VPD INQUIRY: extended INQUIRY data page\n");
- if (0 == sg_ll_inquiry(sg_fd, 0, 1, X_INQ_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, do_verbose)) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- ret = 3;
- if (X_INQ_VPD != rsp_buff[1]) {
- fprintf(stderr, "invalid VPD response; probably a STANDARD "
- "INQUIRY response\n");
- goto err_out;
- }
- if (len > MX_ALLOC_LEN) {
- fprintf(stderr, "response length too long: %d > %d\n", len,
- MX_ALLOC_LEN);
- goto err_out;
- } else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, X_INQ_VPD, rsp_buff, len,
- 1, do_verbose))
- goto err_out;
- }
- ret = 0;
- if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
- else
- decode_x_inq_vpd(rsp_buff, len, do_hex);
- }
- } else if (do_upr_c0_emc) {
- if (!do_raw)
- printf("VPD INQUIRY: Unit Path Report Page (EMC)\n");
- if (0 == sg_ll_inquiry(sg_fd, 0, 1, UPR_EMC_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, do_verbose)) {
- len = rsp_buff[3] + 3;
- ret = 3;
- if (UPR_EMC_VPD != rsp_buff[1]) {
- fprintf(stderr, "invalid VPD response; probably not "
- "supported\n");
- goto err_out;
- }
- if (len > MX_ALLOC_LEN) {
- fprintf(stderr, "response length too long: %d > %d\n", len,
- MX_ALLOC_LEN);
- goto err_out;
- } else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, UPR_EMC_VPD, rsp_buff, len, 1,
- do_verbose))
- goto err_out;
- }
- ret = 0;
- if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
- else if (do_hex)
- dStrHex((const char *)rsp_buff, len, 1);
- else
- decode_upr_vpd_c0_emc(rsp_buff, len);
- }
- } else if (do_scsi_ports_vpd) {
- if (!do_raw)
- printf("VPD INQUIRY: SCSI Ports page\n");
- if (0 == sg_ll_inquiry(sg_fd, 0, 1, SCSI_PORTS_VPD, rsp_buff,
- DEF_ALLOC_LEN, 1, do_verbose)) {
- len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- ret = 3;
- if (SCSI_PORTS_VPD != rsp_buff[1]) {
- fprintf(stderr, "invalid VPD response; probably a STANDARD "
- "INQUIRY response\n");
- goto err_out;
- }
- if (len > MX_ALLOC_LEN) {
- fprintf(stderr, "response length too long: %d > %d\n", len,
- MX_ALLOC_LEN);
- goto err_out;
- } else if (len > DEF_ALLOC_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, SCSI_PORTS_VPD, rsp_buff, len,
- 1, do_verbose))
- goto err_out;
- }
- ret = 0;
- if (do_raw)
- dStrRaw((const char *)rsp_buff, len);
- else
- decode_scsi_ports_vpd(rsp_buff, len, do_hex);
- }
+ goto err_out;
}
+ ret = 0;
err_out:
close(sg_fd);
@@ -1654,6 +1829,7 @@ err_out:
*/
#ifndef ATA_IDENTIFY_DEVICE
#define ATA_IDENTIFY_DEVICE 0xec
+#define ATA_IDENTIFY_PACKET_DEVICE 0xa1
#endif
#ifndef HDIO_DRIVE_CMD
#define HDIO_DRIVE_CMD 0x031f
@@ -1744,49 +1920,95 @@ static void printswap(char *output, char *in, unsigned int n)
if (*output)
printf("%.*s ", (int)n, output);
else
- printf("%.*s ", (int)n, "[No Information Found]\n");
+ printf("%.*s ", (int)n, "[Nothing Found]");
}
#define ATA_IDENTIFY_BUFF_SZ sizeof(struct ata_identify_device)
#define HDIO_DRIVE_CMD_OFFSET 4
-static int ata_command_interface(int device, char *data)
+static int ata_command_interface(int device, char *data, int * atapi_flag)
{
unsigned char buff[ATA_IDENTIFY_BUFF_SZ + HDIO_DRIVE_CMD_OFFSET];
- int retval;
+ unsigned short get_ident[256];
- buff[0] = ATA_IDENTIFY_DEVICE;
- buff[3] = 1;
- /* We are now doing the HDIO_DRIVE_CMD type ioctl. */
- if ((retval = ioctl(device, HDIO_DRIVE_CMD, buff)))
+ if (atapi_flag)
+ *atapi_flag = 0;
+ memset(buff, 0, sizeof(buff));
+ if (ioctl(device, HDIO_GET_IDENTITY, &get_ident) < 0)
return errno;
-
+ if (0x2 == ((get_ident[0] >> 14) &0x3)) { /* ATAPI device */
+ memset(buff, 0, sizeof(buff));
+ buff[0] = ATA_IDENTIFY_PACKET_DEVICE;
+ buff[3] = 1;
+ if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0)
+ return errno;
+ if (atapi_flag)
+ *atapi_flag = 1;
+ } else { /* assume non-packey device */
+ buff[0] = ATA_IDENTIFY_DEVICE;
+ buff[3] = 1;
+ if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0)
+ return errno;
+ }
/* if the command returns data, copy it back */
memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ);
return 0;
}
/* Returns 0 if successful, else errno of error */
-static int try_ata_identity(int ata_fd, int do_raw)
+static int try_ata_identify(int ata_fd, int do_hex, int do_raw,
+ int do_verbose)
{
struct ata_identify_device ata_ident;
char model[64];
char serial[64];
char firm[64];
- int res;
+ int res, atapi;
- res = ata_command_interface(ata_fd, (char *)&ata_ident);
+ memset(&ata_ident, 0, sizeof(ata_ident));
+#if 1
+ res = ata_command_interface(ata_fd, (char *)&ata_ident, &atapi);
+#else
+ res = ioctl(ata_fd, HDIO_GET_IDENTITY, &ata_ident);
+#endif
if (res)
return res;
if (do_raw)
- dStrRaw((const char *)&ata_ident, 256);
+ dStrRaw((const char *)&ata_ident, 512);
else {
- printf("ATA device (probably a disk):\n");
- printf(" ");
- printswap(model, (char *)ata_ident.model, 40);
- printswap(serial, (char *)ata_ident.serial_no, 20);
- printswap(firm, (char *)ata_ident.fw_rev, 8);
- printf("\n");
+ if (do_hex) {
+ if (atapi)
+ printf("ATA IDENTIFY PACKET DEVICE response ");
+ else
+ printf("ATA IDENTIFY DEVICE response ");
+ if (do_hex > 1) {
+ printf("(512 bytes):\n");
+ dStrHex((const char *)&ata_ident, 512, 0);
+ } else {
+ printf("(256 words):\n");
+ dWordHex((const unsigned short *)&ata_ident, 256, 0,
+ sg_is_big_endian());
+ }
+ } else {
+ if (atapi)
+ printf("ATAPI device:\n");
+ else
+ printf("ATA device (probably a disk):\n");
+ printf(" ");
+ printswap(model, (char *)ata_ident.model, 40);
+ printswap(serial, (char *)ata_ident.serial_no, 20);
+ printswap(firm, (char *)ata_ident.fw_rev, 8);
+ printf("\n");
+ if (do_verbose) {
+ if (atapi)
+ printf("ATA IDENTIFY PACKET DEVICE response "
+ "(256 words):\n");
+ else
+ printf("ATA IDENTIFY DEVICE response (256 words):\n");
+ dWordHex((const unsigned short *)&ata_ident, 256, 0,
+ sg_is_big_endian());
+ }
+ }
}
return 0;
}
@@ -1796,205 +2018,220 @@ struct version_descriptor {
const char * name;
};
-/* table from SPC-3 revision 21 [sorted numerically (Annex D listing)] */
+/* table from SPC-4 revision 1 [sorted numerically (Annex D listing)] */
static struct version_descriptor version_descriptor_arr[] = {
{0x0, "Version Descriptor not supported or No standard identified"},
{0x20, "SAM (no version claimed)"},
{0x3b, "SAM T10/0994-D revision 18"},
- {0x3c, "SAM ANSI X3.270:1996"},
+ {0x3c, "SAM ANSI INCITS 270-1996"},
{0x40, "SAM-2 (no version claimed)"},
{0x54, "SAM-2 T10/1157-D revision 23"},
{0x55, "SAM-2 T10/1157-D revision 24"},
- {0x5c, "SAM-2 ANSI INCITS.366:2003"},
+ {0x5c, "SAM-2 ANSI INCITS 366-2003"},
{0x60, "SAM-3 (no version claimed)"},
{0x62, "SAM-3 T10/1561-D revision 7"},
{0x75, "SAM-3 T10/1561-D revision 13"},
{0x76, "SAM-3 T10/1561-D revision 14"},
- {0x77, "SAM-3 ANSI INCITS.402:2005"},
+ {0x77, "SAM-3 ANSI INCITS 402-2005"},
{0x80, "SAM-4 (no version claimed)"},
{0x120, "SPC (no version claimed)"},
{0x13b, "SPC T10/0995-D revision 11a"},
- {0x13c, "SPC ANSI X3.301:1997"},
+ {0x13c, "SPC ANSI INCITS 301-1997"},
{0x140, "MMC (no version claimed)"},
{0x15b, "MMC T10/1048-D revision 10a"},
- {0x15c, "MMC ANSI X3.304:1997"},
+ {0x15c, "MMC ANSI INCITS 304-1997"},
{0x160, "SCC (no version claimed)"},
{0x17b, "SCC T10/1047-D revision 06c"},
- {0x17c, "SCC ANSI X3.276:1997"},
+ {0x17c, "SCC ANSI INCITS 276-1997"},
{0x180, "SBC (no version claimed)"},
{0x19b, "SBC T10/0996-D revision 08c"},
- {0x19c, "SBC ANSI X3.306:1998"},
+ {0x19c, "SBC ANSI INCITS 306-1998"},
{0x1a0, "SMC (no version claimed)"},
{0x1bb, "SMC T10/0999-D revision 10a"},
- {0x1bc, "SMC ANSI NCITS.314:1998"},
+ {0x1bc, "SMC ANSI INCITS 314-1998"},
{0x1c0, "SES (no version claimed)"},
{0x1db, "SES T10/1212-D revision 08b"},
- {0x1dc, "SES ANSI NCITS.305:1998"},
+ {0x1dc, "SES ANSI INCITS 305-1998"},
{0x1dd, "SES T10/1212-D revision 08b w/ Amendment ANSI "
- "NCITS.305/AM1:2000"},
- {0x1de, "SES ANSI NCITS.305:1998 w/ Amendment ANSI "
- "NCITS.305/AM1:2000"},
+ "INCITS.305/AM1:2000"},
+ {0x1de, "SES ANSI INCITS 305-1998 w/ Amendment ANSI "
+ "INCITS.305/AM1:2000"},
{0x1e0, "SCC-2 (no version claimed}"},
{0x1fb, "SCC-2 T10/1125-D revision 04"},
- {0x1fc, "SCC-2 ANSI NCITS.318:1998"},
+ {0x1fc, "SCC-2 ANSI INCITS 318-1998"},
{0x200, "SSC (no version claimed)"},
{0x201, "SSC T10/0997-D revision 17"},
{0x207, "SSC T10/0997-D revision 22"},
- {0x21c, "SSC ANSI NCITS.335:2000"},
+ {0x21c, "SSC ANSI INCITS 335-2000"},
{0x220, "RBC (no version claimed)"},
{0x238, "RBC T10/1240-D revision 10a"},
- {0x23c, "RBC ANSI NCITS.330:2000"},
+ {0x23c, "RBC ANSI INCITS 330-2000"},
{0x240, "MMC-2 (no version claimed)"},
{0x255, "MMC-2 T10/1228-D revision 11"},
{0x25b, "MMC-2 T10/1228-D revision 11a"},
- {0x25c, "MMC-2 ANSI NCITS.333:2000"},
+ {0x25c, "MMC-2 ANSI INCITS 333-2000"},
{0x260, "SPC-2 (no version claimed)"},
{0x267, "SPC-2 T10/1236-D revision 12"},
{0x269, "SPC-2 T10/1236-D revision 18"},
{0x275, "SPC-2 T10/1236-D revision 19"},
{0x276, "SPC-2 T10/1236-D revision 20"},
- {0x277, "SPC-2 ANSI NCITS.351:2001"},
+ {0x277, "SPC-2 ANSI INCITS 351-2001"},
{0x280, "OCRW (no version claimed)"},
- {0x29e, "OCRW ISI/IEC 14776-382"},
+ {0x29e, "OCRW ISO/IEC 14776-381"},
{0x2a0, "MMC-3 (no version claimed)"},
{0x2b5, "MMC-3 T10/1363-D revision 9"},
{0x2b6, "MMC-3 T10/1363-D revision 10g"},
- {0x2b8, "MMC-3 ANSI NCITS.360:2002"},
+ {0x2b8, "MMC-3 ANSI INCITS 360-2002"},
{0x2e0, "SMC-2 (no version claimed)"},
{0x2f5, "SMC-2 T10/1383-D revision 5"},
{0x2fc, "SMC-2 T10/1383-D revision 6"},
{0x2fd, "SMC-2 T10/1383-D revision 7"},
+ {0x2fe, "SMC-2 ANSI INCITS 382-2004"},
{0x300, "SPC-3 (no version claimed)"},
{0x301, "SPC-3 T10/1416-D revision 7"},
{0x307, "SPC-3 T10/1416-D revision 21"},
+ {0x30f, "SPC-3 T10/1416-D revision 22"},
{0x320, "SBC-2 (no version claimed)"},
{0x322, "SBC-2 T10/1417-D revision 5a"},
{0x324, "SBC-2 T10/1417-D revision 15"},
+ {0x32b, "SBC-2 T10/1417-D revision 16"},
+ {0x32d, "SBC-2 ANSI INCITS 405-2005"},
{0x340, "OSD (no version claimed)"},
{0x341, "OSD T10/1355-D revision 0"},
{0x342, "OSD T10/1355-D revision 7a"},
{0x343, "OSD T10/1355-D revision 8"},
{0x344, "OSD T10/1355-D revision 9"},
{0x355, "OSD T10/1355-D revision 10"},
- {0x356, "OSD ANSI INCITS.400:2004"},
+ {0x356, "OSD ANSI INCITS 400-2004"},
{0x360, "SSC-2 (no version claimed)"},
{0x374, "SSC-2 T10/1434-D revision 7"},
{0x375, "SSC-2 T10/1434-D revision 9"},
- {0x37d, "SSC-2 ANSI NCITS.380:2003"},
+ {0x37d, "SSC-2 ANSI INCITS 380-2003"},
{0x380, "BCC (no version claimed)"},
{0x3a0, "MMC-4 (no version claimed)"},
+ {0x3b0, "MMC-4 T10/1545-D revision 5"},
{0x3bd, "MMC-4 T10/1545-D revision 3"},
{0x3be, "MMC-4 T10/1545-D revision 3d"},
- {0x3bf, "MMC-4 ANSI INCITS.401:2005"},
+ {0x3bf, "MMC-4 ANSI INCITS 401-2005"},
{0x3c0, "ADC (no version claimed)"},
{0x3d5, "ADC T10/1558-D revision 6"},
{0x3d6, "ADC T10/1558-D revision 7"},
- {0x3d7, "ADC ANSI INCITS.403:2005"},
+ {0x3d7, "ADC ANSI INCITS 403-2005"},
{0x3e0, "SES-2 (no version claimed)"},
{0x400, "SSC-3 (no version claimed)"},
{0x420, "MMC-5 (no version claimed)"},
{0x440, "OSD-2 (no version claimed)"},
{0x460, "SPC-4 (no version claimed)"},
{0x480, "SMC-3 (no version claimed)"},
+ {0x4a0, "ADC-2 (no version claimed)"},
{0x820, "SSA-TL2 (no version claimed)"},
{0x83b, "SSA-TL2 T10/1147-D revision 05b"},
- {0x83c, "SSA-TL2 ANSI NCITS.308:1998"},
+ {0x83c, "SSA-TL2 ANSI INCITS 308-1998"},
{0x840, "SSA-TL1 (no version claimed)"},
{0x85b, "SSA-TL1 T10/0989-D revision 10b"},
- {0x85c, "SSA-TL1 ANSI X3.295:1996"},
+ {0x85c, "SSA-TL1 ANSI INCITS 295-1996"},
{0x860, "SSA-S3P (no version claimed)"},
{0x87b, "SSA-S3P T10/1051-D revision 05b"},
- {0x87c, "SSA-S3P ANSI NCITS.309:1998"},
+ {0x87c, "SSA-S3P ANSI INCITS 309-1998"},
{0x880, "SSA-S2P (no version claimed)"},
{0x89b, "SSA-S2P T10/1121-D revision 07b"},
- {0x89c, "SSA-S2P ANSI X3.294:1996"},
+ {0x89c, "SSA-S2P ANSI INCITS 294-1996"},
{0x8a0, "SIP (no version claimed)"},
{0x8bb, "SIP T10/0856-D revision 10"},
- {0x8bc, "SIP ANSI X3.292:1997"},
+ {0x8bc, "SIP ANSI INCITS 292-1997"},
{0x8c0, "FCP (no version claimed)"},
{0x8db, "FCP T10/0856-D revision 12"},
- {0x8dc, "FCP ANSI X3.269:1996"},
+ {0x8dc, "FCP ANSI INCITS 269-1996"},
{0x8e0, "SBP-2 (no version claimed)"},
{0x8fb, "SBP-2 T10/1155-D revision 04"},
- {0x8fc, "SBP-2 ANSI NCITS.325:1999"},
+ {0x8fc, "SBP-2 ANSI INCITS 325-1999"},
{0x900, "FCP-2 (no version claimed)"},
{0x901, "FCP-2 T10/1144-D revision 4"},
{0x915, "FCP-2 T10/1144-D revision 7"},
{0x916, "FCP-2 T10/1144-D revision 7a"},
- {0x917, "FCP-2 ANSI INCITS.350:2003"},
+ {0x917, "FCP-2 ANSI INCITS 350-2003"},
{0x918, "FCP-2 T10/1144-D revision 8"},
{0x920, "SST (no version claimed)"},
{0x935, "SST T10/1380-D revision 8b"},
{0x940, "SRP (no version claimed)"},
{0x954, "SRP T10/1415-D revision 10"},
{0x955, "SRP T10/1415-D revision 16a"},
- {0x95c, "SRP ANSI INCITS.365:2002"},
+ {0x95c, "SRP ANSI INCITS 365-2002"},
{0x960, "iSCSI (no version claimed)"},
{0x980, "SBP-3 (no version claimed)"},
{0x982, "SBP-3 T10/1467-D revision 1f"},
{0x994, "SBP-3 T10/1467-D revision 3"},
{0x99a, "SBP-3 T10/1467-D revision 4"},
{0x99b, "SBP-3 T10/1467-D revision 5"},
- {0x99c, "SBP-3 ANSI INCITS.375:2004"},
- {0x9a0, "SRP-2 (no version claimed)"},
+ {0x99c, "SBP-3 ANSI INCITS 375-2004"},
+ /* {0x9a0, "SRP-2 (no version claimed)"}, */
{0x9c0, "ADP (no version claimed)"},
{0x9e0, "ADT (no version claimed)"},
{0x9f9, "ADT T10/1557-D revision 11"},
+ {0x9fa, "ADT T10/1557-D revision 14"},
+ {0x9fd, "ADT ANSI INCITS 406-2005"},
{0xa00, "FCP-3 (no version claimed)"},
+ {0xa0f, "FCP-3 T10/1560-D revision 4"},
+ {0xa20, "ADT-2 (no version claimed)"},
{0xaa0, "SPI (no version claimed)"},
{0xab9, "SPI T10/0855-D revision 15a"},
- {0xaba, "SPI ANSI X3.253:1995"},
+ {0xaba, "SPI ANSI INCITS 253-1995"},
{0xabb, "SPI T10/0855-D revision 15a with SPI Amnd revision 3a"},
- {0xabc, "SPI ANSI X3.253:1995 with SPI Amnd ANSI X3.253/AM1:1998"},
+ {0xabc, "SPI ANSI INCITS 253-1995 with SPI Amnd ANSI INCITS "
+ "253/AM1:1998"},
{0xac0, "Fast-20 (no version claimed)"},
{0xadb, "Fast-20 T10/1071-D revision 06"},
- {0xadc, "Fast-20 ANSI X3.277:1996"},
+ {0xadc, "Fast-20 ANSI INCITS 277-1996"},
{0xae0, "SPI-2 (no version claimed)"},
{0xafb, "SPI-2 T10/1142-D revision 20b"},
- {0xafc, "SPI-2 ANSI X3.302:1999"},
+ {0xafc, "SPI-2 ANSI INCITS 302-1999"},
{0xb00, "SPI-3 (no version claimed)"},
{0xb18, "SPI-3 T10/1302-D revision 10"},
{0xb19, "SPI-3 T10/1302-D revision 13a"},
{0xb1a, "SPI-3 T10/1302-D revision 14"},
- {0xb1c, "SPI-3 ANSI NCITS.336:2000"},
+ {0xb1c, "SPI-3 ANSI INCITS 336-2000"},
{0xb20, "EPI (no version claimed)"},
{0xb3b, "EPI T10/1134-D revision 16"},
- {0xb3c, "EPI ANSI NCITS TR-23:1999"},
+ {0xb3c, "EPI ANSI INCITS TR-23 1999"},
{0xb40, "SPI-4 (no version claimed)"},
{0xb54, "SPI-4 T10/1365-D revision 7"},
{0xb55, "SPI-4 T10/1365-D revision 9"},
- {0xb56, "SPI-4 ANSI INCITS.362:2002"},
+ {0xb56, "SPI-4 ANSI INCITS 362-2002"},
{0xb59, "SPI-4 T10/1365-D revision 10"},
{0xb60, "SPI-5 (no version claimed)"},
{0xb79, "SPI-5 T10/1525-D revision 3"},
{0xb7a, "SPI-5 T10/1525-D revision 5"},
{0xb7b, "SPI-5 T10/1525-D revision 6"},
- {0xb7c, "SPI-5 ANSI INCITS.367:2004"},
+ {0xb7c, "SPI-5 ANSI INCITS 367-2004"},
{0xbe0, "SAS (no version claimed)"},
{0xbe1, "SAS T10/1562-D revision 01"},
{0xbf5, "SAS T10/1562-D revision 03"},
{0xbfa, "SAS T10/1562-D revision 04"},
{0xbfb, "SAS T10/1562-D revision 04"},
{0xbfc, "SAS T10/1562-D revision 05"},
- {0xbfd, "SAS ANSI INCITS.376:2003"},
+ {0xbfd, "SAS ANSI INCITS 376-2003"},
{0xc00, "SAS-1.1 (no version claimed)"},
+ {0xc07, "SAS-1.1 T10/1602-D revision 9"},
+ {0xc0f, "SAS-1.1 T10/1602-D revision 10"},
+ {0xc20, "SAS-2 (no version claimed)"},
{0xd20, "FC-PH (no version claimed)"},
- {0xd3b, "FC-PH ANSI X3.230:1994"},
- {0xd3c, "FC-PH ANSI X3.230:1994 with Amnd 1 ANSI X3.230/AM1:1996"},
+ {0xd3b, "FC-PH ANSI INCITS 230-1994"},
+ {0xd3c, "FC-PH ANSI INCITS 230-1994 with Amnd 1 ANSI INCITS "
+ "230/AM1:1996"},
{0xd40, "FC-AL (no version claimed)"},
- {0xd5c, "FC-AL ANSI X3.272:1996"},
+ {0xd5c, "FC-AL ANSI INCITS 272-1996"},
{0xd60, "FC-AL-2 (no version claimed)"},
{0xd61, "FC-AL-2 T11/1133-D revision 7.0"},
- {0xd7c, "FC-AL-2 ANSI NCITS.332:1999"},
- {0xd7d, "FC-AL-2 ANSI NCITS.332:1999 with Amnd 1 AM1:2002"},
+ {0xd7c, "FC-AL-2 ANSI INCITS 332-1999"},
+ {0xd7d, "FC-AL-2 ANSI INCITS 332-1999 with Amnd 1 AM1:2002"},
{0xd80, "FC-PH-3 (no version claimed)"},
- {0xd9c, "FC-PH-3 ANSI X3.303:1998"},
+ {0xd9c, "FC-PH-3 ANSI INCITS 303-1998"},
{0xda0, "FC-FS (no version claimed)"},
{0xdb7, "FC-FS T11/1331-D revision 1.2"},
{0xdb8, "FC-FS T11/1331-D revision 1.7"},
- {0xdbc, "FC-FS ANSI INCITS.373:2003"},
+ {0xdbc, "FC-FS ANSI INCITS 373-2003"},
{0xdc0, "FC-PI (no version claimed)"},
- {0xddc, "FC-PI ANSI INCITS.352:2002"},
+ {0xddc, "FC-PI ANSI INCITS 352-2002"},
{0xde0, "FC-PI-2 (no version claimed)"},
{0xde2, "FC-PI-2 T11/1506-D revision 5.0"},
{0xe00, "FC-FS-2 (no version claimed)"},
@@ -2006,27 +2243,33 @@ static struct version_descriptor version_descriptor_arr[] = {
{0x1300, "FC-Tape (no version claimed)"},
{0x1301, "FC-Tape T11/1315-D revision 1.16"},
{0x131b, "FC-Tape T11/1315-D revision 1.17"},
- {0x131c, "FC-Tape ANSI NCITS TR-24:1999"},
+ {0x131c, "FC-Tape ANSI INCITS TR-24 1999"},
{0x1320, "FC-FLA (no version claimed)"},
{0x133b, "FC-FLA T11/1235-D revision 7"},
- {0x133c, "FC-FLA ANSI NCITS TR-20:1998"},
+ {0x133c, "FC-FLA ANSI INCITS TR-20 1998"},
{0x1340, "FC-PLDA (no version claimed)"},
{0x135b, "FC-PLDA T11/1162-D revision 2.1"},
- {0x135c, "FC-PLDA ANSI NCITS TR-19:1998"},
+ {0x135c, "FC-PLDA ANSI INCITS TR-19 1998"},
{0x1360, "SSA-PH2 (no version claimed)"},
{0x137b, "SSA-PH2 T10/1145-D revision 09c"},
- {0x137c, "SSA-PH2 ANSI X3.293:1996"},
+ {0x137c, "SSA-PH2 ANSI INCITS 293-1996"},
{0x1380, "SSA-PH3 (no version claimed)"},
{0x139b, "SSA-PH3 T10/1146-D revision 05b"},
- {0x139c, "SSA-PH3 ANSI NCITS.307:1998"},
+ {0x139c, "SSA-PH3 ANSI INCITS 307-1998"},
{0x14a0, "IEEE 1394 (no version claimed)"},
{0x14bd, "ANSI IEEE 1394:1995"},
{0x14c0, "IEEE 1394a (no version claimed)"},
{0x14e0, "IEEE 1394b (no version claimed)"},
{0x15e0, "ATA/ATAPI-6 (no version claimed)"},
- {0x15fd, "ATA/ATAPI-6 ANSI INCITS.361:2002"},
+ {0x15fd, "ATA/ATAPI-6 ANSI INCITS 361-2002"},
{0x1600, "ATA/ATAPI-7 (no version claimed)"},
{0x1602, "ATA/ATAPI-7 T13/1532-D revision 3"},
+ {0x161c, "ATA/ATAPI-7 ANSI INCITS 397-2005"},
+ {0x1620, "ATA/ATAPI-8 ATA-AAM Architecture model (no version claimed)"},
+ {0x1621, "ATA/ATAPI-8 ATA-PT Parallel transport (no version claimed)"},
+ {0x1622, "ATA/ATAPI-8 ATA-AST Serial transport (no version claimed)"},
+ {0x1623, "ATA/ATAPI-8 ATA-ACS ATA?ATAPI command set (no version "
+ "claimed)"},
{0x1728, "Universal Serial Bus Specification, Revision 1.1"},
{0x1729, "Universal Serial Bus Specification, Revision 2.0"},
{0x1730, "USB Mass Storage Class Bulk-Only Transport, Revision 1.0"},
diff --git a/sg_lib.c b/sg_lib.c
index 127e0f47..059e824c 100644
--- a/sg_lib.c
+++ b/sg_lib.c
@@ -41,7 +41,7 @@
* and a GPL notice.
*
* Much of the data in this file is derived from SCSI draft standards
- * found at http://www.t10.org with the "SCSI Primary Commands-3" (SPC-3)
+ * found at http://www.t10.org with the "SCSI Primary Commands-3" (SPC-4)
* being the central point of reference.
*
* Other contributions:
@@ -68,7 +68,7 @@
#include "sg_include.h"
#include "sg_lib.h"
-static char * version_str = "1.11 20050807"; /* spc-3 rev 23+ */
+static char * version_str = "1.13 20050906"; /* spc-4 rev 01a */
FILE * sg_warnings_str = NULL; /* would like to default to stderr */
@@ -495,6 +495,7 @@ static struct error_info additional[] =
{0x00,0x1a,"Rewind operation in progress"},
{0x00,0x1b,"Set capacity operation in progress"},
{0x00,0x1c,"Verify operation in progress"},
+ {0x00,0x1d,"ATA pass through information available"},
{0x01,0x00,"No index/sector signal"},
{0x02,0x00,"No seek complete"},
{0x03,0x00,"Peripheral device write fault"},
@@ -540,6 +541,9 @@ static struct error_info additional[] =
{0x0B,0x00,"Warning"},
{0x0B,0x01,"Warning - specified temperature exceeded"},
{0x0B,0x02,"Warning - enclosure degraded"},
+ {0x0B,0x03,"Warning - background self-test failed"},
+ {0x0B,0x04,"Warning - background pre-scan failed"},
+ {0x0B,0x05,"Warning - background medium scan failed"},
{0x0C,0x00,"Write error"},
{0x0C,0x01,"Write error - recovered with auto reallocation"},
{0x0C,0x02,"Write error - auto reallocation failed"},
@@ -819,6 +823,7 @@ static struct error_info additional[] =
{0x43,0x00,"Message error"},
{0x44,0x00,"Internal target failure"},
+ {0x44,0x71,"ATA device failed Set Features"}, /* was 0x44,0xf1 in rev1 */
{0x45,0x00,"Select or reselect failure"},
{0x46,0x00,"Unsuccessful soft reset"},
{0x47,0x00,"SCSI parity error"},
@@ -2012,7 +2017,7 @@ char * safe_strerror(int errnum)
}
-/* Note the ASCII-hex output goes to stdout. [All other output from functions
+/* Note the ASCII-hex output goes to stdout. [Most other output from functions
in this file go to sg_warnings_str (default stderr).]
'no_ascii' allows for 3 output types:
> 0 each line has address then up to 16 ASCII-hex bytes
@@ -2055,8 +2060,6 @@ void dStrHex(const char* str, int len, int no_ascii)
/* no_ascii>=0, start each line with address (offset) */
k = sprintf(buff + 1, "%.2x", a);
buff[k + 1] = ' ';
- if (bpos >= ((bpstart + (9 * 3))))
- bpos++;
for (i = 0; i < len; i++) {
c = *p++;
@@ -2069,10 +2072,10 @@ void dStrHex(const char* str, int len, int no_ascii)
buff[cpos++] = ' ';
else {
if ((c < ' ') || (c >= 0x7f))
- c='.';
+ c = '.';
buff[cpos++] = c;
}
- if (cpos > (cpstart+15)) {
+ if (cpos > (cpstart + 15)) {
printf("%.76s\n", buff);
bpos = bpstart;
cpos = cpstart;
@@ -2119,6 +2122,114 @@ static void dStrHexErr(const char* str, int len)
return;
}
+/* Returns 1 when executed on big endian machine; else returns 0.
+ Useful for displaying ATA identify words (which need swapping on a
+ big endian machine). */
+int sg_is_big_endian()
+{
+ union u_t {
+ unsigned short s;
+ unsigned char c[sizeof(unsigned short)];
+ } u;
+
+ u.s = 0x0102;
+ return (u.c[0] == 0x01); /* The lowest address contains
+ the most significant byte */
+}
+
+static unsigned short swapb_ushort(unsigned short u)
+{
+ unsigned short r;
+
+ r = (u >> 8) & 0xff;
+ r |= ((u & 0xff) << 8);
+ return r;
+}
+
+/* Note the ASCII-hex output goes to stdout. [Most other output from functions
+ in this file go to sg_warnings_str (default stderr).]
+ '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)
+ 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,
+ int swapb)
+{
+ const unsigned short * p = words;
+ unsigned short c;
+ char buff[82];
+ unsigned char upp, low;
+ int a = 0;
+ const int bpstart = 3;
+ const int cpstart = 52;
+ int cpos = cpstart;
+ int bpos = bpstart;
+ int i, k;
+
+ if (num <= 0)
+ return;
+ memset(buff, ' ', 80);
+ buff[80] = '\0';
+ if (no_ascii < 0) {
+ for (k = 0; k < num; k++) {
+ c = *p++;
+ if (swapb)
+ c = swapb_ushort(c);
+ bpos += 5;
+ sprintf(&buff[bpos], "%.4x", (unsigned int)c);
+ buff[bpos + 4] = ' ';
+ if ((k > 0) && (0 == ((k + 1) % 8))) {
+ printf("%.60s\n", buff);
+ bpos = bpstart;
+ memset(buff, ' ', 80);
+ }
+ }
+ if (bpos > bpstart)
+ printf("%.60s\n", buff);
+ return;
+ }
+ /* no_ascii>=0, start each line with address (offset) */
+ k = sprintf(buff + 1, "%.2x", a);
+ buff[k + 1] = ' ';
+
+ for (i = 0; i < num; i++) {
+ c = *p++;
+ if (swapb)
+ c = swapb_ushort(c);
+ bpos += 5;
+ sprintf(&buff[bpos], "%.4x", (unsigned int)c);
+ buff[bpos + 4] = ' ';
+ if (no_ascii) {
+ buff[cpos++] = ' ';
+ buff[cpos++] = ' ';
+ buff[cpos++] = ' ';
+ } else {
+ upp = (c >> 8) & 0xff;
+ low = c & 0xff;
+ if ((upp < 0x20) || (upp >= 0x7f))
+ upp = '.';
+ buff[cpos++] = upp;
+ if ((low < 0x20) || (low >= 0x7f))
+ low = '.';
+ buff[cpos++] = low;
+ buff[cpos++] = ' ';
+ }
+ if (cpos > (cpstart + 23)) {
+ printf("%.76s\n", buff);
+ bpos = bpstart;
+ cpos = cpstart;
+ a += 8;
+ memset(buff, ' ', 80);
+ k = sprintf(buff + 1, "%.2x", a);
+ buff[k + 1] = ' ';
+ }
+ }
+ if (cpos > cpstart)
+ printf("%.76s\n", buff);
+}
+
/* If the number in 'buf' can be decoded or the multiplier is unknown
then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)).
diff --git a/sg_lib.h b/sg_lib.h
index 685ad71d..7b50c4a0 100644
--- a/sg_lib.h
+++ b/sg_lib.h
@@ -30,7 +30,7 @@
*
*/
-/* Version 1.11 [20050806]
+/* Version 1.13 [20050906]
*
* 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
@@ -167,6 +167,26 @@ extern char * safe_strerror(int errnum);
*/
extern void dStrHex(const char* str, int len, int no_ascii);
+/* Returns 1 when executed on big endian machine; else returns 0.
+ Useful for displaying ATA identify words (which need swapping on a
+ big endian machine).
+*/
+extern int sg_is_big_endian();
+
+/* Print (to stdout) 16 bit 'words' in hex, 8 words per line optionally
+ followed at the right hand side of the line with an ASCII interpretation
+ (pairs of ASCII characters in big endian order (upper first)).
+ Each line is prefixed with an address, starting at 0.
+ All output numbers are in hex. 'no_ascii' allows for 3 output types:
+ > 0 each line has address then up to 8 ASCII-hex words
+ = 0 in addition, the words are listed in ASCII pairs to the right
+ < 0 only the ASCII-hex words are listed (i.e. without address)
+ If 'swapb' non-zero then bytes in each word swapped. Needs to be set
+ for ATA IDENTIFY DEVICE response on big-endian machines.
+*/
+extern void dWordHex(const unsigned short* words, int num, int no_ascii,
+ int swapb);
+
/* If the number in 'buf' can not be decoded or the multiplier is unknown
then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal
multiplier suffix (not both). Recognised multipliers: c C *1; w W *2;
diff --git a/sg_logs.c b/sg_logs.c
index 97b65eec..924fe307 100644
--- a/sg_logs.c
+++ b/sg_logs.c
@@ -23,12 +23,12 @@
*/
-static char * version_str = "0.43 20050808";
+static char * version_str = "0.44 20050916";
#define ME "sg_logs: "
#define MX_ALLOC_LEN (1024 * 17)
-#define PG_CODE_ALL 0x00
+#define PG_CODE_ALL 0x0
#define EBUFF_SZ 256
@@ -145,7 +145,7 @@ static void show_page_name(int page_no,
printf(" 0x08 Format status (sbc-2)\n");
break;
case 0x15:
- printf(" 0x15 Background scan results (sbc-2)\n");
+ printf(" 0x15 Background scan results (sbc-3)\n");
break;
case 0x17:
printf(" 0x17 Non-volatile cache (sbc-2)\n");
@@ -173,6 +173,9 @@ static void show_page_name(int page_no,
case 0xc:
printf(" 0x0c Sequential Access (ssc-2)\n");
break;
+ case 0x14:
+ printf(" 0x14 Device statistics (ssc-3)\n");
+ break;
case 0x2e:
printf(" 0x2e Tape alerts (ssc-2)\n");
break;
diff --git a/sg_modes.c b/sg_modes.c
index 03e9876d..8d42e67e 100644
--- a/sg_modes.c
+++ b/sg_modes.c
@@ -24,7 +24,7 @@
*/
-static char * version_str = "1.09 20050808";
+static char * version_str = "1.10 20050904";
#define ME "sg_modes: "
@@ -117,6 +117,7 @@ static struct page_code_desc pc_desc_disk[] = {
{0x7, 0x0, "Verify error recovery"},
{0x8, 0x0, "Caching"},
{0xa, 0xf1, "Parallel ATA control (SAT)"},
+ {0xa, 0xf2, "Reserved (SATA control) (SAT)"},
{0xb, 0x0, "Medium types supported (obsolete)"},
{0xc, 0x0, "Notch and partition (obsolete)"},
{0xd, 0x0, "Power condition (obsolete, moved to 0x1a)"},
diff --git a/sg_opcodes.8 b/sg_opcodes.8
index 05f0703f..ac0d48e0 100644
--- a/sg_opcodes.8
+++ b/sg_opcodes.8
@@ -74,6 +74,10 @@ print out version string
-?
output usage message. Ignore all other parameters.
.PP
+As of SPC-4 revision 1 the recognized task management functions are:
+abort set, abort task set, clear ACA, clear task set, I_T nexus reset,
+logical unit reset, query task, target reset and wakeup.
+.PP
In the 2.4 series of Linux kernels the given device must be
a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
and SCSI DVDs) can also be specified. For example "sg_opcodes /dev/sda"
@@ -83,7 +87,7 @@ Written by Doug Gilbert
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 2004 Douglas Gilbert
+Copyright \(co 2004-2005 Douglas Gilbert
.br
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg_opcodes.c b/sg_opcodes.c
index 8af75743..0f3cdac4 100644
--- a/sg_opcodes.c
+++ b/sg_opcodes.c
@@ -24,7 +24,7 @@
*/
-static char * version_str = "0.20 20050808";
+static char * version_str = "0.21 20050904";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -357,7 +357,7 @@ void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
printf("\nOpcode Service CDB Name\n");
printf( "(hex) action(h) size \n");
printf("-----------------------------------------------\n");
- /* N.B. SPC-3 does _not_ requiring any ordering of response */
+ /* N.B. SPC-4 does _not_ requiring any ordering of response */
if (! unsorted) {
sort_arr = malloc(cd_len * sizeof(unsigned char *));
if (NULL == sort_arr) {
@@ -568,6 +568,8 @@ int main(int argc, char * argv[])
printf(" Target reset\n");
if (rsoc_buff[0] & 0x1)
printf(" Wakeup\n");
+ if (rsoc_buff[1] & 0x1)
+ printf(" I_T nexus reset\n");
} else if (0 == rep_opts) /* list all supported operation codes */
list_all_codes(rsoc_buff, sizeof(rsoc_buff), do_unsorted, do_alpha);
else { /* asked about specific command */
diff --git a/sg_scan.c b/sg_scan.c
index 5d31c495..2658a04c 100644
--- a/sg_scan.c
+++ b/sg_scan.c
@@ -38,7 +38,7 @@
F. Jansen - modification to extend beyond 26 sg devices.
*/
-static char * version_str = "4.04 20050806";
+static char * version_str = "4.05 20050905";
#define ME "sg_scan: "
@@ -337,6 +337,8 @@ int sg3_inq(int sg_fd, unsigned char * inqBuff, int do_extra)
int ok, err, sg_io;
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(inqBuff, 0, INQ_REPLY_LEN);
+ inqBuff[0] = 0x7f;
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(inqCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_buffer);
@@ -402,6 +404,7 @@ int scsi_inq(int sg_fd, unsigned char * inqBuff)
unsigned char buff[512];
struct lscsi_ioctl_command * sicp = (struct lscsi_ioctl_command *)buff;
+ memset(buff, 0, sizeof(buff));
sicp->inlen = 0;
sicp->outlen = INQ_REPLY_LEN;
memcpy(sicp->data, inqCmdBlk, INQ_CMD_LEN);
diff --git a/sginfo.8 b/sginfo.8
index 1d89e388..0d2e7d6c 100644
--- a/sginfo.8
+++ b/sginfo.8
@@ -1,4 +1,4 @@
-.TH SGINFO "8" "June 2005" "sg3_utils-1.15" SG3_UTILS
+.TH SGINFO "8" "September 2005" "sg3_utils-1.17" SG3_UTILS
.SH NAME
sginfo \- access mode page information for a SCSI (or ATAPI) device
.SH SYNOPSIS
@@ -10,12 +10,15 @@ sginfo \- access mode page information for a SCSI (or ATAPI) device
.\" Add any additional description here
.PP
sginfo is a port of the Linux scsiinfo program by Eric Youngdale. It
-uses SCSI generic (sg) devices. In some cases the high level device
-name (i.e. sd, sr, st, osst, or hd) can also be used. The primary role
-of this program is to access mode page information. If permitted,
+uses SCSI generic (sg) devices; however in some cases the high level
+device name (i.e. sd, sr, st, osst, or hd) can also be used. The primary
+role of this program is to access mode page information. If permitted,
mode page information can be altered. In addition information from
the INQUIRY and READ DEFECTS commands are also available.
.PP
+Those interested in SCSI mode pages may find the sdparm utility
+easier use, especially for changing parameters.
+.PP
Four sets of values are maintained by a SCSI device for each mode
page: current (active), default (manufacturer's supplied values),
saved (values that are retained if the SCSI device is powered down),
@@ -25,9 +28,9 @@ shown. This can be overridden by "-M" (defaults), "-S" (saved)
or "-m" (modifiable (i.e. changeable)).
.PP
Many mode pages are decoded: for disks (see SBC-2), for CD/DVDs (see
-MMC-2/3/4), for tapes (see SSC-2) and for enclosures (see SES-2).
+MMC-2/3/4/5), for tapes (see SSC-2) and for enclosures (see SES-2).
Some mode pages common to all SCSI peripheral device types are defined
-in SPC-3 (primary commands). A decoded mode page has its field names
+in SPC-4 (primary commands). A decoded mode page has its field names
in the first column and the corresponding value in the second column.
A "hex" mode page (and subpage) has its byte position in the first
column (in hex and starting at 0x2) and the corresponding hex value
@@ -285,7 +288,7 @@ back when the mode page is written (i.e. via a MODE SELECT command).
.PP
.SH REFERENCES
SCSI (draft) standards can be found at http://www.t10.org . The relevant
-documents are SPC-3 (mode pages common to all device types),
+documents are SPC-4 (mode pages common to all device types),
SBC-2 (direct access devices [e.g. disks]), MMC-4 (CDs and DVDs) and
SSC-2 (tapes).
.PP
@@ -309,9 +312,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.B plscsi(internet), scsiinfo(internet), sg_modes(sg3_utils),
.B sg_inq(sg3_utils), sdparm(sdparm)
.PP
-plscsi can sent arbitrary (user supplied) SCSI commands; scsiinfo is the
+plscsi can send arbitrary (user supplied) SCSI commands; scsiinfo is the
predecessor of this utility; sg_modes is a low level MODE SENSE based
-utility and sg_inq is specialised for the mandatory SCSI INQUIRY
+utility and sg_inq is specialized for the mandatory SCSI INQUIRY
command which contains a lot of information about advanced devices.
Users may find sdparm more convenient for getting and setting mode
page parameters.
diff --git a/sginfo.c b/sginfo.c
index 9a89a784..28be4db7 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.17 [20050806]";
+static const char * sginfo_version_str = "sginfo version 2.18 [20050906]";
#include <stdio.h>
#include <string.h>
@@ -191,6 +191,7 @@ static int disk_geometry(struct mpage_info * mpi, const char * prefix);
static int disk_notch_parameters(struct mpage_info * mpi, const char * prefix);
static int disk_cache(struct mpage_info * mpi, const char * prefix);
static int disk_xor_control(struct mpage_info * mpi, const char * prefix);
+static int disk_background(struct mpage_info * mpi, const char * prefix);
static int optical_memory(struct mpage_info * mpi, const char * prefix);
static int cdvd_error_recovery(struct mpage_info * mpi, const char * prefix);
static int cdvd_mrw(struct mpage_info * mpi, const char * prefix);
@@ -261,7 +262,7 @@ static struct mpage_name_func mpage_disk[] =
{ 0xb, 0, PC_DISK, "Medium Types Supported", NULL},
{ 0xc, 0, PC_DISK, "Notch and Partition", disk_notch_parameters},
{ 0x10, 0, PC_DISK, "XOR control", disk_xor_control},
- { 0x1c, 1, PC_DISK, "Background control", NULL},
+ { 0x1c, 1, PC_DISK, "Background control", disk_background},
};
static const int mpage_disk_len = sizeof(mpage_disk) / sizeof(mpage_disk[0]);
@@ -1266,7 +1267,7 @@ static int common_informational(struct mpage_info * mpi, const char * prefix)
int status;
unsigned char *pagestart;
- status = setup_mode_page(mpi, 9, cbuffer, &pagestart);
+ status = setup_mode_page(mpi, 10, cbuffer, &pagestart);
if (status)
return status;
@@ -1281,6 +1282,7 @@ static int common_informational(struct mpage_info * mpi, const char * prefix)
bitfield(pagestart + 2, "EWASC", 1, 4);
bitfield(pagestart + 2, "DEXCPT", 1, 3);
bitfield(pagestart + 2, "TEST", 1, 2);
+ bitfield(pagestart + 2, "EBACKERR", 1, 1);
bitfield(pagestart + 2, "LOGERR", 1, 0);
bitfield(pagestart + 3, "MRIE", 0xf, 0);
intfield(pagestart + 4, 4, "Interval Timer");
@@ -1919,6 +1921,34 @@ static int disk_xor_control(struct mpage_info * mpi, const char * prefix)
return 0;
}
+static int disk_background(struct mpage_info * mpi, const char * prefix)
+{
+ int status;
+ unsigned char *pagestart;
+
+ status = setup_mode_page(mpi, 4, 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", get_page_name(mpi), mpi->page,
+ mpi->subpage);
+ printf("--------------------------------------------\n");
+ }
+ bitfield(pagestart + 4, "Enable background medium scan", 1, 0);
+ bitfield(pagestart + 5, "Enable pre-scan", 1, 0);
+ intfield(pagestart + 6, 2, "BMS interval time (hour)");
+ intfield(pagestart + 8, 2, "Pre-scan timeout value (hour)");
+
+ if (x_interface && replace)
+ return put_mode_page(mpi, cbuffer);
+ else
+ printf("\n");
+ return 0;
+}
+
static int optical_memory(struct mpage_info * mpi, const char * prefix)
{
int status;
@@ -2578,7 +2608,7 @@ static int spi4_margin_control(struct mpage_info * mpi, const char * prefix)
bitfield(pagestart + 5, "Protocol identifier", 0xf, 0);
bitfield(pagestart + 7, "Driver Strength", 0xf, 4);
bitfield(pagestart + 8, "Driver Asymmetry", 0xf, 4);
- bitfield(pagestart + 8, "Driver Precompensation", 0xf, 4);
+ bitfield(pagestart + 8, "Driver Precompensation", 0xf, 0);
bitfield(pagestart + 9, "Driver Slew rate", 0xf, 4);
if (x_interface && replace)
@@ -2730,9 +2760,9 @@ static int spi4_negotiated(struct mpage_info * mpi, const char * prefix)
intfield(pagestart + 8, 1, "REQ/ACK offset");
intfield(pagestart + 9, 1, "Transfer width exponent");
bitfield(pagestart + 10, "Protocol option bits", 0x7f, 0);
- bitfield(pagestart + 11, "Transciever mode", 3, 2);
- bitfield(pagestart + 11, "Sent PCOMP_EN", 3, 1);
- bitfield(pagestart + 11, "Received PCOMP_EN", 3, 0);
+ bitfield(pagestart + 11, "Transceiver mode", 3, 2);
+ bitfield(pagestart + 11, "Sent PCOMP_EN", 1, 1);
+ bitfield(pagestart + 11, "Received PCOMP_EN", 1, 0);
if (x_interface && replace)
return put_mode_page(mpi, cbuffer);
@@ -2907,6 +2937,7 @@ static int do_inquiry(int * peri_type, int * resp_byte6,
struct scsi_cmnd_io sci;
memset(cbuffer, 0, INQUIRY_RESP_INITIAL_LEN);
+ cbuffer[0] = 0x7f;
cmd[0] = 0x12; /* INQUIRY */
cmd[1] = 0x00; /* evpd=0 */
diff --git a/sgm_dd.8 b/sgm_dd.8
index 6aefe31b..062d1d3d 100644
--- a/sgm_dd.8
+++ b/sgm_dd.8
@@ -1,21 +1,26 @@
-.TH SGM_DD "8" "February 2005" "sg3_utils-1.13" SG3_UTILS
+.TH SGM_DD "8" "September 2005" "sg3_utils-1.17" SG3_UTILS
.SH NAME
-sgm_dd \- copies data to and from files and devices. Specialised for
-devices that understand the SCSI command set.
+sgm_dd \- copies data to and from files and devices. Specialized for
+devices that understand the SCSI command set and does memory mapped
+transfers from sg devices.
.SH SYNOPSIS
.B sgm_dd
[\fIbpt=<n>\fR] [\fIbs=<n>\fR] [\fIcdbsz=6|10|12|16\fR] [\fIcount=<n>\fR]
[\fIdio=0|1\fR] [\fIfua=0|1|2|3\fR] [\fIibs=<n>\fR] [\fIif=<ifile>\fR]
[\fIobs=<n>\fR] [\fIof=<ofile>\fR] [\fIseek=<n>\fR] [\fIskip=<n>\fR]
-[\fIsync=0|1\fR] [\fItime=0|1\fR] [\fI--version\fR]
+[\fIsync=0|1\fR] [\fItime=0|1\fR] [\fIverbose=<n>\fR] [\fI--version\fR]
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Copy data to and from any files. Specialised for "files" that are
-Linux SCSI generic (sg) devices and raw devices. Uses memory mapped IO on
-sg devices. Similar syntax and semantics to
+Copy data to and from any files. Specialized for "files" that are
+Linux SCSI generic (sg) devices and raw devices. Uses memory mapped
+transfers on sg devices. Similar syntax and semantics to
.B dd(1)
but does not perform any conversions.
+.PP
+Will only perform memory mapped transfers when <ifile> or <ofile> are
+SCSI generic (sg) devices. If both <ifile> and <ofile> are sg devices
+then memory mapped transfers are only performed on <ifile>.
.TP
bpt=BLOCKS
each IO transaction will be made using this number of blocks (or less if
@@ -52,7 +57,7 @@ is issued and no copy takes place.
dio=0 | 1
permits direct IO to be selected on the write-side (i.e. "of"). Only
allowed when the read-side (i.e. "if") is a sg device. When 1 there
-may be a "zero copy" copy (i.e. mmap-ed IO on the read into the user
+may be a "zero copy" copy (i.e. mmap-ed transfer on the read into the user
space and direct IO from there on the write, potentially two DMAs and
no data copying from the CPU). Default is 0
.TP
@@ -95,6 +100,15 @@ time=0 | 1
when 1, times transfer and does throughput calculation, outputting the
results (to stderr) at completion. When 0 (default) doesn't perform timing
.TP
+verbose=<n>
+as <n> increases so does the amount of debug output sent to stderr.
+Default value is zero which yields the minimum amount of debug output.
+A value of 1 reports extra information that is not repetitive. A value
+2 reports cdbs and responses for SCSI commands that are not repetitive
+(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.
+.TP
--version
outputs version number information and exits
.PP
@@ -128,8 +142,8 @@ big numbers). Other values are limited to what can fit in a signed
Data usually gets to the user space in a 2 stage process: first the
SCSI adapter DMAs into kernel buffers and then the sg driver copies
this data into user memory (write operations reverse this sequence).
-With memory mapped IO a kernel buffer reserved by sg is memory mapped
-(see the
+With memory mapped transfers a kernel buffer reserved by sg is memory
+mapped (see the
.B mmap(2)
system call) into the user space. When this is done
the second (redundant) copy from kernel buffers to user space is
diff --git a/sgm_dd.c b/sgm_dd.c
index f5f7ec5a..cd781ad7 100644
--- a/sgm_dd.c
+++ b/sgm_dd.c
@@ -46,7 +46,7 @@
in this case) is transferred to or from the sg device in a single SCSI
command.
- This version uses memory-mapped IO (i.e. mmap() call from the user
+ This version uses memory-mapped transfers (i.e. mmap() call from the user
space) to speed transfers. If both sides of copy are sg devices
then only the read side will be mmap-ed, while the write side will
use normal IO.
@@ -54,7 +54,7 @@
This version is designed for the linux kernel 2.4 and 2.6 series.
*/
-static char * version_str = "1.21 20050806";
+static char * version_str = "1.21 20050909";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -102,6 +102,7 @@ static long long in_full = 0;
static int in_partial = 0;
static long long out_full = 0;
static int out_partial = 0;
+static int verbose = 0;
static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio";
@@ -172,21 +173,56 @@ int dd_filetype(const char * filename)
return FT_OTHER;
}
+static char * dd_filetype_str(int ft, char * buff)
+{
+ int off = 0;
+
+ if (FT_DEV_NULL & ft)
+ off += snprintf(buff + off, 32, "null device ");
+ if (FT_SG & ft)
+ off += snprintf(buff + off, 32, "SCSI generic (sg) device ");
+ if (FT_BLOCK & ft)
+ off += snprintf(buff + off, 32, "block device ");
+ if (FT_ST & ft)
+ off += snprintf(buff + off, 32, "SCSI tape device ");
+ if (FT_RAW & ft)
+ off += snprintf(buff + off, 32, "raw device ");
+ if (FT_OTHER & ft)
+ off += snprintf(buff + off, 32, "other (perhaps name file) ");
+ return buff;
+}
+
void usage()
{
fprintf(stderr, "Usage: "
- "sgm_dd [if=<infile>] [skip=<n>] [of=<ofile>] [seek=<n>]\n"
- " [bs=<num>] [bpt=<num>] [count=<n>] [time=<n>]\n"
- " [cdbsz=6|10|12|16] [fua=0|1|2|3] [sync=0|1]\n"
- " [dio=0|1] [--version]\n"
- " 'bs' must be device block size (default 512)\n"
- " 'bpt' is blocks_per_transfer (default is 128)\n"
- " 'time' 0->no timing(def), 1->time plus calculate throughput\n"
- " 'fua' force unit access: 0->don't(def), 1->of, 2->if, 3->of+if\n"
- " 'sync' 0->no sync(def), 1->SYNCHRONIZE CACHE after xfer\n"
- " 'cdbsz' size of SCSI READ or WRITE command (default is 10)\n"
- " 'dio' 0->indirect IO on write, 1->direct IO on write\n"
- " (only when read side is sg device (using mmap))\n");
+ "sgm_dd [if=<infile>] [skip=<n>] [of=<ofile>] [seek=<n>] "
+ "[bs=<num>]\n"
+ " [count=<n>] [ibs=<n>] [obs=<n>] [bpt=<num>] "
+ "[cdbsz=6|10|12|16]\n"
+ " [dio=0|1] [fua=0|1|2|3] [sync=0|1] [time=<n>] "
+ "[verbose=<n>]\n"
+ " [--version]\n"
+ " bpt is blocks_per_transfer (default is 128)\n"
+ " bs must be device block size (default 512)\n"
+ " cdbsz size of SCSI READ or WRITE command (default is 10)\n"
+ " dio 0->indirect IO on write, 1->direct IO on write\n"
+ " (only when read side is sg device (using mmap))\n"
+ " fua force unit access: 0->don't(def), 1->of, 2->if, "
+ "3->of+if\n");
+ fprintf(stderr,
+ " ibs input block size (if given must be same as 'bs')\n"
+ " if file or device to read from (def stdin)\n"
+ " obs output block size (if given must be same as 'bs')\n"
+ " of file or device to write to (def stdout), name '.' "
+ "translated to\n"
+ " /dev/null\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"
+ " --version print version information then exit\n");
}
/* Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
@@ -196,8 +232,11 @@ int scsi_read_capacity(int sg_fd, long long * num_sect, int * sect_sz)
{
int k, res;
unsigned char rcBuff[RCAP16_REPLY_LEN];
+ int verb;
- res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 0, 0);
+ verb = (verbose ? verbose - 1: 0);
+ res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 0,
+ verb);
if (0 != res)
return res;
@@ -205,7 +244,8 @@ int scsi_read_capacity(int sg_fd, long long * num_sect, int * sect_sz)
(0xff == rcBuff[3])) {
long long ls;
- res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 0, 0);
+ res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 0,
+ verb);
if (0 != res)
return res;
for (k = 0, ls = 0; k < 8; ++k) {
@@ -221,6 +261,9 @@ int scsi_read_capacity(int sg_fd, long long * num_sect, int * sect_sz)
*sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) |
(rcBuff[6] << 8) | rcBuff[7];
}
+ if (verbose)
+ fprintf(stderr, " number of blocks=%lld [0x%llx], block "
+ "size=%d\n", *num_sect, *num_sect, *sect_sz);
return 0;
}
@@ -242,6 +285,9 @@ int read_blkdev_capacity(int sg_fd, long long * num_sect, int * sect_sz)
return -1;
}
*num_sect = ((long long)ull / (long long)*sect_sz);
+ if (verbose)
+ fprintf(stderr, " [bgs64] number of blocks=%lld [0x%llx], "
+ "block size=%d\n", *num_sect, *num_sect, *sect_sz);
#else
unsigned long ul;
@@ -250,10 +296,15 @@ int read_blkdev_capacity(int sg_fd, long long * num_sect, int * sect_sz)
return -1;
}
*num_sect = (long long)ul;
+ if (verbose)
+ fprintf(stderr, " [bgs] number of blocks=%lld [0x%llx], "
+ " block size=%d\n", *num_sect, *num_sect, *sect_sz);
#endif
}
return 0;
#else
+ if (verbose)
+ fprintf(stderr, " BLKSSZGET+BLKGETSIZE ioctl not available\n");
*num_sect = 0;
*sect_sz = 0;
return -1;
@@ -360,6 +411,7 @@ int sg_read(int sg_fd, unsigned char * buff, int blocks, long long from_block,
unsigned char rdCmd[MAX_SCSI_CDBSZ];
unsigned char senseBuff[SENSE_BUFF_LEN];
struct sg_io_hdr io_hdr;
+ int k;
if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, 0)) {
fprintf(stderr, ME "bad rd cdb build, from_block=%lld, blocks=%d\n",
@@ -380,6 +432,12 @@ int sg_read(int sg_fd, unsigned char * buff, int blocks, long long from_block,
io_hdr.pack_id = (int)from_block;
if (do_mmap)
io_hdr.flags |= SG_FLAG_MMAP_IO;
+ if (verbose > 2) {
+ fprintf(stderr, " read cdb: ");
+ for (k = 0; k < cdbsz; ++k)
+ fprintf(stderr, "%02x ", rdCmd[k]);
+ fprintf(stderr, "\n");
+ }
#if 1
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
@@ -405,16 +463,18 @@ int sg_read(int sg_fd, unsigned char * buff, int blocks, long long from_block,
return -1;
}
#endif
+ if (verbose > 2)
+ fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
switch (sg_err_category3(&io_hdr)) {
case SG_LIB_CAT_CLEAN:
break;
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Reading, continuing", &io_hdr, 0);
+ sg_chk_n_print3("Reading, continuing", &io_hdr, verbose);
break;
case SG_LIB_CAT_MEDIA_CHANGED:
return 2;
default:
- sg_chk_n_print3("reading", &io_hdr, 0);
+ sg_chk_n_print3("reading", &io_hdr, verbose);
return -1;
}
sum_of_resids += io_hdr.resid;
@@ -432,6 +492,7 @@ int sg_write(int sg_fd, unsigned char * buff, int blocks, long long to_block,
unsigned char wrCmd[MAX_SCSI_CDBSZ];
unsigned char senseBuff[SENSE_BUFF_LEN];
struct sg_io_hdr io_hdr;
+ int k;
if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, 0)) {
fprintf(stderr, ME "bad wr cdb build, to_block=%lld, blocks=%d\n",
@@ -455,6 +516,12 @@ int sg_write(int sg_fd, unsigned char * buff, int blocks, long long to_block,
io_hdr.flags |= SG_FLAG_MMAP_IO;
if (diop && *diop)
io_hdr.flags |= SG_FLAG_DIRECT_IO;
+ if (verbose > 2) {
+ fprintf(stderr, " write cdb: ");
+ for (k = 0; k < cdbsz; ++k)
+ fprintf(stderr, "%02x ", wrCmd[k]);
+ fprintf(stderr, "\n");
+ }
#if 1
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
@@ -480,16 +547,18 @@ int sg_write(int sg_fd, unsigned char * buff, int blocks, long long to_block,
return -1;
}
#endif
+ if (verbose > 2)
+ fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
switch (sg_err_category3(&io_hdr)) {
case SG_LIB_CAT_CLEAN:
break;
case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Writing, continuing", &io_hdr, 0);
+ sg_chk_n_print3("Writing, continuing", &io_hdr, verbose);
break;
case SG_LIB_CAT_MEDIA_CHANGED:
return 2;
default:
- sg_chk_n_print3("writing", &io_hdr, 0);
+ sg_chk_n_print3("writing", &io_hdr, verbose);
return -1;
}
if (diop && *diop &&
@@ -622,6 +691,8 @@ int main(int argc, char * argv[])
do_sync = sg_get_num(buf);
else if (0 == strcmp(key,"dio"))
do_dio = sg_get_num(buf);
+ else if (0 == strncmp(key, "verb", 4))
+ verbose = sg_get_num(buf);
else if (0 == strncmp(key, "--vers", 6)) {
fprintf(stderr, ME "for Linux sg version 3 driver: %s\n",
version_str);
@@ -663,6 +734,9 @@ int main(int argc, char * argv[])
outfd = STDOUT_FILENO;
if (inf[0] && ('-' != inf[0])) {
in_type = dd_filetype(inf);
+ if (verbose)
+ fprintf(stderr, " >> Input file type: %s\n",
+ dd_filetype_str(in_type, ebuff));
if (FT_ST == in_type) {
fprintf(stderr, ME "unable to use scsi tape device %s\n", inf);
@@ -719,12 +793,18 @@ int main(int argc, char * argv[])
perror(ebuff);
return 1;
}
+ if (verbose)
+ fprintf(stderr, " >> skip: llseek SEEK_SET, "
+ "byte offset=0x%llx\n", offset);
}
}
}
if (outf[0] && ('-' != outf[0])) {
out_type = dd_filetype(outf);
+ if (verbose)
+ fprintf(stderr, " >> Output file type: %s\n",
+ dd_filetype_str(out_type, ebuff));
if (FT_ST == out_type) {
fprintf(stderr, ME "unable to use scsi tape device %s\n", outf);
@@ -793,6 +873,9 @@ int main(int argc, char * argv[])
perror(ebuff);
return 1;
}
+ if (verbose)
+ fprintf(stderr, " >> seek: llseek SEEK_SET, "
+ "byte offset=0x%llx\n", offset);
}
}
}
@@ -949,6 +1032,11 @@ int main(int argc, char * argv[])
}
req_count = dd_count;
+ if (verbose && (dd_count > 0) && (0 == do_dio) &&
+ (FT_SG == in_type) && (FT_SG == out_type))
+ fprintf(stderr, "Since both 'if' and 'of' are sg devices, only do "
+ "mmap-ed transfers on 'if'\n");
+
while (dd_count > 0) {
blocks = (dd_count > blocks_per) ? blocks_per : dd_count;
if (FT_SG == in_type) {
@@ -973,6 +1061,9 @@ int main(int argc, char * argv[])
while (((res = read(infd, wrkPos, blocks * bs)) < 0) &&
(EINTR == errno))
;
+ if (verbose > 2)
+ fprintf(stderr, "read(unix): count=%d, res=%d\n",
+ blocks * bs, res);
if (res < 0) {
snprintf(ebuff, EBUFF_SZ, ME "reading, skip=%lld ", skip);
perror(ebuff);
@@ -1021,6 +1112,9 @@ int main(int argc, char * argv[])
while (((res = write(outfd, wrkPos, blocks * bs)) < 0)
&& (EINTR == errno))
;
+ if (verbose > 2)
+ fprintf(stderr, "write(unix): count=%d, res=%d\n",
+ blocks * bs, res);
if (res < 0) {
snprintf(ebuff, EBUFF_SZ, ME "writing, seek=%lld ", seek);
perror(ebuff);
@@ -1092,7 +1186,7 @@ int main(int argc, char * argv[])
fprintf(stderr, ">> Non-zero sum of residual counts=%d\n",
sum_of_resids);
if (num_dio_not_done)
- fprintf(stderr, ">> dio requested but _not done %d times\n",
+ fprintf(stderr, ">> dio requested but _not_ done %d times\n",
num_dio_not_done);
return res;
}