aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--doc/sg3_utils.812
-rw-r--r--lib/sg_cmds_basic.c18
-rw-r--r--lib/sg_cmds_basic2.c45
-rw-r--r--src/sg_format.c205
-rw-r--r--src/sg_inq.c16
-rw-r--r--src/sg_sanitize.c186
-rw-r--r--src/sg_ses.c173
-rw-r--r--src/sg_vpd.c16
9 files changed, 537 insertions, 141 deletions
diff --git a/ChangeLog b/ChangeLog
index a85d08f1..35dbbac9 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.40 [20141002] [svn: r612]
+Changelog for sg3_utils-1.40 [20141006] [svn: r613]
- sg_write_verify: new utility for WRITE AND VERIFY
- sg_ses_microcode: new utility
- sg_senddiag: add --maxlen= option
@@ -10,6 +10,7 @@ Changelog for sg3_utils-1.40 [20141002] [svn: r612]
- sg_format: make '-FFF' bypass mode sense/select
- add --mode=MP to supply alternate mode page,
default remains read-write error recovery mpage
+ - output unit serial number and LU name prior to
- sg_inq: expand Block limits VPD page output
- sg_vpd: add --all option
- more TPC VPD page decoding
@@ -20,6 +21,7 @@ Changelog for sg3_utils-1.40 [20141002] [svn: r612]
- add --warn option mainly for broken joins
- add optional descriptions to -ee output
- sg_sanitize: add --desc and --zero options
+ - output unit serial number and LU name prior to
- sg_logs: refine tape drive output
- sg_raw: with -vvv decode T10 CDB name
- sg_opcodes: add --compact field
@@ -29,6 +31,9 @@ Changelog for sg3_utils-1.40 [20141002] [svn: r612]
- sg_lib: trim trailing spaces in dStrHex() and friends
- clean up service action string functions
- sg_ll_unmap_v2(): fix group number
+ - sg_ll_inquiry(), sg_ll_mode_sense*(),
+ sg_ll_log_sense(): use resid to clear unfilled
+ data-in buffer
- sg_unaligned.h: add header for building parameters
- examples/sg_tst_async: new Linux sg test utility
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index 100ebe2a..7210c3fd 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -77,11 +77,11 @@ is tightly bound to Linux and hence is not ported to other OSes. A more
generic utility (than sg_dd) called ddpt in a package of the same name has
been ported to other OSes.
.SH LINUX DEVICE NAMING
-Normal disk block devices have names like /dev/sda, /dev/sdb,
-/dev/sdc, etc. SCSI disks in Linux have always had names like that but
-in recent Linux kernels (e.g. lk 2.6 series) it is becoming more common
-for almost all disks to be named like that. Partitions within a disk
-are specified by a number appended to the device name, starting at
+Most disk block devices have names like /dev/sda, /dev/sdb, /dev/sdc, etc.
+SCSI disks in Linux have always had names like that but in recent Linux
+kernels it has become more common for many other disks (including SATA
+disks and USB storage devices) to be named like that. Partitions within a
+disk are specified by a number appended to the device name, starting at
1 (e.g. /dev/sda1 ).
.PP
Tape drives are named /dev/st<num> or /dev/nst<num> where <num> starts
@@ -104,6 +104,8 @@ and alternate device names.
Prior to the Linux kernel 2.6 series these utilities could only use
generic device names (e.g. /dev/sg1 ). In almost all cases in the Linux
kernel 2.6 series, any device name can be used by these utilities.
+.PP
+Very little has changed in Linux device naming in the lk 3 series.
.SH WINDOWS DEVICE NAMING
Storage and related devices can have several device names in Windows.
Probably the most common in the volume name (e.g. "D:"). There are also
diff --git a/lib/sg_cmds_basic.c b/lib/sg_cmds_basic.c
index 27649275..b42d8969 100644
--- a/lib/sg_cmds_basic.c
+++ b/lib/sg_cmds_basic.c
@@ -27,7 +27,7 @@
#endif
-static const char * version_str = "1.68 20140604";
+static const char * version_str = "1.69 20141006";
#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
@@ -46,7 +46,7 @@ static const char * version_str = "1.68 20140604";
#define TUR_CMD 0x0
#define TUR_CMDLEN 6
-#define INQUIRY_RESP_INITIAL_LEN 36
+#define SAFE_STD_INQ_RESP_LEN 36 /* other lengths lock up some devices */
const char *
@@ -235,7 +235,7 @@ int
sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op, void * resp,
int mx_resp_len, int noisy, int verbose)
{
- int res, ret, k, sense_cat;
+ int res, ret, k, sense_cat, resid;
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
unsigned char * up;
@@ -274,6 +274,7 @@ sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op, void * resp,
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b,
noisy, verbose, &sense_cat);
+ resid = get_scsi_pt_resid(ptvp);
destruct_scsi_pt_obj(ptvp);
if (-1 == ret)
;
@@ -295,6 +296,15 @@ sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op, void * resp,
} else
ret = 0;
+ if (resid > 0) {
+ if (resid > mx_resp_len) {
+ fprintf(sg_warnings_strm, "inquiry: resid (%d) should never "
+ "exceed requested len=%d\n", resid, mx_resp_len);
+ return ret ? ret : SG_LIB_CAT_MALFORMED;
+ }
+ /* zero unfilled section of response buffer */
+ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
+ }
return ret;
}
@@ -308,7 +318,7 @@ sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
int res, ret, k, sense_cat;
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
- unsigned char inq_resp[INQUIRY_RESP_INITIAL_LEN];
+ unsigned char inq_resp[SAFE_STD_INQ_RESP_LEN];
struct sg_pt_base * ptvp;
if (inq_data) {
diff --git a/lib/sg_cmds_basic2.c b/lib/sg_cmds_basic2.c
index a9378de8..022b7d7c 100644
--- a/lib/sg_cmds_basic2.c
+++ b/lib/sg_cmds_basic2.c
@@ -262,7 +262,7 @@ int
sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
void * resp, int mx_resp_len, int noisy, int verbose)
{
- int res, ret, k, sense_cat;
+ int res, ret, k, sense_cat, resid;
unsigned char modesCmdBlk[MODE_SENSE6_CMDLEN] =
{MODE_SENSE6_CMD, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
@@ -295,6 +295,8 @@ sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "mode sense (6)", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
+ resid = get_scsi_pt_resid(ptvp);
+ destruct_scsi_pt_obj(ptvp);
if (-1 == ret)
;
else if (-2 == ret) {
@@ -315,7 +317,16 @@ sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
}
ret = 0;
}
- destruct_scsi_pt_obj(ptvp);
+
+ if (resid > 0) {
+ if (resid > mx_resp_len) {
+ fprintf(sg_warnings_strm, "mode sense(6): resid (%d) should "
+ "never exceed requested len=%d\n", resid, mx_resp_len);
+ return ret ? ret : SG_LIB_CAT_MALFORMED;
+ }
+ /* zero unfilled section of response buffer */
+ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
+ }
return ret;
}
@@ -326,7 +337,7 @@ sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code,
int sub_pg_code, void * resp, int mx_resp_len,
int noisy, int verbose)
{
- int res, ret, k, sense_cat;
+ int res, ret, k, sense_cat, resid;
unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] =
{MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
@@ -360,6 +371,8 @@ sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code,
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "mode sense (10)", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
+ resid = get_scsi_pt_resid(ptvp);
+ destruct_scsi_pt_obj(ptvp);
if (-1 == ret)
;
else if (-2 == ret) {
@@ -380,7 +393,16 @@ sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code,
}
ret = 0;
}
- destruct_scsi_pt_obj(ptvp);
+
+ if (resid > 0) {
+ if (resid > mx_resp_len) {
+ fprintf(sg_warnings_strm, "mode sense(10): resid (%d) should "
+ "never exceed requested len=%d\n", resid, mx_resp_len);
+ return ret ? ret : SG_LIB_CAT_MALFORMED;
+ }
+ /* zero unfilled section of response buffer */
+ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
+ }
return ret;
}
@@ -678,7 +700,7 @@ sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code,
int subpg_code, int paramp, unsigned char * resp,
int mx_resp_len, int noisy, int verbose)
{
- int res, ret, k, sense_cat;
+ int res, ret, k, sense_cat, resid;
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];
@@ -715,6 +737,8 @@ sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code,
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "log sense", res, mx_resp_len,
sense_b, noisy, verbose, &sense_cat);
+ resid = get_scsi_pt_resid(ptvp);
+ destruct_scsi_pt_obj(ptvp);
if (-1 == ret)
;
else if (-2 == ret) {
@@ -735,7 +759,16 @@ sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code,
}
ret = 0;
}
- destruct_scsi_pt_obj(ptvp);
+
+ if (resid > 0) {
+ if (resid > mx_resp_len) {
+ fprintf(sg_warnings_strm, "log sense: resid (%d) should "
+ "never exceed requested len=%d\n", resid, mx_resp_len);
+ return ret ? ret : SG_LIB_CAT_MALFORMED;
+ }
+ /* zero unfilled section of response buffer */
+ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
+ }
return ret;
}
diff --git a/src/sg_format.c b/src/sg_format.c
index 90ac932b..bbb28bfa 100644
--- a/src/sg_format.c
+++ b/src/sg_format.c
@@ -32,7 +32,7 @@
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
-static const char * version_str = "1.29 20140921";
+static const char * version_str = "1.30 20141006";
#define RW_ERROR_RECOVERY_PAGE 1 /* can give alternate with --mode=MP */
@@ -303,6 +303,180 @@ scsi_format(int fd, int fmtpinfo, int cmplst, int pf_usage, int immed,
return 0;
}
+#define VPD_DEVICE_ID 0x83
+#define VPD_ASSOC_LU 0
+#define VPD_ASSOC_TPORT 1
+#define TPROTO_ISCSI 5
+
+static char *
+get_lu_name(const unsigned char * ucp, int u_len, char * b, int b_len)
+{
+ int len, off, sns_dlen, dlen, k;
+ unsigned char u_sns[512];
+ char * cp;
+
+ len = u_len - 4;
+ ucp += 4;
+ off = -1;
+ if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU,
+ 8 /* SCSI name string (sns) */,
+ 3 /* UTF-8 */)) {
+ sns_dlen = ucp[off + 3];
+ memcpy(u_sns, ucp + off + 4, sns_dlen);
+ /* now want to check if this is iSCSI */
+ off = -1;
+ if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_TPORT,
+ 8 /* SCSI name string (sns) */,
+ 3 /* UTF-8 */)) {
+ if ((0x80 & ucp[1]) &&
+ (TPROTO_ISCSI == (ucp[0] >> 4))) {
+ snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
+ return b;
+ }
+ }
+ } else
+ sns_dlen = 0;
+ if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU,
+ 3 /* NAA */, 1 /* binary */)) {
+ dlen = ucp[off + 3];
+ if (! ((8 == dlen) || (16 ==dlen)))
+ return b;
+ cp = b;
+ for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
+ snprintf(cp, b_len, "%02x", ucp[off + 4 + k]);
+ cp += 2;
+ b_len -= 2;
+ }
+ } else if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU,
+ 2 /* EUI */, 1 /* binary */)) {
+ dlen = ucp[off + 3];
+ if (! ((8 == dlen) || (12 == dlen) || (16 ==dlen)))
+ return b;
+ cp = b;
+ for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
+ snprintf(cp, b_len, "%02x", ucp[off + 4 + k]);
+ cp += 2;
+ b_len -= 2;
+ }
+ } else if (sns_dlen > 0)
+ snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
+ return b;
+}
+
+#define SAFE_STD_INQ_RESP_LEN 36
+#define VPD_SUPPORTED_VPDS 0x0
+#define VPD_UNIT_SERIAL_NUM 0x80
+#define VPD_DEVICE_ID 0x83
+
+static int
+print_dev_id(int fd, unsigned char * sinq_resp, int max_rlen, int verbose)
+{
+ int res, k, n, verb, pdt, has_sn, has_di;
+ unsigned char b[256];
+ char a[256];
+ char pdt_name[64];
+
+ verb = (verbose > 1) ? verbose - 1 : 0;
+ memset(sinq_resp, 0, max_rlen);
+ res = sg_ll_inquiry(fd, 0, 0 /* evpd */, 0 /* pg_op */, b,
+ SAFE_STD_INQ_RESP_LEN, 1, verb);
+ if (res)
+ return res;
+ n = b[4] + 5;
+ if (n > SAFE_STD_INQ_RESP_LEN)
+ n = SAFE_STD_INQ_RESP_LEN;
+ memcpy(sinq_resp, b, (n < max_rlen) ? n : max_rlen);
+ if (n == SAFE_STD_INQ_RESP_LEN) {
+ pdt = b[0] & 0x1f;
+ printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
+ (const char *)(b + 8), (const char *)(b + 16),
+ (const char *)(b + 32),
+ sg_get_pdt_str(pdt, sizeof(pdt_name), pdt_name), pdt);
+ if (verbose)
+ printf(" PROTECT=%d\n", !!(b[5] & 1));
+ if (b[5] & 1)
+ printf(" << supports protection information>>"
+ "\n");
+ } else {
+ fprintf(stderr, "Short INQUIRY response: %d bytes, expect at "
+ "least " "36\n", n);
+ return SG_LIB_CAT_OTHER;
+ }
+ res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_SUPPORTED_VPDS, b,
+ SAFE_STD_INQ_RESP_LEN, 1, verb);
+ if (res) {
+ if (verbose)
+ fprintf(stderr, "VPD_SUPPORTED_VPDS gave res=%d\n",
+ res);
+ return 0;
+ }
+ if (VPD_SUPPORTED_VPDS != b[1]) {
+ if (verbose)
+ fprintf(stderr, "VPD_SUPPORTED_VPDS corrupted\n");
+ return 0;
+ }
+ n = (b[2] << 8) + b[3];
+ if (n > (SAFE_STD_INQ_RESP_LEN - 4))
+ n = (SAFE_STD_INQ_RESP_LEN - 4);
+ for (k = 0, has_sn = 0, has_di = 0; k < n; ++k) {
+ if (VPD_UNIT_SERIAL_NUM == b[4 + k]) {
+ if (has_di) {
+ if (verbose)
+ fprintf(stderr, "VPD_SUPPORTED_VPDS "
+ "dis-ordered\n");
+ return 0;
+ }
+ ++has_sn;
+ } else if (VPD_DEVICE_ID == b[4 + k]) {
+ ++has_di;
+ break;
+ }
+ }
+ if (has_sn) {
+ res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_UNIT_SERIAL_NUM,
+ b, sizeof(b), 1, verb);
+ if (res) {
+ if (verbose)
+ fprintf(stderr, "VPD_UNIT_SERIAL_NUM gave "
+ "res=%d\n", res);
+ return 0;
+ }
+ if (VPD_UNIT_SERIAL_NUM != b[1]) {
+ if (verbose)
+ fprintf(stderr, "VPD_UNIT_SERIAL_NUM "
+ "corrupted\n");
+ return 0;
+ }
+ n = (b[2] << 8) + b[3];
+ if (n > (int)(sizeof(b) - 4))
+ n = (sizeof(b) - 4);
+ printf(" Unit serial number: %.*s\n", n,
+ (const char *)(b + 4));
+ }
+ if (has_di) {
+ res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_DEVICE_ID, b,
+ sizeof(b), 1, verb);
+ if (res) {
+ if (verbose)
+ fprintf(stderr, "VPD_DEVICE_ID gave res=%d\n",
+ res);
+ return 0;
+ }
+ if (VPD_DEVICE_ID != b[1]) {
+ if (verbose)
+ fprintf(stderr, "VPD_DEVICE_ID corrupted\n");
+ return 0;
+ }
+ n = (b[2] << 8) + b[3];
+ if (n > (int)(sizeof(b) - 4))
+ n = (sizeof(b) - 4);
+ n = strlen(get_lu_name(b, n + 4, a, sizeof(a)));
+ if (n > 0)
+ printf(" LU name: %.*s\n", n, a);
+ }
+ return 0;
+}
+
#define RCAP_REPLY_LEN 32
/* Returns block size or -2 if do_16==0 and the number of blocks is too
@@ -385,7 +559,7 @@ main(int argc, char **argv)
{
int mode_page = RW_ERROR_RECOVERY_PAGE;
int fd, res, calc_len, bd_len, dev_specific_param;
- int offset, j, bd_blk_len, prob, len;
+ int offset, j, bd_blk_len, prob, len, pdt;
uint64_t ull;
int64_t blk_count = 0; /* -c value */
int blk_size = 0; /* -s value */
@@ -408,9 +582,8 @@ main(int argc, char **argv)
int do_si = 0;
int early = 0;
const char * device_name = NULL;
- char pdt_name[64];
char b[80];
- struct sg_simple_inquiry_resp inq_out;
+ unsigned char inq_resp[SAFE_STD_INQ_RESP_LEN];
int ret = 0;
while (1) {
@@ -600,25 +773,11 @@ main(int argc, char **argv)
if (format > 2)
goto format_only;
- if (sg_simple_inquiry(fd, &inq_out, 1, verbose)) {
- fprintf(stderr, "%s doesn't respond to a SCSI INQUIRY\n",
- device_name);
- ret = SG_LIB_CAT_OTHER;
- goto out;
- }
- printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
- inq_out.vendor, inq_out.product, inq_out.revision,
- sg_get_pdt_str(inq_out.peripheral_type, sizeof(pdt_name),
- pdt_name),
- inq_out.peripheral_type);
- if (verbose)
- printf(" PROTECT=%d\n", !!(inq_out.byte_5 & 1));
- if (inq_out.byte_5 & 1)
- printf(" << supports protection information>>\n");
-
- if ((0 != inq_out.peripheral_type) &&
- (7 != inq_out.peripheral_type) &&
- (0xe != inq_out.peripheral_type)) {
+ ret = print_dev_id(fd, inq_resp, sizeof(inq_resp), verbose);
+ if (ret)
+ goto out;
+ pdt = 0x1f & inq_resp[0];
+ if ((0 != pdt) && (7 != pdt) && (0xe != pdt)) {
fprintf(stderr, "This format is only defined for disks "
"(using SBC-2 or RBC) and MO media\n");
ret = SG_LIB_CAT_MALFORMED;
diff --git a/src/sg_inq.c b/src/sg_inq.c
index b9591a51..5d69d40d 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -41,7 +41,7 @@
#include "sg_cmds_basic.h"
#include "sg_pt.h"
-static const char * version_str = "1.40 20140704"; /* SPC-4 rev 37 */
+static const char * version_str = "1.41 20141006"; /* SPC-4 rev 37 */
/* INQUIRY notes:
* It is recommended that the initial allocation length given to a
@@ -935,7 +935,7 @@ static int
pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len,
int * residp, int noisy, int verbose)
{
- int res, ret, k, sense_cat;
+ int res, ret, k, sense_cat, resid;
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
unsigned char * up;
@@ -970,8 +970,9 @@ pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len,
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b,
noisy, verbose, &sense_cat);
+ resid = get_scsi_pt_resid(ptvp);
if (residp)
- *residp = get_scsi_pt_resid(ptvp);
+ *residp = resid;
destruct_scsi_pt_obj(ptvp);
if (-1 == ret)
;
@@ -992,6 +993,15 @@ pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len,
} else
ret = 0;
+ if (resid > 0) {
+ if (resid > mx_resp_len) {
+ pr2serr("INQUIRY resid (%d) should never exceed requested "
+ "len=%d\n", resid, mx_resp_len);
+ return ret ? ret : SG_LIB_CAT_MALFORMED;
+ }
+ /* zero unfilled section of response buffer */
+ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
+ }
return ret;
}
diff --git a/src/sg_sanitize.c b/src/sg_sanitize.c
index 30522b76..860fc7cb 100644
--- a/src/sg_sanitize.c
+++ b/src/sg_sanitize.c
@@ -26,7 +26,7 @@
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
-static const char * version_str = "0.95 20140923";
+static const char * version_str = "0.96 20141006";
/* Not all environments support the Unix sleep() */
#if defined(MSC_VER) || defined(__MINGW32__)
@@ -243,6 +243,172 @@ do_sanitize(int sg_fd, const struct opts_t * op, const void * param_lstp,
return ret;
}
+#define VPD_DEVICE_ID 0x83
+#define VPD_ASSOC_LU 0
+#define VPD_ASSOC_TPORT 1
+#define TPROTO_ISCSI 5
+
+static char *
+get_lu_name(const unsigned char * ucp, int u_len, char * b, int b_len)
+{
+ int len, off, sns_dlen, dlen, k;
+ unsigned char u_sns[512];
+ char * cp;
+
+ len = u_len - 4;
+ ucp += 4;
+ off = -1;
+ if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU,
+ 8 /* SCSI name string (sns) */,
+ 3 /* UTF-8 */)) {
+ sns_dlen = ucp[off + 3];
+ memcpy(u_sns, ucp + off + 4, sns_dlen);
+ /* now want to check if this is iSCSI */
+ off = -1;
+ if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_TPORT,
+ 8 /* SCSI name string (sns) */,
+ 3 /* UTF-8 */)) {
+ if ((0x80 & ucp[1]) && (TPROTO_ISCSI == (ucp[0] >> 4))) {
+ snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
+ return b;
+ }
+ }
+ } else
+ sns_dlen = 0;
+ if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU,
+ 3 /* NAA */, 1 /* binary */)) {
+ dlen = ucp[off + 3];
+ if (! ((8 == dlen) || (16 ==dlen)))
+ return b;
+ cp = b;
+ for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
+ snprintf(cp, b_len, "%02x", ucp[off + 4 + k]);
+ cp += 2;
+ b_len -= 2;
+ }
+ } else if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU,
+ 2 /* EUI */, 1 /* binary */)) {
+ dlen = ucp[off + 3];
+ if (! ((8 == dlen) || (12 == dlen) || (16 ==dlen)))
+ return b;
+ cp = b;
+ for (k = 0; ((k < dlen) && (b_len > 1)); ++k) {
+ snprintf(cp, b_len, "%02x", ucp[off + 4 + k]);
+ cp += 2;
+ b_len -= 2;
+ }
+ } else if (sns_dlen > 0)
+ snprintf(b, b_len, "%.*s", sns_dlen, u_sns);
+ return b;
+}
+
+#define SAFE_STD_INQ_RESP_LEN 36
+#define VPD_SUPPORTED_VPDS 0x0
+#define VPD_UNIT_SERIAL_NUM 0x80
+#define VPD_DEVICE_ID 0x83
+
+static int
+print_dev_id(int fd, unsigned char * sinq_resp, int max_rlen, int verbose)
+{
+ int res, k, n, verb, pdt, has_sn, has_di;
+ unsigned char b[256];
+ char a[256];
+ char pdt_name[64];
+
+ verb = (verbose > 1) ? verbose - 1 : 0;
+ memset(sinq_resp, 0, max_rlen);
+ res = sg_ll_inquiry(fd, 0, 0 /* evpd */, 0 /* pg_op */, b,
+ SAFE_STD_INQ_RESP_LEN, 1, verb);
+ if (res)
+ return res;
+ n = b[4] + 5;
+ if (n > SAFE_STD_INQ_RESP_LEN)
+ n = SAFE_STD_INQ_RESP_LEN;
+ memcpy(sinq_resp, b, (n < max_rlen) ? n : max_rlen);
+ if (n == SAFE_STD_INQ_RESP_LEN) {
+ pdt = b[0] & 0x1f;
+ printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
+ (const char *)(b + 8), (const char *)(b + 16),
+ (const char *)(b + 32),
+ sg_get_pdt_str(pdt, sizeof(pdt_name), pdt_name), pdt);
+ if (verbose)
+ printf(" PROTECT=%d\n", !!(b[5] & 1));
+ if (b[5] & 1)
+ printf(" << supports protection information>>\n");
+ } else {
+ fprintf(stderr, "Short INQUIRY response: %d bytes, expect at least "
+ "36\n", n);
+ return SG_LIB_CAT_OTHER;
+ }
+ res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_SUPPORTED_VPDS, b,
+ SAFE_STD_INQ_RESP_LEN, 1, verb);
+ if (res) {
+ if (verbose)
+ fprintf(stderr, "VPD_SUPPORTED_VPDS gave res=%d\n", res);
+ return 0;
+ }
+ if (VPD_SUPPORTED_VPDS != b[1]) {
+ if (verbose)
+ fprintf(stderr, "VPD_SUPPORTED_VPDS corrupted\n");
+ return 0;
+ }
+ n = (b[2] << 8) + b[3];
+ if (n > (SAFE_STD_INQ_RESP_LEN - 4))
+ n = (SAFE_STD_INQ_RESP_LEN - 4);
+ for (k = 0, has_sn = 0, has_di = 0; k < n; ++k) {
+ if (VPD_UNIT_SERIAL_NUM == b[4 + k]) {
+ if (has_di) {
+ if (verbose)
+ fprintf(stderr, "VPD_SUPPORTED_VPDS dis-ordered\n");
+ return 0;
+ }
+ ++has_sn;
+ } else if (VPD_DEVICE_ID == b[4 + k]) {
+ ++has_di;
+ break;
+ }
+ }
+ if (has_sn) {
+ res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_UNIT_SERIAL_NUM, b,
+ sizeof(b), 1, verb);
+ if (res) {
+ if (verbose)
+ fprintf(stderr, "VPD_UNIT_SERIAL_NUM gave res=%d\n", res);
+ return 0;
+ }
+ if (VPD_UNIT_SERIAL_NUM != b[1]) {
+ if (verbose)
+ fprintf(stderr, "VPD_UNIT_SERIAL_NUM corrupted\n");
+ return 0;
+ }
+ n = (b[2] << 8) + b[3];
+ if (n > (int)(sizeof(b) - 4))
+ n = (sizeof(b) - 4);
+ printf(" Unit serial number: %.*s\n", n, (const char *)(b + 4));
+ }
+ if (has_di) {
+ res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_DEVICE_ID, b,
+ sizeof(b), 1, verb);
+ if (res) {
+ if (verbose)
+ fprintf(stderr, "VPD_DEVICE_ID gave res=%d\n", res);
+ return 0;
+ }
+ if (VPD_DEVICE_ID != b[1]) {
+ if (verbose)
+ fprintf(stderr, "VPD_DEVICE_ID corrupted\n");
+ return 0;
+ }
+ n = (b[2] << 8) + b[3];
+ if (n > (int)(sizeof(b) - 4))
+ n = (sizeof(b) - 4);
+ n = strlen(get_lu_name(b, n + 4, a, sizeof(a)));
+ if (n > 0)
+ printf(" LU name: %.*s\n", n, a);
+ }
+ return 0;
+}
+
int
main(int argc, char * argv[])
@@ -252,7 +418,6 @@ main(int argc, char * argv[])
int param_lst_len = 0;
const char * device_name = NULL;
char ebuff[EBUFF_SZ];
- char pdt_name[32];
char b[80];
unsigned char requestSenseBuff[DEF_REQS_RESP_LEN];
unsigned char * wBuff = NULL;
@@ -260,7 +425,7 @@ main(int argc, char * argv[])
struct opts_t opts;
struct opts_t * op;
struct stat a_stat;
- struct sg_simple_inquiry_resp inq_out;
+ unsigned char inq_resp[SAFE_STD_INQ_RESP_LEN];
op = &opts;
memset(op, 0, sizeof(opts));
@@ -420,18 +585,9 @@ main(int argc, char * argv[])
return SG_LIB_FILE_ERROR;
}
- if (sg_simple_inquiry(sg_fd, &inq_out, 1, vb)) {
- fprintf(stderr, "%s doesn't respond to a SCSI INQUIRY\n",
- device_name);
- ret = SG_LIB_CAT_OTHER;
- goto err_out;
- }
- printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
- inq_out.vendor, inq_out.product, inq_out.revision,
- sg_get_pdt_str(inq_out.peripheral_type, sizeof(pdt_name),
- pdt_name),
- inq_out.peripheral_type);
-
+ ret = print_dev_id(sg_fd, inq_resp, sizeof(inq_resp), op->verbose);
+ if (ret)
+ goto err_out;
if (op->overwrite) {
param_lst_len = op->ipl + 4;
diff --git a/src/sg_ses.c b/src/sg_ses.c
index 9ff360d3..a6ea4482 100644
--- a/src/sg_ses.c
+++ b/src/sg_ses.c
@@ -29,7 +29,7 @@
* commands tailored for SES (enclosure) devices.
*/
-static const char * version_str = "1.95 20140930"; /* ses3r06 */
+static const char * version_str = "1.96 20141004"; /* ses3r06 */
#define MX_ALLOC_LEN ((64 * 1024) - 4) /* max allowable for big enclosures */
#define MX_ELEM_HDR 1024
@@ -101,7 +101,7 @@ struct opts_t {
int do_control;
int do_data;
int dev_slot_num;
- int do_enumerate;
+ int enumerate;
int eiioe_auto;
int eiioe_force;
int do_filter;
@@ -391,12 +391,13 @@ static struct element_type_t element_type_by_code =
static struct acronym2tuple ecs_a2t_arr[] = {
{"active", DEVICE_ETC, 2, 7, 1, NULL}, /* for control only */
{"active", ARRAY_DEV_ETC, 2, 7, 1, NULL}, /* for control only */
- {"conscheck", ARRAY_DEV_ETC, 1, 4, 1, NULL},
+ {"conscheck", ARRAY_DEV_ETC, 1, 4, 1, "consistency check"},
{"disable", -1, 0, 5, 1, NULL}, /* -1 is for all element types */
{"devoff", DEVICE_ETC, 3, 4, 1, NULL}, /* device off */
{"devoff", ARRAY_DEV_ETC, 3, 4, 1, NULL},
- {"dnr", DEVICE_ETC, 2, 6, 1, NULL}, /* do not remove */
- {"dnr", ARRAY_DEV_ETC, 2, 6, 1, NULL},
+ {"dnr", DEVICE_ETC, 2, 6, 1, "do not remove"},
+ {"dnr", ARRAY_DEV_ETC, 2, 6, 1, "do not remove"},
+ {"fail", SAS_CONNECTOR_ETC, 3, 6, 1, NULL},
{"fault", DEVICE_ETC, 3, 5, 1, NULL},
{"fault", ARRAY_DEV_ETC, 3, 5, 1, NULL},
{"hotspare", ARRAY_DEV_ETC, 1, 5, 1, NULL},
@@ -406,32 +407,35 @@ static struct acronym2tuple ecs_a2t_arr[] = {
{"ident", COOLING_ETC, 1, 7, 1, "flash LED"},
{"ident", ENCLOSURE_ETC, 1, 7, 1, "flash LED"},
{"ident", AUD_ALARM_ETC, 1, 7, 1, NULL},
+ {"ident", SAS_CONNECTOR_ETC, 1, 7, 1, "flash LED"},
{"incritarray", ARRAY_DEV_ETC, 1, 3, 1, NULL},
{"infailedarray", ARRAY_DEV_ETC, 1, 2, 1, NULL},
{"info", AUD_ALARM_ETC, 3, 3, 1, "emits warning tone when set"},
{"insert", DEVICE_ETC, 2, 3, 1, NULL},
{"insert", ARRAY_DEV_ETC, 2, 3, 1, NULL},
- {"locate", DEVICE_ETC, 2, 1, 1, NULL},
- {"locate", ARRAY_DEV_ETC, 2, 1, 1, NULL},
- {"locate", POWER_SUPPLY_ETC, 1, 7, 1, NULL},
- {"locate", COOLING_ETC, 1, 7, 1, NULL},
- {"locate", ENCLOSURE_ETC, 1, 7, 1, NULL},
+ {"locate", DEVICE_ETC, 2, 1, 1, "flash LED"},
+ {"locate", ARRAY_DEV_ETC, 2, 1, 1, "flash LED"},
+ {"locate", POWER_SUPPLY_ETC, 1, 7, 1, "flash LED"},
+ {"locate", COOLING_ETC, 1, 7, 1, "flash LED"},
+ {"locate", ENCLOSURE_ETC, 1, 7, 1, "flash LED"},
+ {"locate", SAS_CONNECTOR_ETC, 1, 7, 1, "flash LED"},
{"missing", DEVICE_ETC, 2, 4, 1, NULL},
{"missing", ARRAY_DEV_ETC, 2, 4, 1, NULL},
{"ok", ARRAY_DEV_ETC, 1, 7, 1, NULL},
{"on", POWER_SUPPLY_ETC, 3, 5, 1, "0: turn (remain) off; 1: turn on"},
+ {"overcurrent", SAS_CONNECTOR_ETC, 3, 5, 1, NULL},
{"locate", DEVICE_ETC, 2, 1, 1, NULL},
{"locate", ARRAY_DEV_ETC, 2, 1, 1, NULL},
{"pow_cycle", ENCLOSURE_ETC, 2, 7, 2,
"0: no; 1: start power cycle in pow_c_delay minutes; 2: cancel"},
{"pow_c_delay", ENCLOSURE_ETC, 2, 5, 6,
"delay in minutes before starting power cycle"},
- {"prdfail", -1, 0, 6, 1, NULL},
+ {"prdfail", -1, 0, 6, 1, "predict failure"},
{"rebuildremap", ARRAY_DEV_ETC, 1, 1, 1, NULL},
{"remove", DEVICE_ETC, 2, 2, 1, NULL},
{"remove", ARRAY_DEV_ETC, 2, 2, 1, NULL},
- {"rrabort", ARRAY_DEV_ETC, 1, 0, 1, NULL},
- {"rsvddevice", ARRAY_DEV_ETC, 1, 6, 1, NULL},
+ {"rrabort", ARRAY_DEV_ETC, 1, 0, 1, "rebuild/remap abort"},
+ {"rsvddevice", ARRAY_DEV_ETC, 1, 6, 1, "reserved device"},
{"speed_act", COOLING_ETC, 1, 2, 11, "actual speed (rpm / 10)"},
{"speed_code", COOLING_ETC, 3, 2, 3,
"0: leave; 1: lowest... 7: highest"},
@@ -448,13 +452,16 @@ static struct acronym2tuple th_a2t_arr[] = {
{NULL, 0, 0, 0, 0, NULL},
};
-/* These are for the Additional element status diagnostic page for SAS
- * with the EIP bit set. First phy only. */
+/* These are for the Additional element status diagnostic page for SAS with
+ * the EIP bit set. First phy only. Index from start of AES descriptor */
static struct acronym2tuple ae_sas_a2t_arr[] = {
{"at_sas_addr", -1, 12, 7, 64, NULL}, /* best viewed with --hex --get= */
- {"dev_type", -1, 8, 6, 3, NULL},
+ /* typically this is the expander's SAS address */
+ {"dev_type", -1, 8, 6, 3, "1: SAS/SATA dev, 2: expander"},
+ {"dsn", -1, 7, 7, 8, "device slot number (255: none)"},
+ {"num_phys", -1, 4, 7, 8, "number of phys"},
{"phy_id", -1, 28, 7, 8, NULL},
- {"sas_addr", -1, 20, 7, 64, NULL}, /* from disk's POV */
+ {"sas_addr", -1, 20, 7, 64, NULL}, /* should be disk or tape ... */
{"sata_dev", -1, 11, 0, 1, NULL},
{"sata_port_sel", -1, 11, 7, 1, NULL},
{"smp_init", -1, 10, 1, 1, NULL},
@@ -837,7 +844,7 @@ cl_process(struct opts_t *op, int argc, char *argv[])
op->desc_name = optarg;
break;
case 'e':
- ++op->do_enumerate;
+ ++op->enumerate;
break;
case 'E':
if (0 == strcmp("auto", optarg))
@@ -1022,7 +1029,7 @@ cl_process(struct opts_t *op, int argc, char *argv[])
pr2serr("assume --page=2 (es) option is set\n");
}
}
- if (op->do_list || op->do_enumerate)
+ if (op->do_list || op->enumerate)
return 0;
if (op->do_control && op->do_status) {
pr2serr("cannot have both '--control' and '--status'\n");
@@ -2207,7 +2214,7 @@ ses_element_desc_sdg(const struct type_desc_hdr_t * tdhp, int num_telems,
pr2serr(" <<state of enclosure changed, please try again>>\n");
return;
}
- printf(" element descriptor by type list\n");
+ printf(" element descriptor list (grouped by type):\n");
ucp = resp + 8;
for (k = 0, got1 = 0, tp = tdhp; k < num_telems; ++k, ++tp) {
if ((ucp + 3) > last_ucp)
@@ -3602,37 +3609,37 @@ strcase_eq(const char * s1p, const char * s2p)
static int
is_acronym_in_status_ctl(const struct tuple_acronym_val * tavp)
{
- const struct acronym2tuple * a2tp;
+ const struct acronym2tuple * ap;
- for (a2tp = ecs_a2t_arr; a2tp->acron; ++ a2tp) {
- if (strcase_eq(tavp->acron, a2tp->acron))
+ for (ap = ecs_a2t_arr; ap->acron; ++ ap) {
+ if (strcase_eq(tavp->acron, ap->acron))
break;
}
- return (a2tp->acron ? 1 : 0);
+ return (ap->acron ? 1 : 0);
}
static int
is_acronym_in_threshold(const struct tuple_acronym_val * tavp)
{
- const struct acronym2tuple * a2tp;
+ const struct acronym2tuple * ap;
- for (a2tp = th_a2t_arr; a2tp->acron; ++ a2tp) {
- if (strcase_eq(tavp->acron, a2tp->acron))
+ for (ap = th_a2t_arr; ap->acron; ++ ap) {
+ if (strcase_eq(tavp->acron, ap->acron))
break;
}
- return (a2tp->acron ? 1 : 0);
+ return (ap->acron ? 1 : 0);
}
static int
is_acronym_in_additional(const struct tuple_acronym_val * tavp)
{
- const struct acronym2tuple * a2tp;
+ const struct acronym2tuple * ap;
- for (a2tp = ae_sas_a2t_arr; a2tp->acron; ++ a2tp) {
- if (strcase_eq(tavp->acron, a2tp->acron))
+ for (ap = ae_sas_a2t_arr; ap->acron; ++ ap) {
+ if (strcase_eq(tavp->acron, ap->acron))
break;
}
- return (a2tp->acron ? 1 : 0);
+ return (ap->acron ? 1 : 0);
}
/* DPC_ENC_STATUS DPC_ENC_CONTROL
@@ -3645,7 +3652,7 @@ cgs_enc_ctl_stat(int sg_fd, const struct join_row_t * jrp,
{
int ret, len, s_byte, s_bit, n_bits;
uint64_t ui;
- const struct acronym2tuple * a2tp;
+ const struct acronym2tuple * ap;
if (NULL == tavp->acron) {
s_byte = tavp->start_byte;
@@ -3653,19 +3660,19 @@ cgs_enc_ctl_stat(int sg_fd, const struct join_row_t * jrp,
n_bits = tavp->num_bits;
}
if (tavp->acron) {
- for (a2tp = ecs_a2t_arr; a2tp->acron; ++ a2tp) {
- if (((jrp->etype == a2tp->etype) || (-1 == a2tp->etype)) &&
- strcase_eq(tavp->acron, a2tp->acron))
+ for (ap = ecs_a2t_arr; ap->acron; ++ ap) {
+ if (((jrp->etype == ap->etype) || (-1 == ap->etype)) &&
+ strcase_eq(tavp->acron, ap->acron))
break;
}
- if (a2tp->acron) {
- s_byte = a2tp->start_byte;
- s_bit = a2tp->start_bit;
- n_bits = a2tp->num_bits;
+ if (ap->acron) {
+ s_byte = ap->start_byte;
+ s_bit = ap->start_bit;
+ n_bits = ap->num_bits;
} else {
- if (-1 != a2tp->etype) {
- for (a2tp = ecs_a2t_arr; a2tp->acron; ++ a2tp) {
- if (0 == strcase_eq(tavp->acron, a2tp->acron)) {
+ if (-1 != ap->etype) {
+ for (ap = ecs_a2t_arr; ap->acron; ++ap) {
+ if (0 == strcase_eq(tavp->acron, ap->acron)) {
pr2serr(">>> Found %s acronym but not for element "
"type %d\n", tavp->acron, jrp->etype);
break;
@@ -3710,7 +3717,7 @@ cgs_threshold(int sg_fd, const struct join_row_t * jrp,
{
int ret, len, s_byte, s_bit, n_bits;
uint64_t ui;
- const struct acronym2tuple * a2tp;
+ const struct acronym2tuple * ap;
if (NULL == jrp->thresh_inp) {
pr2serr("No Threshold In/Out element available\n");
@@ -3722,15 +3729,15 @@ cgs_threshold(int sg_fd, const struct join_row_t * jrp,
n_bits = tavp->num_bits;
}
if (tavp->acron) {
- for (a2tp = th_a2t_arr; a2tp->acron; ++ a2tp) {
- if (((jrp->etype == a2tp->etype) || (-1 == a2tp->etype)) &&
- strcase_eq(tavp->acron, a2tp->acron))
+ for (ap = th_a2t_arr; ap->acron; ++ap) {
+ if (((jrp->etype == ap->etype) || (-1 == ap->etype)) &&
+ strcase_eq(tavp->acron, ap->acron))
break;
}
- if (a2tp->acron) {
- s_byte = a2tp->start_byte;
- s_bit = a2tp->start_bit;
- n_bits = a2tp->num_bits;
+ if (ap->acron) {
+ s_byte = ap->start_byte;
+ s_bit = ap->start_bit;
+ n_bits = ap->num_bits;
} else
return -2;
}
@@ -3765,7 +3772,7 @@ cgs_additional_el(const struct join_row_t * jrp,
{
int s_byte, s_bit, n_bits;
uint64_t ui;
- const struct acronym2tuple * a2tp;
+ const struct acronym2tuple * ap;
if (NULL == jrp->add_elem_statp) {
pr2serr("No additional element status element available\n");
@@ -3777,15 +3784,15 @@ cgs_additional_el(const struct join_row_t * jrp,
n_bits = tavp->num_bits;
}
if (tavp->acron) {
- for (a2tp = ae_sas_a2t_arr; a2tp->acron; ++ a2tp) {
- if (((jrp->etype == a2tp->etype) || (-1 == a2tp->etype)) &&
- strcase_eq(tavp->acron, a2tp->acron))
+ for (ap = ae_sas_a2t_arr; ap->acron; ++ap) {
+ if (((jrp->etype == ap->etype) || (-1 == ap->etype)) &&
+ strcase_eq(tavp->acron, ap->acron))
break;
}
- if (a2tp->acron) {
- s_byte = a2tp->start_byte;
- s_bit = a2tp->start_bit;
- n_bits = a2tp->num_bits;
+ if (ap->acron) {
+ s_byte = ap->start_byte;
+ s_bit = ap->start_bit;
+ n_bits = ap->num_bits;
} else
return -2;
}
@@ -3965,16 +3972,16 @@ enumerate_diag_pages(void)
static void
enumerate_work(const struct opts_t * op)
{
- int num;
+ int num, e3;
const struct element_type_t * etp;
- const struct acronym2tuple * a2tp;
+ const struct acronym2tuple * ap;
char b[64];
const char * cp;
if (op->dev_name)
printf(">>> DEVICE %s ignored when --%s option given.\n",
op->dev_name, (op->do_list ? "list" : "enumerate"));
- num = op->do_enumerate + op->do_list;
+ num = op->enumerate + op->do_list;
if (num < 2) {
enumerate_diag_pages();
printf("\nSES element type names, followed by abbreviation and "
@@ -3983,33 +3990,37 @@ enumerate_work(const struct opts_t * op)
printf(" %s [%s] [0x%x]\n", etp->desc, etp->abbrev,
etp->elem_type_code);
} else {
+ e3 = (op->enumerate > 2);
/* command line has multiple --enumerate and/or --list options */
printf("--clear, --get, --set acronyms for Enclosure Status/Control "
"['es' or 'ec'] page:\n");
- for (a2tp = ecs_a2t_arr; a2tp->acron; ++a2tp) {
- cp = (a2tp->etype < 0) ? "*" :
- find_element_tname(a2tp->etype, b, sizeof(b));
- printf(" %s [%s] [%d:%d:%d]\t%s\n", a2tp->acron,
- (cp ? cp : "??"), a2tp->start_byte, a2tp->start_bit,
- a2tp->num_bits, (a2tp->info ? a2tp->info : ""));
+ for (ap = ecs_a2t_arr; ap->acron; ++ap) {
+ cp = (ap->etype < 0) ?
+ "*" : find_element_tname(ap->etype, b, sizeof(b));
+ printf(" %s [%s] [%d:%d:%d]%s\t%s\n", ap->acron,
+ (cp ? cp : "??"), ap->start_byte, ap->start_bit,
+ ap->num_bits, ((e3 && ap->info) ? "\n\t\t" : ""),
+ (ap->info ? ap->info : ""));
}
printf("\n--clear, --get, --set acronyms for Threshold In/Out "
"['th'] page:\n");
- for (a2tp = th_a2t_arr; a2tp->acron; ++a2tp) {
- cp = (a2tp->etype < 0) ? "*" :
- find_element_tname(a2tp->etype, b, sizeof(b));
- printf(" %s [%s] [%d:%d:%d]\t%s\n", a2tp->acron,
- (cp ? cp : "??"), a2tp->start_byte, a2tp->start_bit,
- a2tp->num_bits, (a2tp->info ? a2tp->info : ""));
+ for (ap = th_a2t_arr; ap->acron; ++ap) {
+ cp = (ap->etype < 0) ? "*" :
+ find_element_tname(ap->etype, b, sizeof(b));
+ printf(" %s [%s] [%d:%d:%d]%s\t%s\n", ap->acron,
+ (cp ? cp : "??"), ap->start_byte, ap->start_bit,
+ ap->num_bits, ((e3 && ap->info) ? "\n\t\t" : ""),
+ (ap->info ? ap->info : ""));
}
printf("\n--get acronyms for Additional Element Status ['aes'] page "
"(SAS EIP=1):\n");
- for (a2tp = ae_sas_a2t_arr; a2tp->acron; ++a2tp) {
- cp = (a2tp->etype < 0) ? "*" :
- find_element_tname(a2tp->etype, b, sizeof(b));
- printf(" %s [%s] [%d:%d:%d]\t%s\n", a2tp->acron,
- (cp ? cp : "??"), a2tp->start_byte, a2tp->start_bit,
- a2tp->num_bits, (a2tp->info ? a2tp->info : ""));
+ for (ap = ae_sas_a2t_arr; ap->acron; ++ap) {
+ cp = (ap->etype < 0) ? "*" :
+ find_element_tname(ap->etype, b, sizeof(b));
+ printf(" %s [%s] [%d:%d:%d]%s\t%s\n", ap->acron,
+ (cp ? cp : "??"), ap->start_byte, ap->start_bit,
+ ap->num_bits, ((e3 && ap->info) ? "\n\t\t" : ""),
+ (ap->info ? ap->info : ""));
}
}
}
@@ -4043,7 +4054,7 @@ main(int argc, char * argv[])
usage(op->do_help);
return 0;
}
- if (op->do_enumerate || op->do_list) {
+ if (op->enumerate || op->do_list) {
enumerate_work(op);
return 0;
}
diff --git a/src/sg_vpd.c b/src/sg_vpd.c
index 73338c53..8ecb3a71 100644
--- a/src/sg_vpd.c
+++ b/src/sg_vpd.c
@@ -36,7 +36,7 @@
*/
-static const char * version_str = "0.93 20140916"; /* spc4r37 + sbc4r02 */
+static const char * version_str = "0.94 20141006"; /* spc4r37 + sbc4r02 */
/* These structures are duplicates of those of the same name in
@@ -486,7 +486,7 @@ static int
pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len,
int * residp, int noisy, int verbose)
{
- int res, ret, k, sense_cat;
+ int res, ret, k, sense_cat, resid;
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
unsigned char * up;
@@ -521,8 +521,9 @@ pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len,
res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b,
noisy, verbose, &sense_cat);
+ resid = get_scsi_pt_resid(ptvp);
if (residp)
- *residp = get_scsi_pt_resid(ptvp);
+ *residp = resid;
destruct_scsi_pt_obj(ptvp);
if (-1 == ret)
;
@@ -543,6 +544,15 @@ pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len,
} else
ret = 0;
+ if (resid > 0) {
+ if (resid > mx_resp_len) {
+ pr2serr("INQUIRY resid (%d) should never exceed requested "
+ "len=%d\n", resid, mx_resp_len);
+ return ret ? ret : SG_LIB_CAT_MALFORMED;
+ }
+ /* zero unfilled section of response buffer */
+ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
+ }
return ret;
}