diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2019-08-29 00:15:08 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2019-08-29 00:15:08 +0000 |
commit | b8a9d0f9070ee4a0f10c7d2e779655bffbfe1624 (patch) | |
tree | 45c9d8fe86fc79abccfe6d40f221da341d144f6f /src/sg_get_lba_status.c | |
parent | abf4073cf5d973125dd384bc42f7338ec7e49c48 (diff) | |
download | sg3_utils-b8a9d0f9070ee4a0f10c7d2e779655bffbfe1624.tar.gz |
add sg_get_elem_status utility; inhex folder; some NVMe 1.4; some zbc realms
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@830 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src/sg_get_lba_status.c')
-rw-r--r-- | src/sg_get_lba_status.c | 369 |
1 files changed, 213 insertions, 156 deletions
diff --git a/src/sg_get_lba_status.c b/src/sg_get_lba_status.c index 6018d4f1..1b9df4de 100644 --- a/src/sg_get_lba_status.c +++ b/src/sg_get_lba_status.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2018 Douglas Gilbert. + * Copyright (c) 2009-2019 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. @@ -35,7 +35,7 @@ * device. */ -static const char * version_str = "1.18 20180812"; /* sbc4r15 */ +static const char * version_str = "1.20 20190822"; /* sbc4r15 */ #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) @@ -44,7 +44,7 @@ static const char * version_str = "1.18 20180812"; /* sbc4r15 */ #define MAX_GLBAS_BUFF_LEN (1024 * 1024) #define DEF_GLBAS_BUFF_LEN 24 -static uint8_t glbasBuff[DEF_GLBAS_BUFF_LEN]; +static uint8_t glbasFixedBuff[DEF_GLBAS_BUFF_LEN]; static struct option long_options[] = { @@ -55,6 +55,8 @@ static struct option long_options[] = { {"element_id", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, + {"in", required_argument, 0, 'i'}, /* silent, same as --inhex= */ + {"inhex", required_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"raw", no_argument, 0, 'r'}, @@ -73,12 +75,12 @@ usage() { pr2serr("Usage: sg_get_lba_status [--16] [--32][--brief] " "[--element-id=EI]\n" - " [--help] [--hex] " - "[--lba=LBA] [--maxlen=LEN]\n" - " [--raw] [--readonly] " - "[--report-type=RT]\n" - " [--scan-len=SL] [--verbose] " - "[--version] DEVICE\n" + " [--help] [--hex] [--inhex=FN] " + "[--lba=LBA]\n" + " [--maxlen=LEN] [--raw] [--readonly]\n" + " [--report-type=RT] [--scan-len=SL] " + "[--verbose]\n" + " [--version] DEVICE\n" " where:\n" " --16|-S use GET LBA STATUS(16) cdb (def)\n" " --32|-T use GET LBA STATUS(32) cdb\n" @@ -91,13 +93,19 @@ usage() "(def: 0)\n" " --help|-h print out usage message\n" " --hex|-H output in hexadecimal\n" + " --inhex=FN input taken from file FN rather than " + "DEVICE,\n" + " assumed to be ASCII hex or, if --raw, " + "in binary\n" " --lba=LBA|-l LBA starting LBA (logical block address) " "(def: 0)\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> %d bytes)\n", DEF_GLBAS_BUFF_LEN ); - pr2serr(" --raw|-r output in binary\n" + pr2serr(" --raw|-r output in binary, unless if --inhex=FN " + "is given,\n" + " in which case input file is binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --report-type=RT|-t RT report type: 0->all LBAs (def);\n" " 1-> LBAs with non-zero " @@ -113,7 +121,8 @@ usage() " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI GET LBA STATUS(16) or GET LBA STATUS(32) " - "command\n(SBC-3 and SBC-4)\n" + "command (SBC-3 and\nSBC-4). If --inhex=FN is given then " + "contents of FN is assumed to be a response\nto this command.\n" ); } @@ -156,10 +165,12 @@ main(int argc, char * argv[]) bool do_16 = false; bool do_32 = false; bool do_raw = false; + bool no_final_msg = false; bool o_readonly = false; bool verbose_given = false; bool version_given = false; - int sg_fd, k, j, res, c, rlen, num_descs, completion_cond; + int k, j, res, c, rlen, num_descs, completion_cond, in_len; + int sg_fd = -1; int do_brief = 0; int do_hex = 0; int ret = 0; @@ -174,14 +185,15 @@ main(int argc, char * argv[]) int64_t ll; uint64_t lba = 0; const char * device_name = NULL; + const char * in_fn = NULL; const uint8_t * bp; - uint8_t * glbasBuffp = glbasBuff; + uint8_t * glbasBuffp = glbasFixedBuff; uint8_t * free_glbasBuffp = NULL; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "be:hHl:m:rRs:St:TvV", long_options, + c = getopt_long(argc, argv, "be:hi:Hl:m:rRs:St:TvV", long_options, &option_index); if (c == -1) break; @@ -205,6 +217,9 @@ main(int argc, char * argv[]) case 'H': ++do_hex; break; + case 'i': + in_fn = optarg; + break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { @@ -220,6 +235,8 @@ main(int argc, char * argv[]) MAX_GLBAS_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } + if (0 == maxlen) + maxlen = DEF_GLBAS_BUFF_LEN; break; case 'r': do_raw = true; @@ -296,11 +313,6 @@ main(int argc, char * argv[]) return 0; } - if (NULL == device_name) { - pr2serr("missing device name!\n"); - usage(); - return SG_LIB_SYNTAX_ERROR; - } if (maxlen > DEF_GLBAS_BUFF_LEN) { glbasBuffp = (uint8_t *)sg_memalign(maxlen, 0, &free_glbasBuffp, verbose > 3); @@ -309,11 +321,48 @@ main(int argc, char * argv[]) return sg_convert_errno(ENOMEM); } } + if (device_name && in_fn) { + pr2serr("ignoring DEVICE, best to give DEVICE or --inhex=FN, but " + "not both\n"); + device_name = NULL; + } + if (NULL == device_name) { + if (in_fn) { + if ((ret = sg_f2hex_arr(in_fn, do_raw, false, glbasBuffp, + &in_len, maxlen))) { + if (SG_LIB_LBA_OUT_OF_RANGE == ret) { + no_final_msg = true; + pr2serr("... decode what we have, --maxlen=%d needs to " + "be increased\n", maxlen); + } else + goto fini; + } + if (verbose > 2) + pr2serr("Read %d [0x%x] bytes of user supplied data\n", + in_len, in_len); + if (do_raw) + do_raw = false; /* can interfere on decode */ + if (in_len < 4) { + pr2serr("--in=%s only decoded %d bytes (needs 4 at least)\n", + in_fn, in_len); + ret = SG_LIB_SYNTAX_ERROR; + goto fini; + } + res = 0; + goto start_response; + } else { + pr2serr("missing device name!\n\n"); + usage(); + ret = SG_LIB_FILE_ERROR; + no_final_msg = true; + goto fini; + } + } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; - goto free_buff; + goto fini; } } if (do_16 && do_32) { @@ -334,7 +383,7 @@ main(int argc, char * argv[]) if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = sg_convert_errno(-sg_fd); - goto free_buff; + goto fini; } res = 0; @@ -346,151 +395,158 @@ main(int argc, char * argv[]) glbasBuffp, maxlen, true, verbose); ret = res; - if (0 == res) { - /* in sbc3r25 offset for calculating the 'parameter data length' - * (rlen variable below) was reduced from 8 to 4. */ - if (maxlen >= 4) - rlen = sg_get_unaligned_be32(glbasBuffp + 0) + 4; - else - rlen = maxlen; - k = (rlen > maxlen) ? maxlen : rlen; - if (do_raw) { - dStrRaw((const char *)glbasBuffp, k); - goto the_end; - } - if (do_hex) { - hex2stdout(glbasBuffp, k, 1); - goto the_end; - } - if (maxlen < 4) { - if (verbose) - pr2serr("Exiting because allocation length (maxlen) less " - "than 4\n"); - goto the_end; - } - if ((verbose > 1) || (verbose && (rlen > maxlen))) { - pr2serr("response length %d bytes\n", rlen); - if (rlen > maxlen) - pr2serr(" ... which is greater than maxlen (allocation " - "length %d), truncation\n", maxlen); - } + if (res) + goto error; + +start_response: + /* in sbc3r25 offset for calculating the 'parameter data length' + * (rlen variable below) was reduced from 8 to 4. */ + if (maxlen >= 4) + rlen = sg_get_unaligned_be32(glbasBuffp + 0) + 4; + else + rlen = maxlen; + k = (rlen > maxlen) ? maxlen : rlen; + if (do_raw) { + dStrRaw((const char *)glbasBuffp, k); + goto fini; + } + if (do_hex) { + hex2stdout(glbasBuffp, k, 1); + goto fini; + } + if (maxlen < 4) { + if (verbose) + pr2serr("Exiting because allocation length (maxlen) less " + "than 4\n"); + goto fini; + } + if ((verbose > 1) || (verbose && (rlen > maxlen))) { + pr2serr("response length %d bytes\n", rlen); if (rlen > maxlen) - rlen = maxlen; + pr2serr(" ... which is greater than maxlen (allocation " + "length %d), truncation\n", maxlen); + } + if (rlen > maxlen) + rlen = maxlen; - if (do_brief > 1) { - if (rlen < 24) { - pr2serr("Need maxlen and response length to be at least 24, " - "have %d bytes\n", rlen); - ret = SG_LIB_CAT_OTHER; - goto the_end; - } - res = decode_lba_status_desc(glbasBuffp + 8, &d_lba, &d_blocks, - &add_status); - if ((res < 0) || (res > 15)) { - pr2serr("first LBA status descriptor returned %d ??\n", res); - ret = SG_LIB_LOGIC_ERROR; - goto the_end; - } - if ((lba < d_lba) || (lba >= (d_lba + d_blocks))) { - pr2serr("given LBA not in range of first descriptor:\n" - " descriptor LBA: 0x"); - for (j = 0; j < 8; ++j) - pr2serr("%02x", glbasBuffp[8 + j]); - pr2serr(" blocks: 0x%x p_status: %d add_status: 0x%x\n", - (unsigned int)d_blocks, res, - (unsigned int)add_status); - ret = SG_LIB_CAT_OTHER; - goto the_end; - } - printf("%d\n", res); - goto the_end; + if (do_brief > 1) { + if (rlen < 24) { + pr2serr("Need maxlen and response length to be at least 24, " + "have %d bytes\n", rlen); + ret = SG_LIB_CAT_OTHER; + goto fini; } + res = decode_lba_status_desc(glbasBuffp + 8, &d_lba, &d_blocks, + &add_status); + if ((res < 0) || (res > 15)) { + pr2serr("first LBA status descriptor returned %d ??\n", res); + ret = SG_LIB_LOGIC_ERROR; + goto fini; + } + if ((lba < d_lba) || (lba >= (d_lba + d_blocks))) { + pr2serr("given LBA not in range of first descriptor:\n" + " descriptor LBA: 0x"); + for (j = 0; j < 8; ++j) + pr2serr("%02x", glbasBuffp[8 + j]); + pr2serr(" blocks: 0x%x p_status: %d add_status: 0x%x\n", + (unsigned int)d_blocks, res, + (unsigned int)add_status); + ret = SG_LIB_CAT_OTHER; + goto fini; + } + printf("%d\n", res); + goto fini; + } - if (rlen < 24) { - printf("No complete LBA status descriptors available\n"); - goto the_end; + if (rlen < 24) { + printf("No complete LBA status descriptors available\n"); + goto fini; + } + num_descs = (rlen - 8) / 16; + completion_cond = (*(glbasBuffp + 7) >> 1) & 7; /* added sbc4r14 */ + if (do_brief) + printf("Completion condition=%d\n", completion_cond); + else { + switch (completion_cond) { + case 0: + printf("No indication of the completion condition\n"); + break; + case 1: + printf("Command completed due to meeting allocation length " + "(--maxlen=LEN (def 24))\n"); + break; + case 2: + printf("Command completed due to meeting scan length " + "(--scan-len=SL)\n"); + break; + case 3: + printf("Command completed due to meeting capacity of " + "medium\n"); + break; + default: + printf("Command completion is reserved [%d]\n", + completion_cond); + break; } - num_descs = (rlen - 8) / 16; - completion_cond = (*(glbasBuffp + 7) >> 1) & 7; /* added sbc4r14 */ - if (do_brief) - printf("Completion condition=%d\n", completion_cond); - else { - switch (completion_cond) { + } + printf("RTP=%d\n", *(glbasBuffp + 7) & 0x1); /* added sbc4r12 */ + if (verbose) + pr2serr("%d complete LBA status descriptors found\n", num_descs); + for (bp = glbasBuffp + 8, k = 0; k < num_descs; bp += 16, ++k) { + res = decode_lba_status_desc(bp, &d_lba, &d_blocks, &add_status); + if ((res < 0) || (res > 15)) + pr2serr("descriptor %d: bad LBA status descriptor returned " + "%d\n", k + 1, res); + if (do_brief) { + printf("0x"); + for (j = 0; j < 8; ++j) + printf("%02x", bp[j]); + printf(" 0x%x %d %d\n", (unsigned int)d_blocks, res, + add_status); + } else { + printf("[%d] LBA: 0x", k + 1); + for (j = 0; j < 8; ++j) + printf("%02x", bp[j]); + printf(" blocks: %10u", (unsigned int)d_blocks); + switch (res) { case 0: - printf("No indication of the completion condition\n"); + printf(" mapped (or unknown)"); break; case 1: - printf("Command completed due to meeting allocation length " - "(--maxlen=LEN (def 24))\n"); + printf(" deallocated"); break; case 2: - printf("Command completed due to meeting scan length " - "(--scan-len=SL)\n"); + printf(" anchored"); break; case 3: - printf("Command completed due to meeting capacity of " - "medium\n"); + printf(" mapped"); /* sbc4r12 */ + break; + case 4: + printf(" unknown"); /* sbc4r12 */ break; default: - printf("Command completion is reserved [%d]\n", - completion_cond); + printf(" Provisioning status: %d", res); break; } - } - printf("RTP=%d\n", *(glbasBuffp + 7) & 0x1); /* added sbc4r12 */ - if (verbose) - pr2serr("%d complete LBA status descriptors found\n", num_descs); - for (bp = glbasBuffp + 8, k = 0; k < num_descs; bp += 16, ++k) { - res = decode_lba_status_desc(bp, &d_lba, &d_blocks, &add_status); - if ((res < 0) || (res > 15)) - pr2serr("descriptor %d: bad LBA status descriptor returned " - "%d\n", k + 1, res); - if (do_brief) { - printf("0x"); - for (j = 0; j < 8; ++j) - printf("%02x", bp[j]); - printf(" 0x%x %d\n", (unsigned int)d_blocks, res); - } else { - printf("descriptor LBA: 0x"); - for (j = 0; j < 8; ++j) - printf("%02x", bp[j]); - printf(" blocks: %u", (unsigned int)d_blocks); - switch (res) { - case 0: - printf(" mapped (or unknown)"); - break; - case 1: - printf(" deallocated"); - break; - case 2: - printf(" anchored"); - break; - case 3: - printf(" mapped"); /* sbc4r12 */ - break; - case 4: - printf(" unknown"); /* sbc4r12 */ - break; - default: - printf(" Provisioning status: %d", res); - break; - } - switch (add_status) { - case 0: - printf("\n"); - break; - case 1: - printf(" [may return unrecovered errors]\n"); - break; - default: - printf(" [add_status: 0x%x]\n", (unsigned int)add_status); - break; - } + switch (add_status) { + case 0: + printf("\n"); + break; + case 1: + printf(" [may return unrecovered errors]\n"); + break; + default: + printf(" [add_status: 0x%x]\n", (unsigned int)add_status); + break; } } - if ((num_descs * 16) + 8 < rlen) - pr2serr("incomplete trailing LBA status descriptors found\n"); - } else if (SG_LIB_CAT_INVALID_OP == res) + } + if ((num_descs * 16) + 8 < rlen) + pr2serr("incomplete trailing LBA status descriptors found\n"); + goto fini; + +error: + if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Get LBA Status command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("Get LBA Status command: bad field in cdb\n"); @@ -501,17 +557,18 @@ main(int argc, char * argv[]) pr2serr("Get LBA Status command: %s\n", b); } -the_end: - res = sg_cmds_close_device(sg_fd); - if (res < 0) { - pr2serr("close error: %s\n", safe_strerror(-res)); - if (0 == ret) - ret = sg_convert_errno(-res); +fini: + if (sg_fd >= 0) { + res = sg_cmds_close_device(sg_fd); + if (res < 0) { + pr2serr("close error: %s\n", safe_strerror(-res)); + if (0 == ret) + ret = sg_convert_errno(-res); + } } -free_buff: if (free_glbasBuffp) free(free_glbasBuffp); - if (0 == verbose) { + if ((0 == verbose) && (! no_final_msg)) { if (! sg_if_can2stderr("sg_get_lba_status failed: ", ret)) pr2serr("Some error occurred, try again with '-v' or '-vv' for " "more information\n"); |