X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=extras%2Fscsi_id%2Fscsi_serial.c;h=d1b1d94f53982e91136462d11a02907b1bad4789;hb=d7363ee14c3ea46611d3e706a3e198e07869afc3;hp=20a7928553eb6a0d14c8b363962820eacfd2a5bd;hpb=4e05e4238b2cb63eb3f3cd51cf76f136fa684f2e;p=elogind.git diff --git a/extras/scsi_id/scsi_serial.c b/extras/scsi_id/scsi_serial.c index 20a792855..d1b1d94f5 100644 --- a/extras/scsi_id/scsi_serial.c +++ b/extras/scsi_id/scsi_serial.c @@ -89,6 +89,7 @@ static const char hex_str[]="0123456789abcdef"; #define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ #define SG_ERR_CAT_TIMEOUT 3 #define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ +#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ #define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ #define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ @@ -130,6 +131,8 @@ static int sg_err_category_new(int scsi_status, int msg_status, int return SG_ERR_CAT_MEDIA_CHANGED; if (0x29 == asc) return SG_ERR_CAT_RESET; + } else if (sense_key == ILLEGAL_REQUEST) { + return SG_ERR_CAT_NOTSUPPORTED; } } return SG_ERR_CAT_SENSE; @@ -291,9 +294,9 @@ static int scsi_dump(struct sysfs_device *scsi_dev, struct sg_io_hdr *io) return -1; } -static int scsi_inquiry(struct sysfs_device *scsi_dev, int fd, unsigned - char evpd, unsigned char page, unsigned char *buf, - unsigned int buflen) +static int scsi_inquiry(struct sysfs_device *scsi_dev, int fd, + unsigned char evpd, unsigned char page, + unsigned char *buf, unsigned int buflen) { unsigned char inq_cmd[INQUIRY_CMDLEN] = { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; @@ -331,6 +334,9 @@ resend: retval = sg_err_category3(&io_hdr); switch (retval) { + case SG_ERR_CAT_NOTSUPPORTED: + buf[1] = 0; + /* Fallthrough */ case SG_ERR_CAT_CLEAN: case SG_ERR_CAT_RECOVERED: retval = 0; @@ -361,7 +367,7 @@ error: /* Get list of supported EVPD pages */ static int do_scsi_page0_inquiry(struct sysfs_device *scsi_dev, int fd, - char *buffer, int len) + unsigned char *buffer, unsigned int len) { int retval; struct sysfs_attribute *vendor; @@ -401,7 +407,7 @@ static int do_scsi_page0_inquiry(struct sysfs_device *scsi_dev, int fd, scsi_dev->name); return 1; } - if (!strncmp(&buffer[VENDOR_LENGTH], vendor->value, + if (!strncmp((char *)&buffer[VENDOR_LENGTH], vendor->value, VENDOR_LENGTH)) { log_message(LOG_WARNING, "%s: invalid page0 data\n", scsi_dev->name); @@ -464,8 +470,9 @@ static int prepend_vendor_model(struct sysfs_device *scsi_dev, char *serial) * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill * serial number. **/ -static int check_fill_0x83_id(struct sysfs_device *scsi_dev, char - *page_83, const struct scsi_id_search_values +static int check_fill_0x83_id(struct sysfs_device *scsi_dev, + unsigned char *page_83, + const struct scsi_id_search_values *id_search, char *serial, int max_len) { int i, j, len; @@ -560,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; @@ -609,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) @@ -620,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; @@ -667,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; @@ -675,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; @@ -683,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); @@ -706,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)) { /* @@ -717,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)) { /*