aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2007-09-27 03:41:43 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2007-09-27 03:41:43 +0000
commit7d27a2728146c647e4a048a02603485bf7afb5b0 (patch)
treefdc5b87ab267496e2eb8d5404c6b642f061ec0f4
parentf65bc670878168a76b1110a0c95d5a14773ac72c (diff)
downloadsg3_utils-7d27a2728146c647e4a048a02603485bf7afb5b0.tar.gz
sg_stpg: add --tp= and --state= options
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@107 6180dd3e-e324-4e3e-922d-17de1ae2f315
-rw-r--r--ChangeLog2
-rw-r--r--README2
-rw-r--r--debian/changelog2
-rw-r--r--doc/sg_stpg.870
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/sg_reassign.c18
-rw-r--r--src/sg_stpg.c398
7 files changed, 361 insertions, 133 deletions
diff --git a/ChangeLog b/ChangeLog
index b596513a..ea91a7f5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ 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.25 [20070923]
+Changelog for sg3_utils-1.25 [20070926]
- sg_stpg: new utility to Set Target Port Groups
- sg_cmds_extra: add sg_ll_set_tgt_prt_grp()
- sg_sat_set_features: new utility (actually copied from examples
diff --git a/README b/README
index 2ba13647..97e4b9cd 100644
--- a/README
+++ b/README
@@ -327,4 +327,4 @@ See http://www.torque.net/sg/tools.html
Doug Gilbert
-23rd September 2007
+26th September 2007
diff --git a/debian/changelog b/debian/changelog
index 123e96a2..d9c258f8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.25-0.1) unstable; urgency=low
* New upstream version
- -- Doug Gilbert <dgilbert@interlog.com> Sun, 23 Sep 2007 23:00:00 -0400
+ -- Doug Gilbert <dgilbert@interlog.com> Wed, 26 Sep 2007 23:00:00 -0400
sg3-utils (1.24-1) unstable; urgency=low
diff --git a/doc/sg_stpg.8 b/doc/sg_stpg.8
index 66fd7907..c1739045 100644
--- a/doc/sg_stpg.8
+++ b/doc/sg_stpg.8
@@ -10,20 +10,27 @@ sg_stpg \- sends a SCSI SET TARGET PORT GROUPS command
.SH DESCRIPTION
.\" Add any additional description here
.PP
-Send a SCSI SET TARGET PORT GROUPS command to \fIDEVICE\fR.
-This utility has different modes depending on whether the \fI\-\-tp=\fR
-option is given.
+Send a SCSI SET TARGET PORT GROUPS command to \fIDEVICE\fR. This utility
+has different modes depending on whether the \fI\-\-tp=\fR option is given.
.PP
-A sequence of SCSI commands are sent to the \fIDEVICE\fR leading up to the
-SET TARGET PORT GROUPS command. First a INQUIRY is sent to fetch the device
-identification VPD page to find the (primary) target port group. Then a
-REPORT TARGET PORT GROUPS command is issued to find the current state and
+If \fI\-\-tp=\fR is given then the SET TARGET PORT GROUPS command parameter
+block is built with a descriptor for each element in the list given to
+\fI\-\-tp=\fR. The corresponding asymmetric access state value is either
+taken from the \fI\-\-state=\fR list or, if that is not given, from one
+of the explicit state options (e.g. \fI\-\-unavailable\fR), used repeatedly
+if required.
+.PP
+If \fI\-\-tp=\fR is not given then a sequence of SCSI commands are sent to
+the \fIDEVICE\fR leading up to the SET TARGET PORT GROUPS command. First an
+INQUIRY is sent to fetch the device identification VPD page to find
+the (primary) target port group associated with \fIDEVICE\fR. Then a REPORT
+TARGET PORT GROUPS command is issued to find the current state and
whether a transition to the requested state is supported. If so the
SET TARGET PORT GROUPS command is sent.
.PP
Target port group access is described in SPC\-4 found at www.t10.org
-in section 5.8 (in rev 11 dated 2007/5/14). The Set Target Port
-Groups command is also described in that document.
+in section 5.8 (in rev 11 dated 2007/5/14). The SET TARGET PORT
+GROUPS command is also described in that document.
.PP
.SH OPTIONS
Arguments to long options are mandatory for short options as well.
@@ -38,27 +45,40 @@ output the usage message then exit.
output response to the REPORT TARGET PORT GROUPS command in hex then exit.
.TP
\fB\-o\fR, \fB\-\-optimized\fR
-set active/optimized state.
+set active/optimized state. If no other state options or \fI\-\-tp=\fR
+option are given then active/optimized is the default state.
.TP
\fB\-O\fR, \fB\-l\fR, \fB\-\-offline\fR
-set active/non-optimized state.
+set offline state. This is the appropriate state to set a target port
+to prior to removing the device. Note that a relative target port identifier
+should be given with this state (rather than a target port group identifier
+that all other states take).
.TP
\fB\-r\fR, \fB\-\-raw\fR
output response to the REPORT TARGET PORT GROUPS command in binary to stdout
then exit.
.TP
\fB\-s\fR, \fB\-\-standby\fR
-set standby state. Port group shall those commands listed for "unavailable"
-state plus LOG SELECT/SENSE, MODE SELECT/SENSE, RECEIVE DIAGNOSTIC RESULTS,
-SEND DIAGNOSTIC, PERSISTENT RESERVE IN/OUT commands.
+set standby state. Port group shall accept those commands listed
+for "unavailable" state plus LOG SELECT/SENSE, MODE SELECT/SENSE, RECEIVE
+DIAGNOSTIC RESULTS, SEND DIAGNOSTIC, PERSISTENT RESERVE IN/OUT commands.
.TP
\fB\-S\fR, \fB\-\-state\fR=\fIS,S...\fR
+specifies a comma separated list (one element of more) of states. Either
+a number or an abbreviation can be given. A number is assumed to be a
+decimal number unless it is prefixed by "0x" or has a trailing "h" in
+which case a hexadecimal value is assumed. Only the values 0, 1, 2, 3
+or 14 are accepted. The accepted abbreviations are "an", "ao", "o", "s"
+or "u"; which represent active/non-optimized(1), active/optimized(0),
+offline(14), standby(2) or unavalable(3) respectively.
.TP
\fB\-t\fR, \fB\-\-tp\fR=\fIP,P...\fR
-Specify a comma separated list (one element of more). Each elements is
-either a target port group (when the corresponding state is other
-than "offline") or a relative target port identifier (when the
-corresponding state is "offline").
+specifies a comma separated list (one element of more). Each elements is
+either a target port group identifier (when the corresponding state is
+other than "offline") or a relative target port identifier (when the
+corresponding state is "offline"). Each element is assumed to be a
+decimal number unless it is prefixed by "0x" or has a trailing "h" in
+which case a hexadecimal value is assumed.
.TP
\fB\-u\fR, \fB\-\-unavailable\fR
set unavailable state. Port group shall only accept INQUIRY, REPORT LUNS,
@@ -70,8 +90,20 @@ increase the level of verbosity, (i.e. debug output).
\fB\-V\fR, \fB\-\-version\fR
print the version string and then exit.
.SH NOTES
-The Set Target Port Groups command should be supported whenever the TPGS
+The SET TARGET PORT GROUPS command should be supported whenever the TPGS
value in a standard INQUIRY response is 2 or 3. [View with sg_inq utility.]
+.PP
+Notice that the offline state is termed as a "secondary target port
+asymmetric access state" and takes a relative target port identifier (i.e.
+acts on a single target port). All the other states are termed as "primary
+target port asymmetric access states" and each takes a target port group
+identifier (i.e. acts on one or more target ports).
+.PP
+When \fI\-\-tp=\fR is given then the same number of elements should be
+given to the \fI\-\-state=\fR option. If more than one list element is
+given to \fI\-\-tp=\fR and an equal number of elements is _not_ given
+to the the \fI\-\-state=\fR option, then if only one state is specified
+then it is repeated.
.SH EXIT STATUS
The exit status of sg_stpg is 0 when it is successful. Otherwise see
the sg3_utils(8) man page.
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 99fb63a4..184ccc89 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -79,7 +79,7 @@ fi
%{_libdir}/*.la
%changelog
-* Sun Sep 23 2007 - dgilbert at interlog dot com
+* Wed Sep 26 2007 - dgilbert at interlog dot com
- add sg_sat_set_features, sg_stpg; sg_dd oflag=sparse,null
* sg3_utils-1.25
diff --git a/src/sg_reassign.c b/src/sg_reassign.c
index 2c83748f..fd0b6ba8 100644
--- a/src/sg_reassign.c
+++ b/src/sg_reassign.c
@@ -54,7 +54,7 @@
* vendor specific data is written.
*/
-static char * version_str = "1.11 20070919";
+static char * version_str = "1.11 20070925";
#define ME "sg_reassign: "
@@ -77,7 +77,8 @@ static struct option long_options[] = {
{0, 0, 0, 0},
};
-static void usage()
+static void
+usage()
{
fprintf(stderr, "Usage: "
"sg_reassign [--address=A,A...] [--dummy] [--eight=0|1] "
@@ -118,7 +119,8 @@ static void usage()
/* Trying to decode multipliers as sg_get_llnum() [in sg_libs does] would
* only confuse things here, so use this local trimmed version */
-long long get_llnum(const char * buf)
+long long
+get_llnum(const char * buf)
{
int res, len;
long long num;
@@ -151,8 +153,9 @@ long long get_llnum(const char * buf)
/* space separated list). Assumed decimal unless prefixed by '0x', '0X' */
/* or contains trailing 'h' or 'H' (which indicate hex). */
/* Returns 0 if ok, or 1 if error. */
-static int build_lba_arr(const char * inp, unsigned long long * lba_arr,
- int * lba_arr_len, int max_arr_len)
+static int
+build_lba_arr(const char * inp, unsigned long long * lba_arr,
+ int * lba_arr_len, int max_arr_len)
{
int in_len, k, j, m;
const char * lcp;
@@ -225,7 +228,7 @@ static int build_lba_arr(const char * inp, unsigned long long * lba_arr,
off += (k + 1);
}
*lba_arr_len = off;
- } else { /* hex string on command line */
+ } else { /* list of numbers (default decimal) on command line */
k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX,");
if (in_len != k) {
fprintf(stderr, "build_lba_arr: error at pos %d\n", k + 1);
@@ -255,7 +258,8 @@ static int build_lba_arr(const char * inp, unsigned long long * lba_arr,
}
-int main(int argc, char * argv[])
+int
+main(int argc, char * argv[])
{
int sg_fd, res, c, num, k, j;
int dummy = 0;
diff --git a/src/sg_stpg.c b/src/sg_stpg.c
index e91b4992..77f8679d 100644
--- a/src/sg_stpg.c
+++ b/src/sg_stpg.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <getopt.h>
#include "sg_lib.h"
@@ -45,7 +46,7 @@
* to the given SCSI device.
*/
-static char * version_str = "1.2 20070925";
+static char * version_str = "1.2 20070926";
#define TGT_GRP_BUFF_LEN 1024
#define MX_ALLOC_LEN (0xc000 + 0x80)
@@ -100,9 +101,9 @@ usage()
" --hex|-H print out report response in hex, then "
"exit\n"
" --offline|-l set asymm. access state to offline, takes "
- "relative\n"
- " target port id, rather than target port "
- "group id\n"
+ "relative\n"
+ " target port id, rather than target port "
+ "group id\n"
" --optimized|-o set asymm. access state to "
"active/optimized\n"
" --raw|-r output report response in binary to "
@@ -110,9 +111,10 @@ usage()
" --standby|-s set asymm. access state to standby\n"
" --state=S,S.. |-S S,S... list of states (values or "
"acronyms)\n"
- " --tp=P,P.. |-t P,P... list of target port group or "
- "relative\n"
- " identifiers\n"
+ " --tp=P,P.. |-t P,P... list of target port group "
+ "identifiers,\n"
+ " or relative target port "
+ "identifiers\n"
" --unavailable|-u set asymm. access state to unavailable\n"
" --verbose|-v increase verbosity\n"
" --version|-V print version string and exit\n\n"
@@ -276,6 +278,133 @@ encode_tpgs_states(unsigned char *buff, struct tgtgrp *tgtState, int numgrp)
}
}
+/* Read numbers (up to 32 bits in size) from command line (comma separated */
+/* list). Assumed decimal unless prefixed by '0x', '0X' or contains */
+/* trailing 'h' or 'H' (which indicate hex). Returns 0 if ok, 1 if error. */
+static int
+build_port_arr(const char * inp, int * port_arr, int * port_arr_len,
+ int max_arr_len)
+{
+ int in_len, k;
+ const char * lcp;
+ int v;
+ char * cp;
+
+ if ((NULL == inp) || (NULL == port_arr) ||
+ (NULL == port_arr_len))
+ return 1;
+ lcp = inp;
+ in_len = strlen(inp);
+ if (0 == in_len)
+ *port_arr_len = 0;
+ k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX,");
+ if (in_len != k) {
+ fprintf(stderr, "build_port_arr: error at pos %d\n", k + 1);
+ return 1;
+ }
+ for (k = 0; k < max_arr_len; ++k) {
+ v = sg_get_num_nomult(lcp);
+ if (-1 != v) {
+ port_arr[k] = v;
+ cp = strchr(lcp, ',');
+ if (NULL == cp)
+ break;
+ lcp = cp + 1;
+ } else {
+ fprintf(stderr, "build_port_arr: error at pos %d\n",
+ (int)(lcp - inp + 1));
+ return 1;
+ }
+ }
+ *port_arr_len = k + 1;
+ if (k == max_arr_len) {
+ fprintf(stderr, "build_port_arr: array length exceeded\n");
+ return 1;
+ }
+ return 0;
+}
+
+/* Read numbers (up to 32 bits in size) from command line (comma separated */
+/* list). Assumed decimal unless prefixed by '0x', '0X' or contains */
+/* trailing 'h' or 'H' (which indicate hex). Also accepts 'ao' for active */
+/* optimized [0], 'an' for active/non-optimized [1], 's' for standby [2], */
+/* 'u' for unavailable [3], 'o' for offline [14]. */
+/* Returns 0 if ok, 1 if error. */
+static int
+build_state_arr(const char * inp, int * state_arr, int * state_arr_len,
+ int max_arr_len)
+{
+ int in_len, k, v, try_num;
+ const char * lcp;
+ char * cp;
+
+ if ((NULL == inp) || (NULL == state_arr) ||
+ (NULL == state_arr_len))
+ return 1;
+ lcp = inp;
+ in_len = strlen(inp);
+ if (0 == in_len)
+ *state_arr_len = 0;
+ k = strspn(inp, "0123456789aAbBcCdDeEfFhHnNoOsSuUxX,");
+ if (in_len != k) {
+ fprintf(stderr, "build_state_arr: error at pos %d\n", k + 1);
+ return 1;
+ }
+ for (k = 0; k < max_arr_len; ++k) {
+ try_num = 1;
+ if (isalpha(*lcp)) {
+ try_num = 0;
+ switch (toupper(*lcp)) {
+ case 'A':
+ if ('N' == toupper(*(lcp + 1)))
+ state_arr[k] = 1;
+ else if ('O' == toupper(*(lcp + 1)))
+ state_arr[k] = 0;
+ else
+ try_num = 1;
+ break;
+ case 'O':
+ state_arr[k] = 14;
+ break;
+ case 'S':
+ state_arr[k] = 2;
+ break;
+ case 'U':
+ state_arr[k] = 3;
+ break;
+ default:
+ fprintf(stderr, "build_state_arr: expected 'ao', 'an', 'o', "
+ "'s' or 'u' at pos %d\n", (int)(lcp - inp + 1));
+ return 1;
+ }
+ }
+ if (try_num) {
+ v = sg_get_num_nomult(lcp);
+ if (((v >= 0) && (v <= 3)) || (14 ==v))
+ state_arr[k] = v;
+ else if (-1 == v) {
+ fprintf(stderr, "build_state_arr: error at pos %d\n",
+ (int)(lcp - inp + 1));
+ return 1;
+ } else {
+ fprintf(stderr, "build_state_arr: expect 0,1,2,3 or 14\n");
+ return 1;
+ }
+ }
+ cp = strchr(lcp, ',');
+ if (NULL == cp)
+ break;
+ lcp = cp + 1;
+ }
+ *state_arr_len = k + 1;
+ if (k == max_arr_len) {
+ fprintf(stderr, "build_state_arr: array length exceeded\n");
+ return 1;
+ }
+ return 0;
+}
+
+
int
main(int argc, char * argv[])
{
@@ -368,6 +497,59 @@ main(int argc, char * argv[])
}
}
+ if (state_arg) {
+ if (build_state_arr(state_arg, state_arr, &state_arr_len,
+ MAX_PORT_LIST_ARR_LEN)) {
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (tp_arg) {
+ if (build_port_arr(tp_arg, port_arr, &port_arr_len,
+ MAX_PORT_LIST_ARR_LEN)) {
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if ((state >= 0) && (state_arr_len > 0)) {
+ fprintf(stderr, "either use individual state option or '--state=' "
+ "but not both\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if ((0 == state_arr_len) && (0 == port_arr_len) && (-1 == state))
+ state = 0; /* default to active/optimized */
+ if ((1 == state_arr_len) && (0 == port_arr_len) && (-1 == state)) {
+ state = state_arr[0];
+ state_arr_len = 0;
+ }
+ if (state_arr_len > port_arr_len) {
+ fprintf(stderr, "'state=' list longer than expected\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if ((port_arr_len > 0) && (0 == state_arr_len)) {
+ if (-1 == state) {
+ fprintf(stderr, "target port list given but no state "
+ "indicated\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ state_arr[0] = state;
+ state_arr_len = 1;
+ state = -1;
+ }
+ if ((port_arr_len > 1) && (1 == state_arr_len)) {
+ for (k = 1; k < port_arr_len; ++k)
+ state_arr[k] = state_arr[0];
+ state_arr_len = port_arr_len;
+ }
+ if (port_arr_len != state_arr_len) {
+ fprintf(stderr, "'state=' and '--tp=' lists mismatched\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
if (NULL == device_name) {
fprintf(stderr, "missing device name!\n");
usage();
@@ -380,110 +562,120 @@ main(int argc, char * argv[])
return SG_LIB_FILE_ERROR;
}
- res = sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff,
- DEF_VPD_DEVICE_ID_LEN, 1, verbose);
- if (0 == res) {
- report_len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
- if (VPD_DEVICE_ID != rsp_buff[1]) {
- fprintf(stderr, "invalid VPD response; probably a STANDARD "
- "INQUIRY response\n");
- if (verbose) {
- fprintf(stderr, "First 32 bytes of bad response\n");
- dStrHex((const char *)rsp_buff, 32, 0);
+ if (0 == port_arr_len) {
+ res = sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff,
+ DEF_VPD_DEVICE_ID_LEN, 1, verbose);
+ if (0 == res) {
+ report_len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4;
+ if (VPD_DEVICE_ID != rsp_buff[1]) {
+ fprintf(stderr, "invalid VPD response; probably a STANDARD "
+ "INQUIRY response\n");
+ if (verbose) {
+ fprintf(stderr, "First 32 bytes of bad response\n");
+ dStrHex((const char *)rsp_buff, 32, 0);
+ }
+ return SG_LIB_CAT_MALFORMED;
}
- return SG_LIB_CAT_MALFORMED;
- }
- if (report_len > MX_ALLOC_LEN) {
- fprintf(stderr, "response length too long: %d > %d\n", report_len,
- MX_ALLOC_LEN);
- return SG_LIB_CAT_MALFORMED;
- } else if (report_len > DEF_VPD_DEVICE_ID_LEN) {
- if (sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff,
- report_len, 1, verbose))
- return SG_LIB_CAT_OTHER;
+ if (report_len > MX_ALLOC_LEN) {
+ fprintf(stderr, "response length too long: %d > %d\n", report_len,
+ MX_ALLOC_LEN);
+ return SG_LIB_CAT_MALFORMED;
+ } else if (report_len > DEF_VPD_DEVICE_ID_LEN) {
+ if (sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff,
+ report_len, 1, verbose))
+ return SG_LIB_CAT_OTHER;
+ }
+ decode_target_port(rsp_buff + 4, report_len - 4, &relport, &portgroup);
+ printf("Device is at port Group 0x%02x, relative port 0x%02x\n",
+ portgroup, relport);
}
- decode_target_port(rsp_buff + 4, report_len - 4, &relport, &portgroup);
- printf("Device is at port Group 0x%02x, relative port 0x%02x\n",
- portgroup, relport);
- }
- memset(reportTgtGrpBuff, 0x0, sizeof(reportTgtGrpBuff));
- trunc = 0;
-
- res = sg_ll_report_tgt_prt_grp(sg_fd, reportTgtGrpBuff,
- sizeof(reportTgtGrpBuff), 1, verbose);
- ret = res;
- if (0 == res) {
- report_len = (reportTgtGrpBuff[0] << 24) +
- (reportTgtGrpBuff[1] << 16) +
- (reportTgtGrpBuff[2] << 8) +
- reportTgtGrpBuff[3] + 4;
- if (report_len > (int)sizeof(reportTgtGrpBuff)) {
- trunc = 1;
- fprintf(stderr, " <<report too long for internal buffer,"
- " output truncated\n");
- report_len = (int)sizeof(reportTgtGrpBuff);
- }
- if (raw) {
- dStrRaw((const char *)reportTgtGrpBuff, report_len);
- goto err_out;
- }
- if (verbose)
- printf("Report list length = %d\n", report_len);
- if (hex) {
+ memset(reportTgtGrpBuff, 0x0, sizeof(reportTgtGrpBuff));
+ trunc = 0;
+
+ res = sg_ll_report_tgt_prt_grp(sg_fd, reportTgtGrpBuff,
+ sizeof(reportTgtGrpBuff), 1, verbose);
+ ret = res;
+ if (0 == res) {
+ report_len = (reportTgtGrpBuff[0] << 24) +
+ (reportTgtGrpBuff[1] << 16) +
+ (reportTgtGrpBuff[2] << 8) +
+ reportTgtGrpBuff[3] + 4;
+ if (report_len > (int)sizeof(reportTgtGrpBuff)) {
+ trunc = 1;
+ fprintf(stderr, " <<report too long for internal buffer,"
+ " output truncated\n");
+ report_len = (int)sizeof(reportTgtGrpBuff);
+ }
+ if (raw) {
+ dStrRaw((const char *)reportTgtGrpBuff, report_len);
+ goto err_out;
+ }
if (verbose)
- fprintf(stderr, "\nOutput response in hex:\n");
- dStrHex((const char *)reportTgtGrpBuff, report_len, 1);
- goto err_out;
- }
- memset(tgtGrpState, 0, sizeof(struct tgtgrp) * 256);
- tgtStatePtr = tgtGrpState;
- printf("Current target port groups:\n");
- for (k = 4, ucp = reportTgtGrpBuff + 4, numgrp = 0; k < report_len;
- k += off, ucp += off, numgrp ++) {
-
- printf(" target port group id : 0x%x , Pref=%d\n",
- (ucp[2] << 8) + ucp[3], !!(ucp[0] & 0x80));
- printf(" target port group asymmetric access state : ");
- printf("0x%02x", ucp[0] & 0x0f);
- printf("\n");
- tgtStatePtr->id = (ucp[2] << 8) + ucp[3];
- tgtStatePtr->current = ucp[0] & 0x0f;
- tgtStatePtr->valid = ucp[1];
+ printf("Report list length = %d\n", report_len);
+ if (hex) {
+ if (verbose)
+ fprintf(stderr, "\nOutput response in hex:\n");
+ dStrHex((const char *)reportTgtGrpBuff, report_len, 1);
+ goto err_out;
+ }
+ memset(tgtGrpState, 0, sizeof(struct tgtgrp) * 256);
+ tgtStatePtr = tgtGrpState;
+ printf("Current target port groups:\n");
+ for (k = 4, ucp = reportTgtGrpBuff + 4, numgrp = 0; k < report_len;
+ k += off, ucp += off, numgrp ++) {
+
+ printf(" target port group id : 0x%x , Pref=%d\n",
+ (ucp[2] << 8) + ucp[3], !!(ucp[0] & 0x80));
+ printf(" target port group asymmetric access state : ");
+ printf("0x%02x", ucp[0] & 0x0f);
+ printf("\n");
+ tgtStatePtr->id = (ucp[2] << 8) + ucp[3];
+ tgtStatePtr->current = ucp[0] & 0x0f;
+ tgtStatePtr->valid = ucp[1];
- tgt_port_count = ucp[7];
+ tgt_port_count = ucp[7];
- tgtStatePtr++;
- off = 8 + tgt_port_count * 4;
+ tgtStatePtr++;
+ off = 8 + tgt_port_count * 4;
+ }
+ } else if (SG_LIB_CAT_INVALID_OP == res)
+ fprintf(stderr, "Report Target Port Groups command not supported\n");
+ else if (SG_LIB_CAT_ILLEGAL_REQ == res)
+ fprintf(stderr, "bad field in Report Target Port Groups cdb "
+ "including unsupported service action\n");
+ else if (SG_LIB_CAT_UNIT_ATTENTION == res)
+ fprintf(stderr, "Report Target Port Groups, unit attention\n");
+ else if (SG_LIB_CAT_ABORTED_COMMAND == res)
+ fprintf(stderr, "Report Target Port Groups, aborted command\n");
+ else {
+ fprintf(stderr, "Report Target Port Groups command failed\n");
+ if (0 == verbose)
+ fprintf(stderr, " try '-v' for more information\n");
}
- } else if (SG_LIB_CAT_INVALID_OP == res)
- fprintf(stderr, "Report Target Port Groups command not supported\n");
- else if (SG_LIB_CAT_ILLEGAL_REQ == res)
- fprintf(stderr, "bad field in Report Target Port Groups cdb "
- "including unsupported service action\n");
- else if (SG_LIB_CAT_UNIT_ATTENTION == res)
- fprintf(stderr, "Report Target Port Groups, unit attention\n");
- else if (SG_LIB_CAT_ABORTED_COMMAND == res)
- fprintf(stderr, "Report Target Port Groups, aborted command\n");
- else {
- fprintf(stderr, "Report Target Port Groups command failed\n");
- if (0 == verbose)
- fprintf(stderr, " try '-v' for more information\n");
+ if (0 != res)
+ goto err_out;
+
+ printf("Port group 0x%02x: Set asymmetric access state to", portgroup);
+ decode_tpgs_state(state);
+ printf("\n");
+
+ transition_tpgs_states(tgtGrpState, numgrp, portgroup, state);
+
+ memset(setTgtGrpBuff, 0x0, sizeof(setTgtGrpBuff));
+ trunc = 0;
+
+ encode_tpgs_states(setTgtGrpBuff, tgtGrpState, numgrp);
+ report_len = numgrp * 4 + 4;
+ } else { /* port_arr_len > 0 */
+ memset(setTgtGrpBuff, 0x0, sizeof(setTgtGrpBuff));
+ for (k = 0, ucp = setTgtGrpBuff + 4; k < port_arr_len; ++k, ucp +=4) {
+ ucp[0] = state_arr[k] & 0xf;
+ ucp[2] = (port_arr[k] >> 8) & 0xff;
+ ucp[3] = port_arr[k] & 0xff;
+ }
+ report_len = port_arr_len * 4 + 4;
}
- if (0 != res)
- goto err_out;
-
- printf("Port group 0x%02x: Set asymmetric access state to", portgroup);
- decode_tpgs_state(state);
- printf("\n");
-
- transition_tpgs_states(tgtGrpState, numgrp, portgroup, state);
-
- memset(setTgtGrpBuff, 0x0, sizeof(setTgtGrpBuff));
- trunc = 0;
-
- encode_tpgs_states(setTgtGrpBuff, tgtGrpState, numgrp);
- report_len = numgrp * 4 + 4;
res = sg_ll_set_tgt_prt_grp(sg_fd, setTgtGrpBuff, report_len, 1, verbose);