From: Edward Goggin Date: Wed, 14 Sep 2005 18:23:48 +0000 (+0200) Subject: scsi_id: derive a UID for a SCSI-2 not compliant with the page 83 X-Git-Tag: 174~2544 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=50be1401743704419ba52174302b4c1d06b3898b scsi_id: derive a UID for a SCSI-2 not compliant with the page 83 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. --- diff --git a/extras/scsi_id/scsi_id.8 b/extras/scsi_id/scsi_id.8 index 26df0d3e6..4213468ae 100644 --- a/extras/scsi_id/scsi_id.8 +++ b/extras/scsi_id/scsi_id.8 @@ -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 diff --git a/extras/scsi_id/scsi_id.c b/extras/scsi_id/scsi_id.c index a86b00470..e997be995 100644 --- a/extras/scsi_id/scsi_id.c +++ b/extras/scsi_id/scsi_id.c @@ -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); diff --git a/extras/scsi_id/scsi_id.config b/extras/scsi_id/scsi_id.config index 0567ecb7d..4f31b1c49 100644 --- a/extras/scsi_id/scsi_id.config +++ b/extras/scsi_id/scsi_id.config @@ -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. diff --git a/extras/scsi_id/scsi_id.h b/extras/scsi_id/scsi_id.h index 74b449e98..1c9ed969a 100644 --- a/extras/scsi_id/scsi_id.h +++ b/extras/scsi_id/scsi_id.h @@ -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, +}; diff --git a/extras/scsi_id/scsi_serial.c b/extras/scsi_id/scsi_serial.c index 73d66ee61..d1b1d94f5 100644 --- a/extras/scsi_id/scsi_serial.c +++ b/extras/scsi_id/scsi_serial.c @@ -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)) { /*