sg_luns: add --test=LUNHEX for 64 bit lun support

git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@482 6180dd3e-e324-4e3e-922d-17de1ae2f315
diff --git a/ChangeLog b/ChangeLog
index a6c661f..7ee2f9d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,15 +2,17 @@
 some description at the top of its ".c" file. All utilities in the main
 directory have their own "man" pages. There is also a sg3_utils man page.
 
-Changelog for sg3_utils-1.36 [20130220] [svn: r481]
+Changelog for sg3_utils-1.36 [20130225] [svn: r482]
   - sg_lib: improve snprintf handling
   - sg_vpd: Protocol-specific port information VPD page for
     SAS SSP, persistent connection (spl3r2)
   - sg_xcopy: handle more descriptor types; handle zero
     maximum segment length; allow list IDs to be disabled;
     improve skip/seek handling
-  - sg_reset: and '--no-esc' option to stop reset escalation
+  - sg_reset: and --no-esc option to stop reset escalation
     - clean up including adding long option names
+  - sg_luns: add --test=LUNHEX option for decoding LUNs
+    - decoded luns output in decimal or hex (if -HH given)
 
 Changelog for sg3_utils-1.35 [20130117] [svn: r476]
   - sg_compare_and_write: new utility
diff --git a/README b/README
index 1549c4f..00e9aab 100644
--- a/README
+++ b/README
@@ -374,4 +374,4 @@
 
 
 Douglas Gilbert
-20th February 2013
+25th February 2013
diff --git a/debian/changelog b/debian/changelog
index 1cc18f7..16858e4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@
 
   * New upstream version
 
- -- Douglas Gilbert <dgilbert@interlog.com>  Wed, 20 Feb 2013 19:00:00 -0500
+ -- Douglas Gilbert <dgilbert@interlog.com>  Mon, 25 Feb 2013 01:00:00 -0500
 
 sg3-utils (1.35-0.1) unstable; urgency=low
 
diff --git a/doc/sg_inq.8 b/doc/sg_inq.8
index 000de37..7678065 100644
--- a/doc/sg_inq.8
+++ b/doc/sg_inq.8
@@ -1,4 +1,4 @@
-.TH SG_INQ "8" "January 2013" "sg3_utils\-1.35" SG3_UTILS
+.TH SG_INQ "8" "February 2013" "sg3_utils\-1.36" SG3_UTILS
 .SH NAME
 sg_inq \- issue SCSI INQUIRY command, output and decode response
 .SH SYNOPSIS
@@ -22,7 +22,7 @@
 device and then outputs the response. All SCSI devices are meant
 to respond to a "standard" INQUIRY command with at least a 36 byte
 response (in SCSI 2 and higher). An INQUIRY is termed as "standard"
-when both the EVPD and CmdDt (obsolete) bits are clear.
+when both the EVPD and CmdDt (now obsolete) bits are clear.
 .PP
 This utility supports two command line syntaxes, the preferred one is
 shown first in the synopsis and explained in this section. A later
diff --git a/doc/sg_luns.8 b/doc/sg_luns.8
index d184012..46bc5d2 100644
--- a/doc/sg_luns.8
+++ b/doc/sg_luns.8
@@ -1,16 +1,24 @@
-.TH SG_LUNS "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS
+.TH SG_LUNS "8" "February 2013" "sg3_utils\-1.36" SG3_UTILS
 .SH NAME
 sg_luns \- send SCSI REPORT LUNS command
 .SH SYNOPSIS
 .B sg_luns
 [\fI\-\-decode\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-maxlen=LEN\fR]
-[\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-select=SR\fR] [\fI\-\-verbose\fR]
-[\fI\-\-version\fR] \fIDEVICE\fR
+[\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-select=SR\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.PP
+.B sg_luns
+\fI\-\-test=LUNHEX\fR [\fI\-\-hex\fR] [\fI\-\-verbose\fR]
 .SH DESCRIPTION
 .\" Add any additional description here
 .PP
-Send the SCSI REPORT LUNS command to the \fIDEVICE\fR and outputs the
-response. In the SPC\-3 SCSI standard support for this command is mandatory.
+In the first form shown in the SYNOPSIS this utility sends the SCSI REPORT
+LUNS command to the \fIDEVICE\fR and outputs the response. In the SPC\-3
+SCSI standard support for the REPORT LUNS command is mandatory.
+.PP
+When the \fI\-\-test=LUNHEX\fR option is given (the second form in the
+SYNOPSIS), the \fILUNHEX\fR value (assumed to represent a LUN in hex) is
+decoded as outlined in SAM\-3 and SAM\-4 .
 .SH OPTIONS
 Arguments to long options are mandatory for short options as well.
 .TP
@@ -23,7 +31,10 @@
 output the usage message then exit.
 .TP
 \fB\-H\fR, \fB\-\-hex\fR
-output response to this command in ASCII hex.
+when given once this utility will output response to the REPORT LUNS command
+in ASCII hex then exit. When given twice it causes the decode options to
+output values in hex rather than decimal. When this option is used with
+\fI\-\-test=LUNHEX\fR than decoded values are output in hex.
 .TP
 \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR
 where \fILEN\fR is the (maximum) response length in bytes. It is placed in
@@ -54,9 +65,20 @@
 .br
   \fB2\fR : all luns
 .br
-Values between 0xf8 and 0xff (inclusive) are vendor specific (SPC\-4 (rev 32),
+Values between 0xf8 and 0xff (inclusive) are vendor specific (SPC\-4 rev 32),
 other values greater than 2 are reserved.
 .TP
+\fB\-t\fR, \fB\-\-test\fR=\fILUNHEX\fR
+\fILUNHEX\fR is assumed to be a hexadecimal number in ASCII hex. The number
+can be up to 64 bits in size (i.e. 16 hexadecimal digits). All \fILUNHEX\fR
+values are padded to the right if less than 16 hexadecimal digits are
+given (e.g. \fI\-\-test=0122003a\fR becomes 0122003a00000000). \fILUNHEX\fR
+may be prefixed by '0x' or '0X' (e.g. the last example could have been
+\fI\-\-test=0x0122003a\fR). \fILUNHEX\fR may also be given with spaces or
+tabs between each byte (or anywhere else) but then \fILUNHEX\fR would need
+to be surrounded by single or double quotes. The given hexadecimal number is
+decoded as if the \fI\-\-decode\fR had been given.
+.TP
 \fB\-v\fR, \fB\-\-verbose\fR
 increase the level of verbosity, (i.e. debug output).
 .TP
@@ -70,7 +92,7 @@
 .SH "REPORTING BUGS"
 Report bugs to <dgilbert at interlog dot com>.
 .SH COPYRIGHT
-Copyright \(co 2004\-2012 Douglas Gilbert
+Copyright \(co 2004\-2013 Douglas Gilbert
 .br
 This software is distributed under a FreeBSD license. There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/sg3_utils.spec b/sg3_utils.spec
index d5c3b22..f3cc392 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -79,7 +79,7 @@
 %{_libdir}/*.la
 
 %changelog
-* Wed Feb 20 2013 - dgilbert at interlog dot com
+* Mon Feb 25 2013 - dgilbert at interlog dot com
 - track t10 changes
   * sg3_utils-1.36
 
diff --git a/src/sg_inq.c b/src/sg_inq.c
index 4848574..18d9001 100644
--- a/src/sg_inq.c
+++ b/src/sg_inq.c
@@ -2217,7 +2217,7 @@
 }
 
 
-/* Returns 0 if successful */
+/* Process a standard INQUIRY response. Returns 0 if successful */
 static int
 process_std_inq(int sg_fd, const struct opts_t * optsp)
 {
diff --git a/src/sg_luns.c b/src/sg_luns.c
index 0870577..693ccf4 100644
--- a/src/sg_luns.c
+++ b/src/sg_luns.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2012 Douglas Gilbert.
+ * Copyright (c) 2004-2013 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.
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <getopt.h>
 #define __STDC_FORMAT_MACROS 1
 #include <inttypes.h>
@@ -27,7 +28,7 @@
  * and decodes the response.
  */
 
-static char * version_str = "1.17 20120314";
+static char * version_str = "1.18 20130224";
 
 #define MAX_RLUNS_BUFF_LEN (1024 * 64)
 #define DEF_RLUNS_BUFF_LEN (1024 * 8)
@@ -43,6 +44,7 @@
         {"quiet", no_argument, 0, 'q'},
         {"raw", no_argument, 0, 'r'},
         {"select", required_argument, 0, 's'},
+        {"test", required_argument, 0, 't'},
         {"verbose", no_argument, 0, 'v'},
         {"version", no_argument, 0, 'V'},
         {0, 0, 0, 0},
@@ -52,26 +54,33 @@
 usage()
 {
     fprintf(stderr, "Usage: "
-            "sg_luns    [--decode] [--help] [--hex] [--maxlen=LEN] [--quiet] "
-            "[--raw]\n"
-            "                  [--select=SR] [--verbose] [--version] DEVICE\n"
+            "sg_luns    [--decode] [--help] [--hex] [--maxlen=LEN] "
+            "[--quiet]\n"
+            "                  [--raw] [--select=SR] [--test=LUNHEX] "
+            "[--verbose]\n"
+            "                  [--version] DEVICE\n"
             "  where:\n"
             "    --decode|-d        decode all luns into component parts\n"
             "    --help|-h          print out usage message\n"
-            "    --hex|-H           output in hexadecimal\n"
+            "    --hex|-H           output response in hexadecimal; used "
+            "twice\n"
+            "                       shows decoded values in hex\n"
             "    --maxlen=LEN|-m LEN    max response length (allocation "
             "length in cdb)\n"
             "                           (def: 0 -> %d bytes)\n",
             DEF_RLUNS_BUFF_LEN );
     fprintf(stderr, "    --quiet|-q         output only ASCII hex lun "
             "values\n"
-            "    --raw|-r           output in binary\n"
+            "    --raw|-r           output response in binary\n"
             "    --select=SR|-s SR    select report SR (def: 0)\n"
             "                          0 -> luns apart from 'well "
             "known' lus\n"
             "                          1 -> only 'well known' "
             "logical unit numbers\n"
             "                          2 -> all luns\n"
+            "    --test=LUNHEX|-t LUNHEX    decode LUNHEX and ignore "
+            "other options\n"
+            "                               and DEVICE (apart from '-H')\n"
             "    --verbose|-v       increase verbosity\n"
             "    --version|-V       print version string and exit\n\n"
             "Performs a SCSI REPORT LUNS command\n"
@@ -82,11 +91,10 @@
  * 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)
+decode_lun(const char * leadin, const unsigned char * lunp, int do_hex)
 {
     int k, j, x, a_method, bus_id, target, lun, len_fld, e_a_method;
     int next_level;
-    unsigned int u;
     unsigned char not_spec[8] = {0xff, 0xff, 0xff, 0xff,
                                  0xff, 0xff, 0xff, 0xff};
     char l_leadin[128];
@@ -109,25 +117,40 @@
         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]);
+            if (0 == bus_id) {
+                if (do_hex)
+                    printf("%sPeripheral device addressing: lun=0x%x\n",
+                           l_leadin, lunp[1]);
+                else
+                    printf("%sPeripheral device addressing: lun=%d\n",
+                           l_leadin, lunp[1]);
+            } else {
+                if (do_hex)
+                    printf("%sPeripheral device addressing: bus_id=0x%x, "
+                           "target=0x%x\n", l_leadin, bus_id, 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);
+            if (do_hex)
+                printf("%sFlat space addressing: lun=0x%x\n", l_leadin, lun);
+            else
+                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);
+            if (do_hex)
+                printf("%sLogical unit addressing: bus_id=0x%x, target=0x%x, "
+                       "lun=0x%x\n", l_leadin, bus_id, target, lun);
+            else
+                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_fld = (lunp[0] & 0x30) >> 4;
@@ -152,18 +175,34 @@
                            l_leadin);
                     break;
                 default:
-                    printf("%swell known logical unit %d\n", l_leadin, x);
+                    if (do_hex)
+                        printf("%swell known logical unit 0x%x\n", l_leadin,
+                               x);
+                    else
+                        printf("%swell known logical unit %d\n", l_leadin, x);
                     break;
                 }
             } else if ((1 == len_fld) && (2 == e_a_method)) {
                 x = (lunp[1] << 16) + (lunp[2] << 8) + lunp[3];
-                printf("%sExtended flat space logical unit addressing: "
-                       "value=0x%x\n", l_leadin, x);
+                if (do_hex)
+                    printf("%sExtended flat space addressing: value=0x%x\n",
+                           l_leadin, x);
+                else
+                    printf("%sExtended flat space addressing: value=%d\n",
+                           l_leadin, x);
             } else if ((2 == len_fld) && (2 == e_a_method)) {
-                u = (lunp[1] << 24) + (lunp[2] << 16) + (lunp[3] << 8) +
-                    lunp[4];
-                printf("%sLong extended flat space logical unit addressing: "
-                       "value=0x%x\n", l_leadin, u);
+                ull = 0;
+                for (j = 0; j < 5; ++j) {
+                    if (j > 0)
+                        ull <<= 8;
+                    ull |= lunp[1 + j];
+                }
+                if (do_hex)
+                    printf("%sLong extended flat space addressing: "
+                           "value=0x%" PRIx64 "\n", l_leadin, ull);
+                else
+                    printf("%sLong extended flat space  addressing: "
+                           "value=%" PRIu64 "\n", l_leadin, ull);
             } else if ((3 == len_fld) && (0xf == e_a_method))
                 printf("%sLogical unit _not_ specified addressing\n",
                        l_leadin);
@@ -171,9 +210,14 @@
                 if (len_fld < 2) {
                     if (1 == len_fld)
                         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_fld,
-                           e_a_method, x);
+                    if (do_hex)
+                        printf("%sExtended logical unit addressing: "
+                               "length=%d, e.a. method=%d, value=0x%x\n",
+                               l_leadin, len_fld, e_a_method, x);
+                    else
+                        printf("%sExtended logical unit addressing: "
+                               "length=%d, e.a. method=%d, value=%d\n",
+                               l_leadin, len_fld, e_a_method, x);
                 } else {
                     ull = 0;
                     x = (2 == len_fld) ? 5 : 7;
@@ -182,9 +226,14 @@
                             ull <<= 8;
                         ull |= lunp[1 + j];
                     }
-                    printf("%sExtended logical unit addressing: length=%d, "
-                           "e. a. method=%d, value=0x%" PRIx64 "\n",
-                           l_leadin, len_fld, e_a_method, ull);
+                    if (do_hex)
+                        printf("%sExtended logical unit addressing: "
+                               "length=%d, e. a. method=%d, value=0x%" PRIx64
+                               "\n", l_leadin, len_fld, e_a_method, ull);
+                    else
+                        printf("%sExtended logical unit addressing: "
+                               "length=%d, e. a. method=%d, value=%" PRIu64
+                               "\n", l_leadin, len_fld, e_a_method, ull);
                 }
             }
             break;
@@ -221,13 +270,17 @@
     int do_raw = 0;
     int select_rep = 0;
     int verbose = 0;
+    unsigned int h;
+    const char * test_arg = NULL;
     const char * device_name = NULL;
+    const char * cp;
+    unsigned char lun_arr[8];
     int ret = 0;
 
     while (1) {
         int option_index = 0;
 
-        c = getopt_long(argc, argv, "dhHm:qrs:vV", long_options,
+        c = getopt_long(argc, argv, "dhHm:qrs:t:vV", long_options,
                         &option_index);
         if (c == -1)
             break;
@@ -264,6 +317,9 @@
                 return SG_LIB_SYNTAX_ERROR;
             }
             break;
+        case 't':
+            test_arg = optarg;
+            break;
         case 'v':
             ++verbose;
             break;
@@ -290,6 +346,39 @@
         }
     }
 
+    if (test_arg) {
+        memset(lun_arr, 0, sizeof(lun_arr));
+        cp = test_arg;
+        if (('0' == test_arg[0]) && ('X' == toupper(test_arg[1])))
+            cp += 2;
+        if (strchr(cp, ' ') || strchr(cp, '\t')) {
+            for (k = 0; k < 8; ++k, cp += m) {
+                if (1 != sscanf(cp, " %2x%n", &h, &m))
+                    break;
+                lun_arr[k] = h & 0xff;
+            }
+        } else {
+            for (k = 0; k < 8; ++k, cp += 2) {
+            if (1 != sscanf(cp, "%2x", &h))
+                    break;
+                lun_arr[k] = h & 0xff;
+            }
+        }
+        if (0 == k) {
+            fprintf(stderr, "expected a hex number, optionally prefixed "
+                    "by '0x'\n");
+            return SG_LIB_SYNTAX_ERROR;
+        }
+        if (verbose) {
+            printf("64 bit LUN is T10 preferred (hex) format: ");
+            for (k = 0; k < 8; ++k)
+                printf(" %02x", lun_arr[k]);
+            printf("\n");
+        }
+        printf("Decoded LUN:\n");
+        decode_lun("  ", lun_arr, do_hex);
+        return 0;
+    }
     if (NULL == device_name) {
         fprintf(stderr, "missing device name!\n");
         usage();
@@ -324,7 +413,7 @@
             dStrRaw((const char *)reportLunsBuff, list_len + 8);
             goto the_end;
         }
-        if (do_hex) {
+        if (1 == do_hex) {
             dStrHex((const char *)reportLunsBuff, list_len + 8, 1);
             goto the_end;
         }
@@ -353,7 +442,7 @@
                 printf("%02x", reportLunsBuff[off]);
             printf("\n");
             if (decode)
-                decode_lun("      ", reportLunsBuff + off - 8);
+                decode_lun("      ", reportLunsBuff + off - 8, do_hex);
         }
     } else if (SG_LIB_CAT_INVALID_OP == res)
         fprintf(stderr, "Report Luns command not supported (support "