chiark / gitweb /
scsi_id: derive a UID for a SCSI-2 not compliant with the page 83
authorEdward Goggin <egoggin@emc.com>
Wed, 14 Sep 2005 18:23:48 +0000 (20:23 +0200)
committerKay Sievers <kay.sievers@suse.de>
Wed, 14 Sep 2005 18:23:48 +0000 (20:23 +0200)
This patch is to enable the use of scsi_id to derive a UID for a SCSI-2
device which is not compliant with the page 83 inquiry reply format for
either SPC-2 or SPC-3.  In this case, the page 83 reply does not
contain a list of  Identification descriptors but a single binary encoded
hexa-decimal Vendor Specified Identifier.

The update is being driven by the need for scsi_id to support older
model EMC Symmetrix hardware, that is, models 4, 5, and 6.

extras/scsi_id/scsi_id.8
extras/scsi_id/scsi_id.c
extras/scsi_id/scsi_id.config
extras/scsi_id/scsi_id.h
extras/scsi_id/scsi_serial.c

index 26df0d3e669ac2b1e99a4bab11aaf1c103d306c8..4213468ae4c18b48af2cf5d33940732ad44cbd90 100644 (file)
@@ -91,10 +91,18 @@ to generate any output.
 Prefix the identification string with the  driver model (sysfs) bus id of
 the SCSI device.
 .TP
-.BI \-p "\| 0x80 | 0x83"
-Use SCSI INQUIRY VPD page code 0x80 or 0x83. The default behaviour is to
-query the available VPD pages, and use page 0x83 if found, else page 0x80
-if found, else nothing.
+.BI \-p "\| 0x80 | 0x83 | pre-spc3-83"
+Use SCSI INQUIRY VPD page code 0x80, 0x83, or pre-spc3-83.
+.sp
+The default
+behaviour is to query the availabe VPD pages, and use page 0x83 if found,
+else page 0x80 if found, else nothing.
+.sp
+Page pre-spc3-83 should only be utilized for those scsi devices which
+are not compliant with the SPC-2 or SPC-3 format for page 83.  While this
+option is used for older model 4, 5, and 6 EMC Symmetrix devices, its
+use with SPC-2 or SPC-3 compliant devices will fallback to the page 83
+format supported by these devices.
 .TP
 .BI \-s "\| sysfs\-device"
 Generate an id for the
index a86b004709a219c4fa8cb68125a2c7ff05b63e3a..e997be995675bbd1defcaa4fe2434e0f4dcaea13 100644 (file)
@@ -67,7 +67,7 @@ static int dev_specified;
 static int sys_specified;
 static char config_file[MAX_NAME_LEN] = SCSI_ID_CONFIG_FILE;
 static int display_bus_id;
-static int default_page_code;
+static enum page_code default_page_code;
 static int use_stderr;
 static int debug;
 static int hotplug_mode;
@@ -519,9 +519,11 @@ static int set_options(int argc, char **argv, const char *short_opts,
 
                case 'p':
                        if (strcmp(optarg, "0x80") == 0) {
-                               default_page_code = 0x80;
+                               default_page_code = PAGE_80;
                        } else if (strcmp(optarg, "0x83") == 0) {
-                               default_page_code = 0x83;
+                               default_page_code = PAGE_83;
+                       } else if (strcmp(optarg, "pre-spc3-83") == 0) {
+                               default_page_code = PAGE_83_PRE_SPC3; 
                        } else {
                                log_message(LOG_WARNING,
                                            "Unknown page code '%s'\n", optarg);
@@ -640,9 +642,11 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
 
                case 'p':
                        if (strcmp(optarg, "0x80") == 0) {
-                               *page_code = 0x80;
+                               *page_code = PAGE_80;
                        } else if (strcmp(optarg, "0x83") == 0) {
-                               *page_code = 0x83;
+                               *page_code = PAGE_83;
+                       } else if (strcmp(optarg, "pre-spc3-83") == 0) {
+                               *page_code = PAGE_83_PRE_SPC3; 
                        } else {
                                log_message(LOG_WARNING,
                                            "Unknown page code '%s'\n", optarg);
index 0567ecb7d6adb23d0f84bb794978d2bea63335a7..4f31b1c498b6cf169923be0d215b28cdd72a9062 100644 (file)
@@ -41,3 +41,8 @@ vendor=someone, model=nicedrive, options=-g
 # if you rely on the id for persistent naming or multi-path configuration.
 
 ## vendor=ELBONIA, model=borken, options=-b
+
+# EMC SYMMETRIX models 4 and 5, and some model 6 systems return the VSI
+# field of the page 83 reply according to SCSI-2 format.  This format is
+# binary encoded hexa-decimal as opposed to the Identifiscation descriptor
+# utilized by both SPC-2 and SPC-3 compliant systems.
index 74b449e984f022a127f02f8588112b01e2a1faab..1c9ed969a7cb0cdba3a25d65f79a09fefd002dbf 100644 (file)
@@ -53,3 +53,13 @@ extern void log_message (int level, const char *format, ...)
 #ifndef u8
 typedef unsigned char u8;
 #endif
+
+/*
+ * Page code values. 
+ */
+enum page_code {
+               PAGE_83_PRE_SPC3 = -0x83,
+               PAGE_UNSPECIFIED = 0x00,
+               PAGE_80          = 0x80,
+               PAGE_83          = 0x83,
+};
index 73d66ee615659adf9576db0f181cfafa753fa546..d1b1d94f53982e91136462d11a02907b1bad4789 100644 (file)
@@ -567,12 +567,12 @@ static int do_scsi_page83_inquiry(struct sysfs_device *scsi_dev, int fd,
        unsigned char page_83[SCSI_INQ_BUFF_LEN];
 
        memset(page_83, 0, SCSI_INQ_BUFF_LEN);
-       retval = scsi_inquiry(scsi_dev, fd, 1, 0x83, page_83,
+       retval = scsi_inquiry(scsi_dev, fd, 1, PAGE_83, page_83,
                              SCSI_INQ_BUFF_LEN);
        if (retval < 0)
                return 1;
 
-       if (page_83[1] != 0x83) {
+       if (page_83[1] != PAGE_83) {
                log_message(LOG_WARNING, "%s: Invalid page 0x83\n",
                            scsi_dev->name);
                return 1;
@@ -616,6 +616,74 @@ static int do_scsi_page83_inquiry(struct sysfs_device *scsi_dev, int fd,
        return 1;
 }
 
+/*
+ * Get device identification VPD page for older SCSI-2 device which is not
+ * compliant with either SPC-2 or SPC-3 format.
+ *
+ * Return the hard coded error code value 2 if the page 83 reply is not
+ * conformant to the SCSI-2 format.
+ */
+static int do_scsi_page83_prespc3_inquiry(struct sysfs_device *scsi_dev, int fd,
+                                         char *serial, int len)
+{
+       int retval;
+       int i, j;
+       unsigned char page_83[SCSI_INQ_BUFF_LEN];
+
+       memset(page_83, 0, SCSI_INQ_BUFF_LEN);
+       retval = scsi_inquiry(scsi_dev, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN);
+       if (retval < 0)
+               return 1;
+
+       if (page_83[1] != PAGE_83) {
+               log_message(LOG_WARNING, "%s: Invalid page 0x83\n", scsi_dev->name);
+               return 1;
+       }
+       /*
+        * Model 4, 5, and (some) model 6 EMC Symmetrix devices return
+        * a page 83 reply according to SCSI-2 format instead of SPC-2/3.
+        *
+        * The SCSI-2 page 83 format returns an IEEE WWN in binary
+        * encoded hexi-decimal in the 16 bytes following the initial
+        * 4-byte page 83 reply header.
+        *
+        * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part
+        * of an Identification descriptor.  The 3rd byte of the first
+        * Identification descriptor is a reserved (BSZ) byte field.
+        *
+        * Reference the 7th byte of the page 83 reply to determine
+        * whether the reply is compliant with SCSI-2 or SPC-2/3
+        * specifications.  A zero value in the 7th byte indicates
+        * an SPC-2/3 conformant reply, (i.e., the reserved field of the
+        * first Identification descriptor).  This byte will be non-zero
+        * for a SCSI-2 conformant page 83 reply from these EMC
+        * Symmetrix models since the 7th byte of the reply corresponds
+        * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is,
+        * 0x006048.
+        */
+       if (page_83[6] == 0)
+               return 2;
+
+       serial[0] = hex_str[id_search_list[0].id_type];
+       /*
+        * The first four bytes contain data, not a descriptor.
+        */
+       i = 4;
+       j = strlen(serial);
+       /*
+        * Binary descriptor, convert to ASCII,
+        * using two bytes of ASCII for each byte
+        * in the page_83.
+        */
+       while (i < (page_83[3]+4)) {
+               serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4];
+               serial[j++] = hex_str[page_83[i] & 0x0f];
+               i++;
+       }
+       dprintf("using pre-spc3-83 for %s.\n", scsi_dev->name);
+       return 0;
+}
+
 /* Get unit serial number VPD page */
 static int do_scsi_page80_inquiry(struct sysfs_device *scsi_dev, int fd,
                                  char *serial, int max_len)
@@ -627,11 +695,11 @@ static int do_scsi_page80_inquiry(struct sysfs_device *scsi_dev, int fd,
        unsigned char buf[SCSI_INQ_BUFF_LEN];
 
        memset(buf, 0, SCSI_INQ_BUFF_LEN);
-       retval = scsi_inquiry(scsi_dev, fd, 1, 0x80, buf, SCSI_INQ_BUFF_LEN);
+       retval = scsi_inquiry(scsi_dev, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN);
        if (retval < 0)
                return retval;
 
-       if (buf[1] != 0x80) {
+       if (buf[1] != PAGE_80) {
                log_message(LOG_WARNING, "%s: Invalid page 0x80\n",
                            scsi_dev->name);
                return 1;
@@ -674,7 +742,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
                return 1;
        }
 
-       if (page_code == 0x80) {
+       if (page_code == PAGE_80) {
                if (do_scsi_page80_inquiry(scsi_dev, fd, serial, len)) {
                        retval = 1;
                        goto completed;
@@ -682,7 +750,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
                        retval = 0;
                        goto completed;
                }
-       } else if (page_code == 0x83) {
+       } else if (page_code == PAGE_83) {
                if (do_scsi_page83_inquiry(scsi_dev, fd, serial, len)) {
                        retval = 1;
                        goto completed;
@@ -690,6 +758,31 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
                        retval = 0;
                        goto completed;
                }
+       } else if (page_code == PAGE_83_PRE_SPC3) {
+               retval = do_scsi_page83_prespc3_inquiry(scsi_dev, fd, serial, len);
+               if (retval) {
+                       /*
+                        * Fallback to servicing a SPC-2/3 compliant page 83
+                        * inquiry if the page 83 reply format does not
+                        * conform to pre-SPC3 expectations.
+                        */
+                       if (retval == 2) {
+                               if (do_scsi_page83_inquiry(scsi_dev, fd, serial, len)) {
+                                       retval = 1;
+                                       goto completed;
+                               } else  {
+                                       retval = 0;
+                                       goto completed;
+                               }
+                       }
+                       else {
+                               retval = 1;
+                               goto completed;
+                       }
+               } else  {
+                       retval = 0;
+                       goto completed;
+               }
        } else if (page_code != 0x00) {
                log_message(LOG_WARNING, "%s: unsupported page code 0x%d\n",
                            scsi_dev->name, page_code);
@@ -713,7 +806,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
        dprintf("%s: Checking page0\n", scsi_dev->name);
 
        for (ind = 4; ind <= page0[3] + 3; ind++)
-               if (page0[ind] == 0x83)
+               if (page0[ind] == PAGE_83)
                        if (!do_scsi_page83_inquiry(scsi_dev, fd, serial,
                                                    len)) {
                                /*
@@ -724,7 +817,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
                        }
 
        for (ind = 4; ind <= page0[3] + 3; ind++)
-               if (page0[ind] == 0x80)
+               if (page0[ind] == PAGE_80)
                        if (!do_scsi_page80_inquiry(scsi_dev, fd, serial,
                                                    len)) {
                                /*