aboutsummaryrefslogtreecommitdiff
path: root/src/sg_get_lba_status.c
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2019-08-29 00:15:08 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2019-08-29 00:15:08 +0000
commitb8a9d0f9070ee4a0f10c7d2e779655bffbfe1624 (patch)
tree45c9d8fe86fc79abccfe6d40f221da341d144f6f /src/sg_get_lba_status.c
parentabf4073cf5d973125dd384bc42f7338ec7e49c48 (diff)
downloadsg3_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.c369
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");