diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2022-06-25 04:05:14 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2022-06-25 04:05:14 +0000 |
commit | 2e225c87784735360e9619766efe06782179a86a (patch) | |
tree | 1df2832c733c55207261b829ec7f0146287afe82 /lib | |
parent | a3eb530bb4b93949287f19a2b6fb418901f1f699 (diff) | |
download | sg3_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.c | 151 | ||||
-rw-r--r-- | lib/sg_lib_data.c | 4 | ||||
-rw-r--r-- | lib/sg_pr2serr.c | 1060 | ||||
-rw-r--r-- | lib/sg_pt_haiku.c | 2 |
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 |