add forwarded sense descriptor; new sg_decode_sense utility
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@365 6180dd3e-e324-4e3e-922d-17de1ae2f315
diff --git a/ChangeLog b/ChangeLog
index dc8ef18..e7360e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,8 +2,12 @@
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.31 [20101112] [svn: r364]
- - xxxxxxxxxxxxx
+Changelog for sg3_utils-1.31 [20101205] [svn: r365]
+ - sg_decode_sense: new utility to decode sense data
+ - sync asc/ascq and version descriptors with spc4r28
+ - sg_lib: implement forwarded sense data descriptor
+ - sg_lib, sg_turs, sg_format: more precision for progress
+ indication (two places after decimal point)
Changelog for sg3_utils-1.30 [20101111] [svn: r363]
- sg_referrals: new utility for REPORT REFERRALS
@@ -21,7 +25,7 @@
- sg_vpd: rdac vendor page [0xc8] parse corrections
- extended inquiry vpd page add extended self test
completion minutes field
- - sg_ses: expand --date (in) buffer to 2048 bytes
+ - sg_ses: expand --data (in) buffer to 2048 bytes
- sg_opcodes: add extended parameter data for TMFs (spc4r26)
- sg_dd: clean count calculation, document nocache flag
- treat bsg devices as implicit sg_io
diff --git a/README b/README
index 925dd47..0a1d6ea 100644
--- a/README
+++ b/README
@@ -194,12 +194,12 @@
=========
Here is list in alphabetical order of utilities found in the 'src'
subdirectory of the sg3_utils package:
- - sginfo, sgm_dd, sgp_dd, sg_dd, sg_emc_trespass, sg_get_config,
- sg_get_lba_status, sg_format, sg_ident, sg_inq, sg_logs, sg_luns, sg_map,
- sg_map26, sg_modes, sg_opcodes, sg_persist, sg_prevent, sg_raw, sg_rbuf,
- sg_rdac, sg_read, sg_readcap, sg_read_block_limits, sg_read_buffer,
- sg_read_long, sg_reassign, sg_referrals, sg_request, sg_reset, sg_rmsn,
- sg_rtpg, sg_safte, sg_sat_identify, sg_sat_phy_event,
+ - sginfo, sgm_dd, sgp_dd, sg_dd, sg_decode_sense, sg_emc_trespass,
+ - sg_format, sg_get_config, sg_get_lba_status, sg_ident, sg_inq, sg_logs,
+ - sg_luns, sg_map, sg_map26, sg_modes, sg_opcodes, sg_persist, sg_prevent,
+ - sg_raw, sg_rbuf, sg_rdac, sg_read, sg_readcap, sg_read_block_limits,
+ - sg_read_buffer, sg_read_long, sg_reassign, sg_referrals, sg_request,
+ - sg_reset, sg_rmsn, sg_rtpg, sg_safte, sg_sat_identify, sg_sat_phy_event,
sg_sat_set_features, sg_scan, sg_senddiag, sg_ses, sg_start, sg_stpg,
sg_sync, sg_test_rwbuff, sg_turs, sg_unmap, sg_verify, sg_vpd,
sg_write_buffer, sg_write_long, sg_write_same, sg_wr_mode
@@ -318,10 +318,10 @@
or using '-O' as the first command line option.
The more recent utilities that use "getopt_long" only are:
- - sg_format sg_get_config sg_get_lba_status sg_ident sg_luns sg_map26
- sg_persist sg_prevent sg_raw sg_read_block_limits sg_read_buffer
- sg_read_long sg_reassign sg_referrals sg_requests sg_rmsn sg_rtpg
- sg_safte sg_sat_identify sg_sat_phy_event sg_sat_set_features
+ - sg_decode_sense, sg_format sg_get_config sg_get_lba_status sg_ident
+ sg_luns sg_map26 sg_persist sg_prevent sg_raw sg_read_block_limits
+ sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests sg_rmsn
+ sg_rtpg sg_safte sg_sat_identify sg_sat_phy_event sg_sat_set_features
sg_scan(w) sg_ses sg_stpg sg_sync sg_test_rwbuf sg_unmap sg_verify
sg_vpd sg_write_buffer sg_write_long sg_write_same sg_wr_mode
@@ -345,4 +345,4 @@
Doug Gilbert
-31st October 2010
+5th December 2010
diff --git a/README.freebsd b/README.freebsd
index 1db80d6..401a607 100644
--- a/README.freebsd
+++ b/README.freebsd
@@ -13,6 +13,7 @@
Supported Utilities
===================
Here is a list of utilities that have been ported:
+ sg_decode_sense
sg_format
sg_get_config
sg_get_lba_status
@@ -104,4 +105,4 @@
Doug Gilbert
-13th September 2010
+5th December 2010
diff --git a/README.solaris b/README.solaris
index 1288802..7fa6e30 100644
--- a/README.solaris
+++ b/README.solaris
@@ -11,6 +11,7 @@
Supported Utilities
===================
Here is a list of utilities that have been ported:
+ sg_decode_sense
sg_format
sg_get_config
sg_get_lba_status
@@ -134,4 +135,4 @@
Doug Gilbert
-13th September 2010
+5th December 2010
diff --git a/README.tru64 b/README.tru64
index f35ee47..e3b474d 100644
--- a/README.tru64
+++ b/README.tru64
@@ -8,6 +8,7 @@
Supported Utilities
===================
Here is a list of utilities that have been ported:
+ sg_decode_sense
sg_format
sg_get_config
sg_get_lba_status
@@ -91,4 +92,4 @@
Doug Gilbert
-13th September 2010
+5th December 2010
diff --git a/README.win32 b/README.win32
index 8ea76e5..b7f5404 100644
--- a/README.win32
+++ b/README.win32
@@ -23,6 +23,7 @@
Supported Utilities
===================
Here is a list of utilities that have been ported:
+ sg_decode_sense
sg_format
sg_get_config
sg_get_lba_status
@@ -196,4 +197,4 @@
Doug Gilbert
-13th September 2010
+5th December 2010
diff --git a/debian/compat b/debian/compat
index 7f8f011..45a4fb7 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-7
+8
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 2c4f75e..fa6ecec 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -8,7 +8,7 @@
# sg_scan is shared by Linux and Win32
man_MANS = \
- sg3_utils.8 \
+ sg3_utils.8 sg_decode_sense.8 \
scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
sg_dd.8 sg_emc_trespass.8 sg_format.8 sg_get_config.8 \
sg_get_lba_status.8 sg_ident.8 sginfo.8 sg_inq.8 sg_logs.8 \
@@ -34,7 +34,7 @@
if OS_WIN32_MINGW
man_MANS = \
- sg3_utils.8 \
+ sg3_utils.8 sg_decode_sense.8 \
scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
sg_inq.8 sg_logs.8 sg_luns.8 sg_modes.8 sg_opcodes.8 sg_persist.8 \
@@ -58,7 +58,7 @@
if OS_WIN32_CYGWIN
man_MANS = \
- sg3_utils.8 \
+ sg3_utils.8 sg_decode_sense.8 \
scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
sg_inq.8 sg_logs.8 sg_luns.8 sg_modes.8 sg_opcodes.8 \
@@ -82,7 +82,7 @@
if OS_FREEBSD
man_MANS = \
- sg3_utils.8 \
+ sg3_utils.8 sg_decode_sense.8 \
scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
sg_inq.8 sg_logs.8 sg_luns.8 \
@@ -100,7 +100,7 @@
if OS_SOLARIS
man_MANS = \
- sg3_utils.8 \
+ sg3_utils.8 sg_decode_sense.8 \
scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
sg_inq.8 sg_logs.8 sg_luns.8 \
@@ -118,7 +118,7 @@
if OS_OSF
man_MANS = \
- sg3_utils.8 \
+ sg3_utils.8 sg_decode_sense.8 \
scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
sg_inq.8 sg_logs.8 sg_luns.8 \
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 53b5c90..e0c4763 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -186,7 +186,7 @@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
@OS_FREEBSD_TRUE@man_MANS = \
-@OS_FREEBSD_TRUE@ sg3_utils.8 \
+@OS_FREEBSD_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@OS_FREEBSD_TRUE@ scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
@OS_FREEBSD_TRUE@ sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
@OS_FREEBSD_TRUE@ sg_inq.8 sg_logs.8 sg_luns.8 \
@@ -205,7 +205,7 @@
#
# sg_scan is shared by Linux and Win32
@OS_LINUX_TRUE@man_MANS = \
-@OS_LINUX_TRUE@ sg3_utils.8 \
+@OS_LINUX_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@OS_LINUX_TRUE@ scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
@OS_LINUX_TRUE@ sg_dd.8 sg_emc_trespass.8 sg_format.8 sg_get_config.8 \
@OS_LINUX_TRUE@ sg_get_lba_status.8 sg_ident.8 sginfo.8 sg_inq.8 sg_logs.8 \
@@ -220,7 +220,7 @@
@OS_LINUX_TRUE@ sg_write_buffer.8 sg_write_long.8 sg_write_same.8 sg_wr_mode.8
@OS_OSF_TRUE@man_MANS = \
-@OS_OSF_TRUE@ sg3_utils.8 \
+@OS_OSF_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@OS_OSF_TRUE@ scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
@OS_OSF_TRUE@ sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
@OS_OSF_TRUE@ sg_inq.8 sg_logs.8 sg_luns.8 \
@@ -233,7 +233,7 @@
@OS_OSF_TRUE@ sg_write_buffer.8 sg_write_long.8 sg_write_same.8 sg_wr_mode.8
@OS_SOLARIS_TRUE@man_MANS = \
-@OS_SOLARIS_TRUE@ sg3_utils.8 \
+@OS_SOLARIS_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@OS_SOLARIS_TRUE@ scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
@OS_SOLARIS_TRUE@ sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
@OS_SOLARIS_TRUE@ sg_inq.8 sg_logs.8 sg_luns.8 \
@@ -246,7 +246,7 @@
@OS_SOLARIS_TRUE@ sg_write_buffer.8 sg_write_long.8 sg_write_same.8 sg_wr_mode.8
@OS_WIN32_CYGWIN_TRUE@man_MANS = \
-@OS_WIN32_CYGWIN_TRUE@ sg3_utils.8 \
+@OS_WIN32_CYGWIN_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@OS_WIN32_CYGWIN_TRUE@ scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
@OS_WIN32_CYGWIN_TRUE@ sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
@OS_WIN32_CYGWIN_TRUE@ sg_inq.8 sg_logs.8 sg_luns.8 sg_modes.8 sg_opcodes.8 \
@@ -259,7 +259,7 @@
@OS_WIN32_CYGWIN_TRUE@ sg_write_buffer.8 sg_write_long.8 sg_write_same.8 sg_wr_mode.8
@OS_WIN32_MINGW_TRUE@man_MANS = \
-@OS_WIN32_MINGW_TRUE@ sg3_utils.8 \
+@OS_WIN32_MINGW_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@OS_WIN32_MINGW_TRUE@ scsi_readcap.8 scsi_ready.8 scsi_start.8 scsi_stop.8 \
@OS_WIN32_MINGW_TRUE@ sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 \
@OS_WIN32_MINGW_TRUE@ sg_inq.8 sg_logs.8 sg_luns.8 sg_modes.8 sg_opcodes.8 sg_persist.8 \
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index 586d3db..20927a4 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "September 2010" "sg3_utils\-1.30" SG3_UTILS
+.TH SG3_UTILS "8" "December 2010" "sg3_utils\-1.31" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
@@ -391,7 +391,7 @@
.SH "REPORTING BUGS"
Report bugs to <dgilbert at interlog dot com>.
.SH COPYRIGHT
-Copyright \(co 1999\-2010 Douglas Gilbert
+Copyright \(co 1999\-2011 Douglas Gilbert
.br
Some utilities are distributed under a GPL version 2 license while
others, usually more recent ones, are under a FreeBSD license. The files
diff --git a/doc/sg_decode_sense.8 b/doc/sg_decode_sense.8
new file mode 100644
index 0000000..40551b3
--- /dev/null
+++ b/doc/sg_decode_sense.8
@@ -0,0 +1,79 @@
+.TH SG_DECODE_SENSE "8" "December 2010" "sg3_utils\-1.31" SG3_UTILS
+.SH NAME
+sg_decode_sense \- decode SCSI sense data
+.SH SYNOPSIS
+.B sg_decode_sense
+[\fI\-\-binary=FN\fR] [\fI\-\-help\fR] [\fI\-\-hex=FN\fR]
+[\fI\-\-status=SS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR]
+[\fI\-\-write=WFN\fR] [H1 H2 H3 ...]
+.SH DESCRIPTION
+.\" Add any additional description here
+This utility takes SCSI sense data in binary or as a sequence of
+ASCII hexadecimal bytes and decodes it. The primary reference for the
+decoding is SPC\-3 ANSI INCITS 408-2005 and the most recent draft
+SPC\-4 revision 28 which can be found at http://www.t10.org .
+.PP
+SCSI sense data is often found in kernel log files as a result of
+something going wrong but may just be informative. It is often shown as
+a sequence of hexadecimal bytes, starting with 70, 71, 72 or 73.
+Sense data could be up to 252 bytes long but typically is much shorter
+than that, 18 bytes long is often seen and is usually associated with
+the older "fixed" format sense data.
+.PP
+The sense data can be provided on the command line or in a file. If
+given on the command line the sense data should be a sequence of
+hexadecimal bytes separated by space. Alternatively a file can be
+given with the contents in binary or ASCII hexadecimal bytes. The
+latter form can contain several lines each with none, one or more
+ASCII hexadecimal bytes separated by space (comma or tab). The
+hash symbol may appear and it and the rest of the line is ignored
+making it useful for comments.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-b\fR, \fB\-\-binary\fR=\fIFN\fR
+the sense data is read in binary from a file called \fIFN\fR.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+output the usage message then exit.
+.TP
+\fB\-H\fR, \fB\-\-in\fR=\fIFN\fR
+the sense data is read in ASCII hexadecimal from a file called \fIFN\fR.
+The sense data should appear as a sequence of bytes separated by space,
+comma, tab or newline. Everything from and including a hash symbol to the
+end of that line is ignored.
+.TP
+\fB\-s\fR, \fB\-\-status\fR=\fISS\fR
+where \fISS\fR is a SCSI status byte value, given in hexadecimal. The
+SCSI status byte is related to but distinct from sense data.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+increase the degree of verbosity (debug messages).
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+output version string then exit.
+.TP
+\fB\-w\fR, \fB\-\-write\fR=\fIWFN\fR
+writes the sense data out in binary to a file called \fIWFN\fR. If
+necessary \fIWFN\fR is created. If \fIWFN\fR exists then it is
+truncated prior to writing the sense data to it. This option is
+a convenience and may be helpful in converting the ASCII hexadecimal
+representation of sense data into the equivalent binary.
+.SH NOTES
+Unlike most utilities in this package, this utility does not access a
+SCSI device (logical unit). This utility accesses a library associated
+with this package. Amongst other things the library decodes sense data.
+.SH EXIT STATUS
+The exit status of sg_decode_sense is 0 when it is successful. Otherwise
+see the sg3_utils(8) man page.
+.SH AUTHORS
+Written by Douglas Gilbert.
+.SH "REPORTING BUGS"
+Report bugs to <dgilbert at interlog dot com>.
+.SH COPYRIGHT
+Copyright \(co 2010\-2011 Douglas Gilbert
+.br
+This software is distributed under a FreeBSD license. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH "SEE ALSO"
+.B sg_requests(sg3_utils)
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index 8d612e4..c5f78d4 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -317,7 +317,7 @@
int * progress_outp)
{
const unsigned char * ucp;
- int sk;
+ int sk, sk_pr;
if (sb_len < 7)
return 0;
@@ -336,14 +336,19 @@
return 0;
case 0x72:
case 0x73:
+ /* sense key specific progress (0x2) or progress descriptor (0xa) */
sk = (sensep[1] & 0xf);
- if ((SPC_SK_NO_SENSE != sk) && (SPC_SK_NOT_READY != sk))
- return 0;
- ucp = sg_scsi_sense_desc_find(sensep, sb_len, 2 /* sense key spec. */);
- if (ucp && (0x6 == ucp[1]) && (0x80 & ucp[4])) {
+ sk_pr = (SPC_SK_NO_SENSE == sk) || (SPC_SK_NOT_READY == sk);
+ if (sk_pr && ((ucp = sg_scsi_sense_desc_find(sensep, sb_len, 2))) &&
+ (0x6 == ucp[1]) && (0x80 & ucp[4])) {
if (progress_outp)
*progress_outp = (ucp[5] << 8) + ucp[6];
return 1;
+ } else if (((ucp = sg_scsi_sense_desc_find(sensep, sb_len, 0xa))) &&
+ ((0x6 == ucp[1]))) {
+ if (progress_outp)
+ *progress_outp = (ucp[6] << 8) + ucp[7];
+ return 1;
} else
return 0;
default:
@@ -371,6 +376,12 @@
return buff;
}
+static const char * sdata_src[] = {
+ "unknown",
+ "Extended Copy command source device",
+ "Extended Copy command destination device",
+ };
+
/* Print descriptor format sense descriptors (assumes sense buffer is
in descriptor format) */
@@ -379,9 +390,10 @@
int buff_len, char * buff)
{
int add_sen_len, add_len, desc_len, k, j, sense_key, processed;
- int n, progress;
+ int n, progress, pr, rem;
const unsigned char * descp;
- char b[256];
+ const char * dtsp = " >> descriptor too short";
+ char b[800];
if ((NULL == buff) || (buff_len <= 0))
return;
@@ -393,7 +405,9 @@
sense_key = (sense_buffer[1] & 0xf);
for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
descp += desc_len;
- add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
+ add_len = (k < (add_sen_len - 1)) ? descp[1] : -1;
+ if ((k + add_len + 2) > add_sen_len)
+ add_len = add_sen_len - k - 2;
desc_len = add_len + 2;
n = 0;
n += sprintf(b + n, " Descriptor type: ");
@@ -406,8 +420,10 @@
for (j = 0; j < 8; ++j)
n += sprintf(b + n, "%02x", descp[4 + j]);
n += sprintf(b + n, "\n");
- } else
+ } else {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
+ }
break;
case 1:
n += sprintf(b + n, "Command specific\n");
@@ -416,8 +432,10 @@
for (j = 0; j < 8; ++j)
n += sprintf(b + n, "%02x", descp[4 + j]);
n += sprintf(b + n, "\n");
- } else
+ } else {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
+ }
break;
case 2:
n += sprintf(b + n, "Sense key specific:");
@@ -425,6 +443,7 @@
case SPC_SK_ILLEGAL_REQUEST:
n += sprintf(b + n, " Field pointer\n");
if (add_len < 6) {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
break;
}
@@ -441,6 +460,7 @@
case SPC_SK_RECOVERED_ERROR:
n += sprintf(b + n, " Actual retry count\n");
if (add_len < 6) {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
break;
}
@@ -451,17 +471,19 @@
case SPC_SK_NOT_READY:
n += sprintf(b + n, " Progress indication: ");
if (add_len < 6) {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
- n += sprintf(b + n, " field too short\n");
break;
}
progress = (descp[5] << 8) + descp[6];
- n += sprintf(b + n, "%d %%\n",
- (progress * 100) / 0x10000);
+ pr = (progress * 100) / 65536;
+ rem = ((progress * 100) % 65536) / 655;
+ n += sprintf(b + n, "%d.%02d%%\n", pr, rem);
break;
case SPC_SK_COPY_ABORTED:
n += sprintf(b + n, " Segment pointer\n");
if (add_len < 6) {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
break;
}
@@ -490,8 +512,10 @@
n += sprintf(b + n, "Field replaceable unit\n");
if (add_len >= 2)
n += sprintf(b + n, " code=0x%x\n", descp[3]);
- else
+ else {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
+ }
break;
case 4:
n += sprintf(b + n, "Stream commands\n");
@@ -504,16 +528,20 @@
n += sprintf(b + n, " Incorrect Length Indicator "
"(ILI)");
n += sprintf(b + n, "\n");
- } else
+ } else {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
+ }
break;
case 5:
n += sprintf(b + n, "Block commands\n");
if (add_len >= 2)
n += sprintf(b + n, " Incorrect Length Indicator "
"(ILI) %s\n", (descp[3] & 0x20) ? "set" : "clear");
- else
+ else {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
+ }
break;
case 6:
n += sprintf(b + n, "OSD object identification\n");
@@ -546,18 +574,22 @@
descp[11], descp[9], descp[7]);
n += sprintf(b + n, " device=0x%x status=0x%x\n",
descp[12], descp[13]);
- } else
+ } else {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
+ }
break;
case 0xa: /* Added in SPC-4 rev 17 */
n += sprintf(b + n, "Progress indication\n");
if (add_len < 6) {
+ n += sprintf(b + n, "%s\n", dtsp);
processed = 0;
- n += sprintf(b + n, " field too short\n");
break;
}
progress = (descp[6] << 8) + descp[7];
- n += sprintf(b + n, " %d %%", (progress * 100) / 0x10000);
+ pr = (progress * 100) / 65536;
+ rem = ((progress * 100) % 65536) / 655;
+ n += sprintf(b + n, " %d.02%d%%", pr, rem);
n += sprintf(b + n, " [sense_key=0x%x asc,ascq=0x%x,0x%x]\n",
descp[2], descp[3], descp[4]);
break;
@@ -566,6 +598,38 @@
/* Will decode if this 'feature' stays xxxxxxxxxxxxx */
processed = 0;
break;
+ case 0xc: /* Added in SPC-4 rev 28 */
+ n += sprintf(b + n, "Forwarded sense data\n");
+ if (add_len < 2) {
+ n += sprintf(b + n, "%s\n", dtsp);
+ processed = 0;
+ break;
+ }
+ n += sprintf(b + n, " FSDT: %s\n",
+ (descp[2] & 0x80) ? "set" : "clear");
+ j = descp[2] & 0xf;
+ if (j < 3)
+ n += sprintf(b + n, " Sense data source: %s\n",
+ sdata_src[j]);
+ else
+ n += sprintf(b + n, " Sense data source: reserved [%d]\n",
+ j);
+ {
+ char c[200];
+
+ sg_get_scsi_status_str(descp[3], sizeof(c) - 1, c);
+ c[sizeof(c) - 1] = '\0';
+ n += sprintf(b + n, " Forwarded status: %s\n", c);
+ if (add_len > 2) {
+ /* recursing; hope not to get carried away */
+ n += sprintf(b + n, " vvvvvvvvvvvvvvvv\n");
+ sg_get_sense_str(NULL, descp + 4, add_len - 2, 0,
+ sizeof(c), c);
+ n += sprintf(b + n, "%s", c);
+ n += sprintf(b + n, " ^^^^^^^^^^^^^^^^\n");
+ }
+ }
+ break;
default:
n += sprintf(b + n, "Unknown or vendor specific [0x%x]\n",
descp[0]);
@@ -575,8 +639,7 @@
if (! processed) {
if (add_len > 0) {
n += sprintf(b + n, " ");
- for (j = 0; (j < add_len) && ((k + j + 2) < add_sen_len);
- ++j) {
+ for (j = 0; j < add_len; ++j) {
if ((j > 0) && (0 == (j % 24)))
n += sprintf(b + n, "\n ");
n += sprintf(b + n, "%02x ", descp[j + 2]);
@@ -603,7 +666,7 @@
sg_get_sense_str(const char * leadin, const unsigned char * sense_buffer,
int sb_len, int raw_sinfo, int buff_len, char * buff)
{
- int len, valid, progress, n, r;
+ int len, valid, progress, n, r, pr, rem;
unsigned int info;
int descriptor_format = 0;
const char * error = NULL;
@@ -726,8 +789,10 @@
case SPC_SK_NO_SENSE:
case SPC_SK_NOT_READY:
progress = (sense_buffer[16] << 8) + sense_buffer[17];
- r += sprintf(b + r, " Progress indication: %d %%\n",
- (progress * 100) / 0x10000);
+ pr = (progress * 100) / 65536;
+ rem = ((progress * 100) % 65536) / 655;
+ r += sprintf(b + r, " Progress indication: %d.%02d%%\n",
+ pr, rem);
break;
case SPC_SK_HARDWARE_ERROR:
case SPC_SK_MEDIUM_ERROR:
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index ba2093b..a6abcc9 100644
--- a/lib/sg_lib_data.c
+++ b/lib/sg_lib_data.c
@@ -15,7 +15,7 @@
#endif
-const char * sg_lib_version_str = "1.63 20101028"; /* spc-4 rev 27 */
+const char * sg_lib_version_str = "1.65 20101205"; /* spc-4 rev 28 */
struct sg_lib_value_name_t sg_lib_normal_opcodes[] = {
{0, 0, "Test Unit Ready"},
@@ -471,6 +471,7 @@
{0x10,0x02,"Logical block application tag check failed"},
{0x10,0x03,"Logical block reference tag check failed"},
{0x10,0x04,"Logical block protection error on recover buffered data"},
+ {0x10,0x05,"Logical block protection method error"},
{0x11,0x00,"Unrecovered read error"},
{0x11,0x01,"Read retries exhausted"},
{0x11,0x02,"Error too long to correct"},
diff --git a/src/Makefile.am b/src/Makefile.am
index 433133d..b45ff5e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,9 +8,9 @@
# sg_scan is shared by Linux and Win32
bin_PROGRAMS = \
- sg_dd sg_emc_trespass sg_format sg_get_config sg_get_lba_status \
- sg_ident sginfo sg_inq sg_logs sg_luns sg_map26 sg_map \
- sgm_dd sg_modes sg_opcodes sgp_dd sg_persist sg_prevent \
+ sg_dd sg_decode_sense sg_emc_trespass sg_format sg_get_config \
+ sg_get_lba_status sg_ident sginfo sg_inq sg_logs sg_luns sg_map26 \
+ sg_map sgm_dd sg_modes sg_opcodes sgp_dd sg_persist sg_prevent \
sg_raw sg_rbuf sg_rdac sg_read sg_readcap sg_read_block_limits \
sg_read_buffer sg_read_long sg_reassign sg_referrals \
sg_requests sg_reset sg_rmsn sg_rtpg sg_safte sg_sat_identify \
@@ -30,7 +30,7 @@
if OS_WIN32_MINGW
bin_PROGRAMS = \
- sg_format sg_get_config sg_get_lba_status sg_ident \
+ sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident \
sg_inq sg_logs sg_luns sg_modes sg_opcodes sg_persist \
sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
@@ -51,7 +51,7 @@
if OS_WIN32_CYGWIN
bin_PROGRAMS = \
- sg_format sg_get_config sg_get_lba_status sg_ident \
+ sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident \
sg_inq sg_logs sg_luns sg_modes sg_opcodes sg_persist \
sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
@@ -72,7 +72,7 @@
if OS_FREEBSD
bin_PROGRAMS = \
- sg_format sg_get_config sg_get_lba_status sg_ident \
+ sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident \
sg_inq sg_logs sg_luns sg_modes sg_opcodes sg_persist \
sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
@@ -87,7 +87,7 @@
if OS_SOLARIS
bin_PROGRAMS = \
- sg_format sg_get_config sg_get_lba_status sg_ident \
+ sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident \
sg_inq sg_logs sg_luns sg_modes sg_opcodes sg_persist \
sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
@@ -102,7 +102,7 @@
if OS_OSF
bin_PROGRAMS = \
- sg_format sg_get_config sg_get_lba_status sg_ident \
+ sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident \
sg_inq sg_logs sg_luns sg_modes sg_opcodes sg_persist \
sg_prevent sg_raw sg_rdac sg_readcap sg_read_block_limits \
sg_read_buffer sg_read_long sg_reassign sg_referrals sg_requests \
@@ -120,6 +120,9 @@
sg_dd_SOURCES = sg_dd.c
sg_dd_LDADD = ../lib/libsgutils2.la @os_libs@
+sg_decode_sense_SOURCES = sg_decode_sense.c
+sg_decode_sense_LDADD = ../lib/libsgutils2.la @os_libs@
+
sg_emc_trespass_SOURCES = sg_emc_trespass.c
sg_emc_trespass_LDADD = ../lib/libsgutils2.la @os_libs@
diff --git a/src/Makefile.in b/src/Makefile.in
index d3bf315..8bd8084 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -34,7 +34,8 @@
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@bin_PROGRAMS = sg_format$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@bin_PROGRAMS = sg_decode_sense$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_format$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_get_config$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_get_lba_status$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_ident$(EXEEXT) \
@@ -74,7 +75,8 @@
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_write_long$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_write_same$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_wr_mode$(EXEEXT)
-@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@bin_PROGRAMS = sg_format$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@bin_PROGRAMS = sg_decode_sense$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_format$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_get_config$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_get_lba_status$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_ident$(EXEEXT) \
@@ -114,7 +116,8 @@
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_write_long$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_write_same$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_wr_mode$(EXEEXT)
-@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@bin_PROGRAMS = sg_format$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@bin_PROGRAMS = sg_decode_sense$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_format$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_get_config$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_get_lba_status$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_ident$(EXEEXT) \
@@ -153,7 +156,8 @@
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_write_long$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_write_same$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_wr_mode$(EXEEXT)
-@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@bin_PROGRAMS = sg_format$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@bin_PROGRAMS = sg_decode_sense$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_format$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_get_config$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_get_lba_status$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_ident$(EXEEXT) \
@@ -193,6 +197,7 @@
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_write_same$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_wr_mode$(EXEEXT)
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@bin_PROGRAMS = sg_dd$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_decode_sense$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_emc_trespass$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_format$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_get_config$(EXEEXT) \
@@ -243,8 +248,8 @@
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_write_long$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_write_same$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_wr_mode$(EXEEXT)
-@OS_FREEBSD_TRUE@bin_PROGRAMS = sg_format$(EXEEXT) \
-@OS_FREEBSD_TRUE@ sg_get_config$(EXEEXT) \
+@OS_FREEBSD_TRUE@bin_PROGRAMS = sg_decode_sense$(EXEEXT) \
+@OS_FREEBSD_TRUE@ sg_format$(EXEEXT) sg_get_config$(EXEEXT) \
@OS_FREEBSD_TRUE@ sg_get_lba_status$(EXEEXT) sg_ident$(EXEEXT) \
@OS_FREEBSD_TRUE@ sg_inq$(EXEEXT) sg_logs$(EXEEXT) \
@OS_FREEBSD_TRUE@ sg_luns$(EXEEXT) sg_modes$(EXEEXT) \
@@ -281,6 +286,9 @@
am_sg_dd_OBJECTS = sg_dd.$(OBJEXT)
sg_dd_OBJECTS = $(am_sg_dd_OBJECTS)
sg_dd_DEPENDENCIES = ../lib/libsgutils2.la
+am_sg_decode_sense_OBJECTS = sg_decode_sense.$(OBJEXT)
+sg_decode_sense_OBJECTS = $(am_sg_decode_sense_OBJECTS)
+sg_decode_sense_DEPENDENCIES = ../lib/libsgutils2.la
am_sg_emc_trespass_OBJECTS = sg_emc_trespass.$(OBJEXT)
sg_emc_trespass_OBJECTS = $(am_sg_emc_trespass_OBJECTS)
sg_emc_trespass_DEPENDENCIES = ../lib/libsgutils2.la
@@ -444,14 +452,14 @@
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
-SOURCES = $(sg_dd_SOURCES) $(sg_emc_trespass_SOURCES) \
- $(sg_format_SOURCES) $(sg_get_config_SOURCES) \
- $(sg_get_lba_status_SOURCES) $(sg_ident_SOURCES) \
- $(sg_inq_SOURCES) $(sg_logs_SOURCES) $(sg_luns_SOURCES) \
- $(sg_map_SOURCES) $(sg_map26_SOURCES) $(sg_modes_SOURCES) \
- $(sg_opcodes_SOURCES) $(sg_persist_SOURCES) \
- $(sg_prevent_SOURCES) $(sg_raw_SOURCES) $(sg_rbuf_SOURCES) \
- $(sg_rdac_SOURCES) $(sg_read_SOURCES) \
+SOURCES = $(sg_dd_SOURCES) $(sg_decode_sense_SOURCES) \
+ $(sg_emc_trespass_SOURCES) $(sg_format_SOURCES) \
+ $(sg_get_config_SOURCES) $(sg_get_lba_status_SOURCES) \
+ $(sg_ident_SOURCES) $(sg_inq_SOURCES) $(sg_logs_SOURCES) \
+ $(sg_luns_SOURCES) $(sg_map_SOURCES) $(sg_map26_SOURCES) \
+ $(sg_modes_SOURCES) $(sg_opcodes_SOURCES) \
+ $(sg_persist_SOURCES) $(sg_prevent_SOURCES) $(sg_raw_SOURCES) \
+ $(sg_rbuf_SOURCES) $(sg_rdac_SOURCES) $(sg_read_SOURCES) \
$(sg_read_block_limits_SOURCES) $(sg_read_buffer_SOURCES) \
$(sg_read_long_SOURCES) $(sg_readcap_SOURCES) \
$(sg_reassign_SOURCES) $(sg_referrals_SOURCES) \
@@ -466,14 +474,14 @@
$(sg_write_buffer_SOURCES) $(sg_write_long_SOURCES) \
$(sg_write_same_SOURCES) $(sginfo_SOURCES) $(sgm_dd_SOURCES) \
$(sgp_dd_SOURCES)
-DIST_SOURCES = $(sg_dd_SOURCES) $(sg_emc_trespass_SOURCES) \
- $(sg_format_SOURCES) $(sg_get_config_SOURCES) \
- $(sg_get_lba_status_SOURCES) $(sg_ident_SOURCES) \
- $(sg_inq_SOURCES) $(sg_logs_SOURCES) $(sg_luns_SOURCES) \
- $(sg_map_SOURCES) $(sg_map26_SOURCES) $(sg_modes_SOURCES) \
- $(sg_opcodes_SOURCES) $(sg_persist_SOURCES) \
- $(sg_prevent_SOURCES) $(sg_raw_SOURCES) $(sg_rbuf_SOURCES) \
- $(sg_rdac_SOURCES) $(sg_read_SOURCES) \
+DIST_SOURCES = $(sg_dd_SOURCES) $(sg_decode_sense_SOURCES) \
+ $(sg_emc_trespass_SOURCES) $(sg_format_SOURCES) \
+ $(sg_get_config_SOURCES) $(sg_get_lba_status_SOURCES) \
+ $(sg_ident_SOURCES) $(sg_inq_SOURCES) $(sg_logs_SOURCES) \
+ $(sg_luns_SOURCES) $(sg_map_SOURCES) $(sg_map26_SOURCES) \
+ $(sg_modes_SOURCES) $(sg_opcodes_SOURCES) \
+ $(sg_persist_SOURCES) $(sg_prevent_SOURCES) $(sg_raw_SOURCES) \
+ $(sg_rbuf_SOURCES) $(sg_rdac_SOURCES) $(sg_read_SOURCES) \
$(sg_read_block_limits_SOURCES) $(sg_read_buffer_SOURCES) \
$(sg_read_long_SOURCES) $(sg_readcap_SOURCES) \
$(sg_reassign_SOURCES) $(sg_referrals_SOURCES) \
@@ -609,6 +617,8 @@
# AM_CFLAGS = -I ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W -pedantic -std=c99
sg_dd_SOURCES = sg_dd.c
sg_dd_LDADD = ../lib/libsgutils2.la @os_libs@
+sg_decode_sense_SOURCES = sg_decode_sense.c
+sg_decode_sense_LDADD = ../lib/libsgutils2.la @os_libs@
sg_emc_trespass_SOURCES = sg_emc_trespass.c
sg_emc_trespass_LDADD = ../lib/libsgutils2.la @os_libs@
sg_format_SOURCES = sg_format.c
@@ -789,6 +799,9 @@
sg_dd$(EXEEXT): $(sg_dd_OBJECTS) $(sg_dd_DEPENDENCIES)
@rm -f sg_dd$(EXEEXT)
$(LINK) $(sg_dd_OBJECTS) $(sg_dd_LDADD) $(LIBS)
+sg_decode_sense$(EXEEXT): $(sg_decode_sense_OBJECTS) $(sg_decode_sense_DEPENDENCIES)
+ @rm -f sg_decode_sense$(EXEEXT)
+ $(LINK) $(sg_decode_sense_OBJECTS) $(sg_decode_sense_LDADD) $(LIBS)
sg_emc_trespass$(EXEEXT): $(sg_emc_trespass_OBJECTS) $(sg_emc_trespass_DEPENDENCIES)
@rm -f sg_emc_trespass$(EXEEXT)
$(LINK) $(sg_emc_trespass_OBJECTS) $(sg_emc_trespass_LDADD) $(LIBS)
@@ -947,6 +960,7 @@
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_dd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_decode_sense.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_emc_trespass.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_format.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_get_config.Po@am__quote@
diff --git a/src/sg_decode_sense.c b/src/sg_decode_sense.c
new file mode 100644
index 0000000..b068418
--- /dev/null
+++ b/src/sg_decode_sense.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2010-2011 Douglas Gilbert.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the BSD_LICENSE file.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "sg_lib.h"
+
+
+static char * version_str = "1.00 20101204";
+
+#define MAX_SENSE_LEN (256 + 8) /* max descriptor format currently */
+
+static struct option long_options[] = {
+ {"binary", required_argument, 0, 'b'},
+ {"help", no_argument, 0, 'h'},
+ {"hex", required_argument, 0, 'H'},
+ {"status", required_argument, 0, 's'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"write", required_argument, 0, 'w'},
+ {0, 0, 0, 0},
+};
+
+struct opts_t {
+ int do_binary;
+ const char * fname;
+ int do_help;
+ int do_hex;
+ int do_status;
+ int sstatus;
+ int do_verbose;
+ int do_version;
+ const char * wfname;
+ unsigned char sense[MAX_SENSE_LEN + 4];
+ int sense_len;
+};
+
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage: "
+ "sg_decode_sense [--binary=FN] [--help] [--hex=FN] [--status=SS]\n"
+ " [--verbose] [--version] [--write=WFN] "
+ "H1 H2 H3 ...\n"
+ " where:\n"
+ " --binary=FN|-b FN FN is a file name to read sense "
+ "data in\n"
+ " binary from. If FN is '-' then read "
+ "from stdin\n"
+ " --help|-h print out usage message\n"
+ " --hex=FN|-H FN FN is a file name from which to read "
+ "sense data\n"
+ " in ASCII hexadecimal. Interpret '-' "
+ "as stdin\n"
+ " --status=SS |-s SS SCSI status value in hex\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string then exit\n"
+ " --write=WFN |-w WFN write sense data in binary to WFN, "
+ "create if\n"
+ " required else truncate prior to "
+ "writing\n\n"
+ "Decodes SCSI sense data given on the command line as a sequence "
+ "of\nhexadecimal bytes (H1 H2 H3 ...) . Alternatively the sense "
+ "data can\nbe in a binary file or in a file containing ASCII "
+ "hexadecimal.\n"
+ );
+}
+
+static int
+process_cl(struct opts_t *optsp, int argc, char *argv[])
+{
+ int c;
+ unsigned int ul;
+ char * opt;
+ char *endptr;
+ long val;
+
+ while (1) {
+ c = getopt_long(argc, argv, "b:hH:s:vVw:", long_options, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'b':
+ if (optsp->fname) {
+ fprintf(stderr, "expect only one '--binary=FN' or "
+ "'--hex=FN' option\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ ++optsp->do_binary;
+ optsp->fname = optarg;
+ break;
+ case 'h':
+ case '?':
+ optsp->do_help = 1;
+ return 0;
+ case 'H':
+ if (optsp->fname) {
+ fprintf(stderr, "expect only one '--binary=FN' or "
+ "'--hex=FN' option\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ ++optsp->do_hex;
+ optsp->fname = optarg;
+ break;
+ case 's':
+ if (1 != sscanf(optarg, "%x", &ul)) {
+ fprintf(stderr, "'--status=SS' expects a byte value\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (ul > 0xff) {
+ fprintf(stderr, "'--status=SS' byte value exceeds FF\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ ++optsp->do_status;
+ optsp->sstatus = ul;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ optsp->do_version = 1;
+ return 0;
+ case 'w':
+ optsp->wfname = optarg;
+ break;
+ default:
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+
+ while (optind < argc) {
+ opt = argv[optind++];
+ val = strtol(opt, &endptr, 16);
+ if (*opt == '\0' || *endptr != '\0' || val < 0x00 || val > 0xff) {
+ fprintf(stderr, "Invalid byte '%s'\n", opt);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ if (optsp->sense_len > MAX_SENSE_LEN) {
+ fprintf(stderr, "sense data too long (max. %d bytes)\n",
+ MAX_SENSE_LEN);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->sense[optsp->sense_len++] = (unsigned char)val;
+ }
+ return 0;
+}
+
+/* Read hex numbers from file ('-' taken as stdin).
+ * There should be either one entry per line, a comma separated list or
+ * space separated list. Everything from and including a '#' on a line
+ * is ignored. Returns 0 if ok, or 1 if error. */
+static int file2hex_arr(const char * fname, unsigned char * mp_arr,
+ int * mp_arr_len, int max_arr_len)
+{
+ int fn_len, in_len, k, j, m;
+ unsigned int h;
+ const char * lcp;
+ FILE * fp;
+ char line[512];
+ int off = 0;
+
+ if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len))
+ return 1;
+ fn_len = strlen(fname);
+ if (0 == fn_len)
+ return 1;
+ if ((1 == in_len) && ('-' == fname[0])) /* read from stdin */
+ fp = stdin;
+ else {
+ fp = fopen(fname, "r");
+ if (NULL == fp) {
+ fprintf(stderr, "Unable to open %s for reading\n", fname);
+ return 1;
+ }
+ }
+
+ for (j = 0; j < 512; ++j) {
+ if (NULL == fgets(line, sizeof(line), fp))
+ break;
+ in_len = strlen(line);
+ if (in_len > 0) {
+ if ('\n' == line[in_len - 1]) {
+ --in_len;
+ line[in_len] = '\0';
+ }
+ }
+ if (0 == in_len)
+ continue;
+ lcp = line;
+ m = strspn(lcp, " \t");
+ if (m == in_len)
+ continue;
+ lcp += m;
+ in_len -= m;
+ if ('#' == *lcp)
+ continue;
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
+ if ((k < in_len) && ('#' != lcp[k])) {
+ fprintf(stderr, "build_mode_page: syntax error at "
+ "line %d, pos %d\n", j + 1, m + k + 1);
+ goto bad;
+ }
+ for (k = 0; k < 1024; ++k) {
+ if (1 == sscanf(lcp, "%x", &h)) {
+ if (h > 0xff) {
+ fprintf(stderr, "build_mode_page: hex number "
+ "larger than 0xff in line %d, pos %d\n",
+ j + 1, (int)(lcp - line + 1));
+ goto bad;
+ }
+ if ((off + k) >= max_arr_len) {
+ fprintf(stderr, "build_mode_page: array length "
+ "exceeded\n");
+ goto bad;
+ }
+ mp_arr[off + k] = h;
+ lcp = strpbrk(lcp, " ,\t");
+ if (NULL == lcp)
+ break;
+ lcp += strspn(lcp, " ,\t");
+ if ('\0' == *lcp)
+ break;
+ } else {
+ if ('#' == *lcp) {
+ --k;
+ break;
+ }
+ fprintf(stderr, "build_mode_page: error in "
+ "line %d, at pos %d\n", j + 1,
+ (int)(lcp - line + 1));
+ goto bad;
+ }
+ }
+ off += (k + 1);
+ }
+ *mp_arr_len = off;
+ fclose(fp);
+ return 0;
+bad:
+ fclose(fp);
+ return 1;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int ret = 0;
+ size_t s;
+ struct opts_t opts;
+ char b[2048];
+ FILE * fp = NULL;
+
+ memset(&opts, 0, sizeof(opts));
+ memset(b, 0, sizeof(b));
+ ret = process_cl(&opts, argc, argv);
+ if (ret != 0) {
+ usage();
+ return ret;
+ } else if (opts.do_help) {
+ usage();
+ return 0;
+ } else if (opts.do_version) {
+ fprintf(stderr, "version: %s\n", version_str);
+ return 0;
+ }
+
+
+ if (opts.do_status) {
+ sg_get_scsi_status_str(opts.sstatus, sizeof(b) - 1, b);
+ printf("SCSI status: %s\n", b);
+ }
+
+ if ((0 == opts.sense_len) && (! opts.do_binary) && (! opts.do_hex)) {
+ if (opts.do_status)
+ return 0;
+ fprintf(stderr, ">> Need sense data on the command line or in a "
+ "file\n\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.sense_len && (opts.do_binary || opts.do_hex)) {
+ fprintf(stderr, ">> Need sense data on command line or in a file, "
+ "not both\n\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (opts.do_binary && opts.do_hex) {
+ fprintf(stderr, ">> Either a binary file or a ASCII hexadecimal, "
+ "file not both\n\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ if (opts.do_binary) {
+ fp = fopen(opts.fname, "r");
+ if (NULL == fp) {
+ fprintf(stderr, "unable to open file: %s\n", opts.fname);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ s = fread(opts.sense, 1, MAX_SENSE_LEN, fp);
+ fclose(fp);
+ if (0 == s) {
+ fprintf(stderr, "read nothing from file: %s\n", opts.fname);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ opts.sense_len = s;
+ } else if (opts.do_hex) {
+ ret = file2hex_arr(opts.fname, opts.sense, &opts.sense_len,
+ MAX_SENSE_LEN);
+ if (ret) {
+ fprintf(stderr, "unable to decode ASCII hex from file: %s\n",
+ opts.fname);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+
+ if (opts.sense_len) {
+ if (opts.wfname) {
+ if ((fp = fopen(opts.wfname, "w"))) {
+ s = fwrite(opts.sense, 1, opts.sense_len, fp);
+ if ((int)s != opts.sense_len)
+ fprintf(stderr, "only able to write %d of %d bytes to "
+ "%s\n", s, opts.sense_len, opts.wfname);
+ fclose(fp);
+ } else {
+ perror("open");
+ fprintf(stderr, "trying to write to %s\n", opts.wfname);
+ }
+ }
+ sg_get_sense_str(NULL, opts.sense, opts.sense_len, opts.do_verbose,
+ sizeof(b) - 1, b);
+ printf("%s\n", b);
+ }
+
+ return 0;
+}
diff --git a/src/sg_format.c b/src/sg_format.c
index d92d4b6..be41a46 100644
--- a/src/sg_format.c
+++ b/src/sg_format.c
@@ -45,7 +45,7 @@
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
-static char * version_str = "1.18 20101030";
+static char * version_str = "1.19 20101203";
#define RW_ERROR_RECOVERY_PAGE 1 /* every disk should have one */
#define FORMAT_DEV_PAGE 3 /* Format Device Mode Page [now obsolete] */
@@ -54,9 +54,10 @@
#define THIS_MPAGE_EXISTS RW_ERROR_RECOVERY_PAGE
#define SHORT_TIMEOUT 20 /* 20 seconds unless immed=0 ... */
-#define FORMAT_TIMEOUT (4 * 3600) /* 4 hours ! */
+#define FORMAT_TIMEOUT (15 * 3600) /* 15 hours ! */
+ /* Seagate ST32000444SS 2TB disk takes 9.5 hours */
-#define POLL_DURATION_SECS 30
+#define POLL_DURATION_SECS 60
#if defined(MSC_VER) || defined(__MINGW32__)
#define HAVE_MS_SLEEP
@@ -168,7 +169,7 @@
scsi_format(int fd, int fmtpinfo, int cmplst, int pf_usage, int immed,
int dcrt, int pie, int si, int early, int verbose)
{
- int res, need_hdr, progress, verb, fmt_pl_sz, longlist, off;
+ int res, need_hdr, progress, pr, rem, verb, fmt_pl_sz, longlist, off;
const int SH_FORMAT_HEADER_SZ = 4;
const int LO_FORMAT_HEADER_SZ = 8;
const char INIT_PATTERN_DESC_SZ = 4;
@@ -241,10 +242,12 @@
progress = -1;
res = sg_ll_test_unit_ready_progress(fd, 0, &progress, 0,
verb);
- if (progress >= 0)
- printf("Format in progress, %d%% done\n",
- (progress * 100) / 65536);
- else
+ if (progress >= 0) {
+ pr = (progress * 100) / 65536;
+ rem = ((progress * 100) % 65536) / 655;
+ printf("Format in progress, %d.%02d%% done\n",
+ pr, rem);
+ } else
break;
}
printf("FORMAT Complete\n");
diff --git a/src/sg_inq.c b/src/sg_inq.c
index 619534b..2ed2c9c 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -66,7 +66,7 @@
* information [MAINTENANCE IN, service action = 0xc]; see sg_opcodes.
*/
-static char * version_str = "0.94 20101030"; /* SPC-4 rev 27 */
+static char * version_str = "0.95 20101116"; /* SPC-4 rev 28 */
#define VPD_SUPPORTED_VPDS 0x0
diff --git a/src/sg_inq_data.c b/src/sg_inq_data.c
index 113a901..1e925fc 100644
--- a/src/sg_inq_data.c
+++ b/src/sg_inq_data.c
@@ -23,9 +23,9 @@
const char * sg_ansi_version_arr[] =
{
"no conformance claimed",
- "SCSI-1", /* obsolete */
- "SCSI-2", /* obsolete */
- "SPC", /* withdrawn */
+ "SCSI-1", /* obsolete */
+ "SCSI-2", /* obsolete */
+ "SPC", /* withdrawn */
"SPC-2",
"SPC-3",
"SPC-4",
@@ -39,7 +39,7 @@
const char * name;
};
-/* table from SPC-4 revision 27 [sorted numerically (from Annex D.8)] */
+/* table from SPC-4 revision 28 [sorted numerically (from Annex D.8)] */
/* Can also be obtained from : http://www.t10.org/lists/stds.txt */
struct sg_version_descriptor sg_version_descriptor_arr[] = {
{0x0, "Version Descriptor not supported or No standard identified"},
@@ -184,6 +184,7 @@
{0x4e3, "MMC-6 T10/1836-D revision 2b"},
{0x4e5, "MMC-6 T10/1836-D revision 02g"},
{0x500, "ADC-3 (no version claimed)"},
+ {0x502, "ADC-3 T10/1895-D revision 04"},
{0x520, "SSC-4 (no version claimed)"},
{0x560, "OSD-3 (no version claimed)"},
{0x580, "SES-3 (no version claimed)"},
@@ -215,11 +216,7 @@
{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"},
+ {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"},
{0x960, "iSCSI (no version claimed)"},
{0x980, "SBP-3 (no version claimed)"},
{0x982, "SBP-3 T10/1467-D revision 1f"},
@@ -243,6 +240,7 @@
{0xa27, "ADT-2 T10/1742-D revision 08"},
{0xa40, "FCP-4 (no version claimed)"},
{0xa42, "FCP-4 T10/1828-D revision 01"},
+ {0xa44, "FCP-4 T10/1828-D revision 02"},
{0xaa0, "SPI (no version claimed)"},
{0xab9, "SPI T10/0855-D revision 15a"},
{0xaba, "SPI ANSI INCITS 253-1995"},
diff --git a/src/sg_turs.c b/src/sg_turs.c
index 933fb66..f361170 100644
--- a/src/sg_turs.c
+++ b/src/sg_turs.c
@@ -21,7 +21,7 @@
data transfer (and no REQUEST SENSE command iff the unit is ready)
then this can be used for timing per SCSI command overheads.
- * Copyright (C) 2000-2009 D. Gilbert
+ * Copyright (C) 2000-2010 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -29,7 +29,7 @@
*/
-static char * version_str = "3.27 20090422";
+static char * version_str = "3.28 20101203";
#if defined(MSC_VER) || defined(__MINGW32__)
#define HAVE_MS_SLEEP
@@ -265,7 +265,7 @@
int main(int argc, char * argv[])
{
- int sg_fd, k, res, progress;
+ int sg_fd, k, res, progress, pr, rem;
int num_errs = 0;
int reported = 0;
int ret = 0;
@@ -310,9 +310,11 @@
if (progress < 0) {
ret = res;
break;
- } else
- printf("Progress indication: %d%% done\n",
- (progress * 100) / 65536);
+ } else {
+ pr = (progress * 100) / 65536;
+ rem = ((progress * 100) % 65536) / 655;
+ printf("Progress indication: %d.%02d%% done\n", pr, rem);
+ }
}
if (opts.do_number > 1)
printf("Completed %d Test Unit Ready commands\n",