aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG8
-rw-r--r--COVERAGE3
-rw-r--r--INSTALL6
-rw-r--r--Makefile8
-rw-r--r--README10
-rw-r--r--lib_no_lib/Makefile.no_lib8
-rw-r--r--lib_no_lib/sg3_utils.spec.no_lib9
-rw-r--r--sg3_utils.spec9
-rw-r--r--sg_cmds.c299
-rw-r--r--sg_cmds.h17
-rw-r--r--sg_dd.812
-rw-r--r--sg_dd.c6
-rw-r--r--sg_lib.c17
-rw-r--r--sg_logs.834
-rw-r--r--sg_logs.c191
-rw-r--r--sg_luns.849
-rw-r--r--sg_luns.c303
-rw-r--r--sg_persist.819
-rw-r--r--sg_readcap.c49
-rw-r--r--sg_requests.c4
-rw-r--r--sg_ses.c9
-rw-r--r--sg_start.c4
-rw-r--r--sg_turs.c39
-rw-r--r--sgm_dd.86
-rw-r--r--sgm_dd.c8
-rw-r--r--sgp_dd.810
-rw-r--r--sgp_dd.c8
27 files changed, 840 insertions, 305 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 77625368..85fa81d4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,14 @@ 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.10 [20041030]
+ - sg_readcap, sg_dd, sgm_dd, sgp_dd: fix sg_ll_readcap_10+16 (sg_cmds.c)
+ - sg_luns: new utility to report luns
+ - sg_logs: with '-t' (show temperature) ignore extra parameters in
+ temperature log page (still show them with '-p=d')
+ - sg_ses: clean argument sanity checks
+ - sg_cmds: add more common command wrappers
+
Changelog for sg3_utils-1.09 [20041022]
- sg_ses: new utility to get status and set control on SES devices
- sg_verify: new utility to verify block devices
diff --git a/COVERAGE b/COVERAGE
index 0fa58831..d842140a 100644
--- a/COVERAGE
+++ b/COVERAGE
@@ -27,6 +27,7 @@ READ DEFECT(10) sginfo
READ DEFECT(12) sginfo
READ LONG sg_read_long
RECEIVE DIAGNOSTIC sg_senddiag, sg_ses
+REPORT LUNS sg_luns
REPORT SUPPORTED OPERATION CODES sg_opcodes
REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS sg_opcodes
REQUEST SENSE sg_requests
@@ -49,4 +50,4 @@ IDENTITY sg_inq, sg_scan
Doug Gilbert
-20th October 2004
+26th October 2004
diff --git a/INSTALL b/INSTALL
index c7da7a87..3dd143cb 100644
--- a/INSTALL
+++ b/INSTALL
@@ -13,14 +13,16 @@ 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
Note that the main Makefile does _not_ call the Makefiles in the
subdirectories (i.e. archive, examples and utils directories).
By default, this package now builds a shared library called
libsgutils.so and the corresponding static library: libsgutils.a .
+The GNU "libtool" is required by sg3_utils to build its libraries.
The 'make' will build those libraries and executables and put them
-in the ".libs" subdirectory (as GNU's libtool requires/enforces).
+in the ".libs" subdirectory (as libtool requires/enforces).
The 'make' puts scripts in the main directory with the same names as
the utilities (e.g. sg_dd, sg_inq etc) which set up an appropriate
environment and call the "real" executable "hiding" in the ".libs"
@@ -50,4 +52,4 @@ If the libsgutils.so shared library is troublesome or unwanted
then "no_lib" versions of the Makefile and the sg3_utils.spec file
can be found in the "lib_no_lib" subdirectory.
-21st October 2004
+28th October 2004
diff --git a/Makefile b/Makefile
index bd8a65ef..3c69a09a 100644
--- a/Makefile
+++ b/Makefile
@@ -13,13 +13,14 @@ EXECS = sg_dd sgp_dd sgm_dd sg_read sg_map sg_scan sg_rbuf \
sginfo sg_readcap sg_turs sg_inq sg_test_rwbuf \
sg_start sg_reset sg_modes sg_logs sg_senddiag sg_opcodes \
sg_persist sg_write_long sg_read_long sg_requests sg_ses \
- sg_verify sg_emc_trespass
+ sg_verify sg_emc_trespass sg_luns
MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sginfo.8 sg_readcap.8 sg_turs.8 sg_inq.8 sg_test_rwbuf.8 \
sg_start.8 sg_reset.8 sg_modes.8 sg_logs.8 sg_senddiag.8 \
sg_opcodes.8 sg_persist.8 sg_write_long.8 sg_read_long.8 \
- sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8
+ sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8 \
+ sg_luns.8
MAN_PREF = man8
HEADERS = sg_lib.h sg_cmds.h
@@ -131,6 +132,9 @@ sg_verify: sg_verify.o libsgutils.la
sg_emc_trespass: sg_emc_trespass.o libsgutils.la
libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+sg_luns: sg_luns.o libsgutils.la
+ libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
install -d $(LIBDIR)
diff --git a/README b/README
index 3217a41a..02af977a 100644
--- a/README
+++ b/README
@@ -98,8 +98,8 @@ in this package:
2) scanning and mapping: sg_scan, sg_map and scsi_devfs_scan
3) SCSI support: sg_inq, scsi_inquiry, sginfo, sg_readcap, sg_start,
sg_modes, sg_logs, sg_senddiag, sg_reset, sg_opcodes, sg_persist,
- sg_write_long, sg_read_long, sg_requests, sg_ses, sg_verify
- and sg_emc_trespass
+ sg_write_long, sg_read_long, sg_requests, sg_ses, sg_verify,
+ sg_emc_trespass and sg_luns
4) timing and testing: sg_rbuf, sg_test_rwbuf, sg_read, sg_turs,
and sg_debug
5) example programs: sg_simple1, sg_simple2, sg_simple3, sg_simple4
@@ -294,6 +294,10 @@ a standard INQUIRY response.
"sg_emc_trespass" permits modification of EMC specific trespass
mode page.
+"sg_emc_trespass" sends a REPORT LUNS SCSI command to the given device
+and outputs the response. The '--select' options allows the "select
+report" field to be specified.
+
4) Timing and testing
---------------------
@@ -416,4 +420,4 @@ a similar utility called "plscsi" which is available for Linux and other
operating systems. See http://members.aol.com/plscsi .
Doug Gilbert
-20th October 2004
+30th October 2004
diff --git a/lib_no_lib/Makefile.no_lib b/lib_no_lib/Makefile.no_lib
index dbecef36..1a71a632 100644
--- a/lib_no_lib/Makefile.no_lib
+++ b/lib_no_lib/Makefile.no_lib
@@ -13,13 +13,14 @@ EXECS = sg_dd sgp_dd sgm_dd sg_read sg_map sg_scan sg_rbuf \
sginfo sg_readcap sg_turs sg_inq sg_test_rwbuf \
sg_start sg_reset sg_modes sg_logs sg_senddiag sg_opcodes \
sg_persist sg_write_long sg_read_long sg_requests sg_ses \
- sg_verify sg_emc_trespass
+ sg_verify sg_emc_trespass sg_luns
MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
sginfo.8 sg_readcap.8 sg_turs.8 sg_inq.8 sg_test_rwbuf.8 \
sg_start.8 sg_reset.8 sg_modes.8 sg_logs.8 sg_senddiag.8 \
sg_opcodes.8 sg_persist.8 sg_write_long.8 sg_read_long.8 \
- sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8
+ sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8 \
+ sg_luns.8
MAN_PREF = man8
LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
@@ -117,6 +118,9 @@ sg_verify: sg_verify.o sg_lib.o
sg_emc_trespass: sg_emc_trespass.o sg_lib.o sg_cmds.o
$(LD) -o $@ $(LDFLAGS) $^
+sg_luns: sg_luns.o sg_lib.o sg_cmds.o
+ $(LD) -o $@ $(LDFLAGS) $^
+
install: $(EXECS)
install -d $(INSTDIR)
for name in $^; \
diff --git a/lib_no_lib/sg3_utils.spec.no_lib b/lib_no_lib/sg3_utils.spec.no_lib
index fadaaf22..48e9e1f4 100644
--- a/lib_no_lib/sg3_utils.spec.no_lib
+++ b/lib_no_lib/sg3_utils.spec.no_lib
@@ -6,12 +6,12 @@
Summary: Utilities for SCSI devices in Linux
Name: sg3_utils
-Version: 1.09
+Version: 1.10
Release: 1
Packager: Douglas Gilbert <dgilbert at interlog dot com>
License: GPL/FreeBSD
Group: Utilities/System
-Source: ftp://www.torque.net/sg/p/sg3_utils-1.09.tgz
+Source: ftp://www.torque.net/sg/p/sg3_utils-1.10.tgz
Url: http://www.torque.net/sg/u_index.html
Provides: sg_utils
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root/
@@ -80,6 +80,7 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root) %{_bindir}/sg_ses
%attr(755,root,root) %{_bindir}/sg_verify
%attr(755,root,root) %{_bindir}/sg_emc_trespass
+%attr(755,root,root) %{_bindir}/sg_luns
# Mandrake compresses man pages with bzip2, RedHat with gzip
%attr(-,root,root) %doc %{_mandir}/man8/sg_dd.8*
%attr(-,root,root) %doc %{_mandir}/man8/sgp_dd.8*
@@ -106,9 +107,13 @@ rm -rf $RPM_BUILD_ROOT
%attr(-,root,root) %doc %{_mandir}/man8/sg_ses.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg_verify.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg_sg_emc_trespass.8*
+%attr(-,root,root) %doc %{_mandir}/man8/sg_luns.8*
%changelog
+* Tue Oct 26 2004 - dgilbert at interlog dot com
+- read_capacity (10+16) fix, add sg_luns
+ * sg3_utils-1.10
* Thu Oct 21 2004 - dgilbert at interlog dot com
- sg_requests, sg_ses, sg_verify, sg_err->sg_lib
* sg3_utils-1.09
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 2cb9ae9b..deb161da 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -6,12 +6,12 @@
Summary: Utilities for SCSI devices in Linux
Name: sg3_utils
-Version: 1.09
+Version: 1.10
Release: 1
Packager: Douglas Gilbert <dgilbert at interlog dot com>
License: GPL/FreeBSD
Group: Utilities/System
-Source: ftp://www.torque.net/sg/p/sg3_utils-1.09.tgz
+Source: ftp://www.torque.net/sg/p/sg3_utils-1.10.tgz
Url: http://www.torque.net/sg/u_index.html
Provides: sg_utils
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root/
@@ -89,6 +89,7 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root) %{_bindir}/sg_ses
%attr(755,root,root) %{_bindir}/sg_verify
%attr(755,root,root) %{_bindir}/sg_emc_trespass
+%attr(755,root,root) %{_bindir}/sg_luns
%attr(755,root,root) %{_libdir}/libsgutils.so
%attr(755,root,root) %{_libdir}/libsgutils.so.1
%attr(755,root,root) %{_libdir}/libsgutils.so.1.0.0
@@ -118,6 +119,7 @@ rm -rf $RPM_BUILD_ROOT
%attr(-,root,root) %doc %{_mandir}/man8/sg_ses.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg_verify.8*
%attr(-,root,root) %doc %{_mandir}/man8/sg_emc_trespass.8*
+%attr(-,root,root) %doc %{_mandir}/man8/sg_luns.8*
%files devel
%defattr(-,root,root)
@@ -128,6 +130,9 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Sat Oct 30 2004 - dgilbert at interlog dot com
+- fix read capacity (10+16), add sg_luns
+ * sg3_utils-1.10
* Thu Oct 21 2004 - dgilbert at interlog dot com
- sg_requests, sg_ses, sg_verify, libsgutils(sg_lib.c+sg_cmds.c), devel rpm
* sg3_utils-1.09
diff --git a/sg_cmds.c b/sg_cmds.c
index ebd5efd3..23f470fc 100644
--- a/sg_cmds.c
+++ b/sg_cmds.c
@@ -40,6 +40,8 @@
* CHANGELOG
* v1.00 (20041018)
* fetch low level command execution code from other utilities
+ * v1.01 (20041026)
+ * fix "ll" read capacity calls, add sg_ll_report_luns
*/
#include <stdio.h>
@@ -52,7 +54,7 @@
#include "sg_lib.h"
#include "sg_cmds.h"
-static char * version_str = "1.00 20041019";
+static char * version_str = "1.02 20041030";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
@@ -67,7 +69,7 @@ static char * version_str = "1.00 20041019";
#define SERVICE_ACTION_IN_16_CMDLEN 16
#define READ_CAPACITY_16_SA 0x10
#define READ_CAPACITY_10_CMD 0x25
-#define READ_CAPACITY_10_CMDLEN 0x10
+#define READ_CAPACITY_10_CMDLEN 10
#define MODE_SENSE6_CMD 0x1a
#define MODE_SENSE6_CMDLEN 6
#define MODE_SENSE10_CMD 0x5a
@@ -78,6 +80,14 @@ static char * version_str = "1.00 20041019";
#define MODE_SELECT10_CMDLEN 10
#define REQUEST_SENSE_CMD 0x3
#define REQUEST_SENSE_CMDLEN 6
+#define REPORT_LUNS_CMD 0xa0
+#define REPORT_LUNS_CMDLEN 12
+#define LOG_SENSE_CMD 0x4d
+#define LOG_SENSE_CMDLEN 10
+#define LOG_SELECT_CMD 0x4c
+#define LOG_SELECT_CMDLEN 10
+#define TUR_CMD 0x0
+#define TUR_CMDLEN 6
#define MODE6_RESP_HDR_LEN 4
#define MODE10_RESP_HDR_LEN 8
@@ -115,6 +125,7 @@ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op,
fprintf(sg_warnings_str, "\n");
}
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(inqCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_b);
@@ -176,6 +187,7 @@ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
fprintf(sg_warnings_str, "\n");
}
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(inqCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_b);
@@ -222,9 +234,57 @@ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
}
}
+/* Invokes a SCSI TEST UNIT READY command.
+ * 'pack_id' is just for diagnostics, safe to set to 0.
+ * Return of 0 -> success, -1 -> failure */
+int sg_ll_test_unit_ready(int sg_fd, int pack_id, int noisy, int verbose)
+{
+ int res, k;
+ unsigned char turCmbBlk[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ if (NULL == sg_warnings_str)
+ sg_warnings_str = stderr;
+ if (verbose) {
+ fprintf(sg_warnings_str, " test unit ready cdb: ");
+ for (k = 0; k < TUR_CMDLEN; ++k)
+ fprintf(sg_warnings_str, "%02x ", turCmbBlk[k]);
+ fprintf(sg_warnings_str, "\n");
+ }
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(turCmbBlk);
+ io_hdr.mx_sb_len = sizeof(sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ io_hdr.dxfer_len = 0;
+ io_hdr.dxferp = NULL;
+ io_hdr.cmdp = turCmbBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.pack_id = pack_id; /* diagnostic: safe to set to 0 */
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ fprintf(sg_warnings_str, "test_unit_ready (SG_IO) error: %s\n",
+ safe_strerror(errno));
+ return -1;
+ }
+ res = sg_err_category3(&io_hdr);
+ switch (res) {
+ case SG_LIB_CAT_CLEAN:
+ return 0;
+ default:
+ if (noisy || verbose)
+ sg_chk_n_print3("test unit ready", &io_hdr);
+ return -1;
+ }
+}
+
/* Invokes a SCSI SYNCHRONIZE CACHE (10) command */
/* Return of 0 -> success, -1 -> failure, 2 -> try again */
-int sg_ll_sync_cache(int sg_fd, int sync_nv, int immed, int verbose)
+int sg_ll_sync_cache(int sg_fd, int sync_nv, int immed, int noisy,
+ int verbose)
{
int res, k;
unsigned char scCmdBlk[SYNCHRONIZE_CACHE_CMDLEN] =
@@ -245,6 +305,7 @@ int sg_ll_sync_cache(int sg_fd, int sync_nv, int immed, int verbose)
fprintf(sg_warnings_str, "\n");
}
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(scCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_b);
@@ -261,12 +322,16 @@ int sg_ll_sync_cache(int sg_fd, int sync_nv, int immed, int verbose)
return -1;
}
res = sg_err_category3(&io_hdr);
- if (SG_LIB_CAT_MEDIA_CHANGED == res)
+ switch (res) {
+ case SG_LIB_CAT_CLEAN:
+ return 0;
+ case SG_LIB_CAT_MEDIA_CHANGED:
return 2; /* probably have another go ... */
- else if (SG_LIB_CAT_INVALID_OP == res)
+ case SG_LIB_CAT_INVALID_OP:
return res;
- else if (SG_LIB_CAT_CLEAN != res) {
- sg_chk_n_print3("synchronize cache", &io_hdr);
+ default:
+ if (noisy || verbose)
+ sg_chk_n_print3("synchronize cache", &io_hdr);
return -1;
}
return 0;
@@ -297,7 +362,11 @@ int sg_ll_readcap_16(int sg_fd, int pmi, unsigned long long llba,
rcCmdBlk[8] = (llba >> 8) & 0xff;
rcCmdBlk[9] = llba & 0xff;
}
- rcCmdBlk[13] = 12; /* Allocation length */
+ /* Allocation length, no guidance in SBC-2 rev 15b */
+ rcCmdBlk[10] = (mx_resp_len >> 24) & 0xff;
+ rcCmdBlk[11] = (mx_resp_len >> 16) & 0xff;
+ rcCmdBlk[12] = (mx_resp_len >> 8) & 0xff;
+ rcCmdBlk[13] = mx_resp_len & 0xff;
if (NULL == sg_warnings_str)
sg_warnings_str = stderr;
if (verbose) {
@@ -307,6 +376,7 @@ int sg_ll_readcap_16(int sg_fd, int pmi, unsigned long long llba,
fprintf(sg_warnings_str, "\n");
}
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(rcCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_b);
@@ -368,6 +438,7 @@ int sg_ll_readcap_10(int sg_fd, int pmi, unsigned int lba,
fprintf(sg_warnings_str, "\n");
}
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(rcCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_b);
@@ -457,7 +528,7 @@ int sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
case SG_LIB_CAT_INVALID_OP:
return res;
default:
- if (noisy | verbose) {
+ if (noisy || verbose) {
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "Mode sense (6) error, dbd=%d "
@@ -527,7 +598,7 @@ int sg_ll_mode_sense10(int sg_fd, int dbd, int pc, int pg_code,
case SG_LIB_CAT_INVALID_OP:
return res;
default:
- if (noisy | verbose) {
+ if (noisy || verbose) {
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "Mode sense (10) error, dbd=%d "
@@ -594,7 +665,7 @@ int sg_ll_mode_select6(int sg_fd, int pf, int sp, void * paramp,
case SG_LIB_CAT_INVALID_OP:
return res;
default:
- if (noisy | verbose) {
+ if (noisy || verbose) {
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "Mode select (6) error, pf=%d "
@@ -661,7 +732,7 @@ int sg_ll_mode_select10(int sg_fd, int pf, int sp, void * paramp,
case SG_LIB_CAT_INVALID_OP:
return res;
default:
- if (noisy | verbose) {
+ if (noisy || verbose) {
char ebuff[EBUFF_SZ];
snprintf(ebuff, EBUFF_SZ, "Mode select (10) error, pf=%d "
@@ -717,7 +788,7 @@ int sg_mode_page_offset(const unsigned char * resp, int resp_len,
/* Invokes a SCSI REQUEST SENSE command */
/* Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> Request Sense not
- * supported??, -1 -> other failure */
+ * supported??, -1 -> other failure */
int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len,
int verbose)
{
@@ -739,6 +810,7 @@ int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len,
}
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = REQUEST_SENSE_CMDLEN;
io_hdr.mx_sb_len = sizeof(sense_b);
@@ -776,3 +848,204 @@ int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len,
return -1;
}
}
+
+/* Invokes a SCSI REPORT LUNS command */
+/* Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> Report Luns not
+ * supported, -1 -> other failure */
+int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
+ int mx_resp_len, int noisy, int verbose)
+{
+ int k, res;
+ unsigned char rlCmdBlk[REPORT_LUNS_CMDLEN] =
+ {REPORT_LUNS_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ rlCmdBlk[2] = select_report & 0xff;
+ rlCmdBlk[6] = (mx_resp_len >> 24) & 0xff;
+ rlCmdBlk[7] = (mx_resp_len >> 16) & 0xff;
+ rlCmdBlk[8] = (mx_resp_len >> 8) & 0xff;
+ rlCmdBlk[9] = mx_resp_len & 0xff;
+ if (NULL == sg_warnings_str)
+ sg_warnings_str = stderr;
+ if (verbose) {
+ fprintf(sg_warnings_str, " report luns cdb: ");
+ for (k = 0; k < REPORT_LUNS_CMDLEN; ++k)
+ fprintf(sg_warnings_str, "%02x ", rlCmdBlk[k]);
+ fprintf(sg_warnings_str, "\n");
+ }
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(rlCmdBlk);
+ io_hdr.mx_sb_len = sizeof(sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = rlCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ fprintf(sg_warnings_str, "report_luns (SG_IO) error: %s\n",
+ safe_strerror(errno));
+ return -1;
+ }
+ res = sg_err_category3(&io_hdr);
+ switch (res) {
+ case SG_LIB_CAT_CLEAN:
+ case SG_LIB_CAT_RECOVERED:
+ if (verbose && io_hdr.resid)
+ fprintf(sg_warnings_str, " report_luns: resid=%d\n",
+ io_hdr.resid);
+ return 0;
+ case SG_LIB_CAT_INVALID_OP:
+ return res;
+ case SG_LIB_CAT_MEDIA_CHANGED:
+ return 2;
+ default:
+ if (noisy || verbose)
+ sg_chk_n_print3("REPORT LUNS command error", &io_hdr);
+ return -1;
+ }
+}
+
+/* Invokes a SCSI LOG SENSE command */
+/* Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> Log Sense not
+ * supported, -1 -> other failure */
+int sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code,
+ int paramp, unsigned char * resp, int mx_resp_len,
+ int noisy, int verbose)
+{
+ int res, k;
+ unsigned char logsCmdBlk[LOG_SENSE_CMDLEN] =
+ {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ if (NULL == sg_warnings_str)
+ sg_warnings_str = stderr;
+ if (mx_resp_len > 0xffff) {
+ fprintf(sg_warnings_str, "mx_resp_len too big\n");
+ return -1;
+ }
+ logsCmdBlk[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0));
+ logsCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
+ logsCmdBlk[5] = (unsigned char)((paramp >> 8) & 0xff);
+ logsCmdBlk[6] = (unsigned char)(paramp & 0xff);
+ logsCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ logsCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff);
+ if (verbose) {
+ fprintf(sg_warnings_str, " log sense cdb: ");
+ for (k = 0; k < LOG_SENSE_CMDLEN; ++k)
+ fprintf(sg_warnings_str, "%02x ", logsCmdBlk[k]);
+ fprintf(sg_warnings_str, "\n");
+ }
+
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(logsCmdBlk);
+ io_hdr.mx_sb_len = sizeof(sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = logsCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ fprintf(sg_warnings_str, "log sense (SG_IO) error: %s\n",
+ safe_strerror(errno));
+ return -1;
+ }
+ res = sg_err_category3(&io_hdr);
+ switch (res) {
+ case SG_LIB_CAT_CLEAN:
+ case SG_LIB_CAT_RECOVERED:
+ if (verbose && io_hdr.resid)
+ fprintf(sg_warnings_str, " log_sense: resid=%d\n",
+ io_hdr.resid);
+ return 0;
+ case SG_LIB_CAT_INVALID_OP:
+ return SG_LIB_CAT_INVALID_OP;
+ default:
+ if (noisy || verbose) {
+ char ebuff[EBUFF_SZ];
+ snprintf(ebuff, EBUFF_SZ, "log_sense: ppc=%d, sp=%d, "
+ "pc=%d, page_code=%x, paramp=%x\n ", ppc, sp, pc,
+ pg_code, paramp);
+ sg_chk_n_print3(ebuff, &io_hdr);
+ }
+ return -1;
+ }
+}
+
+
+/* Invokes a SCSI LOG SELECT command */
+/* Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> Log Select not
+ * supported, -1 -> other failure */
+int sg_ll_log_select(int sg_fd, int pcr, int sp, int pc,
+ unsigned char * paramp, int param_len,
+ int noisy, int verbose)
+{
+ int res, k;
+ unsigned char logsCmdBlk[LOG_SELECT_CMDLEN] =
+ {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ if (NULL == sg_warnings_str)
+ sg_warnings_str = stderr;
+ if (param_len > 0xffff) {
+ fprintf(sg_warnings_str, "log select: param_len too big\n");
+ return -1;
+ }
+ logsCmdBlk[1] = (unsigned char)((pcr ? 2 : 0) | (sp ? 1 : 0));
+ logsCmdBlk[2] = (unsigned char)((pc << 6) & 0xc0);
+ logsCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff);
+ logsCmdBlk[8] = (unsigned char)(param_len & 0xff);
+ if (verbose) {
+ fprintf(sg_warnings_str, " log select cdb: ");
+ for (k = 0; k < LOG_SELECT_CMDLEN; ++k)
+ fprintf(sg_warnings_str, "%02x ", logsCmdBlk[k]);
+ fprintf(sg_warnings_str, "\n");
+ }
+
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ memset(sense_b, 0, sizeof(sense_b));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(logsCmdBlk);
+ io_hdr.mx_sb_len = sizeof(sense_b);
+ io_hdr.dxfer_direction = param_len ? SG_DXFER_TO_DEV : SG_DXFER_NONE;
+ io_hdr.dxfer_len = param_len;
+ io_hdr.dxferp = paramp;
+ io_hdr.cmdp = logsCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ fprintf(sg_warnings_str, "log select (SG_IO) error: %s\n",
+ safe_strerror(errno));
+ return -1;
+ }
+ res = sg_err_category3(&io_hdr);
+ switch (res) {
+ case SG_LIB_CAT_CLEAN:
+ case SG_LIB_CAT_RECOVERED:
+ if (verbose && io_hdr.resid)
+ fprintf(sg_warnings_str, " log_select: resid=%d\n",
+ io_hdr.resid);
+ return 0;
+ case SG_LIB_CAT_INVALID_OP:
+ return SG_LIB_CAT_INVALID_OP;
+ default:
+ if (noisy || verbose) {
+ char ebuff[EBUFF_SZ];
+ snprintf(ebuff, EBUFF_SZ, "log_select: pcr=%d, sp=%d, "
+ "pc=%d\n ", pcr, sp, pc);
+ sg_chk_n_print3(ebuff, &io_hdr);
+ }
+ return -1;
+ }
+}
diff --git a/sg_cmds.h b/sg_cmds.h
index a25e2c44..9e9a6438 100644
--- a/sg_cmds.h
+++ b/sg_cmds.h
@@ -8,7 +8,11 @@ extern int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op,
void * resp, int mx_resp_len, int noisy,
int verbose);
-extern int sg_ll_sync_cache(int sg_fd, int sync_nv, int immed, int verbose);
+extern int sg_ll_test_unit_ready(int sg_fd, int pack_id, int noisy,
+ int verbose);
+
+extern int sg_ll_sync_cache(int sg_fd, int sync_nv, int immed, int noisy,
+ int verbose);
extern int sg_ll_readcap_10(int sg_fd, int pmi, unsigned int lba,
void * resp, int mx_resp_len, int verbose);
@@ -33,6 +37,17 @@ extern int sg_ll_mode_select10(int sg_fd, int pf, int sp, void * paramp,
extern int sg_ll_request_sense(int sg_fd, int desc, void * resp,
int mx_resp_len, int verbose);
+extern int sg_ll_report_luns(int sg_fd, int select_report, void * resp,
+ int mx_resp_len, int noisy, int verbose);
+
+extern int sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code,
+ int paramp, unsigned char * resp, int mx_resp_len,
+ int noisy, int verbose);
+
+extern int sg_ll_log_select(int sg_fd, int pcr, int sp, int pc,
+ unsigned char * paramp, int param_len,
+ int noisy, int verbose);
+
struct sg_simple_inquiry_resp {
unsigned char peripheral_qualifier;
unsigned char peripheral_type;
diff --git a/sg_dd.8 b/sg_dd.8
index 3f909748..4122a4cb 100644
--- a/sg_dd.8
+++ b/sg_dd.8
@@ -1,4 +1,4 @@
-.TH SG_DD "8" "September 2004" "sg3_utils-1.09" SG3_UTILS
+.TH SG_DD "8" "October 2004" "sg3_utils-1.10" SG3_UTILS
.SH NAME
sg_dd \- copies data to and from files and devices. Specialised for
devices that understand the SCSI command set.
@@ -37,7 +37,9 @@ are used for IO). When set to 1, block
devices are assumed to accept the SG_IO ioctl and SCSI commands are
issued for IO. This is only supported for 2.6 series kernels. Note
that ATAPI devices (e.g. cd/dvd players) use the SCSI command set
-but ATA disks do not.
+but ATA disks do not. If the input or output device is a block device
+partition then setting this option causes the partition information
+to be ignored (since access is directly to the underlying device).
Default is 0.
.TP
bpt=BLOCKS
@@ -73,8 +75,8 @@ utility. Default is 0 which implies stop on error.
count=BLOCKS
copy this number of blocks from 'if' to 'of'. Default is the
minimum (of 'if' and 'of') number of blocks that sg devices return from
-READ CAPACITY SCSI commands or that block devices report.
-Normal files are not probed for their size. If 'skip'
+READ CAPACITY SCSI commands or that block devices (or their partitions)
+report. Normal files are not probed for their size. If 'skip'
or 'seek' are given and the count is derived (i.e. not explicitly given)
then the derived count is scaled back so that the copy will not overrun the
device. If the file name is a block device partition and count is not given
@@ -145,8 +147,6 @@ for more information about binding raw devices. To be safe, the sg device
mapping to SCSI block devices should be checked with "cat /proc/scsi/scsi",
or sg_map before use.
.PP
-The count is only deduced for sg devices (minimum > 0 if both input and
-output are sg devices) otherwise it defaults to 0. This is for safety!
Raw disk partition information can often be found with
.B fdisk(8)
[the "-ul" argument is useful in this respect].
diff --git a/sg_dd.c b/sg_dd.c
index ee27dfb0..69ec1df1 100644
--- a/sg_dd.c
+++ b/sg_dd.c
@@ -54,7 +54,7 @@
This version is designed for the linux kernel 2.4 and 2.6 series.
*/
-static char * version_str = "5.33 20041011";
+static char * version_str = "5.34 20041029";
#define DEF_BLOCK_SIZE 512
@@ -1021,11 +1021,11 @@ int main(int argc, char * argv[])
if (do_sync) {
if (FT_SG & out_type) {
fprintf(stderr, ">> Synchronizing cache on %s\n", outf);
- res = sg_ll_sync_cache(outfd, 0, 0, 0);
+ res = sg_ll_sync_cache(outfd, 0, 0, 0, 0);
if (2 == res) {
fprintf(stderr,
"Unit attention, media changed(in), continuing\n");
- res = sg_ll_sync_cache(outfd, 0, 0, 0);
+ res = sg_ll_sync_cache(outfd, 0, 0, 0, 0);
}
if (0 != res)
fprintf(stderr, "Unable to synchronize cache\n");
diff --git a/sg_lib.c b/sg_lib.c
index 6548d515..3016be56 100644
--- a/sg_lib.c
+++ b/sg_lib.c
@@ -67,7 +67,7 @@
#include "sg_include.h"
#include "sg_lib.h"
-static char * version_str = "1.00 20041020";
+static char * version_str = "1.01 20041024";
FILE * sg_warnings_str = NULL; /* would like to default to stderr */
@@ -983,7 +983,7 @@ static struct error_info additional[] =
{0x69,0x00,"Data loss on logical unit"},
{0x69,0x01,"Multiple logical unit failures"},
{0x69,0x02,"Parity/data mismatch"},
- {0x6A,0x00,"Informational,refer to log"},
+ {0x6A,0x00,"Informational, refer to log"},
{0x6B,0x00,"State change has occurred"},
{0x6B,0x01,"Redundancy level got better"},
{0x6B,0x02,"Redundancy level got worse"},
@@ -1043,7 +1043,7 @@ static const char *sense_key_desc[] = {
void sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
{
- int k, num;
+ int k, num, rlen;
int found = 0;
struct error_info * eip;
struct error_info2 * ei2p;
@@ -1055,8 +1055,11 @@ void sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
(ascq <= ei2p->code2_max)) {
found = 1;
num = snprintf(buff, buff_len, "Additional sense: ");
- num += snprintf(buff + num, buff_len - num, ei2p->text, ascq);
- snprintf(buff + num, buff_len - num, "\n");
+ rlen = buff_len - num;
+ num += snprintf(buff + num, ((rlen > 0) ? rlen : 0),
+ ei2p->text, ascq);
+ rlen = buff_len - num;
+ snprintf(buff + num, ((rlen > 0) ? rlen : 0), "\n");
}
}
if (found)
@@ -1074,7 +1077,7 @@ void sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
if (asc >= 0x80)
snprintf(buff, buff_len, "vendor specific ASC=%2x, ASCQ=%2x\n",
asc, ascq);
- else if (ascq >= 0x30)
+ else if (ascq >= 0x80)
snprintf(buff, buff_len, "ASC=%2x, vendor specific ASCQ=%2x\n",
asc, ascq);
else
@@ -1645,7 +1648,7 @@ int sg_get_command_size(unsigned char opcode)
void sg_get_command_name(const unsigned char * cmdp, int peri_type,
int buff_len, char * buff)
{
- unsigned char service_action;
+ int service_action;
if ((NULL == buff) || (buff_len < 1))
return;
diff --git a/sg_logs.8 b/sg_logs.8
index 9ce7279c..5655732c 100644
--- a/sg_logs.8
+++ b/sg_logs.8
@@ -32,6 +32,7 @@ response in hex instead.
.TP
-l
lists the names of all logs sense pages supported by this device.
+See the list of common log page codes below.
.TP
-p=<page_code>
log page code to fetch. Should be a hexadecimal number between 0 and 3f
@@ -49,8 +50,14 @@ being output in ASCII).
sets the Parameter Pointer Control (PPC) bit. Default is 0 (i.e. cleared).
.TP
-r
-use LOG SELECT SCSI command to reset all implemented parameters to be
-the target defined (i.e. manufacturer's) default values.
+use LOG SELECT SCSI command to reset all implemented parameter values
+to be the device defined (i.e. manufacturer's) default values. In most
+cases the default values are zeroes. This option seems to
+clear error counter log pages but leaves pages like self-test results,
+start-stop cycle counter and temperature log pages uneffected.
+This option may be required to clear log pages if a counter reaches its
+maximum value since the log page in which the counter is found will
+remain "stuck" until something is done.
.TP
-sp
sets the Saving Parameters (SP) bit. Default is 0 (i.e. cleared).
@@ -76,6 +83,29 @@ The smartmontools package provides much of the information found with
sg_logs in a form suitable for monitoring the health of SCSI disks and
tape drives.
.PP
+Here is a list of commonly used log pages (drop the "0x" prefix when
+using them as an argument to the '-p=' option):
+.PP
+0x0 Supported log pages
+.br
+0x2 Write error counter
+.br
+0x3 Read error counter
+.br
+0x6 Non-medium error
+.br
+0x7 Last n error events
+.br
+0xd Temperature
+.br
+0xe Start-stop cycle counter
+.br
+0x10 Self-test results
+.br
+0x18 Protocol specific port
+.br
+0x2f Informational exceptions
+.PP
In the 2.4 series of Linux kernels the given device must be
a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
and SCSI DVDs) can also be specified. For example "sg_logs -a /dev/sda"
diff --git a/sg_logs.c b/sg_logs.c
index 1479c181..68f1c3bf 100644
--- a/sg_logs.c
+++ b/sg_logs.c
@@ -23,21 +23,12 @@
*/
-static char * version_str = "0.32 20041012";
+static char * version_str = "0.34 20041028";
#define ME "sg_logs: "
-#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
-#define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
-
-#define LOG_SENSE_CMD 0x4d
-#define LOG_SENSE_CMDLEN 10
-#define LOG_SELECT_CMD 0x4c
-#define LOG_SELECT_CMDLEN 10
#define MX_ALLOC_LEN (1024 * 17)
-
#define PG_CODE_ALL 0x00
-
#define EBUFF_SZ 256
@@ -50,165 +41,26 @@ static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code,
int paramp, unsigned char * resp, int mx_resp_len,
int noisy, int verbose)
{
- int res, k;
- unsigned char logsCmdBlk[LOG_SENSE_CMDLEN] =
- {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char logsCmdBlk2[LOG_SENSE_CMDLEN];
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
int actual_len;
+ int res;
- logsCmdBlk[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0));
- logsCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
- logsCmdBlk[5] = (unsigned char)((paramp >> 8) & 0xff);
- logsCmdBlk[6] = (unsigned char)(paramp & 0xff);
- if (mx_resp_len > 0xffff) {
- printf( ME "mx_resp_len too big\n");
- return -1;
- }
- memcpy(logsCmdBlk2, logsCmdBlk, sizeof(logsCmdBlk));
- logsCmdBlk[8] = 4;
- if (verbose) {
- fprintf(stderr, " log sense cdb: ");
- for (k = 0; k < LOG_SENSE_CMDLEN; ++k)
- fprintf(stderr, "%02x ", logsCmdBlk[k]);
- fprintf(stderr, "\n");
- }
- if (mx_resp_len > 3)
- memset(resp, 0, 4);
-
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(logsCmdBlk);
- io_hdr.mx_sb_len = sizeof(sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = 4;
- io_hdr.dxferp = resp;
- io_hdr.cmdp = logsCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
-
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("SG_IO (log sense) error");
- return -1;
- }
- res = sg_err_category3(&io_hdr);
- switch (res) {
- case SG_LIB_CAT_CLEAN:
- case SG_LIB_CAT_RECOVERED:
- break;
- default:
- if (noisy) {
- char ebuff[EBUFF_SZ];
- snprintf(ebuff, EBUFF_SZ, ME "log_sense(short): ppc=%d, sp=%d, "
- "pc=%d, page_code=%x, paramp=%x\n ", ppc, sp, pc,
- pg_code, paramp);
- sg_chk_n_print3(ebuff, &io_hdr);
- }
+ memset(resp, 0, mx_resp_len);
+ if ((res = sg_ll_log_sense(sg_fd, ppc, sp, pc, pg_code, paramp, resp,
+ 4, noisy, verbose))) {
+ if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, "log_sense: not supported\n");
return -1;
}
actual_len = (resp[2] << 8) + resp[3] + 4;
- if (actual_len < 4)
- return 0;
/* Some HBAs don't like odd transfer lengths */
if (actual_len % 2)
actual_len += 1;
if (actual_len > mx_resp_len)
actual_len = mx_resp_len;
- logsCmdBlk2[7] = (unsigned char)((actual_len >> 8) & 0xff);
- logsCmdBlk2[8] = (unsigned char)(actual_len & 0xff);
- if (verbose) {
- fprintf(stderr, " log sense cdb: ");
- for (k = 0; k < LOG_SENSE_CMDLEN; ++k)
- fprintf(stderr, "%02x ", logsCmdBlk2[k]);
- fprintf(stderr, "\n");
- }
-
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(logsCmdBlk2);
- io_hdr.mx_sb_len = sizeof(sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = actual_len;
- io_hdr.dxferp = resp;
- io_hdr.cmdp = logsCmdBlk2;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
-
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("SG_IO (log sense) error");
- return -1;
- }
-#if 0
- printf("SG_IO ioctl: log_sense: status=%d, info=%d, sb_len_wr=%d\n",
- io_hdr.status, io_hdr.info, io_hdr.sb_len_wr);
-#endif
- res = sg_err_category3(&io_hdr);
- switch (res) {
- case SG_LIB_CAT_CLEAN:
- case SG_LIB_CAT_RECOVERED:
- return 0;
- default:
- if (noisy) {
- char ebuff[EBUFF_SZ];
- snprintf(ebuff, EBUFF_SZ, ME "log_sense: ppc=%d, sp=%d, "
- "pc=%d, page_code=%x, paramp=%x\n ", ppc, sp, pc,
- pg_code, paramp);
- sg_chk_n_print3(ebuff, &io_hdr);
- }
- return -1;
- }
-}
-
-/* Return 0 if successful, else -1 */
-static int do_logselect(int sg_fd, int pcr, int sp, int pc,
- unsigned char * paramp, int param_len,
- int noisy, int verbose)
-{
- int res, k;
- unsigned char logsCmdBlk[LOG_SELECT_CMDLEN] =
- {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
-
- logsCmdBlk[1] = (unsigned char)((pcr ? 2 : 0) | (sp ? 1 : 0));
- logsCmdBlk[2] = (unsigned char)((pc << 6) & 0xc0);
- logsCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff);
- logsCmdBlk[8] = (unsigned char)(param_len & 0xff);
- if (verbose) {
- fprintf(stderr, " log select cdb: ");
- for (k = 0; k < LOG_SELECT_CMDLEN; ++k)
- fprintf(stderr, "%02x ", logsCmdBlk[k]);
- fprintf(stderr, "\n");
- }
-
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(logsCmdBlk);
- io_hdr.mx_sb_len = sizeof(sense_b);
- io_hdr.dxfer_direction = param_len ? SG_DXFER_TO_DEV : SG_DXFER_NONE;
- io_hdr.dxfer_len = param_len;
- io_hdr.dxferp = paramp;
- io_hdr.cmdp = logsCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
-
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("SG_IO (log select) error");
- return -1;
- }
- res = sg_err_category3(&io_hdr);
- switch (res) {
- case SG_LIB_CAT_CLEAN:
- case SG_LIB_CAT_RECOVERED:
- break;
- default:
- if (noisy) {
- char ebuff[EBUFF_SZ];
- snprintf(ebuff, EBUFF_SZ, ME "log_select: pcr=%d, sp=%d, "
- "pc=%d\n ", pcr, sp, pc);
- sg_chk_n_print3(ebuff, &io_hdr);
- }
+ if ((res = sg_ll_log_sense(sg_fd, ppc, sp, pc, pg_code, paramp, resp,
+ actual_len, noisy, verbose))) {
+ if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, "log_sense: not supported (b)\n");
return -1;
}
return 0;
@@ -643,7 +495,7 @@ static void show_self_test_page(unsigned char * resp, int len, int show_pcb)
}
static void show_Temperature_page(unsigned char * resp, int len,
- int show_pcb, int hdr)
+ int show_pcb, int hdr, int show_unknown)
{
int k, num, extra, pc, pcb;
unsigned char * ucp;
@@ -680,10 +532,11 @@ static void show_Temperature_page(unsigned char * resp, int len,
printf(" Reference temperature = <not available>");
}
- } else {
+ } else if (show_unknown) {
printf(" unknown parameter code = 0x%x, contents in hex:\n", pc);
dStrHex((const char *)ucp, extra, 1);
- }
+ } else
+ continue;
if (show_pcb) {
get_pcb_str(pcb, pcb_str, sizeof(pcb_str));
printf(" <%s>\n", pcb_str);
@@ -1025,7 +878,7 @@ static void show_ascii_page(unsigned char * resp, int len, int show_pcb,
show_last_n_deferred_error_page(resp, len, show_pcb);
break;
case 0xd:
- show_Temperature_page(resp, len, show_pcb, 1);
+ show_Temperature_page(resp, len, show_pcb, 1, 1);
break;
case 0xe:
show_Start_Stop_page(resp, len, show_pcb);
@@ -1092,7 +945,7 @@ static int fetchTemperature(int sg_fd, unsigned char * resp, int max_len,
int res = 0;
if (0 == do_logs(sg_fd, 0, 0, 1, 0xd, 0, resp, max_len, 0, verbose))
- show_Temperature_page(resp, (resp[2] << 8) + resp[3] + 4, 0, 0);
+ show_Temperature_page(resp, (resp[2] << 8) + resp[3] + 4, 0, 0, 0);
else if (0 == do_logs(sg_fd, 0, 0, 1, 0x2f, 0, resp, max_len, 0, verbose))
show_IE_page(resp, (resp[2] << 8) + resp[3] + 4, 0, 0);
else {
@@ -1216,10 +1069,12 @@ int main(int argc, char * argv[])
if (1 == do_temp)
return fetchTemperature(sg_fd, rsp_buff, MX_ALLOC_LEN, do_verbose);
- if (1 == do_pcreset)
- return do_logselect(sg_fd, 1, do_sp, pc, NULL, 0, 1, do_verbose) ?
- 1 : 0;
-
+ if (1 == do_pcreset) {
+ k = sg_ll_log_select(sg_fd, 1, do_sp, pc, NULL, 0, 1, do_verbose);
+ if (SG_LIB_CAT_INVALID_OP == k)
+ fprintf(stderr, "log_select: not supported\n");
+ return k ? 1 : 0;
+ }
if (0 == do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, paramp,
rsp_buff, MX_ALLOC_LEN, 1, do_verbose))
{
diff --git a/sg_luns.8 b/sg_luns.8
new file mode 100644
index 00000000..20158659
--- /dev/null
+++ b/sg_luns.8
@@ -0,0 +1,49 @@
+.TH SG_LUNS "8" "October 2004" "sg3_utils-1.10" SG3_UTILS
+.SH NAME
+sg_luns \- send the scsi command report luns
+.SH SYNOPSIS
+.B sg_luns
+[\fI--decode\fR] [\fI--help\fR] [\fI--select=<n>\fR] [\fI--verbose\fR]
+[\fI--version\fR] \fI<scsi_device>\fR
+.SH DESCRIPTION
+.\" Add any additional description here
+.PP
+Send REPORT LUNS command to a Linux SCSI device and output the response.
+In the recent SCSI draft standard SPC-3 device support for this command
+is mandatory.
+.TP
+--decode | -d
+decode logical unit numbers into their hierarchical parts. Interprets
+luns as described in SAM-3 (rev 14) when the HiSup bit is set in a
+standard INQUIRY's response.
+.TP
+--help | -h
+output the usage message then exit.
+.TP
+--select=<n> | -s <n>
+this option sets the 'select report' field in the SCSI REPORT LUNS command.
+The default value is 0. When 0 is given (or this option is not specified)
+then the given device should yield a list of luns addressable via
+this "I_T nexus" that use the following lun addressing methods: logical
+unit addressing, peripheral device addressing and flat space addressing.
+When 1 is given the given device should yield a list of only "well known"
+logical units addressable via this "I_T" nexus. When 2 is given the given
+device should yield all luns addressable via this "I_T" nexus. Currently
+SPC-3 (rev 21) doesn't specify any other values.
+.TP
+--verbose | -v
+increase the level of verbosity, (i.e. debug output).
+.TP
+--version | -V
+print the version string and then exit.
+.SH AUTHORS
+Written by Douglas Gilbert.
+.SH "REPORTING BUGS"
+Report bugs to <dgilbert at interlog dot com>.
+.SH COPYRIGHT
+Copyright \(co 2004 Douglas Gilbert
+.br
+This software is distributed under a FreeBSD license. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.SH "SEE ALSO"
+.B sg_inq
diff --git a/sg_luns.c b/sg_luns.c
new file mode 100644
index 00000000..1b966da3
--- /dev/null
+++ b/sg_luns.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2004 Douglas Gilbert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "sg_include.h"
+#include "sg_lib.h"
+#include "sg_cmds.h"
+
+/* A utility program for the Linux OS SCSI subsystem.
+ *
+ *
+ * This program issues the SCSI command REPORT LUNS to the given SCSI device.
+ */
+
+static char * version_str = "1.01 20041028";
+
+#define REPORT_LUNS_BUFF_LEN 1024
+
+#define ME "sg_luns: "
+
+
+static struct option long_options[] = {
+ {"decode", 0, 0, 'd'},
+ {"help", 0, 0, 'h'},
+ {"select", 1, 0, 's'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+static void usage()
+{
+ fprintf(stderr, "Usage: "
+ "sg_luns [--decode] [--help] [--select=<n>] [--verbose] "
+ "[--version]\n"
+ " <scsi_device>\n"
+ " where: --decode|-d decode all luns into parts\n"
+ " --help|-h print out usage message\n"
+ " --select=<n>|-s <n> select report <n> (def: 0)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n"
+ );
+
+}
+
+/* Decoded according to SAM-3 rev 14. Note that one draft: BCC rev 0,
+ * defines its own "bridge addressing method" in place of the
+ * SAM-3 "logical addressing method". */
+static void decode_lun(const char * leadin, unsigned char * lunp)
+{
+ int k, j, x, a_method, bus_id, target, lun, len, e_a_method, next_level;
+ unsigned char not_spec[8] = {0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff};
+ char l_leadin[128];
+ unsigned long long ull;
+
+ if (0 == memcmp(lunp, not_spec, sizeof(not_spec))) {
+ printf("%sLogical unit not specified\n", leadin);
+ return;
+ }
+ memset(l_leadin, 0, sizeof(l_leadin));
+ for (k = 0; k < 4; ++k, lunp += 2) {
+ next_level = 0;
+ strncpy(l_leadin, leadin, sizeof(l_leadin) - 3);
+ if (k > 0) {
+ printf("%s>>%s level addressing:\n", l_leadin,
+ ((1 == k) ? "Second" : ((2 == k) ? "Third" : "Fourth")));
+ strcat(l_leadin, " ");
+ }
+ a_method = (lunp[0] >> 6) & 0x3;
+ switch (a_method) {
+ case 0: /* peripheral device addressing method */
+ bus_id = lunp[0] & 0x3f;
+ if (0 == bus_id)
+ printf("%sPeripheral device addressing: lun=%d\n",
+ l_leadin, lunp[1]);
+ else {
+ printf("%sPeripheral device addressing: bus_id=%d, "
+ "target=%d\n", l_leadin, bus_id, lunp[1]);
+ next_level = 1;
+ }
+ break;
+ case 1: /* flat space addressing method */
+ lun = ((lunp[0] & 0x3f) << 8) + lunp[1];
+ printf("%sFlat space addressing: lun=%d\n", l_leadin, lun);
+ break;
+ case 2: /* logical unit addressing method */
+ target = (lunp[0] & 0x3f);
+ bus_id = (lunp[1] >> 5) & 0x7;
+ lun = lunp[1] & 0x1f;
+ printf("%sLogical unit addressing: bus_id=%d, target=%d, "
+ "lun=%d\n", l_leadin, bus_id, target, lun);
+ break;
+ case 3: /* extended logical unit addressing method */
+ len = (lunp[0] & 0x30) >> 4;
+ e_a_method = lunp[0] & 0xf;
+ x = lunp[1];
+ if ((0 == len) && (1 == e_a_method)) {
+ switch (x) {
+ case 1:
+ printf("%sREPORT LUNS well known logical unit\n",
+ l_leadin);
+ break;
+ case 2:
+ printf("%sACCESS CONTROLS well known logical unit\n",
+ l_leadin);
+ break;
+ case 3:
+ printf("%sTARGET LOG PAGES well known logical unit\n",
+ l_leadin);
+ break;
+ default:
+ printf("%swell known logical unit %d\n", l_leadin, x);
+ break;
+ }
+ } else {
+ if (len < 2) {
+ if (1 == len)
+ x = (lunp[1] << 16) + (lunp[2] << 8) + lunp[3];
+ printf("%sExtended logical unit addressing: length=%d, "
+ "e. a. method=%d, value=0x%x\n", l_leadin, len,
+ e_a_method, x);
+ } else {
+ ull = 0;
+ x = (2 == len) ? 5 : 7;
+ for (j = 0; j < x; ++j) {
+ if (j > 0)
+ ull <<= 8;
+ ull |= lunp[1 + j];
+ }
+ printf("%sExtended logical unit addressing: length=%d, "
+ "e. a. method=%d, value=0x%llx\n", l_leadin, len,
+ e_a_method, ull);
+ }
+ }
+ break;
+ default:
+ printf("%s<<decode_lun: faulty logic>>\n", l_leadin);
+ break;
+ }
+ if (next_level)
+ continue;
+ if ((2 == a_method) && (k < 3) && (lunp[2] || lunp[3]))
+ printf("%s<<unexpected data at next level, continue>>\n",
+ l_leadin);
+ break;
+ }
+}
+
+int main(int argc, char * argv[])
+{
+ int sg_fd, k, m, off, res, c, list_len, luns, trunc;
+ unsigned char reportLunsBuff[REPORT_LUNS_BUFF_LEN];
+ int decode = 0;
+ int select_rep = 0;
+ int verbose = 0;
+ char device_name[256];
+ int ret = 1;
+
+ memset(device_name, 0, sizeof device_name);
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "dhs:vV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'd':
+ decode = 1;
+ break;
+ case 'h':
+ case '?':
+ usage();
+ return 0;
+ case 's':
+ if ((1 != sscanf(optarg, "%d", &select_rep)) ||
+ (select_rep < 0) || (select_rep > 255)) {
+ fprintf(stderr, "bad argument to '--select'\n");
+ return 1;
+ }
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'V':
+ fprintf(stderr, ME "version: %s\n", version_str);
+ return 0;
+ default:
+ fprintf(stderr, "unrecognised switch code 0x%x ??\n", c);
+ usage();
+ return 1;
+ }
+ }
+ if (optind < argc) {
+ if ('\0' == device_name[0]) {
+ strncpy(device_name, argv[optind], sizeof(device_name) - 1);
+ device_name[sizeof(device_name) - 1] = '\0';
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return 1;
+ }
+ }
+
+ if (0 == device_name[0]) {
+ fprintf(stderr, "missing device name!\n");
+ usage();
+ return 1;
+ }
+ sg_fd = open(device_name, O_RDWR);
+ if (sg_fd < 0) {
+ perror(ME "open error");
+ return 1;
+ }
+
+ memset(reportLunsBuff, 0x0, sizeof(reportLunsBuff));
+ trunc = 0;
+
+ res = sg_ll_report_luns(sg_fd, select_rep, reportLunsBuff,
+ sizeof(reportLunsBuff), 1, verbose);
+ if (0 == res) {
+ list_len = (reportLunsBuff[0] << 24) + (reportLunsBuff[1] << 16) +
+ (reportLunsBuff[2] << 8) + reportLunsBuff[3];
+ luns = (list_len / 8);
+ printf("Lun list length = %d which imples %d lun entr%s\n",
+ list_len, luns, ((1 == luns) ? "y" : "ies"));
+ if ((list_len + 8) > (int)sizeof(reportLunsBuff)) {
+ luns = ((sizeof(reportLunsBuff) - 8) / 8);
+ trunc = 1;
+ printf(" <<too many luns for internal buffer, will show %d "
+ "luns>>\n", luns);
+ }
+ if (verbose) {
+ fprintf(stderr, "\nOutput response in hex\n");
+ dStrHex((const char *)reportLunsBuff,
+ (trunc ? (int)sizeof(reportLunsBuff) : list_len + 8), 1);
+ }
+ for (k = 0, off = 8; k < luns; ++k) {
+ if (0 == k)
+ printf("Report luns [select_report=%d]:\n", select_rep);
+ printf(" ");
+ for (m = 0; m < 8; ++m, ++off)
+ printf("%02x", reportLunsBuff[off]);
+ printf("\n");
+ if (decode)
+ decode_lun(" ", reportLunsBuff + off - 8);
+ }
+ ret = 0;
+ } else if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, "Report Luns command not supported (support "
+ "mandatory in SPC-3)\n");
+
+ res = close(sg_fd);
+ if (res < 0) {
+ perror(ME "close error");
+ return 1;
+ }
+ return ret;
+}
diff --git a/sg_persist.8 b/sg_persist.8
index 12be40f8..d0095e63 100644
--- a/sg_persist.8
+++ b/sg_persist.8
@@ -22,8 +22,8 @@ READ RESERVATION, REPORT CAPABILITIES and READ FULL STATUS.
.PP
Before trying to change Persistent reservations and registrations users
should be aware of what they are doing! The relevant sections of the
-SCSI Primary Commands document (SPC-3 most recent draft revision 20a
-dated 17th August 2004) are sections 5.6 (general information), 6.11 (for
+SCSI Primary Commands document (SPC-3 most recent draft revision 21
+dated 22nd September 2004) are sections 5.6 (general information), 6.11 (for
PRIN) and 6.12 (for PROUT). To safeguard against accidental use,
the '--out' option must be given when a PROUT sub-command (e.g. '--register')
is used.
@@ -47,7 +47,8 @@ the potential confusion the term "sub-command" has been introduced.
--clear | -C
Clear is a sub-command of the PROUT command. It releases the
persistent reservation (if any) and clears all registrations from the
-device. [Typically also requires the --param-rk=<h> option.]
+device. It is required to supply a reservation key that is registered
+for this I_T_L nexus (identified by --param-rk).
.TP
--device=<scsi_device> | -d <scsi_device>
This utility needs to have a scsi_device to be specified. This can either
@@ -98,16 +99,16 @@ Default value is 0. This option is needed by some PROUT sub-commands.
--preempt | -P
Preempt is a sub-command of the PROUT command. Preempts
the existing persistent reservation (identified by '--param-sark') with
-the current I_T_L nexus (identified by '--param-rk'). The
-associated '--prout-type<h>' option needs to match the type of the
-reservation.
+the registration key that is registered for this I_T_L nexus (identified
+by '--param-rk'). The associated '--prout-type<h>' option needs to match
+the type of the reservation.
.TP
--preempt-abort | -A
Preempt and Abort is a sub-command of the PROUT command. Preempts
the existing persistent reservation (identified by '--param-sark') with
-the current I_T_L nexus (identified by '--param-rk'). The
-associated '--prout-type<h>' option needs to match the type of the
-reservation. ACA and other pending tasks are aborted.
+the registration key that is registered for this I_T_L nexus (identified
+by '--param-rk'). The associated '--prout-type<h>' option needs to match
+the type of the reservation. ACA and other pending tasks are aborted.
.TP
--prout-type=<h> | -T <h>
specify the PROUT command's 'type' argument. Required by
diff --git a/sg_readcap.c b/sg_readcap.c
index 9cd77800..323413d6 100644
--- a/sg_readcap.c
+++ b/sg_readcap.c
@@ -27,7 +27,7 @@
*/
-static char * version_str = "3.67 20041011";
+static char * version_str = "3.68 20041024";
#define ME "sg_readcap: "
@@ -90,7 +90,7 @@ int main(int argc, char * argv[])
lba = (unsigned int)llba;
}
else if (0 == strcmp("-v", argv[k]))
- ++verbose;
+ ++verbose;
else if (0 == strcmp("-V", argv[k])) {
printf("Version string: %s\n", version_str);
exit(0);
@@ -127,14 +127,13 @@ int main(int argc, char * argv[])
}
if (! do16) {
- // res = do_readcap_10(sg_fd, pmi, lba, &last_blk_addr, &block_size);
res = sg_ll_readcap_10(sg_fd, pmi, lba, resp_buff, RCAP_REPLY_LEN,
- verbose);
- if (0 == res) {
- last_blk_addr = ((resp_buff[0] << 24) | (resp_buff[1] << 16) |
- (resp_buff[2] << 8) | resp_buff[3]);
- if (0xffffffff != last_blk_addr) {
- block_size = ((resp_buff[4] << 24) | (resp_buff[5] << 16) |
+ verbose);
+ if (0 == res) {
+ last_blk_addr = ((resp_buff[0] << 24) | (resp_buff[1] << 16) |
+ (resp_buff[2] << 8) | resp_buff[3]);
+ if (0xffffffff != last_blk_addr) {
+ block_size = ((resp_buff[4] << 24) | (resp_buff[5] << 16) |
(resp_buff[6] << 8) | resp_buff[7]);
printf("Read Capacity results:\n");
if (pmi)
@@ -142,8 +141,8 @@ int main(int argc, char * argv[])
"delay=0x%x\n", lba, last_blk_addr);
else
printf(" Last block address=%u (0x%x), Number of "
- "blocks=%u\n", last_blk_addr, last_blk_addr,
- last_blk_addr + 1);
+ "blocks=%u\n", last_blk_addr, last_blk_addr,
+ last_blk_addr + 1);
printf(" Block size = %u bytes\n", block_size);
if (! pmi) {
unsigned long long total_sz = last_blk_addr + 1;
@@ -158,9 +157,9 @@ int main(int argc, char * argv[])
printf(" Device size: %llu bytes, %.1f MB, %.2f GB\n",
total_sz, sz_mb, sz_gb);
}
- }
+ }
}
- else if (0 == res) {
+ else if (SG_LIB_CAT_INVALID_OP == res) {
do16 = 1;
close(sg_fd);
if ((sg_fd = open(file_name, O_RDWR)) < 0) {
@@ -169,23 +168,25 @@ int main(int argc, char * argv[])
perror(ebuff);
return 1;
}
- }
+ if (verbose)
+ fprintf(stderr, "READ CAPACITY (10) not supported, trying "
+ "READ CAPACITY (16)\n");
+ } else if (verbose)
+ fprintf(stderr, "READ CAPACITY (10) failed [res=%d]\n", res);
}
if (do16) {
- // res = do_readcap_16(sg_fd, pmi, llba, &llast_blk_addr, &block_size,
- // &byte12);
res = sg_ll_readcap_16(sg_fd, pmi, llba, resp_buff, RCAP16_REPLY_LEN,
verbose);
if (0 == res) {
- for (k = 0, llast_blk_addr = 0; k < 8; ++k) {
- llast_blk_addr <<= 8;
- llast_blk_addr |= resp_buff[k];
- }
- block_size = ((resp_buff[8] << 24) | (resp_buff[9] << 16) |
+ for (k = 0, llast_blk_addr = 0; k < 8; ++k) {
+ llast_blk_addr <<= 8;
+ llast_blk_addr |= resp_buff[k];
+ }
+ block_size = ((resp_buff[8] << 24) | (resp_buff[9] << 16) |
(resp_buff[10] << 8) | resp_buff[11]);
printf("Read Capacity results:\n");
printf(" Protection: prot_en=%d, rto_en=%d\n",
- (resp_buff[12] & 0x1), ((resp_buff[12] & 0x2) ? 1 : 0));
+ (resp_buff[12] & 0x1), ((resp_buff[12] & 0x2) ? 1 : 0));
if (pmi)
printf(" PMI mode: given lba=0x%llx, last block before "
"delay=0x%llx\n", llba, llast_blk_addr);
@@ -208,6 +209,10 @@ int main(int argc, char * argv[])
total_sz, sz_mb, sz_gb);
}
}
+ else if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, "READ CAPACITY (16) not supported\n");
+ else if (verbose)
+ fprintf(stderr, "READ CAPACITY (16) failed [res=%d]\n", res);
}
close(sg_fd);
return 0;
diff --git a/sg_requests.c b/sg_requests.c
index 5cfad82b..44b4b65e 100644
--- a/sg_requests.c
+++ b/sg_requests.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2004 Douglas Gilbert.
+ * Copyright (c) 2004 Douglas Gilbert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,7 +50,7 @@
* This program issues the SCSI command REQUEST SENSE to the given SCSI device.
*/
-static char * version_str = "1.02 20041015";
+static char * version_str = "1.03 20041026";
#define REQUEST_SENSE_BUFF_LEN 252
diff --git a/sg_ses.c b/sg_ses.c
index e44e7579..25fa868c 100644
--- a/sg_ses.c
+++ b/sg_ses.c
@@ -50,7 +50,7 @@
* tailored for SES (enclosure) devices.
*/
-static char * version_str = "1.07 20041015";
+static char * version_str = "1.08 20041026";
#define SEND_DIAGNOSTIC_CMD 0x1d
#define SEND_DIAGNOSTIC_CMDLEN 6
@@ -103,7 +103,8 @@ static void usage()
" --hex|-H print status response in hex\n"
" --inner-hex|-i print innermost level of a"
" status page in hex\n"
- " --list|-l list pages and elements then exit\n"
+ " --list|-l list known pages and elements (ignore"
+ " device)\n"
" --page=<n>|-p <n> page code value <n> (def: 0)\n"
" --raw|-r print status page in hex suitable "
"for '-d'\n"
@@ -1451,7 +1452,7 @@ int main(int argc, char * argv[])
switch (c) {
case 'b':
byte1 = sg_get_num(optarg);
- if ((byte1 < 0) && (byte1 > 255)) {
+ if ((byte1 < 0) || (byte1 > 255)) {
fprintf(stderr, "bad argument to '--byte1' (0 to 255 "
"inclusive)\n");
return 1;
@@ -1486,7 +1487,7 @@ int main(int argc, char * argv[])
break;
case 'p':
page_code = sg_get_num(optarg);
- if ((page_code < 0) && (page_code > 255)) {
+ if ((page_code < 0) || (page_code > 255)) {
fprintf(stderr, "bad argument to '--page' (0 to 255 "
"inclusive)\n");
return 1;
diff --git a/sg_start.c b/sg_start.c
index 0867e295..80bc0f6c 100644
--- a/sg_start.c
+++ b/sg_start.c
@@ -31,7 +31,7 @@
*/
-static char * version_str = "0.38 20041011";
+static char * version_str = "0.39 20041029";
#define START_STOP 0x1b
@@ -186,7 +186,7 @@ int main(int argc, char * argv[])
}
if (synccache)
- sg_ll_sync_cache(fd, 0, 0, verbose);
+ sg_ll_sync_cache(fd, 0, 0, 1, verbose);
if (power_conds > 0)
do_start_stop(fd, 0, immed, 0, power_conds, verbose);
diff --git a/sg_turs.c b/sg_turs.c
index b50f97cd..aa977e4c 100644
--- a/sg_turs.c
+++ b/sg_turs.c
@@ -11,6 +11,7 @@
#include <sys/time.h>
#include "sg_include.h"
#include "sg_lib.h"
+#include "sg_cmds.h"
/* This program sends a user specified number of TEST UNIT READY commands
to the given sg device. Since TUR is a simple command involing no
@@ -25,21 +26,16 @@
*/
-static char * version_str = "3.12 20041011";
+static char * version_str = "3.13 20041029";
-#define TUR_CMD_LEN 6
#define EBUFF_SZ 256
int main(int argc, char * argv[])
{
int sg_fd, k;
- unsigned char turCmdBlk [TUR_CMD_LEN] =
- {0x00, 0, 0, 0, 0, 0};
- struct sg_io_hdr io_hdr;
char * file_name = 0;
char ebuff[EBUFF_SZ];
- unsigned char sense_buffer[32];
int num_turs = 1;
int num_errs = 0;
int do_time = 0;
@@ -94,40 +90,15 @@ int main(int argc, char * argv[])
perror(ebuff);
return 1;
}
- /* Prepare TEST UNIT READY command */
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(turCmdBlk);
- io_hdr.mx_sb_len = sizeof(sense_buffer);
- io_hdr.dxfer_direction = SG_DXFER_NONE;
- io_hdr.cmdp = turCmdBlk;
- io_hdr.sbp = sense_buffer;
- io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
- if (verbose) {
- fprintf(stderr, " Test unit ready cmd: ");
- for (k = 0; k < TUR_CMD_LEN; ++k)
- fprintf(stderr, "%02x ", turCmdBlk[k]);
- fprintf(stderr, "\n");
- }
if (do_time) {
start_tm.tv_sec = 0;
start_tm.tv_usec = 0;
gettimeofday(&start_tm, NULL);
}
for (k = 0; k < num_turs; ++k) {
- io_hdr.pack_id = k;
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("sg_turs: Test Unit Ready SG_IO ioctl error");
- close(sg_fd);
- return 1;
- }
- if (io_hdr.info & SG_INFO_OK_MASK) {
+ if (sg_ll_test_unit_ready(sg_fd, k, ((1 == num_turs) ? 1 : 0),
+ verbose))
++num_errs;
- if (1 == num_turs) { /* then print out the error message */
- if (SG_LIB_CAT_CLEAN != sg_err_category3(&io_hdr))
- sg_chk_n_print3("tur", &io_hdr);
- }
- }
}
if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
struct timeval res_tm;
@@ -154,5 +125,5 @@ int main(int argc, char * argv[])
printf("Completed %d Test Unit Ready commands with %d errors\n",
num_turs, num_errs);
close(sg_fd);
- return 0;
+ return num_errs ? 1 : 0;
}
diff --git a/sgm_dd.8 b/sgm_dd.8
index 0af3cbc3..64fb4932 100644
--- a/sgm_dd.8
+++ b/sgm_dd.8
@@ -40,8 +40,8 @@ to 16 byte SCSI commands).
count=BLOCKS
copy this number of blocks from 'if' to 'of'. Default is the
minimum (of 'if' and 'of') number of blocks that sg devices return from
-READ CAPACITY SCSI commands or that block devices report.
-Normal files are not probed for their size. If 'skip'
+READ CAPACITY SCSI commands or that block devices (or their partitions)
+report. Normal files are not probed for their size. If 'skip'
or 'seek' are given and the count is derived (i.e. not explicitly given)
then the derived count is scaled back so that the copy will not overrun the
device. If the file name is a block device partition and count is not given
@@ -105,8 +105,6 @@ for more information about binding raw devices. To be safe, the sg device
mapping to SCSI block devices should be checked with "cat /proc/scsi/scsi"
before use.
.PP
-The count is only deduced for sg devices (minimum > 0 if both input and
-output are sg devices) otherwise it defaults to 0. This is for safety!
Raw device partition information can often be found with
.B fdisk(8)
[the "-ul" argument is useful in this respect].
diff --git a/sgm_dd.c b/sgm_dd.c
index d7933365..b16fb62e 100644
--- a/sgm_dd.c
+++ b/sgm_dd.c
@@ -57,7 +57,7 @@
This version is designed for the linux kernel 2.4 and 2.6 series.
*/
-static char * version_str = "1.14 20041011";
+static char * version_str = "1.15 20041029";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -74,7 +74,7 @@ static char * version_str = "1.14 20041011";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
#define READ_CAP_REPLY_LEN 8
-#define RCAP16_REPLY_LEN 12
+#define RCAP16_REPLY_LEN 32
#ifndef SERVICE_ACTION_IN
#define SERVICE_ACTION_IN 0x9e
@@ -1018,11 +1018,11 @@ int main(int argc, char * argv[])
if (do_sync) {
if (FT_SG == out_type) {
fprintf(stderr, ">> Synchronizing cache on %s\n", outf);
- res = sg_ll_sync_cache(outfd, 0, 0, 0);
+ res = sg_ll_sync_cache(outfd, 0, 0, 0, 0);
if (2 == res) {
fprintf(stderr,
"Unit attention, media changed(in), continuing\n");
- res = sg_ll_sync_cache(outfd, 0, 0, 0);
+ res = sg_ll_sync_cache(outfd, 0, 0, 0, 0);
}
if (0 != res)
fprintf(stderr, "Unable to synchronize cache\n");
diff --git a/sgp_dd.8 b/sgp_dd.8
index 4fcb7e3c..a88748e2 100644
--- a/sgp_dd.8
+++ b/sgp_dd.8
@@ -1,4 +1,4 @@
-.TH SGP_DD "8" "August 2004" "sg3_utils-1.08" SG3_UTILS
+.TH SGP_DD "8" "October 2004" "sg3_utils-1.10" SG3_UTILS
.SH NAME
sgp_dd \- copies data to and from files and devices. Specialised for
devices that understand the SCSI command set.
@@ -43,9 +43,9 @@ Similar to "conv=noerror" in
utility. Default is 0 which implies stop on error
.TP
count=BLOCKS
-copy this number of blocks from 'if' to 'of'. Default is the
-minimum (of 'if' and 'of') number of blocks that sg devices return from
-READ CAPACITY SCSI commands or that block devices report.
+copy this number of blocks from 'if' to 'of'. Default is the minimum (
+of 'if' and 'of') number of blocks that sg devices return from READ
+CAPACITY SCSI commands or that block devices (or their partitions) report.
Normal files are not probed for their size. If 'skip'
or 'seek' are given and the count is derived (i.e. not explicitly given)
then the derived count is scaled back so that the copy will not overrun the
@@ -116,8 +116,6 @@ for more information about binding raw devices. To be safe, the sg device
mapping to SCSI block devices should be checked with "cat /proc/scsi/scsi"
before use.
.PP
-The count is only deduced for sg devices (minimum > 0 if both input and
-output are sg devices) otherwise it defaults to 0. This is for safety!
Raw device partition information can often be found with
.B fdisk(8)
[the "-ul" argument is useful in this respect].
diff --git a/sgp_dd.c b/sgp_dd.c
index 5bdf7068..049a91db 100644
--- a/sgp_dd.c
+++ b/sgp_dd.c
@@ -52,7 +52,7 @@
*/
-static char * version_str = "5.18 20041011";
+static char * version_str = "5.19 20041029";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -65,7 +65,7 @@ static char * version_str = "5.18 20041011";
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
#define READ_CAP_REPLY_LEN 8
-#define RCAP16_REPLY_LEN 12
+#define RCAP16_REPLY_LEN 32
#ifndef SERVICE_ACTION_IN
#define SERVICE_ACTION_IN 0x9e
@@ -1325,11 +1325,11 @@ int main(int argc, char * argv[])
if (do_sync) {
if (FT_SG == rcoll.out_type) {
fprintf(stderr, ">> Synchronizing cache on %s\n", outf);
- res = sg_ll_sync_cache(rcoll.outfd, 0, 0, 0);
+ res = sg_ll_sync_cache(rcoll.outfd, 0, 0, 0, 0);
if (2 == res) {
fprintf(stderr,
"Unit attention, media changed(in), continuing\n");
- res = sg_ll_sync_cache(rcoll.outfd, 0, 0, 0);
+ res = sg_ll_sync_cache(rcoll.outfd, 0, 0, 0, 0);
}
if (0 != res)
fprintf(stderr, "Unable to synchronize cache\n");