#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 */
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;
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 };
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;
/* 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;
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);
* 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;
return 0;
}
+/* Extract the raw binary from VPD 0x83 pre-SPC devices */
+static int check_fill_0x83_prespc3(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;
+
+ serial[0] = hex_str[id_search->id_type];
+ /* serial has been memset to zero before */
+ j = strlen(serial); /* j = 1; */
+
+ for (i = 0; i < page_83[3]; ++i) {
+ serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4];
+ serial[j++] = hex_str[ page_83[4+i] & 0x0f];
+ }
+ dprintf("using pre-spc3-83 for %s.\n", scsi_dev->name);
+ return 0;
+}
+
+
/* Get device identification VPD page */
static int do_scsi_page83_inquiry(struct sysfs_device *scsi_dev, int fd,
char *serial, int len)
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;
* the form: "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 check_fill_0x83_prespc3(scsi_dev, page_83,
+ id_search_list, serial, len);
+
/*
* Search for a match in the prioritized id_search_list.
*/
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)
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;
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;
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;
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);
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)) {
/*
}
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)) {
/*