aboutsummaryrefslogtreecommitdiff
path: root/sg_opcodes.c
diff options
context:
space:
mode:
Diffstat (limited to 'sg_opcodes.c')
-rw-r--r--sg_opcodes.c1248
1 files changed, 922 insertions, 326 deletions
diff --git a/sg_opcodes.c b/sg_opcodes.c
index fc2d0e57..017fb38c 100644
--- a/sg_opcodes.c
+++ b/sg_opcodes.c
@@ -1,32 +1,59 @@
+/* A utility program originally written for the Linux OS SCSI subsystem.
+ * Copyright (C) 2004-2007 D. Gilbert
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+
+ This program outputs information provided by a SCSI REPORT SUPPORTED
+ OPERATION CODES [0xa3/0xc] and REPORT SUPPORTED TASK MANAGEMENT
+ FUNCTIONS [0xa3/0xd] commands.
+ */
+
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <getopt.h>
+
#include "sg_lib.h"
#include "sg_cmds_basic.h"
#include "sg_cmds_extra.h"
-#include "sg_io_linux.h"
-/* A utility program for the Linux OS SCSI subsystem.
-* Copyright (C) 2004-2006 D. Gilbert
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2, or (at your option)
-* any later version.
+static char * version_str = "0.29 20070127";
- This program outputs information provided by a SCSI "Report supported
- operation codes" command [0xa3/0xc].
+// #define USE_LINUX_SG_IO_IF 1
-*/
+/* Notes:
+ * - this file has both Linux specific pass through code using the
+ * SG_IO ioctl and a more generic sg_pt mechanism that is portable
+ * to other OSes. The code is conditionally compiled depending
+ * on the USE_LINUX_SG_IO_IF define and whether the Makefile
+ * indicates the OS is linux.
+ * N.B. Various Makefiles are set assuming this is not defined.
+ *
+ * - since support for the SCSI REPORT SUPPORTED OPERATION CODES and
+ * REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS is uncommon, dummy
+ * response code is provided. Uncomment the '#define TEST_CODE'
+ * line for test mode.
+ */
-static char * version_str = "0.26 20061015";
+#if defined(USE_LINUX_SG_IO_IF) && defined(SG3_UTILS_LINUX)
+ #define USE_SG_IO
+#endif
+#ifdef USE_SG_IO
+ #include <sys/ioctl.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+ #include "sg_io_linux.h"
+ #define EBUFF_SZ 256
+ static char ebuff[EBUFF_SZ];
+#else
+ #include "sg_pt.h"
+#endif
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
#define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
@@ -40,21 +67,29 @@ static char * version_str = "0.26 20061015";
#define NAME_BUFF_SZ 64
-#define EBUFF_SZ 256
static int peri_type = 0; /* ugly but not easy to pass to alpha compare */
+static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode,
+ int rq_servact, void * resp, int mx_resp_len, int noisy,
+ int verbose);
+static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
+ int verbose);
+
/* <<<<<<<<<<<<<<< start of test code */
-/* #define TEST_CODE */
+// #define TEST_CODE
#ifdef TEST_CODE
#warning "<<<< TEST_CODE response compiled in >>>>"
#define DUMMY_CMDS 17
+#define DUMMY_CMD_LEN 8
+#define DUMMY_TO_CMDS 4
+#define DUMMY_TO_CMD_LEN 20
struct cmd_descript_t {
- unsigned char d[8];
+ unsigned char d[DUMMY_CMD_LEN];
};
struct dummy_resp_t {
@@ -62,190 +97,355 @@ struct dummy_resp_t {
struct cmd_descript_t descript[DUMMY_CMDS];
};
-static struct dummy_resp_t dummy_resp = { {0, 0, 0, 8 * DUMMY_CMDS},
- {{{0, 0, 0, 0, 0, 0, 0, 6}},
- {{0xa3, 0, 0, 0xc, 0, 1, 0, 12}},
- {{0x12, 0, 0, 0, 0, 0, 0, 6}},
- {{0x1d, 0, 0, 0, 0, 0, 0, 6}},
- {{0x25, 0, 0, 0, 0, 0, 0, 10}},
- {{0x28, 0, 0, 0, 0, 0, 0, 10}},
- {{0x2a, 0, 0, 0, 0, 0, 0, 10}},
- {{0x1a, 0, 0, 0, 0, 0, 0, 6}},
- {{0x15, 0, 0, 0, 0, 0, 0, 6}},
- {{0xa3, 0, 0, 0x5, 0, 1, 0, 12}},
- {{0x5a, 0, 0, 0, 0, 0, 0, 10}},
- {{0x55, 0, 0, 0, 0, 0, 0, 10}},
- {{2, 0, 0, 0, 0, 0, 0, 6}},
- {{3, 0, 0, 0, 0, 0, 0, 6}},
- {{4, 0, 0, 0, 0, 0, 0, 6}},
- {{0xa0, 0, 0, 0, 0, 0, 0, 12}},
- {{0x7f, 0, 0, 0x1, 0, 1, 0, 32}},
+static struct dummy_resp_t dummy_resp = {
+ {0, 0, 0, DUMMY_CMD_LEN * DUMMY_CMDS},
+ {{{0, 0, 0, 0, 0, 0, 0, 6}}, /* tur */
+ {{0xa3, 0, 0, 0xc, 0, 1, 0, 12}}, /* rsoc */
+ {{0x12, 0, 0, 0, 0, 0, 0, 6}}, /* inq */
+ {{0x1d, 0, 0, 0, 0, 0, 0, 6}}, /* sd */
+ {{0x25, 0, 0, 0, 0, 0, 0, 10}}, /* rc */
+ {{0x28, 0, 0, 0, 0, 0, 0, 10}}, /* r(10) */
+ {{0x2a, 0, 0, 0, 0, 0, 0, 10}}, /* w(10) */
+ {{0x1a, 0, 0, 0, 0, 0, 0, 6}}, /* ms(6) */
+ {{0x15, 0, 0, 0, 0, 0, 0, 6}}, /* msel(6) */
+ {{0xa3, 0, 0, 0x5, 0, 1, 0, 12}}, /* rii */
+ {{0x5a, 0, 0, 0, 0, 0, 0, 10}}, /* ms(10) */
+ {{0x55, 0, 0, 0, 0, 0, 0, 10}}, /* msel(10) */
+ {{2, 0, 0, 0, 0, 0, 0, 6}}, /* ?? */
+ {{3, 0, 0, 0, 0, 0, 0, 6}}, /* rs */
+ {{4, 0, 0, 0, 0, 0, 0, 6}}, /* f */
+ {{0xa0, 0, 0, 0, 0, 0, 0, 12}}, /* rl */
+ {{0x7f, 0, 0, 0x3, 0, 1, 0, 32}}, /* vl:xdr(32) */
+}};
+
+struct cmd_descript_to_t {
+ unsigned char d[DUMMY_TO_CMD_LEN];
+};
+
+struct dummy_resp_to_t {
+ unsigned char cdl[4];
+ struct cmd_descript_to_t descript[DUMMY_TO_CMDS];
+};
+
+static struct dummy_resp_to_t dummy_to_resp =
+ {{0, 0, 0, DUMMY_TO_CMD_LEN * DUMMY_TO_CMDS},
+ {{{0, 0, 0, 0, 0, 0x2, 0, 6,
+ 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}}, /* tur */
+ {{0xa3, 0, 0, 0xc, 0, 0x3, 0, 12,
+ 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6}}, /* rsoc */
+ {{4, 0, 0, 0, 0, 0x2, 0, 6,
+ 0, 0xa, 0, 0, 0, 0, 0x8, 0, 0, 0, 0x10, 0}}, /* f */
+ {{0x7f, 0, 0, 0x3, 0, 0x3, 0, 32,
+ 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7}}, /* vl:xdr(32) */
}};
static unsigned char dummy_1_cmd[] = {
0, 3, 0, 6, 0x12, 0x3, 0xff, 0x0, 0xff, 0x1
};
+static unsigned char dummy_1_to_cmd[] = {
+ 0, 0x83, 0, 6, 0x12, 0x3, 0xff, 0x0, 0xff, 0x1,
+ 0, 0xa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, /* inq */
+};
+
static unsigned char dummy_rsmft_r0 = 0xff;
static unsigned char dummy_rsmft_r1 = 0x1;
#endif
/* <<<<<<<<<<<<<<< end of test code */
+static struct option long_options[] = {
+ {"alpha", 0, 0, 'a'},
+ {"help", 0, 0, 'h'},
+ {"hex", 0, 0, 'H'},
+ {"new", 0, 0, 'N'},
+ {"opcode", 1, 0, 'o'},
+ {"old", 0, 0, 'O'},
+ {"raw", 0, 0, 'r'},
+ {"rctd", 0, 0, 'R'},
+ {"sa", 1, 0, 's'},
+ {"tmf", 0, 0, 't'},
+ {"unsorted", 0, 0, 'u'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {0, 0, 0, 0},
+};
-/* Report Supported Operation Codes */
-/* Returns 0 when successful */
-static int do_rsoc(int sg_fd, int rep_opts, int rq_opcode, int rq_servact,
- void * resp, int mx_resp_len, int noisy, int verbose)
+struct opts_t {
+ int do_alpha;
+ int do_help;
+ int do_hex;
+ int do_opcode;
+ int do_raw;
+ int do_rctd;
+ int do_servact;
+ int do_verbose;
+ int do_version;
+ int do_unsorted;
+ int do_taskman;
+ const char * device_name;
+ int opt_new;
+};
+
+static void usage()
{
- int res, k;
- unsigned char rsocCmdBlk[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
+ fprintf(stderr,
+ "Usage: sg_opcodes [--alpha] [--help] [--hex] [--opcode=OP] "
+ "[--raw] [--rctd]\n"
+ " [--sa=SA] [--tmf] [--unsorted] [--verbose] "
+ "[--version]\n"
+ " DEVICE\n"
+ " where:\n"
+ " --alpha|-a output list of operation codes sorted "
+ "alphabetically\n"
+ " --help|-h print usage message then exit\n"
+ " --hex|-H output response in hex\n"
+ " --opcode=OP|-o OP first byte of command to query\n"
+ " (decimal, prefix with '0x' for hex)\n"
+ " --raw|-r output response in binary to stdout\n"
+ " --rctd|-R set RCTD (return command timeout "
+ "descriptor) bit\n"
+ " --sa=SA|-s SA service action in addition to opcode\n"
+ " (decimal, prefix with '0x' for hex)\n"
+ " --tmf|-t output list of supported task management "
+ "functions\n"
+ " --unsorted|-u output list of operation codes as is "
+ "(unsorted)\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print vesrion string then exit\n\n"
+ "Performs a SCSI REPORT SUPPORTED OPERATION CODES or REPORT "
+ "SUPPORTED\nTASK MANAGEMENT FUNCTIONS command\n");
+}
- if (rep_opts)
- rsocCmdBlk[2] = (rep_opts & 0x7);
- if (rq_opcode > 0)
- rsocCmdBlk[3] = (rq_opcode & 0xff);
- if (rq_servact > 0) {
- rsocCmdBlk[4] = (unsigned char)((rq_servact >> 8) & 0xff);
- rsocCmdBlk[5] = (unsigned char)(rq_servact & 0xff);
+static void usage_old()
+{
+ fprintf(stderr,
+ "Usage: sg_opcodes [-a] [-H] [-o=OP] [-r] [-R] [-s=SA]"
+ " [-t] [-u]\n"
+ " [-v] [-V] DEVICE\n"
+ " where:\n"
+ " -a output list of operation codes sorted "
+ "alphabetically\n"
+ " -H print response in hex\n"
+ " -o=OP first byte of command to query (in hex)\n"
+ " -r output response in binary to stdout\n"
+ " -R set RCTD (return command timeout "
+ "descriptor) bit\n"
+ " -s=SA in addition to opcode (in hex)\n"
+ " -t output list of supported task management functions\n"
+ " -u output list of operation codes as is (unsorted)\n"
+ " -v verbose\n"
+ " -V output version string\n"
+ " -? output this usage message\n\n"
+ "Performs a SCSI REPORT SUPPORTED OPERATION CODES (or REPORT "
+ "TASK MANAGEMENT\nFUNCTIONS) command\n");
+}
- }
- rsocCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
- rsocCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
- rsocCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
- rsocCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+static int process_cl_new(struct opts_t * optsp, int argc, char * argv[])
+{
+ int c, n;
- if (verbose) {
- fprintf(stderr, " Report Supported Operation Codes cmd: ");
- for (k = 0; k < RSOC_CMD_LEN; ++k)
- fprintf(stderr, "%02x ", rsocCmdBlk[k]);
- fprintf(stderr, "\n");
- }
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(rsocCmdBlk);
- io_hdr.mx_sb_len = sizeof(sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = mx_resp_len;
- io_hdr.dxferp = resp;
- io_hdr.cmdp = rsocCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
+ while (1) {
+ int option_index = 0;
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("SG_IO (rsoc) error");
- return -1;
- }
- if (verbose > 2)
- fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
- res = sg_err_category3(&io_hdr);
- switch (res) {
- case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Report supported operation codes", &io_hdr,
- verbose > 1);
- /* fall through */
- case SG_LIB_CAT_CLEAN:
- return 0;
- default:
- if (noisy | verbose) {
- char ebuff[EBUFF_SZ];
+ c = getopt_long(argc, argv, "ahHNo:OrRs:tuvV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
- if (0 == rep_opts)
- snprintf(ebuff, EBUFF_SZ, "RSOC error, rep_opts=0 (all) ");
- else if (1 == rep_opts)
- snprintf(ebuff, EBUFF_SZ, "RSOC error, rq_opcode=0x%x ",
- rq_opcode);
- else
- snprintf(ebuff, EBUFF_SZ, "RSOC error, rq_opcode=0x%x, "
- "rq_sa=0x%x ", rq_opcode, rq_servact);
- sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
+ switch (c) {
+ case 'a':
+ optsp->do_alpha = 1;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'N':
+ break; /* ignore */
+ case 'o':
+ n = sg_get_num(optarg);
+ if ((n < 0) || (n > 255)) {
+ fprintf(stderr, "bad argument to '--opcode'\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_opcode = n;
+ break;
+ case 'O':
+ optsp->opt_new = 0;
+ return 0;
+ case 'r':
+ ++optsp->do_raw;
+ break;
+ case 'R':
+ ++optsp->do_rctd;
+ break;
+ case 's':
+ n = sg_get_num(optarg);
+ if (n < 0) {
+ fprintf(stderr, "bad argument to '--sa'\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_servact = n;
+ break;
+ case 't':
+ ++optsp->do_taskman;
+ break;
+ case 'u':
+ ++optsp->do_unsorted;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ default:
+ fprintf(stderr, "unrecognised switch code %c [0x%x]\n", c, c);
+ if (optsp->do_help)
+ break;
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (optind < argc) {
+ if (NULL == optsp->device_name) {
+ optsp->device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ fprintf(stderr, "Unexpected extra argument: %s\n",
+ argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
}
- return res;
}
+ return 0;
}
-/* Report Supported Task Management Function */
-/* Returns 0 when successful */
-static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
- int verbose)
+static int process_cl_old(struct opts_t * optsp, int argc, char * argv[])
{
- int res, k;
- unsigned char rstmfCmdBlk[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
-
- rstmfCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
- rstmfCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
- rstmfCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
- rstmfCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+ int k, jmp_out, plen, n, num;
+ const char * cp;
- if (verbose) {
- fprintf(stderr, " Report Supported Task Management Functions cmd: ");
- for (k = 0; k < RSTMF_CMD_LEN; ++k)
- fprintf(stderr, "%02x ", rstmfCmdBlk[k]);
- fprintf(stderr, "\n");
+ for (k = 1; k < argc; ++k) {
+ cp = argv[k];
+ plen = strlen(cp);
+ if (plen <= 0)
+ continue;
+ if ('-' == *cp) {
+ for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
+ switch (*cp) {
+ case 'a':
+ ++optsp->do_alpha;
+ break;
+ case 'H':
+ ++optsp->do_hex;
+ break;
+ case 'N':
+ optsp->opt_new = 1;
+ return 0;
+ case 'O':
+ break;
+ case 'R':
+ ++optsp->do_rctd;
+ break;
+ case 't':
+ ++optsp->do_taskman;
+ break;
+ case 'u':
+ ++optsp->do_unsorted;
+ break;
+ case 'v':
+ ++optsp->do_verbose;
+ break;
+ case 'V':
+ ++optsp->do_version;
+ break;
+ case 'h':
+ case '?':
+ ++optsp->do_help;
+ break;
+ default:
+ jmp_out = 1;
+ break;
+ }
+ if (jmp_out)
+ break;
+ }
+ if (plen <= 0)
+ continue;
+ if (0 == strncmp("o=", cp, 2)) {
+ num = sscanf(cp + 2, "%x", (unsigned int *)&n);
+ if ((1 != num) || (n > 255)) {
+ fprintf(stderr, "Bad number after 'o=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_opcode = n;
+ } else if (0 == strncmp("s=", cp, 2)) {
+ num = sscanf(cp + 2, "%x", (unsigned int *)&n);
+ if (1 != num) {
+ fprintf(stderr, "Bad number after 's=' option\n");
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ optsp->do_servact = n;
+ } else if (0 == strncmp("-old", cp, 4))
+ ;
+ else if (jmp_out) {
+ fprintf(stderr, "Unrecognized option: %s\n", cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else if (NULL == optsp->device_name)
+ optsp->device_name = cp;
+ else {
+ fprintf(stderr, "too many arguments, got: %s, not expecting: "
+ "%s\n", optsp->device_name, cp);
+ usage_old();
+ return SG_LIB_SYNTAX_ERROR;
+ }
}
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(rstmfCmdBlk);
- io_hdr.mx_sb_len = sizeof(sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = mx_resp_len;
- io_hdr.dxferp = resp;
- io_hdr.cmdp = rstmfCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
+ return 0;
+}
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
- perror("SG_IO (rstmf) error");
- return -1;
- }
- if (verbose > 2)
- fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
- res = sg_err_category3(&io_hdr);
- switch (res) {
- case SG_LIB_CAT_RECOVERED:
- sg_chk_n_print3("Report supported task management fns", &io_hdr,
- verbose > 1);
- /* fall through */
- case SG_LIB_CAT_CLEAN:
- return 0;
- default:
- if (noisy | verbose) {
- char ebuff[EBUFF_SZ];
- snprintf(ebuff, EBUFF_SZ, "RSTMF error ");
- sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
- }
- return res;
+static int process_cl(struct opts_t * optsp, int argc, char * argv[])
+{
+ int res;
+ char * cp;
+
+ cp = getenv("SG3_UTILS_OLD_OPTS");
+ if (cp) {
+ optsp->opt_new = 0;
+ res = process_cl_old(optsp, argc, argv);
+ if ((0 == res) && optsp->opt_new)
+ res = process_cl_new(optsp, argc, argv);
+ } else {
+ optsp->opt_new = 1;
+ res = process_cl_new(optsp, argc, argv);
+ if ((0 == res) && (0 == optsp->opt_new))
+ res = process_cl_old(optsp, argc, argv);
}
+ return res;
}
-static void usage()
+static void dStrRaw(const char* str, int len)
{
- fprintf(stderr,
- "Usage: sg_opcodes [-a] [-o=<opcode> [-s=<service_action>] ]"
- " [-t] [-u] [-v]\n"
- " [-V] <scsi_device>\n"
- " where:\n"
- " -a output list of operation codes sorted "
- "alphabetically\n"
- " -o=<opcode> first byte of command to query (in hex)\n"
- " -s=<service_action> in addition to opcode (in hex)\n"
- " -t output list of supported task management functions\n"
- " -u output list of operation codes as is (unsorted)\n"
- " -v verbose\n"
- " -V output version string\n"
- " -? output this usage message\n\n"
- "Performs a REPORT SUPPORTED OPERATION CODES (or supported task "
- "management\nfunctions) SCSI command\n");
+ int k;
+
+ for (k = 0 ; k < len; ++k)
+ printf("%c", str[k]);
}
/* returns -1 when left < right, 0 when left == right, else returns 1 */
-int opcode_num_compare(const void * left, const void * right)
+static int opcode_num_compare(const void * left, const void * right)
{
const unsigned char * ll = *(unsigned char **)left;
const unsigned char * rr = *(unsigned char **)right;
@@ -275,7 +475,7 @@ int opcode_num_compare(const void * left, const void * right)
}
/* returns -1 when left < right, 0 when left == right, else returns 1 */
-int opcode_alpha_compare(const void * left, const void * right)
+static int opcode_alpha_compare(const void * left, const void * right)
{
const unsigned char * ll = *(unsigned char **)left;
const unsigned char * rr = *(unsigned char **)right;
@@ -304,10 +504,11 @@ int opcode_alpha_compare(const void * left, const void * right)
return strncmp(l_name_buff, r_name_buff, NAME_BUFF_SZ);
}
-void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
- int alpha)
+static void list_all_codes(unsigned char * rsoc_buff, int rsoc_len,
+ int unsorted, int alpha, int rctd)
{
- int k, cd_len, serv_act;
+ int k, j, cd_len, serv_act, len;
+ unsigned long to;
unsigned char * ucp;
char name_buff[NAME_BUFF_SZ];
char sa_buff[8];
@@ -324,12 +525,19 @@ void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
printf("sg_opcodes: no commands to display\n");
return;
}
- printf("\nOpcode Service CDB Name\n");
- printf( "(hex) action(h) size \n");
- printf("-----------------------------------------------\n");
+ if (rctd) {
+ printf("\nOpcode Service CDB Nominal Recommended Name\n");
+ printf( "(hex) action(h) size timeout timeout(sec) \n");
+ printf("-----------------------------------------------------------"
+ "-----\n");
+ } else {
+ printf("\nOpcode Service CDB Name\n");
+ printf( "(hex) action(h) size \n");
+ printf("-----------------------------------------------\n");
+ }
/* N.B. SPC-4 does _not_ requiring any ordering of response */
if (! unsorted) {
- sort_arr = malloc(cd_len * sizeof(unsigned char *));
+ sort_arr = (unsigned char **)malloc(cd_len * sizeof(unsigned char *));
if (NULL == sort_arr) {
printf("sg_opcodes: no memory to sort operation codes, "
"try '-u'\n");
@@ -337,13 +545,16 @@ void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
}
memset(sort_arr, 0, cd_len * sizeof(unsigned char *));
ucp = rsoc_buff + 4;
- for (k = 0; k < cd_len; k += 8, ucp += 8)
- sort_arr[(k / 8)] = ucp;
- qsort(sort_arr, (cd_len / 8), sizeof(unsigned char *),
+ for (k = 0, j = 0; k < cd_len; ++j, k += len, ucp += len) {
+ sort_arr[j] = ucp;
+ len = (ucp[5] & 0x2) ? 20 : 8;
+ }
+ qsort(sort_arr, j, sizeof(unsigned char *),
(alpha ? opcode_alpha_compare : opcode_num_compare));
}
- for (k = 0; k < cd_len; k += 8) {
- ucp = unsorted ? (rsoc_buff + 4 + k) : sort_arr[(k / 8)];
+ for (k = 0, j = 0; k < cd_len; ++j, k += len) {
+ ucp = unsorted ? (rsoc_buff + 4 + k) : sort_arr[j];
+ len = (ucp[5] & 0x2) ? 20 : 8;
if (ucp[5] & 1) {
serv_act = ((ucp[2] << 8) | ucp[3]);
sg_get_opcode_sa_name(ucp[0], serv_act, peri_type,
@@ -354,161 +565,252 @@ void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, int unsorted,
NAME_BUFF_SZ, name_buff);
memset(sa_buff, ' ', sizeof(sa_buff));
}
- printf(" %.2x %.4s %3d %s\n",
- ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]), name_buff);
+ if (rctd) {
+ if (ucp[5] & 0x2) {
+ printf(" %.2x %.4s %3d", ucp[0], sa_buff,
+ ((ucp[6] << 8) | ucp[7]));
+ to = (ucp[12] << 24) + (ucp[13] << 16) + (ucp[14] << 8) +
+ ucp[15];
+ if (0 == to)
+ printf(" -");
+ else
+ printf(" %8lu", to);
+ to = (ucp[16] << 24) + (ucp[17] << 16) + (ucp[18] << 8) +
+ ucp[19];
+ if (0 == to)
+ printf(" -");
+ else
+ printf(" %8lu", to);
+ printf(" %s\n", name_buff);
+ } else
+ printf(" %.2x %.4s %3d "
+ "%s\n", ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]),
+ name_buff);
+ } else
+ printf(" %.2x %.4s %3d %s\n",
+ ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]), name_buff);
+ }
+}
+
+static void decode_cmd_to_descriptor(unsigned char * dp, int max_b_len,
+ char * b)
+{
+ int len;
+ unsigned long to;
+
+ if ((max_b_len < 2) || (NULL == dp))
+ return;
+ b[max_b_len - 1] = '\0';
+ --max_b_len;
+ len = (dp[0] << 8) + dp[1];
+ if (10 != len) {
+ snprintf(b, max_b_len, "command timeout descriptor length %d "
+ "(expect 10)", len);
+ return;
+ }
+ to = (dp[4] << 24) + (dp[5] << 16) + (dp[6] << 8) + dp[7];
+ if (0 == to)
+ snprintf(b, max_b_len, "no nominal timeout, ");
+ else
+ snprintf(b, max_b_len, "nominal timeout: %lu secs, ", to);
+ len = strlen(b);
+ max_b_len -= len;
+ b += len;
+ to = (dp[8] << 24) + (dp[9] << 16) + (dp[10] << 8) + dp[11];
+ if (0 == to)
+ snprintf(b, max_b_len, "no recommended timeout");
+ else
+ snprintf(b, max_b_len, "recommended timeout: %lu secs", to);
+ return;
+}
+
+static void list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts,
+ int do_opcode, int do_servact)
+{
+ int k;
+ char name_buff[NAME_BUFF_SZ];
+ unsigned char * ucp;
+ const char * cp;
+ int v = 0;
+
+
+ printf("\n Opcode=0x%.2x", do_opcode);
+ if (rep_opts > 1)
+ printf(" Service_action=0x%.4x", do_servact);
+ printf("\n");
+ sg_get_opcode_sa_name(((do_opcode > 0) ? do_opcode : 0),
+ ((do_servact > 0) ? do_servact : 0),
+ peri_type, NAME_BUFF_SZ, name_buff);
+ printf(" Command_name: %s\n", name_buff);
+ switch((int)(rsoc_buff[1] & 7)) {
+ case 0:
+ cp = "not currently available";
+ break;
+ case 1:
+ cp = "NOT supported";
+ break;
+ case 3:
+ cp = "supported (conforming to SCSI standard)";
+ v = 1;
+ break;
+ case 5:
+ cp = "supported (in a vendor specific manner)";
+ v = 1;
+ break;
+ default:
+ snprintf(name_buff, NAME_BUFF_SZ, "support reserved [0x%x]",
+ rsoc_buff[1] & 7);
+ cp = name_buff;
+ break;
+ }
+ printf(" Command %s\n", cp);
+ if (v) {
+ printf(" Usage data: ");
+ ucp = rsoc_buff + 4;
+ for (k = 0; k < cd_len; ++k)
+ printf("%.2x ", ucp[k]);
+ printf("\n");
+ }
+ if (0x80 & rsoc_buff[1]) { /* CTDP */
+ ucp = rsoc_buff + 4 + cd_len;
+ decode_cmd_to_descriptor(ucp, NAME_BUFF_SZ, name_buff);
+ printf(" %s\n", name_buff);
}
}
int main(int argc, char * argv[])
{
- int sg_fd, k, num, cd_len, plen, jmp_out, res;
- const char * file_name = 0;
- char ebuff[EBUFF_SZ];
+ int sg_fd, cd_len, res, len;
unsigned char rsoc_buff[MX_ALLOC_LEN];
- unsigned char * ucp;
- char name_buff[NAME_BUFF_SZ];
- int do_alpha = 0;
- int do_opcode = -1;
- int do_servact = -1;
- int do_verbose = 0;
- int do_unsorted = 0;
- int do_taskman = 0;
int rep_opts = 0;
const char * cp;
char buff[48];
struct sg_simple_inquiry_resp inq_resp;
const char * op_name;
+ struct opts_t opts;
- for (k = 1; k < argc; ++k) {
- cp = argv[k];
- plen = strlen(cp);
- if (plen <= 0)
- continue;
- if ('-' == *cp) {
- for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
- switch (*cp) {
- case 'a':
- do_alpha = 1;
- break;
- case 't':
- do_taskman = 1;
- break;
- case 'u':
- do_unsorted = 1;
- break;
- case 'v':
- ++do_verbose;
- break;
- case 'V':
- fprintf(stderr, "Version string: %s\n", version_str);
- exit(0);
- case 'h':
- case '?':
- usage();
- return 0;
- default:
- jmp_out = 1;
- break;
- }
- if (jmp_out)
- break;
- }
- if (plen <= 0)
- continue;
- if (0 == strncmp("o=", cp, 2)) {
- num = sscanf(cp + 2, "%x", (unsigned int *)&do_opcode);
- if ((1 != num) || (do_opcode > 255)) {
- fprintf(stderr, "Bad number after 'o=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == strncmp("s=", cp, 2)) {
- num = sscanf(cp + 2, "%x", (unsigned int *)&do_servact);
- if (1 != num) {
- fprintf(stderr, "Bad number after 's=' option\n");
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (jmp_out) {
- fprintf(stderr, "Unrecognized option: %s\n", cp);
- usage();
- return SG_LIB_SYNTAX_ERROR;
- }
- } else if (0 == file_name)
- file_name = cp;
- else {
- fprintf(stderr, "too many arguments, got: %s, not expecting: "
- "%s\n", file_name, cp);
+ memset(&opts, 0, sizeof(opts));
+ opts.do_opcode = -1;
+ opts.do_servact = -1;
+ res = process_cl(&opts, argc, argv);
+ if (res)
+ return SG_LIB_SYNTAX_ERROR;
+ if (opts.do_help) {
+ if (opts.opt_new)
usage();
- return SG_LIB_SYNTAX_ERROR;
- }
+ else
+ usage_old();
+ return 0;
+ }
+ if (opts.do_version) {
+ fprintf(stderr, "Version string: %s\n", version_str);
+ return 0;
}
- if (0 == file_name) {
- fprintf(stderr, "No <scsi_device> argument given\n");
- usage();
+ if (NULL == opts.device_name) {
+ fprintf(stderr, "No DEVICE argument given\n");
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- if ((-1 != do_servact) && (-1 == do_opcode)) {
+ if ((-1 != opts.do_servact) && (-1 == opts.do_opcode)) {
fprintf(stderr, "When '-s' is chosen, so must '-o' be chosen\n");
- usage();
+ if (opts.opt_new)
+ usage();
+ else
+ usage_old();
return SG_LIB_SYNTAX_ERROR;
}
- if (do_unsorted && do_alpha)
+ if (opts.do_unsorted && opts.do_alpha)
fprintf(stderr, "warning: unsorted ('-u') and alpha ('-a') options "
"chosen, ignoring alpha\n");
- if (do_taskman && ((-1 != do_opcode) || do_alpha || do_unsorted)) {
+ if (opts.do_taskman && ((-1 != opts.do_opcode) || opts.do_alpha ||
+ opts.do_unsorted)) {
fprintf(stderr, "warning: task management functions ('-t') chosen "
"so alpha ('-a'),\n unsorted ('-u') and opcode "
"('-o') options ignored\n");
}
- op_name = do_taskman ? "Report supported task management functions" :
+ op_name = opts.do_taskman ? "Report supported task management functions" :
"Report supported operation codes";
- if ((sg_fd = open(file_name, O_RDONLY | O_NONBLOCK)) < 0) {
- snprintf(ebuff, EBUFF_SZ, "sg_opcodes: error opening file: %s (ro)",
- file_name);
+#ifdef USE_SG_IO
+ if ((sg_fd = open(opts.device_name, O_RDONLY | O_NONBLOCK)) < 0) {
+ snprintf(ebuff, EBUFF_SZ, "sg_opcodes: error opening file (ro): %s",
+ opts.device_name);
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
- if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, do_verbose)) {
- printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product,
- inq_resp.revision);
+#else
+ if ((sg_fd = scsi_pt_open_device(opts.device_name, 1 /* RO */,
+ opts.do_verbose)) < 0) {
+ fprintf(stderr, "sg_opcodes: error opening file (ro): %s: %s\n",
+ opts.device_name, safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+#endif
+ if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, opts.do_verbose)) {
peri_type = inq_resp.peripheral_type;
- cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
- if (strlen(cp) > 0)
- printf(" Peripheral device type: %s\n", cp);
- else
- printf(" Peripheral device type: 0x%x\n", peri_type);
+ if (0 == opts.do_raw) {
+ printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product,
+ inq_resp.revision);
+ cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
+ if (strlen(cp) > 0)
+ printf(" Peripheral device type: %s\n", cp);
+ else
+ printf(" Peripheral device type: 0x%x\n", peri_type);
+ }
} else {
- printf("sg_opcodes: %s doesn't respond to a SCSI INQUIRY\n", file_name);
+ fprintf(stderr, "sg_opcodes: %s doesn't respond to a SCSI "
+ "INQUIRY\n", opts.device_name);
return SG_LIB_CAT_OTHER;
}
+#ifdef USE_SG_IO
close(sg_fd);
+#else
+ res = sg_cmds_close_device(sg_fd);
+ if (res < 0) {
+ fprintf(stderr, "close error: %s\n", safe_strerror(-res));
+ return SG_LIB_FILE_ERROR;
+ }
+#endif
+
#ifndef TEST_CODE
if (5 == peri_type) {
- printf("'%s' command not supported\nfor CD/DVD devices\n", op_name);
+ printf("'%s' command not supported\nfor CD/DVD devices\n",
+ op_name);
return SG_LIB_CAT_OTHER;
}
#endif
- if ((sg_fd = open(file_name, O_RDWR | O_NONBLOCK)) < 0) {
+#ifdef USE_SG_IO
+ if ((sg_fd = open(opts.device_name, O_RDWR | O_NONBLOCK)) < 0) {
snprintf(ebuff, EBUFF_SZ, "sg_opcodes: error opening file: %s (rw)",
- file_name);
+ opts.device_name);
perror(ebuff);
return SG_LIB_FILE_ERROR;
}
- if (do_opcode >= 0)
- rep_opts = ((do_servact >= 0) ? 2 : 1);
+#else
+ if ((sg_fd = scsi_pt_open_device(opts.device_name, 0 /* RW */,
+ opts.do_verbose)) < 0) {
+ fprintf(stderr, "sg_opcodes: error opening file (rw): %s: %s\n",
+ opts.device_name, safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+#endif
+ if (opts.do_opcode >= 0)
+ rep_opts = ((opts.do_servact >= 0) ? 2 : 1);
memset(rsoc_buff, 0, sizeof(rsoc_buff));
#ifndef TEST_CODE
- if (do_taskman)
+ if (opts.do_taskman)
res = do_rstmf(sg_fd, rsoc_buff, sizeof(rsoc_buff), 0,
- do_verbose);
+ opts.do_verbose);
else
- res = do_rsoc(sg_fd, rep_opts, do_opcode, do_servact, rsoc_buff,
- sizeof(rsoc_buff), 0, do_verbose);
+ res = do_rsoc(sg_fd, opts.do_rctd, rep_opts, opts.do_opcode,
+ opts.do_servact, rsoc_buff, sizeof(rsoc_buff), 0,
+ opts.do_verbose);
switch (res) {
case 0:
case SG_LIB_CAT_RECOVERED:
@@ -526,21 +828,46 @@ int main(int argc, char * argv[])
fprintf(stderr, "%s: operation not supported\n", op_name);
goto err_out;
case SG_LIB_CAT_ILLEGAL_REQ:
- fprintf(stderr, "%s: bad field in cdb\n", op_name);
+ fprintf(stderr, "bad field in cdb including %s not supported\n",
+ op_name);
goto err_out;
default:
fprintf(stderr, "%s failed\n", op_name);
goto err_out;
}
#else
- if (do_taskman) {
+ if (opts.do_taskman) {
rsoc_buff[0] = dummy_rsmft_r0;
rsoc_buff[1] = dummy_rsmft_r1;
- } else
- memcpy(rsoc_buff, (unsigned char *)&dummy_resp, sizeof(dummy_resp));
+ } else if (opts.do_rctd) {
+ if (0 == rep_opts) {
+#if 1
+ memcpy(rsoc_buff, (unsigned char *)&dummy_to_resp,
+ sizeof(dummy_to_resp));
+#else
+ memcpy(rsoc_buff, (unsigned char *)&dummy_resp,
+ sizeof(dummy_resp));
+#endif
+ } else
+ memcpy(rsoc_buff, dummy_1_to_cmd, sizeof(dummy_1_to_cmd));
+ } else {
+ if (0 == rep_opts)
+ memcpy(rsoc_buff, (unsigned char *)&dummy_resp,
+ sizeof(dummy_resp));
+ else
+ memcpy(rsoc_buff, dummy_1_cmd, sizeof(dummy_1_cmd));
+ }
#endif
- if (do_taskman) {
+ if (opts.do_taskman) {
+ if (opts.do_raw) {
+ dStrRaw((const char *)rsoc_buff, 4);
+ goto err_out;
+ }
printf("\nTask Management Functions supported by device:\n");
+ if (opts.do_hex) {
+ dStrHex((const char *)rsoc_buff, 4, 1);
+ goto err_out;
+ }
if (rsoc_buff[0] & 0x80)
printf(" Abort task\n");
if (rsoc_buff[0] & 0x40)
@@ -559,47 +886,316 @@ int main(int argc, char * argv[])
printf(" Wakeup\n");
if (rsoc_buff[1] & 0x1)
printf(" I_T nexus reset\n");
- } else if (0 == rep_opts) /* list all supported operation codes */
- list_all_codes(rsoc_buff, sizeof(rsoc_buff), do_unsorted, do_alpha);
- else { /* asked about specific command */
- const char * cp;
- int v = 0;
-
-#ifdef TEST_CODE
- memcpy(rsoc_buff, dummy_1_cmd, sizeof(dummy_1_cmd));
-#endif
- printf("\n Opcode=0x%.2x", do_opcode);
- if (rep_opts > 1)
- printf(" Service_action=0x%.4x", do_servact);
- printf("\n");
- sg_get_opcode_sa_name(((do_opcode > 0) ? do_opcode : 0),
- ((do_servact > 0) ? do_servact : 0),
- peri_type, NAME_BUFF_SZ, name_buff);
- printf(" Command_name: %s\n", name_buff);
- switch((int)(rsoc_buff[1] & 7)) {
- case 0: cp = "not currently available"; break;
- case 1: cp = "NOT supported"; break;
- case 3: cp = "supported (conforming to SCSI standard)"; v = 1; break;
- case 5: cp = "supported (in a vendor specific manner)"; v = 1; break;
- default:
- snprintf(name_buff, NAME_BUFF_SZ, "support reserved [0x%x]",
- rsoc_buff[1] & 7);
- cp = name_buff;
- break;
+ } else if (0 == rep_opts) { /* list all supported operation codes */
+ len = ((rsoc_buff[0] << 24) | (rsoc_buff[1] << 16) |
+ (rsoc_buff[2] << 8) | rsoc_buff[3]) + 4;
+ if (len > (int)sizeof(rsoc_buff))
+ len = sizeof(rsoc_buff);
+ if (opts.do_raw) {
+ dStrRaw((const char *)rsoc_buff, len);
+ goto err_out;
+ }
+ if (opts.do_hex) {
+ dStrHex((const char *)rsoc_buff, len, 1);
+ goto err_out;
+ }
+ list_all_codes(rsoc_buff, sizeof(rsoc_buff), opts.do_unsorted,
+ opts.do_alpha, opts.do_rctd);
+ } else { /* asked about specific command */
+ cd_len = ((rsoc_buff[2] << 8) | rsoc_buff[3]);
+ len = cd_len + 4;
+ if (len > (int)sizeof(rsoc_buff))
+ len = sizeof(rsoc_buff);
+ if (opts.do_raw) {
+ dStrRaw((const char *)rsoc_buff, len);
+ goto err_out;
}
- printf(" Command %s\n", cp);
- if (v) {
- printf(" Usage data: ");
- cd_len = ((rsoc_buff[2] << 8) | rsoc_buff[3]);
- ucp = rsoc_buff + 4;
- for (k = 0; k < cd_len; ++k)
- printf("%.2x ", ucp[k]);
- printf("\n");
+ if (opts.do_hex) {
+ dStrHex((const char *)rsoc_buff, len, 1);
+ goto err_out;
}
+ list_one(rsoc_buff, cd_len, rep_opts, opts.do_opcode,
+ opts.do_servact);
}
res = 0;
err_out:
+#ifdef USE_SG_IO
close(sg_fd);
+#else
+ sg_cmds_close_device(sg_fd);
+#endif
return res;
}
+
+
+#ifdef USE_SG_IO
+/* Report Supported Operation Codes */
+/* Returns 0 when successful */
+static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode,
+ int rq_servact, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int res, k;
+ unsigned char rsocCmdBlk[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ if (rctd)
+ rsocCmdBlk[2] |= 0x80;
+ if (rep_opts)
+ rsocCmdBlk[2] |= (rep_opts & 0x7);
+ if (rq_opcode > 0)
+ rsocCmdBlk[3] = (rq_opcode & 0xff);
+ if (rq_servact > 0) {
+ rsocCmdBlk[4] = (unsigned char)((rq_servact >> 8) & 0xff);
+ rsocCmdBlk[5] = (unsigned char)(rq_servact & 0xff);
+
+ }
+ rsocCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
+ rsocCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rsocCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rsocCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+
+ if (verbose) {
+ fprintf(stderr, " Report Supported Operation Codes cmd: ");
+ for (k = 0; k < RSOC_CMD_LEN; ++k)
+ fprintf(stderr, "%02x ", rsocCmdBlk[k]);
+ fprintf(stderr, "\n");
+ }
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(rsocCmdBlk);
+ io_hdr.mx_sb_len = sizeof(sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = rsocCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ perror("SG_IO (rsoc) error");
+ return -1;
+ }
+ if (verbose > 2)
+ fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
+ res = sg_err_category3(&io_hdr);
+ switch (res) {
+ case SG_LIB_CAT_RECOVERED:
+ sg_chk_n_print3("Report supported operation codes", &io_hdr,
+ verbose > 1);
+ /* fall through */
+ case SG_LIB_CAT_CLEAN:
+ return 0;
+ default:
+ if (noisy | verbose) {
+ char ebuff[EBUFF_SZ];
+
+ if (0 == rep_opts)
+ snprintf(ebuff, EBUFF_SZ, "RSOC error, rep_opts=0 (all) ");
+ else if (1 == rep_opts)
+ snprintf(ebuff, EBUFF_SZ, "RSOC error, rq_opcode=0x%x ",
+ rq_opcode);
+ else
+ snprintf(ebuff, EBUFF_SZ, "RSOC error, rq_opcode=0x%x, "
+ "rq_sa=0x%x ", rq_opcode, rq_servact);
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
+ }
+ return res;
+ }
+}
+
+/* Report Supported Task Management Function */
+/* Returns 0 when successful */
+static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int res, k;
+ unsigned char rstmfCmdBlk[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ rstmfCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
+ rstmfCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rstmfCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rstmfCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+
+ if (verbose) {
+ fprintf(stderr, " Report Supported Task Management Functions "
+ "cmd: ");
+ for (k = 0; k < RSTMF_CMD_LEN; ++k)
+ fprintf(stderr, "%02x ", rstmfCmdBlk[k]);
+ fprintf(stderr, "\n");
+ }
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof(rstmfCmdBlk);
+ io_hdr.mx_sb_len = sizeof(sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = rstmfCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
+ perror("SG_IO (rstmf) error");
+ return -1;
+ }
+ if (verbose > 2)
+ fprintf(stderr, " duration=%u ms\n", io_hdr.duration);
+ res = sg_err_category3(&io_hdr);
+ switch (res) {
+ case SG_LIB_CAT_RECOVERED:
+ sg_chk_n_print3("Report supported task management fns", &io_hdr,
+ verbose > 1);
+ /* fall through */
+ case SG_LIB_CAT_CLEAN:
+ return 0;
+ default:
+ if (noisy | verbose) {
+ char ebuff[EBUFF_SZ];
+ snprintf(ebuff, EBUFF_SZ, "RSTMF error ");
+ sg_chk_n_print3(ebuff, &io_hdr, verbose > 1);
+ }
+ return res;
+ }
+}
+
+#else /* use generic pass through code instead */
+
+static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode,
+ int rq_servact, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int k, ret, res, sense_cat;
+ unsigned char rsocCmdBlk[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ void * ptvp;
+
+ if (rctd)
+ rsocCmdBlk[2] |= 0x80;
+ if (rep_opts)
+ rsocCmdBlk[2] |= (rep_opts & 0x7);
+ if (rq_opcode > 0)
+ rsocCmdBlk[3] = (rq_opcode & 0xff);
+ if (rq_servact > 0) {
+ rsocCmdBlk[4] = (unsigned char)((rq_servact >> 8) & 0xff);
+ rsocCmdBlk[5] = (unsigned char)(rq_servact & 0xff);
+
+ }
+ rsocCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
+ rsocCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rsocCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rsocCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+
+ if (verbose) {
+ fprintf(stderr, " Report Supported Operation Codes cmd: ");
+ for (k = 0; k < RSOC_CMD_LEN; ++k)
+ fprintf(stderr, "%02x ", rsocCmdBlk[k]);
+ fprintf(stderr, "\n");
+ }
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ fprintf(sg_warnings_strm, "Report Supported Operation Codes: out "
+ "of memory\n");
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, rsocCmdBlk, sizeof(rsocCmdBlk));
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
+ res = do_scsi_pt(ptvp, sg_fd, DEF_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, "Report Supported Operation Codes", res,
+ mx_resp_len, sense_b, noisy, verbose,
+ &sense_cat);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_NOT_READY:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ case SG_LIB_CAT_INVALID_OP:
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ ret = sense_cat;
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ } else
+ ret = 0;
+
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+static int do_rstmf(int sg_fd, void * resp, int mx_resp_len, int noisy,
+ int verbose)
+{
+ int k, ret, res, sense_cat;
+ unsigned char rstmfCmdBlk[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ void * ptvp;
+
+ rstmfCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff);
+ rstmfCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff);
+ rstmfCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ rstmfCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff);
+
+ if (verbose) {
+ fprintf(stderr, " Report Supported Task Management Functions "
+ "cmd: ");
+ for (k = 0; k < RSTMF_CMD_LEN; ++k)
+ fprintf(stderr, "%02x ", rstmfCmdBlk[k]);
+ fprintf(stderr, "\n");
+ }
+ ptvp = construct_scsi_pt_obj();
+ if (NULL == ptvp) {
+ fprintf(sg_warnings_strm, "Report Supported Task Management "
+ "Functions: out of memory\n");
+ return -1;
+ }
+ set_scsi_pt_cdb(ptvp, rstmfCmdBlk, sizeof(rstmfCmdBlk));
+ set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
+ set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
+ res = do_scsi_pt(ptvp, sg_fd, DEF_TIMEOUT, verbose);
+ ret = sg_cmds_process_resp(ptvp, "Report Supported Task management "
+ "functions", res, mx_resp_len, sense_b, noisy,
+ verbose, &sense_cat);
+ if (-1 == ret)
+ ;
+ else if (-2 == ret) {
+ switch (sense_cat) {
+ case SG_LIB_CAT_NOT_READY:
+ case SG_LIB_CAT_UNIT_ATTENTION:
+ case SG_LIB_CAT_INVALID_OP:
+ case SG_LIB_CAT_ILLEGAL_REQ:
+ case SG_LIB_CAT_ABORTED_COMMAND:
+ ret = sense_cat;
+ break;
+ case SG_LIB_CAT_RECOVERED:
+ case SG_LIB_CAT_NO_SENSE:
+ ret = 0;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ } else
+ ret = 0;
+
+ destruct_scsi_pt_obj(ptvp);
+ return ret;
+}
+
+#endif