diff options
Diffstat (limited to 'sg_luns.c')
-rw-r--r-- | sg_luns.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/sg_luns.c b/sg_luns.c new file mode 100644 index 00000000..1b966da3 --- /dev/null +++ b/sg_luns.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2004 Douglas Gilbert. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <unistd.h> +#include <signal.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/time.h> +#include "sg_include.h" +#include "sg_lib.h" +#include "sg_cmds.h" + +/* A utility program for the Linux OS SCSI subsystem. + * + * + * This program issues the SCSI command REPORT LUNS to the given SCSI device. + */ + +static char * version_str = "1.01 20041028"; + +#define REPORT_LUNS_BUFF_LEN 1024 + +#define ME "sg_luns: " + + +static struct option long_options[] = { + {"decode", 0, 0, 'd'}, + {"help", 0, 0, 'h'}, + {"select", 1, 0, 's'}, + {"verbose", 0, 0, 'v'}, + {"version", 0, 0, 'V'}, + {0, 0, 0, 0}, +}; + +static void usage() +{ + fprintf(stderr, "Usage: " + "sg_luns [--decode] [--help] [--select=<n>] [--verbose] " + "[--version]\n" + " <scsi_device>\n" + " where: --decode|-d decode all luns into parts\n" + " --help|-h print out usage message\n" + " --select=<n>|-s <n> select report <n> (def: 0)\n" + " --verbose|-v increase verbosity\n" + " --version|-V print version string and exit\n" + ); + +} + +/* Decoded according to SAM-3 rev 14. Note that one draft: BCC rev 0, + * defines its own "bridge addressing method" in place of the + * SAM-3 "logical addressing method". */ +static void decode_lun(const char * leadin, unsigned char * lunp) +{ + int k, j, x, a_method, bus_id, target, lun, len, e_a_method, next_level; + unsigned char not_spec[8] = {0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff}; + char l_leadin[128]; + unsigned long long ull; + + if (0 == memcmp(lunp, not_spec, sizeof(not_spec))) { + printf("%sLogical unit not specified\n", leadin); + return; + } + memset(l_leadin, 0, sizeof(l_leadin)); + for (k = 0; k < 4; ++k, lunp += 2) { + next_level = 0; + strncpy(l_leadin, leadin, sizeof(l_leadin) - 3); + if (k > 0) { + printf("%s>>%s level addressing:\n", l_leadin, + ((1 == k) ? "Second" : ((2 == k) ? "Third" : "Fourth"))); + strcat(l_leadin, " "); + } + a_method = (lunp[0] >> 6) & 0x3; + switch (a_method) { + case 0: /* peripheral device addressing method */ + bus_id = lunp[0] & 0x3f; + if (0 == bus_id) + printf("%sPeripheral device addressing: lun=%d\n", + l_leadin, lunp[1]); + else { + printf("%sPeripheral device addressing: bus_id=%d, " + "target=%d\n", l_leadin, bus_id, lunp[1]); + next_level = 1; + } + break; + case 1: /* flat space addressing method */ + lun = ((lunp[0] & 0x3f) << 8) + lunp[1]; + printf("%sFlat space addressing: lun=%d\n", l_leadin, lun); + break; + case 2: /* logical unit addressing method */ + target = (lunp[0] & 0x3f); + bus_id = (lunp[1] >> 5) & 0x7; + lun = lunp[1] & 0x1f; + printf("%sLogical unit addressing: bus_id=%d, target=%d, " + "lun=%d\n", l_leadin, bus_id, target, lun); + break; + case 3: /* extended logical unit addressing method */ + len = (lunp[0] & 0x30) >> 4; + e_a_method = lunp[0] & 0xf; + x = lunp[1]; + if ((0 == len) && (1 == e_a_method)) { + switch (x) { + case 1: + printf("%sREPORT LUNS well known logical unit\n", + l_leadin); + break; + case 2: + printf("%sACCESS CONTROLS well known logical unit\n", + l_leadin); + break; + case 3: + printf("%sTARGET LOG PAGES well known logical unit\n", + l_leadin); + break; + default: + printf("%swell known logical unit %d\n", l_leadin, x); + break; + } + } else { + if (len < 2) { + if (1 == len) + x = (lunp[1] << 16) + (lunp[2] << 8) + lunp[3]; + printf("%sExtended logical unit addressing: length=%d, " + "e. a. method=%d, value=0x%x\n", l_leadin, len, + e_a_method, x); + } else { + ull = 0; + x = (2 == len) ? 5 : 7; + for (j = 0; j < x; ++j) { + if (j > 0) + ull <<= 8; + ull |= lunp[1 + j]; + } + printf("%sExtended logical unit addressing: length=%d, " + "e. a. method=%d, value=0x%llx\n", l_leadin, len, + e_a_method, ull); + } + } + break; + default: + printf("%s<<decode_lun: faulty logic>>\n", l_leadin); + break; + } + if (next_level) + continue; + if ((2 == a_method) && (k < 3) && (lunp[2] || lunp[3])) + printf("%s<<unexpected data at next level, continue>>\n", + l_leadin); + break; + } +} + +int main(int argc, char * argv[]) +{ + int sg_fd, k, m, off, res, c, list_len, luns, trunc; + unsigned char reportLunsBuff[REPORT_LUNS_BUFF_LEN]; + int decode = 0; + int select_rep = 0; + int verbose = 0; + char device_name[256]; + int ret = 1; + + memset(device_name, 0, sizeof device_name); + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "dhs:vV", long_options, + &option_index); + if (c == -1) + break; + + switch (c) { + case 'd': + decode = 1; + break; + case 'h': + case '?': + usage(); + return 0; + case 's': + if ((1 != sscanf(optarg, "%d", &select_rep)) || + (select_rep < 0) || (select_rep > 255)) { + fprintf(stderr, "bad argument to '--select'\n"); + return 1; + } + break; + case 'v': + ++verbose; + break; + case 'V': + fprintf(stderr, ME "version: %s\n", version_str); + return 0; + default: + fprintf(stderr, "unrecognised switch code 0x%x ??\n", c); + usage(); + return 1; + } + } + if (optind < argc) { + if ('\0' == device_name[0]) { + strncpy(device_name, argv[optind], sizeof(device_name) - 1); + device_name[sizeof(device_name) - 1] = '\0'; + ++optind; + } + if (optind < argc) { + for (; optind < argc; ++optind) + fprintf(stderr, "Unexpected extra argument: %s\n", + argv[optind]); + usage(); + return 1; + } + } + + if (0 == device_name[0]) { + fprintf(stderr, "missing device name!\n"); + usage(); + return 1; + } + sg_fd = open(device_name, O_RDWR); + if (sg_fd < 0) { + perror(ME "open error"); + return 1; + } + + memset(reportLunsBuff, 0x0, sizeof(reportLunsBuff)); + trunc = 0; + + res = sg_ll_report_luns(sg_fd, select_rep, reportLunsBuff, + sizeof(reportLunsBuff), 1, verbose); + if (0 == res) { + list_len = (reportLunsBuff[0] << 24) + (reportLunsBuff[1] << 16) + + (reportLunsBuff[2] << 8) + reportLunsBuff[3]; + luns = (list_len / 8); + printf("Lun list length = %d which imples %d lun entr%s\n", + list_len, luns, ((1 == luns) ? "y" : "ies")); + if ((list_len + 8) > (int)sizeof(reportLunsBuff)) { + luns = ((sizeof(reportLunsBuff) - 8) / 8); + trunc = 1; + printf(" <<too many luns for internal buffer, will show %d " + "luns>>\n", luns); + } + if (verbose) { + fprintf(stderr, "\nOutput response in hex\n"); + dStrHex((const char *)reportLunsBuff, + (trunc ? (int)sizeof(reportLunsBuff) : list_len + 8), 1); + } + for (k = 0, off = 8; k < luns; ++k) { + if (0 == k) + printf("Report luns [select_report=%d]:\n", select_rep); + printf(" "); + for (m = 0; m < 8; ++m, ++off) + printf("%02x", reportLunsBuff[off]); + printf("\n"); + if (decode) + decode_lun(" ", reportLunsBuff + off - 8); + } + ret = 0; + } else if (SG_LIB_CAT_INVALID_OP == res) + fprintf(stderr, "Report Luns command not supported (support " + "mandatory in SPC-3)\n"); + + res = close(sg_fd); + if (res < 0) { + perror(ME "close error"); + return 1; + } + return ret; +} |