/* * Copyright (c) 2004-2007 Christophe Varoqui and 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 #include #include #include #include #include #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program for the Linux OS SCSI subsystem. * * * This program issues the SCSI command REPORT TARGET PORT GROUPS * to the given SCSI device. */ static char * version_str = "1.11 20070127"; #define REPORT_TGT_GRP_BUFF_LEN 1024 #define ME "sg_rtpg: " #define TPGS_STATE_OPTIMIZED 0x0 #define TPGS_STATE_NONOPTIMIZED 0x1 #define TPGS_STATE_STANDBY 0x2 #define TPGS_STATE_UNAVAILABLE 0x3 #define TPGS_STATE_TRANSITIONING 0xf #define STATUS_CODE_NOSTATUS 0x0 #define STATUS_CODE_CHANGED_BY_SET 0x1 #define STATUS_CODE_CHANGED_BY_IMPLICIT 0x2 /* <<<<<<<<<<<<<<< start of test code */ /* #define TEST_CODE */ #ifdef TEST_CODE #warning "<<<< TEST_CODE response compiled in >>>>" unsigned char dummy_resp[32] = { 0, 0, 0, 28, 0x80, 0x3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0x1, 0x3, 0, 2, 0, 0, 0, 1, 0, 0, 0, 3, }; #endif /* <<<<<<<<<<<<<<< end of test code */ static struct option long_options[] = { {"decode", 0, 0, 'd'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"raw", 0, 0, 'r'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_rtpg [--decode] [--help] [--hex] [--raw] [--verbose] " "[--version]\n" " DEVICE\n" " where:\n" " --decode|-d decode status and asym. access state\n" " --help|-h print out usage message\n" " --hex|-H print out response in hex\n" " --raw|-r output response in binary to stdout\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI REPORT TARGET PORT GROUPS command\n" ); } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } static void decode_status(const int st) { switch (st) { case STATUS_CODE_NOSTATUS: printf(" (no status available)"); break; case STATUS_CODE_CHANGED_BY_SET: printf(" (status changed by SET TARGET PORT GROUPS)"); break; case STATUS_CODE_CHANGED_BY_IMPLICIT: printf(" (status changed by implicit TPGS behaviour)"); break; default: printf(" (unknown status code)"); break; } } static void decode_tpgs_state(const int st) { switch (st) { case TPGS_STATE_OPTIMIZED: printf(" (active/optimized)"); break; case TPGS_STATE_NONOPTIMIZED: printf(" (active/non optimized)"); break; case TPGS_STATE_STANDBY: printf(" (standby)"); break; case TPGS_STATE_UNAVAILABLE: printf(" (unavailable)"); break; case TPGS_STATE_TRANSITIONING: printf(" (transitioning between states)"); break; default: printf(" (unknown)"); break; } } int main(int argc, char * argv[]) { int sg_fd, k, j, off, res, c, report_len, tgt_port_count, trunc; unsigned char reportTgtGrpBuff[REPORT_TGT_GRP_BUFF_LEN]; unsigned char * ucp; int decode = 0; int hex = 0; int raw = 0; int verbose = 0; char device_name[256]; int ret = 0; memset(device_name, 0, sizeof device_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "dhHrvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': decode = 1; break; case 'h': case '?': usage(); return 0; case 'H': hex = 1; break; case 'r': raw = 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 SG_LIB_SYNTAX_ERROR; } } 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 SG_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(reportTgtGrpBuff, 0x0, sizeof(reportTgtGrpBuff)); trunc = 0; #ifndef TEST_CODE res = sg_ll_report_tgt_prt_grp(sg_fd, reportTgtGrpBuff, sizeof(reportTgtGrpBuff), 1, verbose); #else memcpy(reportTgtGrpBuff, dummy_resp, sizeof(dummy_resp)); res = 0; #endif ret = res; if (0 == res) { report_len = (reportTgtGrpBuff[0] << 24) + (reportTgtGrpBuff[1] << 16) + (reportTgtGrpBuff[2] << 8) + reportTgtGrpBuff[3] + 4; if (report_len > (int)sizeof(reportTgtGrpBuff)) { trunc = 1; fprintf(stderr, " <= 0) ? ret : SG_LIB_CAT_OTHER; }