aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2022-06-25 04:05:14 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2022-06-25 04:05:14 +0000
commit2e225c87784735360e9619766efe06782179a86a (patch)
tree1df2832c733c55207261b829ec7f0146287afe82 /lib
parenta3eb530bb4b93949287f19a2b6fb418901f1f699 (diff)
downloadsg3_utils-2e225c87784735360e9619766efe06782179a86a.tar.gz
sg_rem_rest_elem: new utility for removing or restoring elements; bug fixes
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@955 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'lib')
-rw-r--r--lib/sg_lib.c151
-rw-r--r--lib/sg_lib_data.c4
-rw-r--r--lib/sg_pr2serr.c1060
-rw-r--r--lib/sg_pt_haiku.c2
4 files changed, 1129 insertions, 88 deletions
diff --git a/lib/sg_lib.c b/lib/sg_lib.c
index 8922d323..418638b5 100644
--- a/lib/sg_lib.c
+++ b/lib/sg_lib.c
@@ -325,7 +325,8 @@ sg_get_sense_key_str(int sense_key, int buff_len, char * buff)
/* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
char *
-sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
+sg_get_additional_sense_str(int asc, int ascq, bool add_sense_leadin,
+ int buff_len, char * buff)
{
int k, num, rlen;
bool found = false;
@@ -341,7 +342,10 @@ sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
(ascq >= ei2p->ascq_min) &&
(ascq <= ei2p->ascq_max)) {
found = true;
- num = sg_scnpr(buff, buff_len, "Additional sense: ");
+ if (add_sense_leadin)
+ num = sg_scnpr(buff, buff_len, "Additional sense: ");
+ else
+ num = 0;
rlen = buff_len - num;
sg_scnpr(buff + num, ((rlen > 0) ? rlen : 0), ei2p->text, ascq);
}
@@ -355,7 +359,10 @@ sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
if (eip->asc == asc &&
eip->ascq == ascq) {
found = true;
- sg_scnpr(buff, buff_len, "Additional sense: %s", eip->text);
+ if (add_sense_leadin)
+ sg_scnpr(buff, buff_len, "Additional sense: %s", eip->text);
+ else
+ sg_scnpr(buff, buff_len, "%s", eip->text);
}
}
if (! found) {
@@ -371,6 +378,13 @@ sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
return buff;
}
+/* Yield string associated with ASC/ASCQ values. Returns 'buff'. */
+char *
+sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff)
+{
+ return sg_get_additional_sense_str(asc, ascq, true, buff_len, buff);
+}
+
/* Attempt to find the first SCSI sense data descriptor that matches the
* given 'desc_type'. If found return pointer to start of sense data
* descriptor; otherwise (including fixed format sense data) returns NULL. */
@@ -829,7 +843,7 @@ sg_get_desig_assoc_str(int val)
static const char * desig_type_str_arr[] =
{
- "vendor specific [0x0]",
+ "Vendor specific [0x0]",
"T10 vendor identification",
"EUI-64 based",
"NAA",
@@ -979,7 +993,6 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
if (piv && ((1 == assoc) || (2 == assoc)))
n += sg_scnpr(b + n, blen - n, "%s transport: %s\n", lip,
sg_get_trans_proto_str(p_id, sizeof(e), e));
- /* printf(" associated with the %s\n", sdparm_assoc_arr[assoc]); */
switch (desig_type) {
case 0: /* vendor specific */
k = 0;
@@ -1049,7 +1062,7 @@ sg_get_designation_descriptor_str(const char * lip, const uint8_t * ddp,
}
ccc_id = sg_get_unaligned_be64(ip + ci_off);
n += sg_scnpr(b + n, blen - n, "%s IEEE identifier: 0x%"
- PRIx64 "x\n", lip, ccc_id);
+ PRIx64 "\n", lip, ccc_id);
if (12 == dlen) {
d_id = sg_get_unaligned_be32(ip + 8);
n += sg_scnpr(b + n, blen - n, "%s Directory ID: 0x%x\n",
@@ -1405,10 +1418,10 @@ uds_referral_descriptor_str(char * b, int blen, const uint8_t * dp,
!!(dp[2] & 0x1));
dp += 4;
for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) {
- int tpgd = dp[3];
+ int ntpgd = dp[3];
uint64_t ull;
- g = (tpgd * 4) + 20;
+ g = (ntpgd * 4) + 20;
n += sg_scnpr(b + n, blen - n, "%s Descriptor %d\n", lip, f);
if ((k + g) > dlen) {
n += sg_scnpr(b + n, blen - n, "%s truncated descriptor, "
@@ -1421,7 +1434,7 @@ uds_referral_descriptor_str(char * b, int blen, const uint8_t * dp,
ull = sg_get_unaligned_be64(dp + 12);
n += sg_scnpr(b + n, blen - n, "%s last uds LBA: 0x%" PRIx64
"\n", lip, ull);
- for (j = 0; j < tpgd; ++j) {
+ for (j = 0; j < ntpgd; ++j) {
tp = dp + 20 + (j * 4);
decode_tpgs_state(tp[0] & 0xf, c, sizeof(c));
n += sg_scnpr(b + n, blen - n, "%s tpg: %d state: %s\n",
@@ -1453,10 +1466,10 @@ sg_get_sense_descriptors_str(const char * lip, const uint8_t * sbp,
uint16_t sct_sc;
bool processed;
const uint8_t * descp;
- const char * dtsp = " >> descriptor too short";
- const char * eccp = "Extended copy command";
- const char * ddp = "destination device";
char z[64];
+ static const char * dtsp = " >> descriptor too short";
+ static const char * eccp = "Extended copy command";
+ static const char * ddp = "destination device";
if ((NULL == b) || (blen <= 0))
return 0;
@@ -1821,8 +1834,8 @@ sg_get_sense_str(const char * lip, const uint8_t * sbp, int sb_len,
if (NULL == lip)
lip = "";
if ((NULL == sbp) || (sb_len < 1)) {
- n += sg_scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip);
- return n;
+ n += sg_scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip);
+ return n;
}
resp_code = 0x7f & sbp[0];
valid_info_fld = !!(sbp[0] & 0x80);
@@ -2811,17 +2824,14 @@ safe_strerror(int errnum)
return errstr;
}
-static void
+static int
trimTrailingSpaces(char * b)
{
- int k;
+ int n = strlen(b);
- for (k = ((int)strlen(b) - 1); k >= 0; --k) {
- if (' ' != b[k])
- break;
- }
- if ('\0' != b[k + 1])
- b[k + 1] = '\0';
+ while ((n > 0) && (' ' == b[n - 1]))
+ b[--n] = '\0';
+ return n;
}
/* Read binary starting at 'str' for 'len' bytes and output as ASCII
@@ -2932,22 +2942,23 @@ dStrHexErr(const char* str, int len, int no_ascii)
#define DSHS_LINE_BLEN 160 /* maximum characters per line */
#define DSHS_BPL 16 /* bytes per line */
-/* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space
- * separated) to 'b' not to exceed 'b_len' characters. Each line
- * starts with 'leadin' (NULL for no leadin) and there are 16 bytes
- * per line with an extra space between the 8th and 9th bytes. 'format'
- * is 0 for repeat in printable ASCII ('.' for non printable chars) to
- * right of each line; 1 don't (so just output ASCII hex). Note that
- * an address is not printed on each line preceding the hex data. Returns
- * number of bytes written to 'b' excluding the trailing '\0'.
- * The only difference between dStrHexStr() and hex2str() is the type of
- * the first argument. */
+/* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space separated)
+ * to 'b' not to exceed 'b_len' characters. Each line starts with 'leadin'
+ * (NULL for no leadin) and there are 16 bytes per line with an extra space
+ * between the 8th and 9th bytes. 'oformat' is 0 for repeat in printable ASCII
+ * ('.' for non printable chars) to right of each line; 1 don't (so just
+ * output ASCII hex). If 'oformat' is 2 output same as 1 but any LFs are
+ * replaced by space (and trailing spaces are trimmed). Note that an address
+ * is not printed on each line preceding the hex data. Returns number of bytes
+ * written to 'b' excluding the trailing '\0'. The only difference between
+ * dStrHexStr() and hex2str() is the type of the first argument. */
int
-dStrHexStr(const char * str, int len, const char * leadin, int format,
+dStrHexStr(const char * str, int len, const char * leadin, int oformat,
int b_len, char * b)
{
+ bool want_ascii = (0 == oformat);
+ char lf_or = (oformat > 1) ? ' ' : '\n';
int bpstart, bpos, k, n, prior_ascii_len;
- bool want_ascii;
char buff[DSHS_LINE_BLEN + 2]; /* allow for trailing null */
char a[DSHS_BPL + 1]; /* printable ASCII bytes or '.' */
const char * p = str;
@@ -2959,7 +2970,6 @@ dStrHexStr(const char * str, int len, const char * leadin, int format,
}
if (b_len <= 0)
return 0;
- want_ascii = !format;
if (want_ascii) {
memset(a, ' ', DSHS_BPL);
a[DSHS_BPL] = '\0';
@@ -2995,9 +3005,9 @@ dStrHexStr(const char * str, int len, const char * leadin, int format,
prior_ascii_len, buff, a);
memset(a, ' ', DSHS_BPL);
} else
- n += sg_scnpr(b + n, b_len - n, "%s\n", buff);
+ n += sg_scnpr(b + n, b_len - n, "%s%c", buff, lf_or);
if (n >= (b_len - 1))
- return n;
+ goto fini;
memset(buff, ' ', DSHS_LINE_BLEN);
bpos = bpstart;
if (bpstart > 0)
@@ -3011,8 +3021,11 @@ dStrHexStr(const char * str, int len, const char * leadin, int format,
n += sg_scnpr(b + n, b_len - n, "%-*s %s\n", prior_ascii_len,
buff, a);
else
- n += sg_scnpr(b + n, b_len - n, "%s\n", buff);
+ n += sg_scnpr(b + n, b_len - n, "%s%c", buff, lf_or);
}
+fini:
+ if (oformat > 1)
+ n = trimTrailingSpaces(b);
return n;
}
@@ -3029,14 +3042,14 @@ hex2stderr(const uint8_t * b_str, int len, int no_ascii)
}
int
-hex2str(const uint8_t * b_str, int len, const char * leadin, int format,
+hex2str(const uint8_t * b_str, int len, const char * leadin, int oformat,
int b_len, char * b)
{
- return dStrHexStr((const char *)b_str, len, leadin, format, b_len, b);
+ return dStrHexStr((const char *)b_str, len, leadin, oformat, b_len, b);
}
void
-hex2fp(const uint8_t * b_str, int len, const char * leadin, int format,
+hex2fp(const uint8_t * b_str, int len, const char * leadin, int oformat,
FILE * fp)
{
int k, num;
@@ -3048,7 +3061,7 @@ hex2fp(const uint8_t * b_str, int len, const char * leadin, int format,
}
for (k = 0; k < len; k += num) {
num = ((k + 64) < len) ? 64 : (len - k);
- hex2str(b_str + k, num, leadin, format, sizeof(b), b);
+ hex2str(b_str + k, num, leadin, oformat, sizeof(b), b);
fprintf(fp, "%s", b);
}
}
@@ -3393,7 +3406,7 @@ sg_get_llnum(const char * buf)
buf += n;
len -= n;
}
- /* following hack to keep C++ happy */
+ /* following cast hack to keep C++ happy */
cp = strpbrk((char *)buf, " \t,#-");
if (cp) {
len = cp - buf;
@@ -3542,11 +3555,12 @@ sg_get_llnum_nomult(const char * buf)
/* Read ASCII hex bytes or binary from fname (a file named '-' taken as
* stdin). If reading ASCII hex then there should be either one entry per
- * line or a comma, space or tab separated list of bytes. If no_space is
- * set then a string of ACSII hex digits is expected, 2 per byte. Everything
- * from and including a '#' on a line is ignored. Returns 0 if ok, or an
- * error code. If the error code is SG_LIB_LBA_OUT_OF_RANGE then mp_arr
- * would be exceeded and both mp_arr and mp_arr_len are written to. */
+ * line or a comma, space, hyphen or tab separated list of bytes. If
+ * no_space is * set then a string of ACSII hex digits is expected, 2 per
+ * byte. Everything from and including a '#' on a line is ignored. Returns
+ * 0 if ok, or an error code. If the error code is
+ * SG_LIB_LBA_OUT_OF_RANGE then mp_arr would be exceeded and both mp_arr
+ * and mp_arr_len are written to. */
int
sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
uint8_t * mp_arr, int * mp_arr_len, int max_arr_len)
@@ -3682,7 +3696,7 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
in_len -= m;
if ('#' == *lcp)
continue;
- k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t");
+ k = strspn(lcp, "0123456789aAbBcCdDeEfF ,-\t");
if ((k < in_len) && ('#' != lcp[k]) && ('\r' != lcp[k])) {
pr2ws("%s: syntax error at line %d, pos %d\n", __func__,
j + 1, m + k + 1);
@@ -3730,10 +3744,10 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space,
goto fini;
} else
mp_arr[off + k] = h;
- lcp = strpbrk(lcp, " ,\t");
+ lcp = strpbrk(lcp, " ,-\t");
if (NULL == lcp)
break;
- lcp += strspn(lcp, " ,\t");
+ lcp += strspn(lcp, " ,-\t");
if ('\0' == *lcp)
break;
} else {
@@ -3831,6 +3845,41 @@ sg_get_page_size(void)
#endif
}
+#if defined(SG_LIB_WIN32)
+#if defined(MSC_VER) || defined(__MINGW32__)
+/* windows.h already included above */
+#define sg_sleep_for(seconds) Sleep( (seconds) * 1000)
+#else
+#define sg_sleep_for(seconds) sleep(seconds)
+#endif
+#else
+#define sg_sleep_for(seconds) sleep(seconds)
+#endif
+
+void
+sg_sleep_secs(int num_secs)
+{
+ sg_sleep_for(num_secs);
+}
+
+void
+sg_warn_and_wait(const char * cmd_name, const char * dev_name,
+ bool stress_all)
+{
+ int k;
+ const char * stressp = stress_all ? "ALL d" : "D";
+ const char * will_mayp = stress_all ? "will" : "may";
+
+ for (k = 0; k < 3; ++k) {
+ printf("\nA %s command will commence in 15 seconds\n", cmd_name);
+ printf(" %sata on %s %s be DESTROYED%s\n", stressp, dev_name,
+ will_mayp, (stress_all ? "" : " or modified"));
+ printf(" Press control-C to abort\n");
+ sg_sleep_secs(5);
+ }
+ sg_sleep_secs(1);
+}
+
/* Returns pointer to heap (or NULL) that is aligned to a align_to byte
* boundary. Sends back *buff_to_free pointer in third argument that may be
* different from the return value. If it is different then the *buff_to_free
diff --git a/lib/sg_lib_data.c b/lib/sg_lib_data.c
index d0931eb7..3e291eb2 100644
--- a/lib/sg_lib_data.c
+++ b/lib/sg_lib_data.c
@@ -19,8 +19,8 @@
#include "sg_lib_data.h"
-const char * sg_lib_version_str = "2.88 20220305";
-/* spc6r06, sbc5r01, zbc2r12 */
+const char * sg_lib_version_str = "2.90 20220622";
+/* spc6r06, sbc5r01, zbc2r13 */
/* indexed by pdt; those that map to own index do not decay */
diff --git a/lib/sg_pr2serr.c b/lib/sg_pr2serr.c
index 5c869aee..9ae466b3 100644
--- a/lib/sg_pr2serr.c
+++ b/lib/sg_pr2serr.c
@@ -18,6 +18,15 @@
#include "sg_pr2serr.h"
#include "sg_json_builder.h"
+/* Comment out next line to remove dependency on sg_lib.h */
+#define SG_PRSE_SENSE_DECODE 1
+
+#ifdef SG_PRSE_SENSE_DECODE
+#include "sg_lib.h"
+#include "sg_lib_data.h"
+#include "sg_unaligned.h"
+#endif
+
#define sgj_opts_ev "SG3_UTILS_JSON_OPTS"
@@ -110,6 +119,9 @@ sgj_parse_opts(sgj_state * jsp, const char * j_optarg)
case '8':
jsp->pr_indent_size = 8;
break;
+ case 'a': /* abbreviated name expansion */
+ jsp->pr_ane = ! prev_negate;
+ break;
case 'e':
jsp->pr_exit_status = ! prev_negate;
break;
@@ -152,6 +164,7 @@ static void
sgj_def_opts(sgj_state * jsp)
{
jsp->pr_as_json = true;
+ jsp->pr_ane = false;
jsp->pr_exit_status = true;
jsp->pr_hex = false;
jsp->pr_leadin = true;
@@ -371,8 +384,8 @@ sgj_new_unattached_array(sgj_state * jsp)
}
sgj_opaque_p
-sgj_add_val_s(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- const char * value)
+sgj_add_nv_s(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ const char * value)
{
if (jsp && jsp->pr_as_json && value) {
if (name)
@@ -386,8 +399,8 @@ sgj_add_val_s(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
sgj_opaque_p
-sgj_add_val_i(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- int64_t value)
+sgj_add_nv_i(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t value)
{
if (jsp && jsp->pr_as_json) {
if (name)
@@ -402,8 +415,7 @@ sgj_add_val_i(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
sgj_opaque_p
-sgj_add_val_b(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- bool value)
+sgj_add_nv_b(sgj_state * jsp, sgj_opaque_p jop, const char * name, bool value)
{
if (jsp && jsp->pr_as_json) {
if (name)
@@ -418,8 +430,8 @@ sgj_add_val_b(sgj_state * jsp, sgj_opaque_p jop, const char * name,
/* jop will 'own' ua_jop (if returned value is non-NULL) */
sgj_opaque_p
-sgj_add_val_o(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- sgj_opaque_p ua_jop)
+sgj_add_nv_o(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ sgj_opaque_p ua_jop)
{
if (jsp && jsp->pr_as_json && ua_jop) {
if (name)
@@ -433,42 +445,166 @@ sgj_add_val_o(sgj_state * jsp, sgj_opaque_p jop, const char * name,
}
void
-sgj_add_name_pair_ihex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
- uint64_t value)
+sgj_add_nv_ihex(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ uint64_t value)
{
if ((NULL == jsp) || (NULL == name) || (! jsp->pr_as_json))
return;
else if (jsp->pr_hex) {
sgj_opaque_p jo2p =
- sgj_new_named_object(jsp, (jop ? jop : jsp->basep), name);
+ sgj_new_named_object(jsp, jop, name);
char b[64];
if (NULL == jo2p)
return;
- sgj_add_val_i(jsp, jo2p, "i", (int64_t)value);
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)value);
snprintf(b, sizeof(b), "%" PRIx64, value);
- sgj_add_val_s(jsp, jo2p, "hex", b);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
} else
- sgj_add_val_i(jsp, jop, name, (int64_t)value);
+ sgj_add_nv_i(jsp, jop, name, (int64_t)value);
}
+static const char * sc_mn_s = "meaning";
+
void
-sgj_add_name_pair_istr(sgj_state * jsp, sgj_opaque_p jop,
- const char * name, int64_t value,
- const char * str_name, const char * str)
+sgj_add_nv_istr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, const char * str_name, const char * val_s)
{
if ((NULL == jsp) || (! jsp->pr_as_json))
return;
else if (jsp->pr_string) {
sgj_opaque_p jo2p =
- sgj_new_named_object(jsp, (jop ? jop : jsp->basep), name);
+ sgj_new_named_object(jsp, jop, name);
if (NULL == jo2p)
return;
- sgj_add_val_i(jsp, jo2p, "i", (int64_t)value);
- if (str)
- sgj_add_val_s(jsp, jo2p, str_name ? str_name : "string", str);
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (val_s)
+ sgj_add_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s);
} else
- sgj_add_val_i(jsp, jop, name, value);
+ sgj_add_nv_i(jsp, jop, name, val_i);
+}
+
+void
+sgj_add_nv_ihexstr(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, const char * str_name, const char * val_s)
+{
+ if ((NULL == jsp) || (! jsp->pr_as_json))
+ return;
+ if ((! jsp->pr_hex) && (! jsp->pr_string))
+ sgj_add_nv_i(jsp, jop, name, val_i);
+ else {
+ char b[64];
+ sgj_opaque_p jo2p =
+ sgj_new_named_object(jsp, jop, name);
+
+ if (NULL == jo2p)
+ return;
+ if (jsp->pr_string) {
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (jsp->pr_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ if (val_s)
+ sgj_add_nv_s(jsp, jo2p, str_name ? str_name : sc_mn_s, val_s);
+ } else if (jsp->pr_hex) {
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ }
+}
+
+static const char * sc_ane_s = "abbreviated_name_expansion";
+
+void
+sgj_add_nv_ihex_ane(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, bool want_hex, const char * ane_s)
+{
+ bool as_hex = jsp->pr_hex && want_hex;
+ bool as_ane = jsp->pr_ane && ane_s;
+
+ if ((NULL == jsp) || (! jsp->pr_as_json))
+ return;
+ if (! (as_hex || as_ane))
+ sgj_add_nv_i(jsp, jop, name, val_i);
+ else {
+ char b[64];
+ sgj_opaque_p jo2p =
+ sgj_new_named_object(jsp, jop, name);
+
+ if (NULL == jo2p)
+ return;
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (as_ane) {
+ if (jsp->pr_hex && want_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ sgj_add_nv_s(jsp, jo2p, sc_ane_s, ane_s);
+ } else if (as_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ }
+}
+
+void
+sgj_add_nv_hex_bytes(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ const uint8_t * byte_arr, int num_bytes)
+{
+ int blen = num_bytes * 4;
+ char * bp;
+
+ if ((NULL == jsp) || (! jsp->pr_as_json) || (! jsp->pr_hex))
+ return;
+ bp = (char *)calloc(blen + 4, 1);
+ if (bp) {
+ hex2str(byte_arr, num_bytes, NULL, 2, blen, bp);
+ sgj_add_nv_s(jsp, jop, name, bp);
+ free(bp);
+ }
+}
+
+void
+sgj_add_nv_ihexstr_ane(sgj_state * jsp, sgj_opaque_p jop, const char * name,
+ int64_t val_i, bool want_hex, const char * str_name,
+ const char * val_s, const char * ane_s)
+{
+ bool as_hex = jsp->pr_hex && want_hex;
+ bool as_str = jsp->pr_string && val_s;
+ bool as_ane = jsp->pr_ane && ane_s;
+ const char * sname = str_name ? str_name : sc_mn_s;
+
+ if ((NULL == jsp) || (! jsp->pr_as_json))
+ return;
+ if (! (as_hex || as_ane || as_str))
+ sgj_add_nv_i(jsp, jop, name, val_i);
+ else {
+ char b[64];
+ sgj_opaque_p jo2p =
+ sgj_new_named_object(jsp, jop, name);
+
+ if (NULL == jo2p)
+ return;
+ sgj_add_nv_i(jsp, jo2p, "i", (int64_t)val_i);
+ if (as_ane) {
+ if (as_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ }
+ if (as_str) {
+ sgj_add_nv_s(jsp, jo2p, sname, val_s);
+ }
+ sgj_add_nv_s(jsp, jo2p, sc_ane_s, ane_s);
+ } else if (as_hex) {
+ snprintf(b, sizeof(b), "%" PRIx64, val_i);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ if (as_str)
+ sgj_add_nv_s(jsp, jo2p, sname, val_s);
+ } else if (as_str)
+ sgj_add_nv_s(jsp, jo2p, sname, val_s);
+ }
}
/* Returns number of characters placed in 'out' excluding trailing NULL */
@@ -511,8 +647,8 @@ sgj_jsonify_name(const char * in, char * out, int maxlen_out)
}
static void
-sgj_pr_twin_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep, json_value * jvp)
+sgj_pr_hr_js_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep, json_value * jvp)
{
bool eaten = false;
bool as_json = (jsp && jsp->pr_as_json);
@@ -631,33 +767,889 @@ sgj_pr_twin_xx(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
}
void
-sgj_pr_twin_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep,
- const char * value)
+sgj_pr_hr_js_vs(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep,
+ const char * value)
{
json_value * jvp;
/* make json_value even if jsp->pr_as_json is false */
jvp = value ? json_string_new(value) : NULL;
- sgj_pr_twin_xx(jsp, jop, leadin_sp, name, sep, jvp);
+ sgj_pr_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp);
}
void
-sgj_pr_twin_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep, int64_t value)
+sgj_pr_hr_js_vi(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep, int64_t value)
{
json_value * jvp;
jvp = json_integer_new(value);
- sgj_pr_twin_xx(jsp, jop, leadin_sp, name, sep, jvp);
+ sgj_pr_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp);
}
void
-sgj_pr_twin_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
- const char * name, enum sgj_separator_t sep, bool value)
+sgj_pr_hr_js_vb(sgj_state * jsp, sgj_opaque_p jop, int leadin_sp,
+ const char * name, enum sgj_separator_t sep, bool value)
{
json_value * jvp;
jvp = json_boolean_new(value);
- sgj_pr_twin_xx(jsp, jop, leadin_sp, name, sep, jvp);
+ sgj_pr_hr_js_xx(jsp, jop, leadin_sp, name, sep, jvp);
+}
+
+#ifdef SG_PRSE_SENSE_DECODE
+
+static const char * dtsp = "descriptor too short";
+static const char * sksvp = "sense-key specific valid";
+static const char * ddep = "designation_descriptor_error";
+static const char * naa_exp = "Network Address Authority";
+static const char * aoi_exp = "IEEE-Administered Organizational Identifier";
+
+bool
+sgj_get_designation_descriptor(sgj_state * jsp, sgj_opaque_p jop,
+ const uint8_t * ddp, int dd_len)
+{
+ int p_id, piv, c_set, assoc, desig_type, d_id, naa;
+ int n, aoi, vsi, dlen;
+ uint64_t ull;
+ const uint8_t * ip;
+ char e[80];
+ char b[256];
+ const char * cp;
+ const char * naa_sp;
+ static const int blen = sizeof(b);
+ static const int elen = sizeof(e);
+
+ if (dd_len < 4) {
+ sgj_add_nv_s(jsp, jop, ddep, "too short");
+ return false;
+ }
+ dlen = ddp[3];
+ if (dlen > (dd_len - 4)) {
+ snprintf(e, elen, "too long: says it is %d bytes, but given %d "
+ "bytes\n", dlen, dd_len - 4);
+ sgj_add_nv_s(jsp, jop, ddep, e);
+ return false;
+ }
+ ip = ddp + 4;
+ p_id = ((ddp[0] >> 4) & 0xf);
+ c_set = (ddp[0] & 0xf);
+ piv = ((ddp[1] & 0x80) ? 1 : 0);
+ assoc = ((ddp[1] >> 4) & 0x3);
+ desig_type = (ddp[1] & 0xf);
+ cp = sg_get_desig_assoc_str(assoc);
+ if (assoc == 3)
+ cp = "Reserved [0x3]"; /* should not happen */
+ sgj_add_nv_ihexstr(jsp, jop, "association", assoc, NULL, cp);
+ cp = sg_get_desig_type_str(desig_type);
+ if (NULL == cp)
+ cp = "unknown";
+ sgj_add_nv_ihexstr(jsp, jop, "designator_type", desig_type,
+ NULL, cp);
+ cp = sg_get_desig_code_set_str(c_set);
+ if (NULL == cp)
+ cp = "unknown";
+ sgj_add_nv_ihexstr(jsp, jop, "code_set", desig_type,
+ NULL, cp);
+ sgj_add_nv_ihex_ane(jsp, jop, "piv", piv, false,
+ "Protocol Identifier Valid");
+ sg_get_trans_proto_str(p_id, elen, e);
+ sgj_add_nv_ihexstr(jsp, jop, "protocol_identifier", p_id, NULL, e);
+ switch (desig_type) {
+ case 0: /* vendor specific */
+ sgj_add_nv_hex_bytes(jsp, jop, "vendor_specific_hex", ip, dlen);
+ break;
+ case 1: /* T10 vendor identification */
+ n = (dlen < 8) ? dlen : 8;
+ snprintf(b, blen, "%.*s", n, ip);
+ sgj_add_nv_s(jsp, jop, "t10_vendor_identification", b);
+ b[0] = '\0';
+ if (dlen > 8)
+ snprintf(b, blen, "%.*s", dlen - 8, ip + 8);
+ sgj_add_nv_s(jsp, jop, "vendor_specific_identifier", b);
+ break;
+ case 2: /* EUI-64 based */
+ sgj_add_nv_i(jsp, jop, "eui_64_based_designator_length", dlen);
+ ull = sg_get_unaligned_be64(ip);
+ switch (dlen) {
+ case 8:
+ sgj_add_nv_ihex(jsp, jop, "ieee_identifier", ull);
+ break;
+ case 12:
+ sgj_add_nv_ihex(jsp, jop, "ieee_identifier", ull);
+ sgj_add_nv_ihex(jsp, jop, "directory_id",
+ sg_get_unaligned_be32(ip + 8));
+ break;
+ case 16:
+ sgj_add_nv_ihex(jsp, jop, "identifier_extension", ull);
+ sgj_add_nv_ihex(jsp, jop, "ieee_identifier",
+ sg_get_unaligned_be64(ip + 8));
+ break;
+ default:
+ sgj_add_nv_s(jsp, jop, "eui_64", "decoding falied");
+ break;
+ }
+ break;
+ case 3: /* NAA <n> */
+ sgj_add_nv_hex_bytes(jsp, jop, "full_naa_in_hex", ip, dlen);
+ naa = (ip[0] >> 4) & 0xff;
+ switch (naa) {
+ case 2:
+ naa_sp = "IEEE Extended";
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, false, NULL, naa_sp,
+ naa_exp);
+ d_id = (((ip[0] & 0xf) << 8) | ip[1]);
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier_a", d_id);
+ aoi = sg_get_unaligned_be24(ip + 2);
+ sgj_add_nv_ihex_ane(jsp, jop, "aoi", aoi, true, aoi_exp);
+ vsi = sg_get_unaligned_be24(ip + 5);
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier_b", vsi);
+ break;
+ case 3:
+ naa_sp = "Locally Assigned";
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, false, NULL, naa_sp,
+ naa_exp);
+ ull = sg_get_unaligned_be64(ip + 0) & 0xfffffffffffffffULL;
+ sgj_add_nv_ihex(jsp, jop, "locally_administered_value", ull);
+ break;
+ case 5:
+ naa_sp = "IEEE Registered";
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, false, NULL, naa_sp,
+ naa_exp);
+ aoi = (sg_get_unaligned_be32(ip + 0) >> 4) & 0xffffff;
+ sgj_add_nv_ihex_ane(jsp, jop, "aoi", aoi, true, aoi_exp);
+ ull = sg_get_unaligned_be48(ip + 2) & 0xfffffffffULL;
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier", ull);
+ break;
+ case 6:
+ naa_sp = "IEEE Registered Extended";
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, false, NULL, naa_sp,
+ naa_exp);
+ aoi = (sg_get_unaligned_be32(ip + 0) >> 4) & 0xffffff;
+ sgj_add_nv_ihex_ane(jsp, jop, "aoi", aoi, true, aoi_exp);
+ ull = sg_get_unaligned_be48(ip + 2) & 0xfffffffffULL;
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier", ull);
+ ull = sg_get_unaligned_be64(ip + 8);
+ sgj_add_nv_ihex(jsp, jop, "vendor_specific_identifier_extension",
+ ull);
+ break;
+ default:
+ snprintf(b, blen, "unknown NAA value=0x%x", naa);
+ sgj_add_nv_ihexstr_ane(jsp, jop, "naa", naa, true, NULL, b,
+ naa_exp);
+ break;
+ }
+ break;
+#if 0
+ case 4: /* Relative target port */
+ if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
+ n += sg_scnpr(b + n, blen - n, "%s << expected binary "
+ "code_set, target port association, length 4 >>\n",
+ lip);
+ n += hex2str(ip, dlen, "", 1, blen - n, b + n);
+ break;
+ }
+ d_id = sg_get_unaligned_be16(ip + 2);
+ n += sg_scnpr(b + n, blen - n, "%s Relative target port: 0x%x\n",
+ lip, d_id);
+ break;
+ case 5: /* (primary) Target port group */
+ if ((1 != c_set) || (1 != assoc) || (4 != dlen)) {
+ n += sg_scnpr(b + n, blen - n, "%s << expected binary "
+ "code_set, target port association, length 4 >>\n",
+ lip);
+ n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
+ break;
+ }
+ d_id = sg_get_unaligned_be16(ip + 2);
+ n += sg_scnpr(b + n, blen - n, "%s Target port group: 0x%x\n",
+ lip, d_id);
+ break;
+ case 6: /* Logical unit group */
+ if ((1 != c_set) || (0 != assoc) || (4 != dlen)) {
+ n += sg_scnpr(b + n, blen - n, "%s << expected binary "
+ "code_set, logical unit association, length 4 >>\n",
+ lip);
+ n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
+ break;
+ }
+ d_id = sg_get_unaligned_be16(ip + 2);
+ n += sg_scnpr(b + n, blen - n, "%s Logical unit group: 0x%x\n",
+ lip, d_id);
+ break;
+ case 7: /* MD5 logical unit identifier */
+ if ((1 != c_set) || (0 != assoc)) {
+ n += sg_scnpr(b + n, blen - n, "%s << expected binary "
+ "code_set, logical unit association >>\n", lip);
+ n += hex2str(ip, dlen, "", 1, blen - n, b + n);
+ break;
+ }
+ n += sg_scnpr(b + n, blen - n, "%s MD5 logical unit "
+ "identifier:\n", lip);
+ n += hex2str(ip, dlen, lip, 1, blen - n, b + n);
+ break;
+ case 8: /* SCSI name string */
+ if (3 != c_set) { /* accept ASCII as subset of UTF-8 */
+ if (2 == c_set) {
+ if (do_long)
+ n += sg_scnpr(b + n, blen - n, "%s << expected "
+ "UTF-8, use ASCII >>\n", lip);
+ } else {
+ n += sg_scnpr(b + n, blen - n, "%s << expected UTF-8 "
+ "code_set >>\n", lip);
+ n += hex2str(ip, dlen, lip, 0, blen - n, b + n);
+ break;
+ }
+ }
+ n += sg_scnpr(b + n, blen - n, "%s SCSI name string:\n", lip);
+ /* does %s print out UTF-8 ok??
+ * Seems to depend on the locale. Looks ok here with my
+ * locale setting: en_AU.UTF-8
+ */
+ n += sg_scnpr(b + n, blen - n, "%s %.*s\n", lip, dlen,
+ (const char *)ip);
+ break;
+ case 9: /* Protocol specific port identifier */
+ /* added in spc4r36, PIV must be set, proto_id indicates */
+ /* whether UAS (USB) or SOP (PCIe) or ... */
+ if (! piv)
+ n += sg_scnpr(b + n, blen - n, " %s >>>> Protocol specific "
+ "port identifier expects protocol\n%s "
+ "identifier to be valid and it is not\n", lip, lip);
+ if (TPROTO_UAS == p_id) {
+ n += sg_scnpr(b + n, blen - n, "%s USB device address: "
+ "0x%x\n", lip, 0x7f & ip[0]);
+ n += sg_scnpr(b + n, blen - n, "%s USB interface number: "
+ "0x%x\n", lip, ip[2]);
+ } else if (TPROTO_SOP == p_id) {
+ n += sg_scnpr(b + n, blen - n, "%s PCIe routing ID, bus "
+ "number: 0x%x\n", lip, ip[0]);
+ n += sg_scnpr(b + n, blen - n, "%s function number: "
+ "0x%x\n", lip, ip[1]);
+ n += sg_scnpr(b + n, blen - n, "%s [or device number: "
+ "0x%x, function number: 0x%x]\n", lip,
+ (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
+ } else
+ n += sg_scnpr(b + n, blen - n, "%s >>>> unexpected protocol "
+ "identifier: %s\n%s with Protocol "
+ "specific port identifier\n", lip,
+ sg_get_trans_proto_str(p_id, elen, e), lip);
+ break;
+ case 0xa: /* UUID identifier */
+ n += sg_t10_uuid_desig2str(ip, dlen, c_set, do_long, false, lip,
+ blen - n, b + n);
+ break;
+#endif
+ default: /* reserved */
+ hex2str(ip, dlen, NULL, 1, blen, b);
+ sgj_add_nv_s(jsp, jop, "reserved_designator_hex", b);
+ break;
+ }
+ return true;
}
+
+static void
+sgj_progress_indication(sgj_state * jsp, sgj_opaque_p jop,
+ uint16_t prog_indic, bool is_another)
+{
+ uint32_t progress, pr, rem;
+ sgj_opaque_p jo2p;
+ char b[64];
+
+ if (is_another)
+ jo2p = sgj_new_named_object(jsp, jop, "another_progress_indication");
+ else
+ jo2p = sgj_new_named_object(jsp, jop, "progress_indication");
+ if (NULL == jo2p)
+ return;
+ progress = prog_indic;
+ sgj_add_nv_i(jsp, jo2p, "i", progress);
+ snprintf(b, sizeof(b), "%x", progress);
+ sgj_add_nv_s(jsp, jo2p, "hex", b);
+ progress *= 100;
+ pr = progress / 65536;
+ rem = (progress % 65536) / 656;
+ snprintf(b, sizeof(b), "%d.02%d%%\n", pr, rem);
+ sgj_add_nv_s(jsp, jo2p, "percentage", b);
+}
+
+static bool
+sgj_decode_sks(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * dp, int dlen,
+ int sense_key)
+{
+ switch (sense_key) {
+ case SPC_SK_ILLEGAL_REQUEST:
+ if (dlen < 3) {
+ sgj_add_nv_s(jsp, jop, "illegal_request_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_add_nv_ihex_ane(jsp, jop, "c_d", !! (dp[0] & 0x40), false,
+ "c: cdb; d: data-out");
+ sgj_add_nv_ihex_ane(jsp, jop, "bpv", !! (dp[0] & 0x8), false,
+ "bit pointer (index) valid");
+ sgj_add_nv_i(jsp, jop, "bit_pointer", dp[0] & 0x7);
+ sgj_add_nv_ihex(jsp, jop, "field_pointer",
+ sg_get_unaligned_be16(dp + 1));
+ break;
+ case SPC_SK_HARDWARE_ERROR:
+ case SPC_SK_MEDIUM_ERROR:
+ case SPC_SK_RECOVERED_ERROR:
+ if (dlen < 3) {
+ sgj_add_nv_s(jsp, jop, "actual_retry_count_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_add_nv_ihex(jsp, jop, "actual_retry_count",
+ sg_get_unaligned_be16(dp + 1));
+ break;
+ case SPC_SK_NO_SENSE:
+ case SPC_SK_NOT_READY:
+ if (dlen < 7) {
+ sgj_add_nv_s(jsp, jop, "progress_indication_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_progress_indication(jsp, jop, sg_get_unaligned_be16(dp + 1),
+ false);
+ break;
+ case SPC_SK_COPY_ABORTED:
+ if (dlen < 7) {
+ sgj_add_nv_s(jsp, jop, "segment_indication_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_add_nv_ihex_ane(jsp, jop, "sd", !! (dp[0] & 0x20), false,
+ "field pointer relative to: 1->segment "
+ "descriptor, 0->parameter list");
+ sgj_add_nv_ihex_ane(jsp, jop, "bpv", !! (dp[0] & 0x8), false,
+ "bit pointer (index) valid");
+ sgj_add_nv_i(jsp, jop, "bit_pointer", dp[0] & 0x7);
+ sgj_add_nv_ihex(jsp, jop, "field_pointer",
+ sg_get_unaligned_be16(dp + 1));
+ break;
+ case SPC_SK_UNIT_ATTENTION:
+ if (dlen < 7) {
+ sgj_add_nv_s(jsp, jop, "segment_indication_sks", dtsp);
+ return false;
+ }
+ sgj_add_nv_ihex_ane(jsp, jop, "sksv", !! (dp[0] & 0x80), false,
+ sksvp);
+ sgj_add_nv_i(jsp, jop, "overflow", !! (dp[0] & 0x80));
+ break;
+ default:
+ sgj_add_nv_ihex(jsp, jop, "unexpected_sense_key", sense_key);
+ return false;
+ }
+ return true;
+}
+
+#define TPGS_STATE_OPTIMIZED 0x0
+#define TPGS_STATE_NONOPTIMIZED 0x1
+#define TPGS_STATE_STANDBY 0x2
+#define TPGS_STATE_UNAVAILABLE 0x3
+#define TPGS_STATE_OFFLINE 0xe
+#define TPGS_STATE_TRANSITIONING 0xf
+
+static int
+decode_tpgs_state(int st, char * b, int blen)
+{
+ switch (st) {
+ case TPGS_STATE_OPTIMIZED:
+ return sg_scnpr(b, blen, "active/optimized");
+ case TPGS_STATE_NONOPTIMIZED:
+ return sg_scnpr(b, blen, "active/non optimized");
+ case TPGS_STATE_STANDBY:
+ return sg_scnpr(b, blen, "standby");
+ case TPGS_STATE_UNAVAILABLE:
+ return sg_scnpr(b, blen, "unavailable");
+ case TPGS_STATE_OFFLINE:
+ return sg_scnpr(b, blen, "offline");
+ case TPGS_STATE_TRANSITIONING:
+ return sg_scnpr(b, blen, "transitioning between states");
+ default:
+ return sg_scnpr(b, blen, "unknown: 0x%x", st);
+ }
+}
+
+static bool
+sgj_uds_referral_descriptor(sgj_state * jsp, sgj_opaque_p jop,
+ const uint8_t * dp, int alen)
+{
+ int dlen = alen - 2;
+ int k, j, g, f, aas;
+ uint64_t ull;
+ const uint8_t * tp;
+ sgj_opaque_p jap, jo2p, ja2p, jo3p;
+ char c[40];
+
+ sgj_add_nv_ihex_ane(jsp, jop, "not_all_r", (dp[2] & 0x1), false,
+ "Not all referrals");
+ dp += 4;
+ jap = sgj_new_named_array(jsp, jop,
+ "user_data_segment_referral_descriptor");
+ for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) {
+ int ntpgd = dp[3];
+
+ jo2p = sgj_new_unattached_object(jsp);
+ g = (ntpgd * 4) + 20;
+ sgj_add_nv_ihex(jsp, jo2p, "number_of_target_port_group_descriptors",
+ ntpgd);
+ if ((k + g) > dlen) {
+ sgj_add_nv_i(jsp, jo2p, "truncated_descriptor_dlen", dlen);
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ return false;
+ }
+ ull = sg_get_unaligned_be64(dp + 4);
+ sgj_add_nv_ihex(jsp, jo2p, "first_user_date_sgment_lba", ull);
+ ull = sg_get_unaligned_be64(dp + 12);
+ sgj_add_nv_ihex(jsp, jo2p, "last_user_date_sgment_lba", ull);
+ ja2p = sgj_new_named_array(jsp, jo2p, "target_port_group_descriptor");
+ for (j = 0; j < ntpgd; ++j) {
+ jo3p = sgj_new_unattached_object(jsp);
+ tp = dp + 20 + (j * 4);
+ aas = tp[0] & 0xf;
+ decode_tpgs_state(aas, c, sizeof(c));
+ sgj_add_nv_ihexstr(jsp, jo3p, "asymmetric_access_state", aas,
+ NULL, c);
+ sgj_add_nv_ihex(jsp, jo3p, "target_port_group",
+ sg_get_unaligned_be16(tp + 2));
+ sgj_add_nv_o(jsp, ja2p, NULL /* name */, jo3p);
+ }
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+ return true;
+}
+
+static bool
+sgj_get_sense_descriptors(sgj_state * jsp, sgj_opaque_p jop,
+ const struct sg_scsi_sense_hdr * sshp,
+ const uint8_t * sbp, int sb_len)
+{
+ bool processed = true;
+ int add_sb_len, desc_len, k, dt, sense_key, n, sds;
+#if 0
+ uint16_t sct_sc;
+#endif
+ uint64_t ull;
+ const uint8_t * descp;
+ sgj_opaque_p jap, jo2p, jo3p;
+ char b[80];
+ static const int blen = sizeof(b);
+ static const char * parsing = "parsing_error";
+#if 0
+ static const char * eccp = "Extended copy command";
+ static const char * ddp = "destination device";
+#endif
+
+ add_sb_len = sshp->additional_length;
+ add_sb_len = (add_sb_len < sb_len) ? add_sb_len : sb_len;
+ sense_key = sshp->sense_key;
+ jap = sgj_new_named_array(jsp, jop, "sense_data_descriptor");
+
+ for (descp = sbp, k = 0; (k < add_sb_len);
+ k += desc_len, descp += desc_len) {
+ int add_d_len = (k < (add_sb_len - 1)) ? descp[1] : -1;
+
+ jo2p = sgj_new_unattached_object(jsp);
+ if ((k + add_d_len + 2) > add_sb_len)
+ add_d_len = add_sb_len - k - 2;
+ desc_len = add_d_len + 2;
+ processed = true;
+ dt = descp[0];
+ switch (dt) {
+ case 0:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt,
+ NULL, "Information");
+ if (add_d_len >= 10) {
+ int valid = !! (0x80 & descp[2]);
+ sgj_add_nv_ihexstr(jsp, jo2p, "valid", valid, NULL,
+ valid ? "as per T10" : "Vendor specific");
+ sgj_add_nv_ihex(jsp, jo2p, "information",
+ sg_get_unaligned_be64(descp + 4));
+ } else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 1:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt,
+ NULL, "Command specific");
+ if (add_d_len >= 10) {
+ sgj_add_nv_ihex(jsp, jo2p, "command_specific_information",
+ sg_get_unaligned_be64(descp + 4));
+ } else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 2: /* Sense Key Specific */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Sense key specific");
+ processed = sgj_decode_sks(jsp, jo2p, descp + 4, desc_len - 4,
+ sense_key);
+ break;
+ case 3:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Field replaceable unit code");
+ if (add_d_len >= 2)
+ sgj_add_nv_ihex(jsp, jo2p, "field_replaceable_unit_code",
+ descp[3]);
+ else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 4:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Stream commands");
+ if (add_d_len >= 2) {
+ sgj_add_nv_i(jsp, jo2p, "filemark", !! (descp[3] & 0x80));
+ sgj_add_nv_ihex_ane(jsp, jo2p, "eom", !! (descp[3] & 0x40),
+ false, "End Of Medium");
+ sgj_add_nv_ihex_ane(jsp, jo2p, "ili", !! (descp[3] & 0x20),
+ false, "Incorrect Length Indicator");
+ } else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 5:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Block commands");
+ if (add_d_len >= 2)
+ sgj_add_nv_ihex_ane(jsp, jo2p, "ili", !! (descp[3] & 0x20),
+ false, "Incorrect Length Indicator");
+ else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 6:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "OSD object identification");
+ sgj_add_nv_s(jsp, jo2p, parsing, "Unsupported");
+ processed = false;
+ break;
+ case 7:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "OSD response integrity check value");
+ sgj_add_nv_s(jsp, jo2p, parsing, "Unsupported");
+ break;
+ case 8:
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "OSD attribute identification");
+ sgj_add_nv_s(jsp, jo2p, parsing, "Unsupported");
+ processed = false;
+ break;
+ case 9: /* this is defined in SAT (SAT-2) */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "ATA status return");
+ if (add_d_len >= 12) {
+ sgj_add_nv_i(jsp, jo2p, "extend", !! (descp[2] & 1));
+ sgj_add_nv_ihex(jsp, jo2p, "error", descp[3]);
+ sgj_add_nv_ihex(jsp, jo2p, "count",
+ sg_get_unaligned_be16(descp + 4));
+ ull = ((uint64_t)descp[10] << 40) |
+ ((uint64_t)descp[8] << 32) |
+ (descp[6] << 24) |
+ (descp[11] << 16) |
+ (descp[9] << 8) |
+ descp[7];
+ sgj_add_nv_ihex(jsp, jo2p, "lba", ull);
+ sgj_add_nv_ihex(jsp, jo2p, "device", descp[12]);
+ sgj_add_nv_ihex(jsp, jo2p, "status", descp[13]);
+ } else {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 0xa:
+ /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Another progress indication");
+ if (add_d_len < 6) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ sgj_add_nv_ihex(jsp, jo2p, "another_sense_key", descp[2]);
+ sgj_add_nv_ihex(jsp, jo2p, "another_additional_sense_code",
+ descp[3]);
+ sgj_add_nv_ihex(jsp, jo2p,
+ "another_additional_sense_code_qualifier",
+ descp[4]);
+ sgj_progress_indication(jsp, jo2p,
+ sg_get_unaligned_be16(descp + 6), true);
+ break;
+ case 0xb: /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "User data segment referral");
+ if (add_d_len < 2) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ if (! sgj_uds_referral_descriptor(jsp, jo2p, descp, add_d_len)) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ }
+ break;
+ case 0xc: /* Added in SPC-4 rev 28 */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", dt, NULL,
+ "Forwarded sense data");
+ if (add_d_len < 2) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ sgj_add_nv_ihex_ane(jsp, jo2p, "fsdt", !! (0x80 & descp[2]),
+ NULL, "Forwarded Sense Data Truncated");
+ sds = (0x7 & descp[2]);
+ if (sds < 1)
+ snprintf(b, blen, "%s [%d]", "Unknown", sds);
+ else if (sds > 9)
+ snprintf(b, blen, "%s [%d]", "Reserved", sds);
+ else {
+ n = 0;
+ n += sg_scnpr(b + n, blen - n, "EXTENDED COPY command copy %s",
+ (sds == 1) ? "source" : "destination");
+ if (sds > 1)
+ n += sg_scnpr(b + n, blen - n, " %d", sds - 1);
+ }
+ sgj_add_nv_ihexstr(jsp, jo2p, "sense_data_source",
+ (0x7 & descp[2]), NULL, b);
+ jo3p = sgj_new_named_object(jsp, jo2p, "forwarded_sense_data");
+ sgj_get_sense(jsp, jo3p, descp + 4, desc_len - 4);
+ break;
+ case 0xd: /* Added in SBC-3 rev 36d */
+ /* this descriptor combines descriptors 0, 1, 2 and 3 */
+ sgj_add_nv_ihexstr(jsp, jo2p, "descriptor_type", 0xc, NULL,
+ "Direct-access block device");
+ if (add_d_len < 28) {
+ sgj_add_nv_s(jsp, jo2p, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ sgj_add_nv_i(jsp, jo2p, "valid", (0x80 & descp[2]));
+ sgj_add_nv_ihex_ane(jsp, jo2p, "ili", !! (0x20 & descp[2]),
+ NULL, "Incorrect Length Indicator");
+ processed = sgj_decode_sks(jsp, jo2p, descp + 4, desc_len - 4,
+ sense_key);
+ sgj_add_nv_ihex(jsp, jo2p, "field_replaceable_unit_code",
+ descp[7]);
+ sgj_add_nv_ihex(jsp, jo2p, "information",
+ sg_get_unaligned_be64(descp + 8));
+ sgj_add_nv_ihex(jsp, jo2p, "command_specific_information",
+ sg_get_unaligned_be64(descp + 16));
+ break;
+#if 0
+ case 0xe: /* Added in SPC-5 rev 6 (for Bind/Unbind) */
+ n += sg_scnpr(b + n, blen - n, "Device designation\n");
+ j = (int)SG_ARRAY_SIZE(dd_usage_reason_str_arr);
+ if (descp[3] < j)
+ n += sg_scnpr(b + n, blen - n, "%s Usage reason: %s\n",
+ lip, dd_usage_reason_str_arr[descp[3]]);
+ else
+ n += sg_scnpr(b + n, blen - n, "%s Usage reason: "
+ "reserved[%d]\n", lip, descp[3]);
+ n += sg_get_designation_descriptor_str(z, descp + 4, descp[1] - 2,
+ true, false, blen - n,
+ b + n);
+ break;
+ case 0xf: /* Added in SPC-5 rev 10 (for Write buffer) */
+ n += sg_scnpr(b + n, blen - n, "Microcode activation ");
+ if (add_d_len < 6) {
+ sgj_add_nv_s(jsp, jop, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ progress = sg_get_unaligned_be16(descp + 6);
+ n += sg_scnpr(b + n, blen - n, "time: ");
+ if (0 == progress)
+ n += sg_scnpr(b + n, blen - n, "unknown\n");
+ else
+ n += sg_scnpr(b + n, blen - n, "%d seconds\n", progress);
+ break;
+ case 0xde: /* NVME Status Field; vendor (sg3_utils) specific */
+ n += sg_scnpr(b + n, blen - n, "NVMe Status: ");
+ if (add_d_len < 6) {
+ sgj_add_nv_s(jsp, jop, parsing, dtsp);
+ processed = false;
+ break;
+ }
+ n += sg_scnpr(b + n, blen - n, "DNR=%d, M=%d, ",
+ (int)!!(0x80 & descp[5]), (int)!!(0x40 & descp[5]));
+ sct_sc = sg_get_unaligned_be16(descp + 6);
+ n += sg_scnpr(b + n, blen - n, "SCT_SC=0x%x\n", sct_sc);
+ if (sct_sc > 0) {
+ char d[80];
+
+ n += sg_scnpr(b + n, blen - n, " %s\n",
+ sg_get_nvme_cmd_status_str(sct_sc, sizeof(d), d));
+ }
+ break;
+#endif
+ default:
+ if (dt >= 0x80)
+ sgj_add_nv_ihex(jsp, jo2p, "vendor_specific_descriptor_type",
+ dt);
+ else
+ sgj_add_nv_ihex(jsp, jo2p, "unknown_descriptor_type", dt);
+ processed = false;
+ break;
+ }
+#if 0
+ if (! processed) {
+ if (add_d_len > 0) {
+ n += sg_scnpr(b + n, blen - n, "%s ", lip);
+ for (j = 0; j < add_d_len; ++j) {
+ if ((j > 0) && (0 == (j % 24)))
+ n += sg_scnpr(b + n, blen - n, "\n%s ", lip);
+ n += sg_scnpr(b + n, blen - n, "%02x ", descp[j + 2]);
+ }
+ n += sg_scnpr(b + n, blen - n, "\n");
+ }
+ }
+ if (add_d_len < 0)
+ n += sg_scnpr(b + n, blen - n, "%s short descriptor\n", lip);
+#endif
+ sgj_add_nv_o(jsp, jap, NULL /* name */, jo2p);
+ }
+ return processed;
+}
+
+#define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d /* corresponding ASC is 0 */
+
+/* Fetch sense information */
+bool
+sgj_get_sense(sgj_state * jsp, sgj_opaque_p jop, const uint8_t * sbp,
+ int sb_len)
+{
+ bool descriptor_format = false;
+ bool sdat_ovfl = false;
+ bool ret = true;
+ bool valid_info_fld;
+ int len, n;
+ uint32_t info;
+ uint8_t resp_code;
+ const char * ebp = NULL;
+ char ebuff[64];
+ char b[256];
+ struct sg_scsi_sense_hdr ssh;
+ static int blen = sizeof(b);
+ static int elen = sizeof(ebuff);
+
+ if ((NULL == sbp) || (sb_len < 1)) {
+ snprintf(ebuff, elen, "sense buffer empty\n");
+ ebp = ebuff;
+ ret = false;
+ goto fini;
+ }
+ resp_code = 0x7f & sbp[0];
+ valid_info_fld = !!(sbp[0] & 0x80);
+ len = sb_len;
+ if (! sg_scsi_normalize_sense(sbp, sb_len, &ssh)) {
+ ebp = "unable to normalize sense buffer";
+ ret = false;
+ goto fini;
+ }
+ /* We have been able to normalize the sense buffer */
+ switch (resp_code) {
+ case 0x70: /* fixed, current */
+ ebp = "Fixed format, current";
+ len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
+ len = (len > sb_len) ? sb_len : len;
+ sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
+ break;
+ case 0x71: /* fixed, deferred */
+ /* error related to a previous command */
+ ebp = "Fixed format, <<<deferred>>>";
+ len = (sb_len > 7) ? (sbp[7] + 8) : sb_len;
+ len = (len > sb_len) ? sb_len : len;
+ sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false;
+ break;
+ case 0x72: /* descriptor, current */
+ descriptor_format = true;
+ ebp = "Descriptor format, current";
+ sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
+ break;
+ case 0x73: /* descriptor, deferred */
+ descriptor_format = true;
+ ebp = "Descriptor format, <<<deferred>>>";
+ sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false;
+ break;
+ default:
+ sg_scnpr(ebuff, elen, "Unknown code: 0x%x", resp_code);
+ ebp = ebuff;
+ break;
+ }
+ sgj_add_nv_ihexstr(jsp, jop, "response_code", resp_code, NULL, ebp);
+ sgj_add_nv_b(jsp, jop, "descriptor_format", descriptor_format);
+ sgj_add_nv_ihex_ane(jsp, jop, "sdat_ovfl", sdat_ovfl, false,
+ "Sense data overflow");
+ sgj_add_nv_ihexstr(jsp, jop, "sense_key", ssh.sense_key, NULL,
+ sg_lib_sense_key_desc[ssh.sense_key]);
+ sgj_add_nv_ihex(jsp, jop, "additional_sense_code", ssh.asc);
+ sgj_add_nv_ihex(jsp, jop, "additional_sense_code_qualifier", ssh.ascq);
+ sgj_add_nv_s(jsp, jop, "additional_sense_str",
+ sg_get_additional_sense_str(ssh.asc, ssh.ascq, false,
+ blen, b));
+ if (descriptor_format) {
+ if (len > 8) {
+ ret = sgj_get_sense_descriptors(jsp, jop, &ssh, sbp + 8, len - 8);
+ if (ret == false) {
+ ebp = "unable to decode sense descriptor";
+ goto fini;
+ }
+ }
+ } else if ((len > 12) && (0 == ssh.asc) &&
+ (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) {
+ /* SAT ATA PASS-THROUGH fixed format */
+ sgj_add_nv_ihex(jsp, jop, "error", sbp[3]);
+ sgj_add_nv_ihex(jsp, jop, "status", sbp[4]);
+ sgj_add_nv_ihex(jsp, jop, "device", sbp[5]);
+ sgj_add_nv_i(jsp, jop, "extend", !! (0x80 & sbp[8]));
+ sgj_add_nv_i(jsp, jop, "count_upper_nonzero", !! (0x40 & sbp[8]));
+ sgj_add_nv_i(jsp, jop, "lba_upper_nonzero", !! (0x20 & sbp[8]));
+ sgj_add_nv_i(jsp, jop, "log_index", (0x7 & sbp[8]));
+ sgj_add_nv_i(jsp, jop, "lba", sg_get_unaligned_le24(sbp + 9));
+ } else if (len > 2) { /* fixed format */
+ sgj_add_nv_i(jsp, jop, "valid", valid_info_fld);
+ sgj_add_nv_i(jsp, jop, "filemark", !! (sbp[2] & 0x80));
+ sgj_add_nv_ihex_ane(jsp, jop, "eom", !! (sbp[2] & 0x40),
+ false, "End Of Medium");
+ sgj_add_nv_ihex_ane(jsp, jop, "ili", !! (sbp[2] & 0x20),
+ false, "Incorrect Length Indicator");
+ info = sg_get_unaligned_be32(sbp + 3);
+ sgj_add_nv_ihex(jsp, jop, "information", info);
+ sgj_add_nv_ihex(jsp, jop, "additional_sense_length", sbp[7]);
+ if (sb_len > 11) {
+ info = sg_get_unaligned_be32(sbp + 8);
+ sgj_add_nv_ihex(jsp, jop, "command_specific_information", info);
+ }
+ if (sb_len > 14)
+ sgj_add_nv_ihex(jsp, jop, "field_replaceable_unit_code", sbp[14]);
+ if (sb_len > 17)
+ sgj_decode_sks(jsp, jop, sbp + 15, sb_len - 15, ssh.sense_key);
+ n = sbp[7];
+ n = (sb_len > n) ? n : sb_len;
+ sgj_add_nv_ihex(jsp, jop, "number_of_bytes_beyond_18",
+ (n > 18) ? n - 18 : 0);
+ } else {
+ snprintf(ebuff, sizeof(ebuff), "sb_len=%d too short", sb_len);
+ ebp = ebuff;
+ ret = false;
+ }
+fini:
+ if ((! ret) && ebp)
+ sgj_add_nv_s(jsp, jop, "sense_decode_error", ebp);
+ return ret;
+}
+
+#endif
diff --git a/lib/sg_pt_haiku.c b/lib/sg_pt_haiku.c
index c9ed291c..6b1ed222 100644
--- a/lib/sg_pt_haiku.c
+++ b/lib/sg_pt_haiku.c
@@ -148,7 +148,7 @@ set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb,
if (ptp->raw_command.command[i])
++ptp->in_err;
memcpy(ptp->raw_command.command, cdb, cdb_len);
- ptp->raw_command.command_length = (uint8)cdb_len;
+ ptp->raw_command.command_length = (uint8_t)cdb_len;
}
void