diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2022-02-18 05:36:07 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2022-02-18 05:36:07 +0000 |
commit | 8385f6006c857fb6a7e66b4b29da1d91c5300bb6 (patch) | |
tree | ab5c5d5dd98601663aaaa68e1b7b88d6e52fa0ad /src | |
parent | b3918431020005cc1fbf1d3fe836da0048c15c8c (diff) | |
download | sg3_utils-8385f6006c857fb6a7e66b4b29da1d91c5300bb6.tar.gz |
sg_read_buffer: add --eh_code= and --no_output options; sg_inq, sg_vpd: Device Identication VPD page, change IEEE Company_id to AOI
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@938 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src')
-rw-r--r-- | src/sg_inq.c | 39 | ||||
-rw-r--r-- | src/sg_read_buffer.c | 449 | ||||
-rw-r--r-- | src/sg_vpd.c | 10 | ||||
-rw-r--r-- | src/sg_vpd_vendor.c | 17 | ||||
-rw-r--r-- | src/sg_write_x.c | 5 | ||||
-rw-r--r-- | src/sg_z_act_query.c | 5 |
6 files changed, 324 insertions, 201 deletions
diff --git a/src/sg_inq.c b/src/sg_inq.c index 38b033b6..92333975 100644 --- a/src/sg_inq.c +++ b/src/sg_inq.c @@ -51,7 +51,7 @@ #include "sg_pt_nvme.h" #endif -static const char * version_str = "2.14 20220109"; /* spc6r06 */ +static const char * version_str = "2.16 20220217"; /* spc6r06 */ /* INQUIRY notes: * It is recommended that the initial allocation length given to a @@ -1337,12 +1337,11 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex, { int u, j, m, id_len, p_id, c_set, piv, assoc, desig_type, i_len; int off, ci_off, c_id, d_id, naa, vsi, k; - uint64_t vsei; - uint64_t id_ext; + uint64_t vsei, id_ext, ccc_id; const uint8_t * bp; const uint8_t * ip; - char b[64]; const char * cp; + char b[64]; if (buff[2] != 0) { /* @@ -1452,11 +1451,8 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex, hex2stderr(ip, i_len, -1); break; } - c_id = sg_get_unaligned_be24(ip + ci_off); - printf(" IEEE Company_id: 0x%x\n", c_id); - vsei = sg_get_unaligned_be48(ip + ci_off + 3); - printf(" Vendor Specific Extension Identifier: 0x%" PRIx64 - "\n", vsei); + ccc_id = sg_get_unaligned_be64(ip + ci_off); + printf(" IEEE identifier: 0x%" PRIx64 "\n", ccc_id); if (12 == i_len) { d_id = sg_get_unaligned_be32(ip + 8); printf(" Directory ID: 0x%x\n", d_id); @@ -1487,7 +1483,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex, vsi = sg_get_unaligned_be24(ip + 5); printf(" NAA 2, vendor specific identifier A: 0x%x\n", d_id); - printf(" IEEE Company_id: 0x%x\n", c_id); + printf(" AOI: 0x%x\n", c_id); printf(" vendor specific identifier B: 0x%x\n", vsi); printf(" [0x"); for (m = 0; m < 8; ++m) @@ -1521,7 +1517,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex, vsei <<= 8; vsei |= ip[3 + m]; } - printf(" NAA 5, IEEE Company_id: 0x%x\n", c_id); + printf(" NAA 5, AOI: 0x%x\n", c_id); printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n", vsei); printf(" [0x"); @@ -1543,7 +1539,7 @@ decode_dev_ids(const char * leadin, uint8_t * buff, int len, int do_hex, vsei <<= 8; vsei |= ip[3 + m]; } - printf(" NAA 6, IEEE Company_id: 0x%x\n", c_id); + printf(" NAA 6, AOI: 0x%x\n", c_id); printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n", vsei); vsei = sg_get_unaligned_be64(ip + 8); @@ -2032,9 +2028,8 @@ decode_softw_inf_id(uint8_t * buff, int len, int do_hex) len -= 4; buff += 4; for ( ; len > 5; len -= 6, buff += 6) - printf(" IEEE Company_id: 0x%06x, vendor specific extension " - "id: 0x%06x\n", sg_get_unaligned_be24(buff + 0), - sg_get_unaligned_be24(buff + 3)); + printf(" IEEE identifier: 0x%" PRIx64 "\n", + sg_get_unaligned_be48(buff + 0)); } /* VPD_ATA_INFO [0x89] */ @@ -2189,7 +2184,7 @@ decode_b0_vpd(uint8_t * buff, int len, int do_hex) } pdt = PDT_MASK & buff[0]; switch (pdt) { - case PDT_DISK: case PDT_WO: case PDT_OPTICAL: + case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: if (len < 16) { pr2serr("Block limits VPD page length too short=%d\n", len); return; @@ -2335,7 +2330,7 @@ decode_b1_vpd(uint8_t * buff, int len, int do_hex) } pdt = PDT_MASK & buff[0]; switch (pdt) { - case PDT_DISK: case PDT_WO: case PDT_OPTICAL: + case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: if (len < 64) { pr2serr("Block device characteristics VPD page length too " "short=%d\n", len); @@ -2410,7 +2405,7 @@ decode_b3_vpd(uint8_t * buff, int len, int do_hex) } pdt = PDT_MASK & buff[0]; switch (pdt) { - case PDT_DISK: case PDT_WO: case PDT_OPTICAL: + case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: if (len < 0x10) { pr2serr("Referrals VPD page length too short=%d\n", len); return; @@ -3541,7 +3536,7 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len) pdt = rp[0] & PDT_MASK; if (! op->do_raw && (op->do_hex < 2)) { switch (pdt) { - case PDT_DISK: case PDT_WO: case PDT_OPTICAL: + case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("VPD INQUIRY: Block limits page (SBC)\n"); break; case PDT_TAPE: case PDT_MCHANGER: @@ -3569,7 +3564,7 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len) pdt = rp[0] & PDT_MASK; if (! op->do_raw && (op->do_hex < 2)) { switch (pdt) { - case PDT_DISK: case PDT_WO: case PDT_OPTICAL: + case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("VPD INQUIRY: Block device characteristics page " "(SBC)\n"); break; @@ -3607,7 +3602,7 @@ vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len) pdt = rp[0] & PDT_MASK; if (! op->do_raw && (op->do_hex < 2)) { switch (pdt) { - case PDT_DISK: case PDT_WO: case PDT_OPTICAL: + case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("VPD INQUIRY: Referrals VPD page (SBC)\n"); break; default: @@ -3902,7 +3897,7 @@ show_nvme_id_ctrl(const uint8_t *dinp, const char *dev_name, int do_long) printf(" PCI vendor ID VID/SSVID: 0x%x/0x%x\n", sg_get_unaligned_le16(dinp + 0), sg_get_unaligned_le16(dinp + 2)); - printf(" IEEE OUI Identifier: 0x%x\n", + printf(" IEEE OUI Identifier: 0x%x\n", /* this has been renamed AOI */ sg_get_unaligned_le24(dinp + 73)); got_fguid = ! sg_all_zeros(dinp + 112, 16); if (got_fguid) { diff --git a/src/sg_read_buffer.c b/src/sg_read_buffer.c index 01a79c33..cbc5023b 100644 --- a/src/sg_read_buffer.c +++ b/src/sg_read_buffer.c @@ -39,8 +39,7 @@ * device. */ -static const char * version_str = "1.34 20220118"; /* spc6r05 */ - +static const char * version_str = "1.35 20220217"; /* spc6r06 */ #ifndef SG_READ_BUFFER_10_CMD #define SG_READ_BUFFER_10_CMD 0x3c @@ -51,13 +50,26 @@ static const char * version_str = "1.34 20220118"; /* spc6r05 */ #define SG_READ_BUFFER_16_CMDLEN 16 #endif +#define MODE_HEADER_DATA 0 +#define MODE_VENDOR 1 +#define MODE_DATA 2 +#define MODE_DESCRIPTOR 3 +#define MODE_ECHO_BUFFER 0x0A +#define MODE_ECHO_BDESC 0x0B +#define MODE_READ_MICROCODE_ST 0x0F +#define MODE_EN_EX_ECHO 0x1A +#define MODE_ERR_HISTORY 0x1C + #define MAX_DEF_INHEX_LEN 8192 -#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ -#define DEF_PT_TIMEOUT 60 /* 60 seconds */ +#define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ +#define DEF_PT_TIMEOUT 60 /* 60 seconds */ +#define DEF_RESPONSE_LEN 4 /* increased to 64 fo MODE_ERR_HISTORY */ static struct option long_options[] = { {"16", no_argument, 0, 'L'}, + {"eh_code", required_argument, 0, 'e'}, + {"eh-code", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"id", required_argument, 0, 'i'}, @@ -65,6 +77,8 @@ static struct option long_options[] = { {"length", required_argument, 0, 'l'}, {"long", no_argument, 0, 'L'}, {"mode", required_argument, 0, 'm'}, + {"no_output", no_argument, 0, 'N'}, + {"no-output", no_argument, 0, 'N'}, {"offset", required_argument, 0, 'o'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, @@ -74,19 +88,48 @@ static struct option long_options[] = { {0, 0, 0, 0}, /* sentinel */ }; +struct opts_t { + bool do_long; + bool o_readonly; + bool do_raw; + bool eh_code_given; + bool no_output; + bool rb_id_given; + bool rb_len_given; + bool rb_mode_given; + bool verbose_given; + bool version_given; + int sg_fd; + int do_help; + int do_hex; + int eh_code; + int rb_id; + int rb_len; + int rb_mode; + int rb_mode_sp; + int verbose; + uint64_t rb_offset; + const char * device_name; + const char * inhex_name; +}; + static void usage() { - pr2serr("Usage: sg_read_buffer [--16] [--help] [--hex] [--id=ID] " - "[--inhex=FN]\n" - " [--length=LEN] [--long] [--mode=MO] " - "[--offset=OFF]\n" - " [--raw] [--readonly] [--specific=MS] " - "[--verbose]\n" - " [--version] DEVICE\n" + pr2serr("Usage: sg_read_buffer [--16] [--eh_code=EHC] [--help] [--hex] " + "[--id=ID]\n" + " [--inhex=FN] [--length=LEN] [--long] " + "[--mode=MO]\n" + " [--no_output] [--offset=OFF] [--raw] " + "[--readonly]\n" + " [--specific=MS] [--verbose] [--version] " + "DEVICE\n" " where:\n" " --16|-L issue READ BUFFER(16) (def: 10)\n" + " --eh_code=EHC|-e EHC same as '-m eh -i EHC' where " + "EHC is the\n" + " error history code\n" " --help|-h print out usage message\n" " --hex|-H print output in hex\n" " --id=ID|-i ID buffer identifier (0 (default) to 255)\n" @@ -94,10 +137,12 @@ usage() "decode\n" " rather than DEVICE. If --raw given " "then binary\n" - " --length=LEN|-l LEN length in bytes to read (def: 4)\n" + " --length=LEN|-l LEN length in bytes to read (def: 4, " + "64 for eh)\n" " --long|-L issue READ BUFFER(16) (def: 10)\n" " --mode=MO|-m MO read buffer mode, MO is number or " "acronym (def: 0)\n" + " --no_output|-N perform the command then exit\n" " --offset=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n" " --raw|-r output response in binary to stdout\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" @@ -106,22 +151,12 @@ usage() " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI READ BUFFER (10 or 16) command. Use '-m xxx' to " - "list\navailable modes. Numbers given in options are decimal " - "unless they have\na hex indicator (e.g. a leading '0x').\n" + "list\navailable modes. Some responses are decoded, others are " + "output in hex.\n" ); } -#define MODE_HEADER_DATA 0 -#define MODE_VENDOR 1 -#define MODE_DATA 2 -#define MODE_DESCRIPTOR 3 -#define MODE_ECHO_BUFFER 0x0A -#define MODE_ECHO_BDESC 0x0B -#define MODE_READ_MICROCODE_ST 0x0F -#define MODE_EN_EX_ECHO 0x1A -#define MODE_ERR_HISTORY 0x1C - static struct mode_s { const char *mode_string; int mode; @@ -138,7 +173,7 @@ static struct mode_s { "(spc-5)"}, { "en_ex", MODE_EN_EX_ECHO, "enable expander communications protocol and echo buffer (spc-3)"}, - { "err_hist", MODE_ERR_HISTORY, "error history (spc-4)"}, + { "err_hist|eh", MODE_ERR_HISTORY, "error history (spc-4)"}, { NULL, 999, NULL}, /* end sentinel */ }; @@ -159,9 +194,8 @@ print_modes(void) /* Invokes a SCSI READ BUFFER(10) command (spc5r02). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int -sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, - uint32_t rb_offset, void * resp, int mx_resp_len, - int * residp, bool noisy, int verbose) +sg_ll_read_buffer_10(void * resp, int * residp, bool noisy, + const struct opts_t * op) { int ret, res, sense_cat; uint8_t rb10_cb[SG_READ_BUFFER_10_CMDLEN] = @@ -169,13 +203,13 @@ sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, uint8_t sense_b[SENSE_BUFF_LEN] = {0}; struct sg_pt_base * ptvp; - rb10_cb[1] = (uint8_t)(rb_mode & 0x1f); - if (rb_mode_sp) - rb10_cb[1] |= (uint8_t)((rb_mode_sp & 0x7) << 5); - rb10_cb[2] = (uint8_t)rb_id; - sg_put_unaligned_be24(rb_offset, rb10_cb + 3); - sg_put_unaligned_be24(mx_resp_len, rb10_cb + 6); - if (verbose) { + rb10_cb[1] = (uint8_t)(op->rb_mode & 0x1f); + if (op->rb_mode_sp) + rb10_cb[1] |= (uint8_t)((op->rb_mode_sp & 0x7) << 5); + rb10_cb[2] = (uint8_t)op->rb_id; + sg_put_unaligned_be24(op->rb_offset, rb10_cb + 3); + sg_put_unaligned_be24(op->rb_len, rb10_cb + 6); + if (op->verbose) { char b[128]; pr2serr(" Read buffer(10) cdb: %s\n", @@ -190,10 +224,10 @@ sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, } set_scsi_pt_cdb(ptvp, rb10_cb, sizeof(rb10_cb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); - set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); - res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); - ret = sg_cmds_process_resp(ptvp, "Read buffer(10)", res, noisy, verbose, - &sense_cat); + set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->rb_len); + res = do_scsi_pt(ptvp, op->sg_fd, DEF_PT_TIMEOUT, op->verbose); + ret = sg_cmds_process_resp(ptvp, "Read buffer(10)", res, noisy, + op->verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; @@ -210,7 +244,7 @@ sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, break; } } else { - if ((verbose > 2) && (ret > 0)) { + if ((op->verbose > 2) && (ret > 0)) { pr2serr(" Read buffer(10): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); @@ -226,9 +260,8 @@ sg_ll_read_buffer_10(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, /* Invokes a SCSI READ BUFFER(16) command (spc5r02). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int -sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, - uint64_t rb_offset, void * resp, int mx_resp_len, - int * residp, bool noisy, int verbose) +sg_ll_read_buffer_16(void * resp, int * residp, bool noisy, + const struct opts_t * op) { int ret, res, sense_cat; uint8_t rb16_cb[SG_READ_BUFFER_16_CMDLEN] = @@ -237,13 +270,13 @@ sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, uint8_t sense_b[SENSE_BUFF_LEN] = {0}; struct sg_pt_base * ptvp; - rb16_cb[1] = (uint8_t)(rb_mode & 0x1f); - if (rb_mode_sp) - rb16_cb[1] |= (uint8_t)((rb_mode_sp & 0x7) << 5); - sg_put_unaligned_be64(rb_offset, rb16_cb + 2); - sg_put_unaligned_be24(mx_resp_len, rb16_cb + 11); - rb16_cb[14] = (uint8_t)rb_id; - if (verbose) { + rb16_cb[1] = (uint8_t)(op->rb_mode & 0x1f); + if (op->rb_mode_sp) + rb16_cb[1] |= (uint8_t)((op->rb_mode_sp & 0x7) << 5); + sg_put_unaligned_be64(op->rb_offset, rb16_cb + 2); + sg_put_unaligned_be32(op->rb_len, rb16_cb + 10); + rb16_cb[14] = (uint8_t)op->rb_id; + if (op->verbose) { char b[128]; pr2serr(" Read buffer(16) cdb: %s\n", @@ -253,15 +286,15 @@ sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { - pr2serr("Read buffer(16): out of memory\n"); + pr2serr("%s: out of memory\n", __func__); return -1; } set_scsi_pt_cdb(ptvp, rb16_cb, sizeof(rb16_cb)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); - set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len); - res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); - ret = sg_cmds_process_resp(ptvp, "Read buffer(16)", res, noisy, verbose, - &sense_cat); + set_scsi_pt_data_in(ptvp, (uint8_t *)resp, op->rb_len); + res = do_scsi_pt(ptvp, op->sg_fd, DEF_PT_TIMEOUT, op->verbose); + ret = sg_cmds_process_resp(ptvp, "Read buffer(16)", res, noisy, + op->verbose, &sense_cat); if (-1 == ret) { if (get_scsi_pt_transport_err(ptvp)) ret = SG_LIB_TRANSPORT_ERROR; @@ -278,7 +311,7 @@ sg_ll_read_buffer_16(int sg_fd, int rb_mode, int rb_mode_sp, int rb_id, break; } } else { - if ((verbose > 2) && (ret > 0)) { + if ((op->verbose > 2) && (ret > 0)) { pr2serr(" Read buffer(16): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret), -1); @@ -343,7 +376,7 @@ struct sg_lib_simple_value_name_t down_micro_st_arr[] = { }; static void -decode_microcode_status(uint8_t * resp, int rb_len) +decode_microcode_status(const uint8_t * resp, const struct opts_t * op) { int n; uint32_t u; @@ -351,7 +384,7 @@ decode_microcode_status(uint8_t * resp, int rb_len) const struct sg_lib_simple_value_name_t * vnp; char b[32]; - if ((NULL == resp) || (rb_len < 1)) + if ((NULL == resp) || (op->rb_len < 1)) return; n = resp[0]; if (n < (int)SG_ARRAY_SIZE(act_micro_st_arr)) @@ -362,7 +395,7 @@ decode_microcode_status(uint8_t * resp, int rb_len) } printf("Activated microcode status: %s\n", cp); - if (rb_len < 2) + if (op->rb_len < 2) return; n = resp[1]; if (n < (int)SG_ARRAY_SIZE(red_micro_st_arr)) @@ -373,7 +406,7 @@ decode_microcode_status(uint8_t * resp, int rb_len) } printf("Redundant microcode status: %s\n", cp); - if (rb_len < 3) + if (op->rb_len < 3) return; n = resp[2]; for (vnp = down_micro_st_arr, cp = NULL; vnp->name; ++vnp) { @@ -388,11 +421,11 @@ decode_microcode_status(uint8_t * resp, int rb_len) } printf("Download microcode status: %s\n", cp); - if (rb_len > 7) { + if (op->rb_len > 7) { u = sg_get_unaligned_be32(resp + 4); printf("Download microcode maximum size (bytes): %u [0x%x]\n", u, u); } - if (rb_len > 15) { + if (op->rb_len > 15) { u = sg_get_unaligned_be32(resp + 12); printf("Download microcode expected buffer offset (bytes): %u " "[0x%x]\n", u, u); @@ -400,6 +433,59 @@ decode_microcode_status(uint8_t * resp, int rb_len) } static void +decode_error_history(const uint8_t * resp, const struct opts_t * op) +{ + static const char * eh_s = "Error history"; + int k, num; + uint32_t dir_len; + const uint8_t * up; + + if (op->rb_id < 0x4) { /* eh directory variants */ + if (op->rb_len < 8) { + pr2serr("%s response buffer too short [%d] to show directory " + "header\n", eh_s, op->rb_len); + return; + } + printf("%s directory header:\n", eh_s); + printf(" T10 Vendor: %.8s\n", resp + 0); + printf(" Version: %u\n", resp[8]); + printf(" EHS_retrieved: %u\n", 0x3 & (resp[9] >> 3)); + printf(" EHS_source: %u\n", 0x3 & (resp[9] >> 1)); + printf(" CLR_SUP: %u\n", 0x1 & resp[9]); + if (op->rb_len < 32) { + pr2serr("%s response buffer too short [%d] to show directory " + "length\n", eh_s, op->rb_len); + return; + } + dir_len = sg_get_unaligned_be16(resp + 30); + printf(" Directory length: %u\n", dir_len); + if ((unsigned)op->rb_len < (32 + dir_len)) { + pr2serr("%s directory entries truncated, try adding '-l %u' " + "option\n", eh_s, 32 + dir_len); + } + num = (op->rb_len - 32) / 8; + for (k = 0, up = resp + 32; k < num; ++k, up += 8) { + if (k > 0) + printf("\n"); + printf(" Supported buffer ID: 0x%x\n", up[0]); + printf(" Buffer format: 0x%x\n", up[1]); + printf(" Buffer source: 0x%x\n", 0xf & up[2]); + printf(" Maximum available length: 0x%x\n", + sg_get_unaligned_be32(up + 4)); + } + } else if ((op->rb_id >= 0x10) && (op->rb_id <= 0xef)) + hex2stdout(resp, op->rb_len, (op->verbose > 1 ? 0 : 1)); + else if (0xfe == op->rb_id) + pr2serr("clear %s I_T nexus [0x%x]\n", eh_s, op->rb_id); + else if (0xff == op->rb_id) + pr2serr("clear %s I_T nexus and release any snapshots [0x%x]\n", + eh_s, op->rb_id); + else + pr2serr("Reserved Buffer ID value [0x%x] for %s\n", op->rb_id, eh_s); + +} + +static void dStrRaw(const uint8_t * str, int len) { int k; @@ -411,84 +497,90 @@ dStrRaw(const uint8_t * str, int len) int main(int argc, char * argv[]) { - bool do_long = false; - bool o_readonly = false; - bool do_raw = false; - bool verbose_given = false; - bool version_given = false; int res, c, len, k; int inhex_len = 0; - int sg_fd = -1; - int do_help = 0; - int do_hex = 0; - int rb_id = 0; - int rb_len = 4; - int rb_mode = 0; - int rb_mode_sp = 0; int resid = 0; - int verbose = 0; int ret = 0; int64_t ll; - uint64_t rb_offset = 0; - const char * device_name = NULL; - const char * fname = NULL; + const char * cp = NULL; uint8_t * resp = NULL; uint8_t * free_resp = NULL; const struct mode_s * mp; + struct opts_t opts = {0}; + struct opts_t * op = &opts; + + op->sg_fd = -1; + op->rb_len = DEF_RESPONSE_LEN; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "hHi:I:l:Lm:o:rRS:vV", long_options, + c = getopt_long(argc, argv, "e:hHi:I:l:Lm:No:rRS:vV", long_options, &option_index); if (c == -1) break; switch (c) { + case 'e': + if (op->rb_mode_given && (MODE_ERR_HISTORY != op->rb_mode)) { + pr2serr("mode incompatible with --eh_code= option\n"); + return SG_LIB_CONTRADICT; + } + op->eh_code = sg_get_num(optarg); + if ((op->eh_code < 0) || (op->eh_code > 255)) { + pr2serr("argument to '--eh_code=' should be in the range 0 " + "to 255\n"); + return SG_LIB_SYNTAX_ERROR; + } + op->rb_mode = MODE_ERR_HISTORY; + op->eh_code_given = true; + break; case 'h': case '?': - ++do_help; + ++op->do_help; break; case 'H': - ++do_hex; + ++op->do_hex; break; case 'i': - rb_id = sg_get_num(optarg); - if ((rb_id < 0) || (rb_id > 255)) { - pr2serr("argument to '--id' should be in the range 0 to " + op->rb_id = sg_get_num(optarg); + if ((op->rb_id < 0) || (op->rb_id > 255)) { + pr2serr("argument to '--id=' should be in the range 0 to " "255\n"); return SG_LIB_SYNTAX_ERROR; } + op->rb_id_given = true; break; case 'I': - if (fname) { + if (op->inhex_name) { pr2serr("--inhex= option given more than once. Once only " "please\n"); return SG_LIB_SYNTAX_ERROR; } else - fname = optarg; + op->inhex_name = optarg; break; case 'l': - rb_len = sg_get_num(optarg); - if (rb_len < 0) { + op->rb_len = sg_get_num(optarg); + if (op->rb_len < 0) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } - if (rb_len > 0xffffff) { + if (op->rb_len > 0xffffff) { pr2serr("argument to '--length' must be <= 0xffffff\n"); return SG_LIB_SYNTAX_ERROR; } + op->rb_len_given = true; break; case 'L': - do_long = true; + op->do_long = true; break; case 'm': if (NULL == optarg) { pr2serr("bad argument to '--mode'\n"); return SG_LIB_SYNTAX_ERROR; } else if (isdigit((uint8_t)*optarg)) { - rb_mode = sg_get_num(optarg); - if ((rb_mode < 0) || (rb_mode > 31)) { + op->rb_mode = sg_get_num(optarg); + if ((op->rb_mode < 0) || (op->rb_mode > 31)) { pr2serr("argument to '--mode' should be in the range 0 " "to 31\n"); return SG_LIB_SYNTAX_ERROR; @@ -496,9 +588,24 @@ main(int argc, char * argv[]) } else { len = strlen(optarg); for (mp = modes; mp->mode_string; ++mp) { - if (0 == strncmp(mp->mode_string, optarg, len)) { - rb_mode = mp->mode; - break; + cp = strchr(mp->mode_string, '|'); + if (NULL == cp) { + if (0 == strncmp(mp->mode_string, optarg, len)) { + op->rb_mode = mp->mode; + break; + } + } else { + int f_len = cp - mp->mode_string; + + if ((f_len == len) && + (0 == memcmp(mp->mode_string, optarg, len))) { + op->rb_mode = mp->mode; + break; + } + if (0 == strncmp(cp + 1, optarg, len)) { + op->rb_mode = mp->mode; + break; + } } } if (NULL == mp->mode_string) { @@ -506,6 +613,14 @@ main(int argc, char * argv[]) return SG_LIB_SYNTAX_ERROR; } } + if (op->eh_code_given && (MODE_ERR_HISTORY != op->rb_mode)) { + pr2serr("mode incompatible with --eh_code= option\n"); + return SG_LIB_CONTRADICT; + } + op->rb_mode_given = true; + break; + case 'N': + op->no_output = true; break; case 'o': ll = sg_get_llnum(optarg); @@ -513,27 +628,27 @@ main(int argc, char * argv[]) pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } - rb_offset = ll; + op->rb_offset = ll; break; case 'r': - do_raw = true; + op->do_raw = true; break; case 'R': - o_readonly = true; + op->o_readonly = true; break; case 'S': - rb_mode_sp = sg_get_num(optarg); - if ((rb_mode_sp < 0) || (rb_mode_sp > 7)) { + op->rb_mode_sp = sg_get_num(optarg); + if ((op->rb_mode_sp < 0) || (op->rb_mode_sp > 7)) { pr2serr("expected argument to '--specific' to be 0 to 7\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': - verbose_given = true; - ++verbose; + op->verbose_given = true; + ++op->verbose; break; case 'V': - version_given = true; + op->version_given = true; break; default: pr2serr("unrecognised option code 0x%x ??\n", c); @@ -541,8 +656,8 @@ main(int argc, char * argv[]) return SG_LIB_SYNTAX_ERROR; } } - if (do_help) { - if (do_help > 1) { + if (op->do_help) { + if (op->do_help > 1) { usage(); pr2serr("\n"); print_modes(); @@ -551,8 +666,8 @@ main(int argc, char * argv[]) return 0; } if (optind < argc) { - if (NULL == device_name) { - device_name = argv[optind]; + if (NULL == op->device_name) { + op->device_name = argv[optind]; ++optind; } if (optind < argc) { @@ -565,54 +680,67 @@ main(int argc, char * argv[]) #ifdef DEBUG pr2serr("In DEBUG mode, "); - if (verbose_given && version_given) { + if (op->verbose_given && op->version_given) { pr2serr("but override: '-vV' given, zero verbose and continue\n"); - verbose_given = false; - version_given = false; - verbose = 0; - } else if (! verbose_given) { + op->verbose_given = false; + op->version_given = false; + op->verbose = 0; + } else if (! op->verbose_given) { pr2serr("set '-vv'\n"); - verbose = 2; + op->verbose = 2; } else - pr2serr("keep verbose=%d\n", verbose); + pr2serr("keep verbose=%d\n", op->verbose); #else - if (verbose_given && version_given) + if (op->verbose_given && op->version_given) pr2serr("Not in DEBUG mode, so '-vV' has no special action\n"); #endif - if (version_given) { + if (op->version_given) { pr2serr("version: %s\n", version_str); return 0; } + if ((MODE_ERR_HISTORY == op->rb_mode) && (NULL == op->inhex_name)) { + if (! op->rb_len_given) + op->rb_len = 64; + } + if (op->eh_code_given) { + if (op->rb_id_given && (op->eh_code != op->rb_id)) { + pr2serr("Buffer ID incompatible with --eh_code= option\n"); + return SG_LIB_CONTRADICT; + } + op->rb_id = op->eh_code; + } - if (device_name && fname) { + if (op->device_name && op->inhex_name) { pr2serr("Confused: both DEVICE (%s) and --inhex= option given. One " - "only please\n", device_name); + "only please\n", op->device_name); return SG_LIB_SYNTAX_ERROR; - } else if (fname) { - rb_len = (rb_len > MAX_DEF_INHEX_LEN) ? rb_len : MAX_DEF_INHEX_LEN; - resp = (uint8_t *)sg_memalign(rb_len, 0, &free_resp, false); - ret = sg_f2hex_arr(fname, do_raw, false, resp, &inhex_len, rb_len); + } else if (op->inhex_name) { + op->rb_len = (op->rb_len > MAX_DEF_INHEX_LEN) ? op->rb_len : + MAX_DEF_INHEX_LEN; + resp = (uint8_t *)sg_memalign(op->rb_len, 0, &free_resp, false); + ret = sg_f2hex_arr(op->inhex_name, op->do_raw, false, resp, + &inhex_len, op->rb_len); if (ret) goto fini; - if (do_raw) - do_raw = false; /* only used for input in this case */ - rb_len = inhex_len; + if (op->do_raw) + op->do_raw = false; /* only used for input in this case */ + op->rb_len = inhex_len; resid = 0; goto decode_result; - } else if (NULL == device_name) { + } else if (NULL == op->device_name) { pr2serr("Missing device name!\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } - len = rb_len ? rb_len : 8; + len = op->rb_len ? op->rb_len : 8; resp = (uint8_t *)sg_memalign(len, 0, &free_resp, false); if (NULL == resp) { pr2serr("unable to allocate %d bytes on the heap\n", len); return SG_LIB_CAT_OTHER; } - if (do_raw) { + if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; @@ -622,55 +750,56 @@ main(int argc, char * argv[]) #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT - if (verbose > 4) + if (op->verbose > 4) pr2serr("Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif - sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); - if (sg_fd < 0) { - if (verbose) - pr2serr("open error: %s: %s\n", device_name, - safe_strerror(-sg_fd)); - ret = sg_convert_errno(-sg_fd); + op->sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly, + op->verbose); + if (op->sg_fd < 0) { + if (op->verbose) + pr2serr("open error: %s: %s\n", op->device_name, + safe_strerror(-op->sg_fd)); + ret = sg_convert_errno(-op->sg_fd); goto fini; } - if (do_long) - res = sg_ll_read_buffer_16(sg_fd, rb_mode, rb_mode_sp, rb_id, - rb_offset, resp, rb_len, &resid, true, - verbose); - else if (rb_offset > 0xffffff) { + if (op->do_long) + res = sg_ll_read_buffer_16(resp, &resid, true, op); + else if (op->rb_offset > 0xffffff) { pr2serr("--offset value is too large for READ BUFFER(10), try " "--16\n"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } else - res = sg_ll_read_buffer_10(sg_fd, rb_mode, rb_mode_sp, rb_id, - (uint32_t)rb_offset, resp, rb_len, &resid, - true, verbose); + res = sg_ll_read_buffer_10(resp, &resid, true, op); if (0 != res) { char b[80]; ret = res; if (res > 0) { - sg_get_category_sense_str(res, sizeof(b), b, verbose); - pr2serr("Read buffer(%d) failed: %s\n", (do_long ? 16 : 10), b); + sg_get_category_sense_str(res, sizeof(b), b, op->verbose); + pr2serr("Read buffer(%d) failed: %s\n", + (op->do_long ? 16 : 10), b); } goto fini; } if (resid > 0) - rb_len -= resid; /* got back less than requested */ + op->rb_len -= resid; /* got back less than requested */ + if (op->no_output) + goto fini; decode_result: - if (rb_len > 0) { - if (do_raw) - dStrRaw(resp, rb_len); - else if (do_hex || (rb_len < 4)) - hex2stdout((const uint8_t *)resp, rb_len, ((do_hex > 1) ? 0 : 1)); - else { - switch (rb_mode) { + if (op->rb_len > 0) { + if (op->do_raw) + dStrRaw(resp, op->rb_len); + else if (op->do_hex || (op->rb_len < 4)) { + k = (op->do_hex > 2) ? -1 : (2 - op->do_hex); + hex2stdout(resp, op->rb_len, k); + } else { + switch (op->rb_mode) { case MODE_DESCRIPTOR: k = sg_get_unaligned_be24(resp + 1); printf("OFFSET BOUNDARY: %d, Buffer offset alignment: " @@ -683,11 +812,13 @@ decode_result: printf("Echo buffer capacity: %d (0x%x)\n", k, k); break; case MODE_READ_MICROCODE_ST: - decode_microcode_status(resp, rb_len); + decode_microcode_status(resp, op); + break; + case MODE_ERR_HISTORY: + decode_error_history(resp, op); break; default: - hex2stdout((const uint8_t *)resp, rb_len, - (verbose > 1 ? 0 : 1)); + hex2stdout(resp, op->rb_len, (op->verbose > 1 ? 0 : 1)); break; } } @@ -696,15 +827,15 @@ decode_result: fini: if (free_resp) free(free_resp); - if (sg_fd >= 0) { - res = sg_cmds_close_device(sg_fd); + if (op->sg_fd >= 0) { + res = sg_cmds_close_device(op->sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = sg_convert_errno(-res); } } - if (0 == verbose) { + if (0 == op->verbose) { if (! sg_if_can2stderr("sg_read_buffer failed: ", ret)) pr2serr("Some error occurred, try again with '-v' " "or '-vv' for more information\n"); diff --git a/src/sg_vpd.c b/src/sg_vpd.c index 46b7e603..31954183 100644 --- a/src/sg_vpd.c +++ b/src/sg_vpd.c @@ -40,7 +40,7 @@ */ -static const char * version_str = "1.68 20220118"; /* spc6r06 + sbc5r01 */ +static const char * version_str = "1.69 20220217"; /* spc6r06 + sbc5r01 */ /* standard VPD pages, in ascending page number order */ #define VPD_SUPPORTED_VPDS 0x0 @@ -1150,11 +1150,9 @@ decode_softw_inf_id(uint8_t * buff, int len, int do_hex) } len -= 4; buff += 4; - for ( ; len > 5; len -= 6, buff += 6) { - printf(" IEEE Company_id: 0x%06x, vendor specific extension " - "id: 0x%06x\n", sg_get_unaligned_be24(buff), - sg_get_unaligned_be24(buff + 3)); - } + for ( ; len > 5; len -= 6, buff += 6) + printf(" IEEE identifier: 0x%" PRIx64 "\n", + sg_get_unaligned_be48(buff + 0)); } /* VPD_ATA_INFO */ diff --git a/src/sg_vpd_vendor.c b/src/sg_vpd_vendor.c index 4f3b25e5..d79ccc7d 100644 --- a/src/sg_vpd_vendor.c +++ b/src/sg_vpd_vendor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2019 Douglas Gilbert. + * Copyright (c) 2006-2022 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. @@ -11,6 +11,7 @@ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> +#include <stdbool.h> #include <string.h> #define __STDC_FORMAT_MACROS 1 #include <inttypes.h> @@ -232,11 +233,11 @@ dup_sanity_chk(int sz_opts_t, int sz_values_name_t) sz_values_name_t); } -static int +static bool is_like_pdt(int actual_pdt, const struct svpd_values_name_t * vnp) { if (actual_pdt == vnp->pdt) - return 1; + return true; if (PDT_DISK == vnp->pdt) { switch (actual_pdt) { case PDT_DISK: @@ -244,21 +245,21 @@ is_like_pdt(int actual_pdt, const struct svpd_values_name_t * vnp) case PDT_PROCESSOR: case PDT_SAC: case PDT_ZBC: - return 1; + return true; default: - return 0; + return false; } } else if (PDT_TAPE == vnp->pdt) { switch (actual_pdt) { case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: - return 1; + return true; default: - return 0; + return false; } } else - return 0; + return false; } static const struct svpd_values_name_t * diff --git a/src/sg_write_x.c b/src/sg_write_x.c index 81ee1a67..b7c34f75 100644 --- a/src/sg_write_x.c +++ b/src/sg_write_x.c @@ -38,7 +38,7 @@ #include "sg_unaligned.h" #include "sg_pr2serr.h" -static const char * version_str = "1.30 20220127"; +static const char * version_str = "1.31 20220217"; /* Protection Information refers to 8 bytes of extra information usually * associated with each logical block and is often abbreviated to PI while @@ -2197,10 +2197,9 @@ main(int argc, char * argv[]) uint64_t addr_arr[MAX_NUM_ADDR]; uint32_t num_arr[MAX_NUM_ADDR]; struct stat if_stat, sf_stat; - struct opts_t opts; + struct opts_t opts = {0}; op = &opts; - memset(op, 0, sizeof(opts)); memset(&if_stat, 0, sizeof(if_stat)); memset(&sf_stat, 0, sizeof(sf_stat)); op->numblocks = DEF_WR_NUMBLOCKS; diff --git a/src/sg_z_act_query.c b/src/sg_z_act_query.c index a345b2e8..cd347820 100644 --- a/src/sg_z_act_query.c +++ b/src/sg_z_act_query.c @@ -38,7 +38,7 @@ * command to the given SCSI device. Based on zbc2r12.pdf . */ -static const char * version_str = "1.02 20211203"; +static const char * version_str = "1.03 20211217"; #define SG_ZBC_IN_CMDLEN 16 #define Z_ACTIVATE_SA 0x8 @@ -365,10 +365,9 @@ main(int argc, char * argv[]) uint8_t * free_zibp = NULL; const char * sa_name; char b[80]; - struct opts_t opts; + struct opts_t opts = {0}; struct opts_t * op = &opts; - memset(&opts, 0, sizeof(opts)); while (1) { int option_index = 0; |