aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2009-08-24 23:11:14 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2009-08-24 23:11:14 +0000
commitc6737e9da997d3dac104a489a8c79459ba43e099 (patch)
treed440e7d5716dbb820b8b131f79102d3d2976ccc7
parentde29bd3c4d8f6c98c8b1ec6c0b0bb28733181b24 (diff)
downloadsg3_utils-c6737e9da997d3dac104a489a8c79459ba43e099.tar.gz
sg_persist: tranport specific transportIDs, read transportIDs from file; add Progress indication sense data descriptor
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@290 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog5
-rw-r--r--README2
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg_persist.8129
-rw-r--r--examples/transport_ids.txt44
-rw-r--r--lib/sg_lib.c12
-rw-r--r--lib/sg_lib_data.c2
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/sg_persist.c446
9 files changed, 452 insertions, 192 deletions
diff --git a/ChangeLog b/ChangeLog
index 117b41b7..589d65ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,12 +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. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.28 [20090818] [svn: r289]
+Changelog for sg3_utils-1.28 [20090824] [svn: r290]
- sg_unmap: new utility for thin provisioning
- add examples/sg_unmap_example.txt
- sg_read_block_limits: new utility for tape drives
- sg_logs: add cache memory statistics log (sub)page
- sg_vpd, sg_inq: extend Block limits VPD page (sbc3r19)
+ - sg_persist: add transport specific transportID format
+ - allow transportIDs to be read from named file
- sg_opcodes: allow --opcode= option to take OP and SA
values (comma seperated)
- tweak print format, remove test code
@@ -17,6 +19,7 @@ Changelog for sg3_utils-1.28 [20090818] [svn: r289]
- sg_raw: extend max cdb length from 16 to 256 bytes
- align heap allocs to page boundaries
- sg_lib: sg_set_binary_mode() needs config.h included
+ - add progress indication sense data descriptor (0xa)
- change SG3_UTILS_* constants to SG_LIB_*
- decode service actions within persistent reserve in/out
- sync with spc4r20
diff --git a/README b/README
index bb362ad6..2b4833a2 100644
--- a/README
+++ b/README
@@ -338,4 +338,4 @@ See http://sg.danny.cz/sg/tools.html
Doug Gilbert
-18th August 2009
+24th August 2009
diff --git a/debian/changelog b/debian/changelog
index 668e942b..7b6a633e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.28-0.1) unstable; urgency=low
* New upstream version
- -- Doug Gilbert <dgilbert@interlog.com> Tue, 18 Aug 2009 19:30:00 -0400
+ -- Doug Gilbert <dgilbert@interlog.com> Mon, 28 Aug 2009 19:00:00 -0400
sg3-utils (1.27-0.1) unstable; urgency=low
diff --git a/doc/sg_persist.8 b/doc/sg_persist.8
index 8d159a23..faf22c4b 100644
--- a/doc/sg_persist.8
+++ b/doc/sg_persist.8
@@ -1,4 +1,4 @@
-.TH SG_PERSIST "8" "April 2009" "sg3_utils\-1.27" SG3_UTILS
+.TH SG_PERSIST "8" "August 2009" "sg3_utils\-1.28" SG3_UTILS
.SH NAME
sg_persist \- sends a SCSI PERSISTENT RESERVE (IN or OUT) command
to manipulate registrations and reservations
@@ -36,7 +36,7 @@ READ RESERVATION, REPORT CAPABILITIES and READ FULL STATUS.
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 (i.e. SPC\-4 whose most recent draft is
-revision 18 dated 18 February 2009) are sections 5.7 (titled "Reservations"),
+revision 20 dated 22 May 2009) are sections 5.7 (titled "Reservations"),
6.13 (for the PRIN command) and 6.14 (for the PROUT command). To safeguard
against accidental use, the \fI\-\-out\fR option must be given when a
PROUT sub\-command (e.g. \fI\-\-register\fR) is used.
@@ -213,32 +213,16 @@ Reserve is a sub\-command of the PROUT command. It creates a new
persistent reservation (if permitted). The \fI\-\-prout\-type=TYPE\fR
and \fI\-\-param\-rk=RK\fR options must also be specified.
.TP
-\fB\-X\fR, \fB\-\-transport\-id\fR=\fIH,H...\fR
-a transportID is required for the PROUT 'register and move' sub\-command
-and is optional for the PROUT 'register' and 'register and ignore
-existing key' sub\-commands. The latter two sub\-commands can take multiple
-transportIDs in a list but only one is supported with this option
-variant (use the \fI\-\-transport\-id=\-\fR variant if multiple
-transportIDs are required). \fIH,H...\fR is a comma separated list of hex
-bytes which represent the transportID. A (single) space separated list
-of hex bytes is also allowed but the list needs to be in quotes. The list
-of hex numbers will be padded out with zeros to 24 bytes which is the
-minimum length of a transportID. A transportID longer than 24 bytes (e.g.
-for iSCSI) is padded with zeros so its length is a multiple of 4.
-.TP
-\fB\-X\fR, \fB\-\-transport\-id=\-\fR
-a transportID is required for the PROUT 'register and move' sub\-command
-and is optional for the PROUT 'register' and 'register and ignore
-existing key' sub\-commands. The latter two sub\-commands can take multiple
-transportIDs in a list. The option argument of '\-' indicates that
-stdin should be read for the transportID(s). Empty lines are ignored.
-Everything from and including a "#" on a line is ignored.
-Leading spaces and tabs are ignored. All numbers
-are assumed to be hexadecimal and can be separated by space, comma or
-tab. There can be one transportID per line. TranportIDs will be padded
-out with zeros to 24 bytes which is the minimum length of a
-transportID. A transportID longer than 24 bytes (e.g. for iSCSI) is
-padded with zeros so its length is a multiple of 4.
+\fB\-X\fR, \fB\-\-transport\-id\fR=\fITIDS\fR
+The \fITIDS\fR argument can take one of several forms. It can be a
+comma (or single space) separated list of ASCII hex bytes representing
+a single TransportID as defined in SPC\-4. They are usually 24 bytes
+long apart from in iSCSI. The \fITIDS\fR argument may be a transport
+specific form (e.g. "sas,5000c50005b32001"). The \fITIDS\fR argument
+may be "-" in which case one or more TransportIDs can be read from stdin.
+The \fITIDS\fR argument may be of the form "file=<name>" in which case
+one or more TransportIDs can be read from a file called <name>. See
+the "TRANSPORT IDs" section below for more information.
.TP
\fB\-U\fR, \fB\-\-unreg\fR
optional when the PROUT register and move sub\-command is invoked. If given
@@ -258,11 +242,69 @@ print out version string. Ignore all other parameters.
.TP
\fB\-?\fR
output usage message. Ignore all other parameters.
+.SH TRANSPORT IDs
+TransportIDs are used in persistent reservations to identify initiators.
+The format of a TransportID differs depending on the type of transport
+being used. Their format is described in SPC\-4 (in draft revision
+20 see section 7.5.4).
+.PP
+A TransportID is required for the PROUT 'register and move' sub\-command and
+the PROUT 'register' sub\-command can have zero, one or more TransportIDs.
+.PP
+When the \fI\-\-transport\-id=TIDS\fR option is given then the \fITIDS\fR
+argument may be a comma (or single space) separated list of ASCII hex bytes
+that represent a single TransportID as defined in SPC\-4. Alternatively the
+\fITIDS\fR argument may be a transport specific string starting with
+either "fcp,", "spi,", "sbp,", "srp,", "iqn", or "sas,". The "iqn" form is
+an iSCSI qualified name. Apart from "iqn" the other transport specific
+leadin string may be given in upper case (e.g. "FCP,").
+.PP
+The "fcp," form should be followed by 16 ASCII hex digits that represent an
+initiator's N_PORT_NAME. The "spi," form should be followed
+by "<scsi_address>,<relative_target_port_identifier>" (both decimal numbers).
+The "sbp," form should be followed by 16 ASCII hex digits that represent an
+initiator's EUI-64 name. The "srp," form should be followed by 32 ASCII hex
+digits that represent an initiator port identifier. The "sas," form should be
+followed by 16 ASCII hex digits that represent an initiator's port SAS
+address.
+.PP
+There are two iSCSI qualified name forms. The shorter form contains the
+iSCSI name of the initiator
+port (e.g. "iqn.5886.com.acme.diskarrays-sn-a8675309"). The longer form adds
+the initiator session id (ISID in hex) separated by ",i,0x".
+For example "iqn.5886.com.acme.diskarrays-sn-a8675309,i,0x1234567890ab".
+On the command line to stop punctuation in an iSCSI name being (mis)-
+interpreted by the shell, putting the option argument containing the iSCSI
+name in double quotes is advised. iSCSI names are encoded in UTF-8 so if
+non (7 bit) ASCII characters appear in the iSCSI name on the command line,
+there will be difficulties if they are not encoded in UTF-8. The locale can
+be changed temporarily by prefixing the command line invocation of
+sg_persist with "LANG=en_US.utf-8" for example.
+.PP
+Alternatively the \fITIDS\fR argument may specify a file (or pipe) from which
+one or more TransportIDs may be read. If the \fITIDS\fR argument is "-"
+then stdin (standard input) is read. If the \fITIDS\fR argument is of the
+form "file=<name>" than a file called <name> is read.
+A valid SPC\-4 TransportID is built from the transport specific string
+outlined in the previous paragraphs. The parsing of the data read is
+realtively simple. Empty lines are ignored. Everything from and including
+a "#" on a line is ignored. Leading spaces and tabs are ignored. There
+can be one transportID per line. The transportID can either be a comma,
+space or tab separated list of ASCII hex bytes that represent a
+TransportID as defined in SPC\-4. Padding with zero bytes to a minimum
+length of 24 bytes is performed if necessary. The transportID may also
+be transport specific string type discussed above.
+.PP
+In SPC\-3 the SPEC_I_PT bit set to one and TransportIDs were allowed for
+the PROUT register and ignore existing key sub\-command. In SPC\-4 that
+is disallowed yielding a CHECK CONDITION status with and ILLEGAL REQUEST
+sense key and an additional sense code set to INVALID FIELD IN PARAMETER
+LIST.
.SH NOTES
In the 2.4 series of Linux kernels the \fIDEVICE\fR must be
a SCSI generic (sg) device. In the 2.6 series any SCSI device
name (e.g. /dev/sdc, /dev/st1m or /dev/sg3) can be specified.
-For example "sg_persist \-\-read\-keys /dev/sda"
+For example "sg_persist \-\-read\-keys /dev/sdb"
will work in the 2.6 series kernels.
.PP
The only scope for PROUT commands supported in the current draft of
@@ -275,29 +317,33 @@ CONFLICT status. This can be a bit confusing when you know there is
only one (active) initiator: the "conflict" is with the SPC standard, not
another initiator.
.PP
-TransportIDs are defined in SPC\-4 and their structures differ depending
-on the transport.
+Some recent disks accept some PRIN and PROUT sub\-commands when the
+media is stopped. One exception was setting the APTPL flag (with
+the \fI\-\-param\-aptpl\fR option) during a key register operation,
+it complained if the disk one stopped. The error indicated it wanted
+the disk spun up and when that happened, the registration was
+successful.
.SH EXAMPLES
.PP
Due to defaults the simplest example executes the 'read keys' sub\-command
of the PRIN command:
.PP
- sg_persist /dev/sda
+ sg_persist /dev/sdb
.PP
This is the same as the following (long\-winded) command:
.PP
- sg_persist \-\-in \-\-read\-keys \-\-device=/dev/sda
+ sg_persist \-\-in \-\-read\-keys \-\-device=/dev/sdb
.PP
To read the current reservation either the '\-\-read\-reservation' form or
the shorter '\-r' can be used:
.PP
- sg_persist \-r /dev/sda
+ sg_persist \-r /dev/sdb
.PP
To
.B register
the new reservation key 0x123abc the following could be used:
.PP
- sg_persist \-\-out \-\-register \-\-param\-sark=123abc /dev/sda
+ sg_persist \-\-out \-\-register \-\-param\-sark=123abc /dev/sdb
.PP
Given the above registration succeeds, to
.B reserve
@@ -306,7 +352,7 @@ could be used:
.PP
sg_persist \-\-out \-\-reserve \-\-param\-rk=123abc
.br
- \-\-prout\-type=1 /dev/sda
+ \-\-prout\-type=1 /dev/sdb
.PP
To
.B release
@@ -316,7 +362,7 @@ reservation):
.PP
sg_persist \-\-out \-\-release \-\-param\-rk=123abc
.br
- \-\-prout\-type=1 /dev/sda
+ \-\-prout\-type=1 /dev/sdb
.PP
Finally to
.B unregister
@@ -324,14 +370,15 @@ a reservation key (and not effect other
registrations which is what '\-\-clear' would do) the command
is a little surprising:
.PP
- sg_persist \-\-out \-\-register \-\-param\-rk=123abc /dev/sda
+ sg_persist \-\-out \-\-register \-\-param\-rk=123abc /dev/sdb
.PP
Now have a close look at the difference between the register and
unregister examples above.
.PP
An example file that is suitably formatted to pass transportIDs via
-the '\-\-transport\-id=\-' option can be found in the examples sub\-directory
-of the sg3_utils package. That file is called 'transport_ids.txt'.
+a '\-\-transport\-id=file=transport_ids.txt' option can be found in the
+examples sub\-directory of the sg3_utils package. There is also a
+simple test script called sg_persist_tst.sh in the same directory.
.SH EXIT STATUS
The exit status of sg_persist is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
@@ -345,4 +392,4 @@ Copyright \(co 2004\-2009 Douglas Gilbert
This software is distributed under the GPL version 2. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
.SH "SEE ALSO"
-.B scsires(internet), examples/sg_persist_tst.sh(sg3_utils tarball)
+.B scsires(internet)
diff --git a/examples/transport_ids.txt b/examples/transport_ids.txt
index c84be7c0..0c604569 100644
--- a/examples/transport_ids.txt
+++ b/examples/transport_ids.txt
@@ -1,6 +1,6 @@
# This file is an example for the sg_persist utility.
# It discusses using "TransportID"s which are defined (most recently)
-# in SPC-4 revison 9 section 7.5.4 titled: "TransportID identifiers".
+# in SPC-4 revison 20 section 7.5.4 titled: "TransportID identifiers".
#
# The sg_persist utility can take one or more "transportID"s from stdin when
# either the '--transport-id=-" or "-X -" option is given on the command
@@ -10,32 +10,22 @@
# they are well formed) use the verbose flag 3 times (i.e. "... -vvv ...").
# Here is a simple example (for SPI) of a comma separted hex list:
-1,0,0,7,0,0,0,1 # SPI, initiator address=0x7, relative_port_num=1
+1,0,0,7,0,0,0,1 # SPI, initiator address=7, relative_port_num=1
- # Leading spaces and tabs before a '#' or ok
+# and here is the transport specific format for the same thing:
+# spi,1,7
+
+# An example for SAS follows, first as a hex string, then in transport
+# specific format (incremented by 1)
+6,0,0,0,50,6,5,b0,0,6,f2,60
+sas,500605b00006f261
+
+# For iSCSI the hex list form is awkward, better to use the transport
+# specific format. [The leading spaces are ignored.]
+ iqn.5886.com.acme.diskarrays-sn-a8675309
+
+
+ # Leading spaces and tabs before a '#' are ok.
-# Leading spaces and tabs are ignored as are redundant separators (space,
-# comma or tab).
-# 1,2 ,,,3,4,5,6,7,8,9
-
-# Playing around with an iSCSI transportID which is the only one defined
-# (in SPC-3 rev20) that can be more than 24 bytes in length.
-#5, 0, 0, 18, 41,42,43,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0
-
-# Just playing around with protocol identifiers that aren't defined
-#1c,22,33,44,55,66,77,88,99
-#a b , c d e f
-
-# 'report and move' requires one (and only one) transportID.
-# 'register' and 'register and ignore existing key' can optionally take
-# one or more transportIDs.
-
-# This file should work for something like this:
-# sg_persist --out --register-move --prout-type=1 --transport-id=-
-# --param-rk=111 --param-sark=fff --unreg
-# /dev/sda < examples/transport_ids.txt
-#
-# ... since there is only one line in this file that has a
-# transportID on it that will be decoded (i.e. the "SPI" one above).
-# dpg 20070223
+# dpg 20090824
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index acaa91c4..783f31e3 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -571,6 +571,18 @@ sg_get_sense_descriptors_str(const unsigned char * sense_buffer, int sb_len,
} else
processed = 0;
break;
+ case 0xa: /* Added in SPC-4 rev 17 */
+ n += sprintf(b + n, "Progress indication\n");
+ if (add_len < 6) {
+ 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);
+ n += sprintf(b + n, " [sense_key=0x%x asc,ascq=0x%x,0x%x]\n",
+ descp[2], descp[3], descp[4]);
+ break;
default:
n += sprintf(b + n, "Unknown or vendor specific [0x%x]\n",
descp[0]);
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index 55d5e988..90331975 100644
--- a/lib/sg_lib_data.c
+++ b/lib/sg_lib_data.c
@@ -37,7 +37,7 @@
#endif
-const char * sg_lib_version_str = "1.52 20090816"; /* spc-4 rev 20+ */
+const char * sg_lib_version_str = "1.53 20090824"; /* spc-4 rev 20+ */
struct sg_lib_value_name_t sg_lib_normal_opcodes[] = {
{0, 0, "Test Unit Ready"},
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 3d566a60..cf935de1 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -79,7 +79,7 @@ fi
%{_libdir}/*.la
%changelog
-* Tue Aug 18 2009 - dgilbert at interlog dot com
+* Mon Aug 24 2009 - dgilbert at interlog dot com
- add sg_unmap, sg_read_block_limits; sg_logs: cache memory stats lpage
* sg3_utils-1.28
diff --git a/src/sg_persist.c b/src/sg_persist.c
index 76dad174..bafaf097 100644
--- a/src/sg_persist.c
+++ b/src/sg_persist.c
@@ -27,7 +27,7 @@
*/
-static char * version_str = "0.36 20090402";
+static char * version_str = "0.37 20090824";
#define PRIN_RKEY_SA 0x0
@@ -43,6 +43,8 @@ static char * version_str = "0.36 20090402";
#define PROUT_REG_IGN_SA 0x6
#define PROUT_REG_MOVE_SA 0x7
#define MX_ALLOC_LEN 8192
+#define MX_TIDS 32
+#define MX_TID_LEN 256
struct opts_t {
unsigned int prout_type;
@@ -57,8 +59,7 @@ struct opts_t {
int param_unreg;
int inquiry;
int hex;
- unsigned char transportid_arr[MX_ALLOC_LEN];
- int transportid_arr_len;
+ unsigned char transportid_arr[MX_TIDS * MX_TID_LEN];
int num_transportids;
unsigned int alloc_len;
int verbose;
@@ -163,10 +164,10 @@ usage()
" --param-alltgpt|-Y PR Out parameter 'ALL_TG_PT'\n"
" --param-aptpl|-Z PR Out parameter 'APTPL'\n"
" --param-rk=RK|-K RK PR Out parameter reservation key\n"
- " (RK in hex)\n"
+ " (RK is in hex)\n"
" --param-sark=SARK|-S SARK PR Out parameter service "
"action\n"
- " reservation key (SARK in "
+ " reservation key (SARK is in "
"hex)\n"
" --preempt|-P PR Out: Preempt\n"
" --preempt-abort|-A PR Out: Preempt and Abort\n"
@@ -185,10 +186,9 @@ usage()
" --release|-L PR Out: Release\n"
" --report-capabilities|-c PR In: Report Capabilities\n"
" --reserve|-R PR Out: Reserve\n"
- " --transport-id=H,H...|-X H,H... TransportID "
- "hex number(s),\n"
- " comma separated list of bytes\n"
- " --transport-id=-|-X - read TransportID from stdin\n"
+ " --transport-id=TIDS|-X TIDS one or more "
+ "TransportIDs can\n"
+ " be given in several forms\n"
" --unreg|-U optional with PR Out Register "
"and Move\n"
" --verbose|-v output additional debug "
@@ -199,13 +199,16 @@ usage()
}
static void
-decode_transport_id(const char * leadin, unsigned char * ucp, int len)
+decode_transport_id(const char * leadin, unsigned char * ucp, int len,
+ int num_tids)
{
int format_code, proto_id, num, j, k;
uint64_t ull;
int bump;
- for (k = 0, bump = 24; k < len; k += bump, ucp += bump) {
+ if (num_tids > 0)
+ len = num_tids * MX_TID_LEN;
+ for (k = 0, bump = MX_TID_LEN; k < len; k += bump, ucp += bump) {
if ((len < 24) || (0 != (len % 4)))
printf("%sTransport Id short or not multiple of 4 "
"[length=%d]:\n", leadin, len);
@@ -220,7 +223,6 @@ decode_transport_id(const char * leadin, unsigned char * ucp, int len)
printf("%s [Unexpected format code: %d]\n", leadin,
format_code);
dStrHex((const char *)&ucp[8], 8, 0);
- bump = 24;
break;
case TPROTO_SPI: /* Parallel SCSI */
printf("%s Parallel SCSI initiator SCSI address: 0x%x\n",
@@ -230,13 +232,11 @@ decode_transport_id(const char * leadin, unsigned char * ucp, int len)
format_code);
printf("%s relative port number (of corresponding target): "
"0x%x\n", leadin, ((ucp[6] << 8) | ucp[7]));
- bump = 24;
break;
case TPROTO_SSA:
printf("%s SSA (transport id not defined):\n", leadin);
printf("%s format code: %d\n", leadin, format_code);
dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
- bump = 24;
break;
case TPROTO_1394: /* IEEE 1394 */
printf("%s IEEE 1394 EUI-64 name:\n", leadin);
@@ -244,7 +244,6 @@ decode_transport_id(const char * leadin, unsigned char * ucp, int len)
printf("%s [Unexpected format code: %d]\n", leadin,
format_code);
dStrHex((const char *)&ucp[8], 8, 0);
- bump = 24;
break;
case TPROTO_SRP:
printf("%s RDMA initiator port identifier:\n", leadin);
@@ -252,7 +251,6 @@ decode_transport_id(const char * leadin, unsigned char * ucp, int len)
printf("%s [Unexpected format code: %d]\n", leadin,
format_code);
dStrHex((const char *)&ucp[8], 16, 0);
- bump = 24;
break;
case TPROTO_ISCSI:
printf("%s iSCSI ", leadin);
@@ -260,12 +258,11 @@ decode_transport_id(const char * leadin, unsigned char * ucp, int len)
if (0 == format_code)
printf("name: %.*s\n", num, &ucp[4]);
else if (1 == format_code)
- printf("world wide unique port id: %.*s\n", num, &ucp[4]);
+ printf("name and session id: %.*s\n", num, &ucp[4]);
else {
printf(" [Unexpected format code: %d]\n", format_code);
dStrHex((const char *)ucp, num + 4, 0);
}
- bump = (((num + 4) < 24) ? 24 : num + 4);
break;
case TPROTO_SAS:
ull = 0;
@@ -274,30 +271,26 @@ decode_transport_id(const char * leadin, unsigned char * ucp, int len)
ull <<= 8;
ull |= ucp[4 + j];
}
- printf("%s SAS address: 0x%" PRIx64 "\n", leadin, ull);
+ printf("%s SAS address: 0x%016" PRIx64 "\n", leadin, ull);
if (0 != format_code)
printf("%s [Unexpected format code: %d]\n", leadin,
format_code);
- bump = 24;
break;
case TPROTO_ADT:
printf("%s ADT:\n", leadin);
printf("%s format code: %d\n", leadin, format_code);
dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
- bump = 24;
break;
case TPROTO_ATA:
printf("%s ATAPI:\n", leadin);
printf("%s format code: %d\n", leadin, format_code);
dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
- bump = 24;
break;
case TPROTO_NONE:
default:
fprintf(stderr, "%s unknown protocol id=0x%x "
"format_code=%d\n", leadin, proto_id, format_code);
dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
- bump = 24;
break;
}
}
@@ -348,7 +341,7 @@ prin_work(int sg_fd, const struct opts_t * optsp)
printf(" Persist Through Power Loss Capable(PTPL_C): %d\n",
!!(pr_buff[2] & 0x1));
printf(" Type Mask Valid(TMV): %d\n", !!(pr_buff[3] & 0x80));
- printf(" Allow commands: %d\n", (pr_buff[3] >> 4) & 0x7);
+ printf(" Allow Commands: %d\n", (pr_buff[3] >> 4) & 0x7);
printf(" Persist Through Power Loss Active(PTPL_A): %d\n",
!!(pr_buff[3] & 0x1));
if (pr_buff[3] & 0x80) {
@@ -429,6 +422,11 @@ prin_work(int sg_fd, const struct opts_t * optsp)
} else if (PRIN_RFSTAT_SA == optsp->prin_sa) {
printf(" PR generation=0x%x\n", pr_gen);
ucp = pr_buff + 8;
+ if (0 == add_len) {
+ printf(" No full status descriptors\n");
+ if (optsp->verbose)
+ printf(" So there are no registered IT nexuses\n");
+ }
for (k = 0; k < add_len; k += num, ucp += num) {
add_desc_len = ((ucp[20] << 24) | (ucp[21] << 16) |
(ucp[22] << 8) | ucp[23]);
@@ -460,22 +458,51 @@ prin_work(int sg_fd, const struct opts_t * optsp)
} else
printf(" not reservation holder\n");
if (add_desc_len > 0)
- decode_transport_id(" ", &ucp[24], add_desc_len);
+ decode_transport_id(" ", &ucp[24], add_desc_len, 0);
}
}
}
return 0;
}
+/* Compact the 2 dimensional transportid_arr into a one dimensional
+ * array in place returning the length. */
static int
-prout_work(int sg_fd, const struct opts_t * optsp)
+compact_transportid_array(struct opts_t * optsp)
+{
+ int k, off, protocol_id, len;
+ int compact_len = 0;
+ unsigned char * ucp = optsp->transportid_arr;
+
+ for (k = 0, off = 0; ((k < optsp->num_transportids) && (k < MX_TIDS));
+ ++k, off += MX_TID_LEN) {
+ protocol_id = ucp[off] & 0xf;
+ if (TPROTO_ISCSI == protocol_id) {
+ len = (ucp[off + 2] << 8) + ucp[off + 3] + 4;
+ if (len < 24)
+ len = 24;
+ if (off > compact_len)
+ memmove(ucp + compact_len, ucp + off, len);
+ compact_len += len;
+
+ } else {
+ if (off > compact_len)
+ memmove(ucp + compact_len, ucp + off, 24);
+ compact_len += 24;
+ }
+ }
+ return compact_len;
+}
+
+static int
+prout_work(int sg_fd, struct opts_t * optsp)
{
int j, len, res, t_arr_len;
unsigned char pr_buff[MX_ALLOC_LEN];
uint64_t param_rk;
uint64_t param_sark;
- t_arr_len = optsp->transportid_arr_len;
+ t_arr_len = compact_transportid_array(optsp);
param_rk = optsp->param_rk;
memset(pr_buff, 0, sizeof(pr_buff));
for (j = 7; j >= 0; --j) {
@@ -531,14 +558,14 @@ prout_work(int sg_fd, const struct opts_t * optsp)
}
static int
-prout_rmove_work(int sg_fd, const struct opts_t * optsp)
+prout_reg_move_work(int sg_fd, struct opts_t * optsp)
{
int j, len, res, t_arr_len;
unsigned char pr_buff[MX_ALLOC_LEN];
uint64_t param_rk;
uint64_t param_sark;
- t_arr_len = optsp->transportid_arr_len;
+ t_arr_len = compact_transportid_array(optsp);
param_rk = optsp->param_rk;
memset(pr_buff, 0, sizeof(pr_buff));
for (j = 7; j >= 0; --j) {
@@ -587,103 +614,288 @@ prout_rmove_work(int sg_fd, const struct opts_t * optsp)
return 0;
}
-/* Build transportid byte array from ASCII hexadecimal number which are comma
- * (or (single) space) separated. Direct form can only contain one transport
- * ID. In the indirect form (when '-'==*inp) there can be multiple transport
- * IDs, all assumed to contain the same number of bytes each. Fuller
- * description in manpage of sg_persist(8). Returns 0 if successful, else 1 .
- * N.B. Contains transport ID related special handling (e.g. rounds up to
- * 24 bytes)
+/* Decode various symbolic forms of TransportIDs into SPC-4 format.
+ * Returns 1 if one found, else returns 0. */
+static int
+decode_sym_transportid(const char * lcp, unsigned char * tidp)
+{
+ int k, j, n, b, c, len, alen;
+ const char * ecp;
+ const char * isip;
+
+ if ((0 == memcmp("sas,", lcp, 4)) || (0 == memcmp("SAS,", lcp, 4))) {
+ lcp += 4;
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF");
+ if (16 != k) {
+ fprintf(stderr, "badly formed symbolic SAS TransportID: %s\n",
+ lcp);
+ return 0;
+ }
+ memset(tidp, 0, 24);
+ tidp[0] = TPROTO_SAS;
+ for (k = 0, j = 0, b = 0; k < 16; ++k) {
+ c = lcp[k];
+ if (isdigit(c))
+ n = c - 0x30;
+ else if (isupper(c))
+ n = c - 0x37;
+ else
+ n = c - 0x57;
+ if (k & 1) {
+ tidp[4 + j] = b | n;
+ ++j;
+ } else
+ b = n << 4;
+ }
+ return 1;
+ } else if ((0 == memcmp("spi,", lcp, 4)) ||
+ (0 == memcmp("SPI,", lcp, 4))) {
+ lcp += 4;
+ if (2 != sscanf(lcp, "%d,%d", &b, &c)) {
+ fprintf(stderr, "badly formed symbolic SPI TransportID: %s\n",
+ lcp);
+ return 0;
+ }
+ tidp[0] = TPROTO_SPI;
+ tidp[2] = (b >> 8) & 0xff;
+ tidp[3] = b & 0xff;
+ tidp[6] = (c >> 8) & 0xff;
+ tidp[7] = c & 0xff;
+ return 1;
+ } else if ((0 == memcmp("fcp,", lcp, 4)) ||
+ (0 == memcmp("FCP,", lcp, 4))) {
+ lcp += 4;
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF");
+ if (16 != k) {
+ fprintf(stderr, "badly formed symbolic FCP TransportID: %s\n",
+ lcp);
+ return 0;
+ }
+ memset(tidp, 0, 24);
+ tidp[0] = TPROTO_FCP;
+ for (k = 0, j = 0, b = 0; k < 16; ++k) {
+ c = lcp[k];
+ if (isdigit(c))
+ n = c - 0x30;
+ else if (isupper(c))
+ n = c - 0x37;
+ else
+ n = c - 0x57;
+ if (k & 1) {
+ tidp[8 + j] = b | n;
+ ++j;
+ } else
+ b = n << 4;
+ }
+ return 1;
+ } else if ((0 == memcmp("sbp,", lcp, 4)) ||
+ (0 == memcmp("SBP,", lcp, 4))) {
+ lcp += 4;
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF");
+ if (16 != k) {
+ fprintf(stderr, "badly formed symbolic SBP TransportID: %s\n",
+ lcp);
+ return 0;
+ }
+ memset(tidp, 0, 24);
+ tidp[0] = TPROTO_1394;
+ for (k = 0, j = 0, b = 0; k < 16; ++k) {
+ c = lcp[k];
+ if (isdigit(c))
+ n = c - 0x30;
+ else if (isupper(c))
+ n = c - 0x37;
+ else
+ n = c - 0x57;
+ if (k & 1) {
+ tidp[8 + j] = b | n;
+ ++j;
+ } else
+ b = n << 4;
+ }
+ return 1;
+ } else if ((0 == memcmp("srp,", lcp, 4)) ||
+ (0 == memcmp("SRP,", lcp, 4))) {
+ lcp += 4;
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF");
+ if (16 != k) {
+ fprintf(stderr, "badly formed symbolic SRP TransportID: %s\n",
+ lcp);
+ return 0;
+ }
+ memset(tidp, 0, 24);
+ tidp[0] = TPROTO_SRP;
+ for (k = 0, j = 0, b = 0; k < 32; ++k) {
+ c = lcp[k];
+ if (isdigit(c))
+ n = c - 0x30;
+ else if (isupper(c))
+ n = c - 0x37;
+ else
+ n = c - 0x57;
+ if (k & 1) {
+ tidp[8 + j] = b | n;
+ ++j;
+ } else
+ b = n << 4;
+ }
+ return 1;
+ } else if (0 == memcmp("iqn.", lcp, 4)) {
+ ecp = strpbrk(lcp, " \t");
+ isip = strstr(lcp, ",i,0x");
+ if (ecp && (isip > ecp))
+ isip = NULL;
+ len = ecp ? (ecp - lcp) : (int)strlen(lcp);
+ memset(tidp, 0, 24);
+ tidp[0] = TPROTO_ISCSI | (isip ? 0x40 : 0x0);
+ alen = len + 1; /* at least one trailing null */
+ if (alen < 20)
+ alen = 20;
+ else if (0 != (alen % 4))
+ alen = ((alen / 4) + 1) * 4;
+ if (alen > 241) { /* sam5r02.pdf A.2 (Annex) */
+ fprintf(stderr, "iSCSI name too long, alen=%d\n", alen);
+ return 0;
+ }
+ tidp[3] = alen & 0xff;
+ memcpy(tidp + 4, lcp, len);
+ return 1;
+ }
+ fprintf(stderr, "unable to parse symbolic TransportID: %s\n", lcp);
+ return 0;
+}
+
+/* Read one or more TransportIDs from the given file or from stdin.
+ * Returns 0 if successful, 1 otherwise. */
+static int
+decode_file_tids(const char * fnp, struct opts_t * optsp)
+{
+ FILE * fp = stdin;
+ int in_len, k, j, m;
+ unsigned int h;
+ const char * lcp;
+ char line[512];
+ int off = 0;
+ int num = 0;
+ unsigned char * tid_arr = optsp->transportid_arr;
+
+ if (fnp) {
+ fp = fopen(fnp, "r");
+ if (NULL == fp) {
+ fprintf(stderr, "decode_file_tids: unable to open %s\n", fnp);
+ return 1;
+ }
+ }
+ for (j = 0, off = 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;
+ if (decode_sym_transportid(lcp, tid_arr + off))
+ goto my_cont_a;
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
+ if ((k < in_len) && ('#' != lcp[k])) {
+ fprintf(stderr, "decode_file_tids: 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, "decode_file_tids: hex number "
+ "larger than 0xff in line %d, pos %d\n",
+ j + 1, (int)(lcp - line + 1));
+ goto bad;
+ }
+ if ((off + k) >= (int)sizeof(optsp->transportid_arr)) {
+ fprintf(stderr, "decode_file_tids: array length "
+ "exceeded\n");
+ goto bad;
+ }
+ tid_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, "decode_file_tids: error in "
+ "line %d, at pos %d\n", j + 1,
+ (int)(lcp - line + 1));
+ goto bad;
+ }
+ }
+my_cont_a:
+ off += MX_TID_LEN;
+ if (off >= (MX_TIDS * MX_TID_LEN)) {
+ fprintf(stderr, "decode_file_tids: array length exceeded\n");
+ goto bad;
+ }
+ ++num;
+ }
+ optsp->num_transportids = num;
+ return 0;
+
+bad:
+ if (fnp)
+ fclose(fp);
+ return 1;
+}
+
+/* Build transportid array which may contain one or more TransportIDs.
+ * A single TransportID can appear on the command line either as a list of
+ * comma (or single space) separated ASCII hex bytes, or in some transport
+ * protocol specific form (e.g. "sas,5000c50005b32001"). One or more
+ * TransportIDs may be given in a file (syntax: "file=<name>") or read from
+ * stdin in (when "-" is given). Fuller description in manpage of
+ * sg_persist(8). Returns 0 if successful, else 1 .
*/
static int
build_transportid(const char * inp, struct opts_t * optsp)
{
- int in_len, k, j, m;
+ int in_len, k;
unsigned int h;
const char * lcp;
- unsigned char * tid_arr;
+ unsigned char * tid_arr = optsp->transportid_arr;
char * cp;
char * c2p;
- tid_arr = optsp->transportid_arr;
lcp = inp;
in_len = strlen(inp);
if (0 == in_len) {
- optsp->transportid_arr_len = 0;
optsp->num_transportids = 0;
}
- if ('-' == inp[0]) { /* read from stdin */
- char line[512];
- int off = 0;
- int num = 0;
-
- for (j = 0, off = 0; j < 512; ++j) {
- if (NULL == fgets(line, sizeof(line), stdin))
- 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_transportid: syntax error at "
- "line %d, pos %d\n", j + 1, m + k + 1);
- return 1;
- }
- for (k = 0; k < 1024; ++k) {
- if (1 == sscanf(lcp, "%x", &h)) {
- if (h > 0xff) {
- fprintf(stderr, "build_transportid: hex number "
- "larger than 0xff in line %d, pos %d\n",
- j + 1, (int)(lcp - line + 1));
- return 1;
- }
- if ((off + k) >= (int)sizeof(optsp->transportid_arr)) {
- fprintf(stderr, "build_transportid: array length "
- "exceeded\n");
- return 1;
- }
- tid_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_transportid: error in "
- "line %d, at pos %d\n", j + 1,
- (int)(lcp - line + 1));
- return 1;
- }
- }
- if (k < 24)
- k = 24;
- else if (0 != (k % 4))
- k = ((k / 4) + 1) * 4;
- off += k;
- ++num;
- }
- optsp->transportid_arr_len = off;
- optsp->num_transportids = num;
- } else { /* hex string on command line */
+ if (('-' == inp[0]) ||
+ (0 == memcmp("file=", inp, 5)) ||
+ (0 == memcmp("FILE=", inp, 5))) {
+ if ('-' == inp[0])
+ lcp = NULL; /* read from stdin */
+ else
+ lcp = inp + 5; /* read from given file */
+ return decode_file_tids(lcp, optsp);
+ } else { /* TransportID given directly on command line */
+ if (decode_sym_transportid(lcp, tid_arr))
+ goto my_cont_b;
k = strspn(inp, "0123456789aAbBcCdDeEfF, ");
if (in_len != k) {
fprintf(stderr, "build_transportid: error at pos %d\n",
@@ -713,11 +925,7 @@ build_transportid(const char * inp, struct opts_t * optsp)
return 1;
}
}
- if (k < 24)
- k = 24;
- else if (0 != (k % 4))
- k = ((k / 4) + 1) * 4;
- optsp->transportid_arr_len = k;
+my_cont_b:
optsp->num_transportids = 1;
if (k >= (int)sizeof(optsp->transportid_arr)) {
fprintf(stderr, "build_transportid: array length exceeded\n");
@@ -981,7 +1189,7 @@ main(int argc, char * argv[])
"command line (or stdin): %d\n", opts.num_transportids);
fprintf(stderr, " Decode given transport-ids:\n");
decode_transport_id(" ", opts.transportid_arr,
- opts.transportid_arr_len);
+ 0, opts.num_transportids);
}
if (opts.inquiry) {
@@ -1018,7 +1226,7 @@ main(int argc, char * argv[])
if (opts.prin)
ret = prin_work(sg_fd, &opts);
else if (PROUT_REG_MOVE_SA == opts.prout_sa)
- ret = prout_rmove_work(sg_fd, &opts);
+ ret = prout_reg_move_work(sg_fd, &opts);
else /* PROUT commands other than 'register and move' */
ret = prout_work(sg_fd, &opts);