commit 08a140c02f9010f356e5b18dc7b7652cc15fc79d Author: Hannes Reinecke Date: Fri Sep 26 15:31:07 2008 +0200 multipath: Check return value for get_inq() Check the return value of get_inq() to correctly handle devices with unconnected LUNs. References: 419123 Signed-off-by: Hannes Reinecke diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index dd45e03..e1a67ac 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -275,7 +275,7 @@ devt2devname (char *devname, char *devt) int do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, - void *resp, int mx_resp_len, int noisy) + void *resp, int mx_resp_len) { unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 0, 0, 0, 0, 0 }; @@ -334,7 +334,7 @@ get_serial (char * str, int maxlen, int fd) if (fd < 0) return 1; - if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) { + if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN)) { len = buff[3]; if (len >= maxlen) return 1; @@ -348,26 +348,69 @@ get_serial (char * str, int maxlen, int fd) } static int -get_inq (char * vendor, char * product, char * rev, int fd) +get_inq (char * dev, char * vendor, char * product, char * rev, int fd) { - char buff[MX_ALLOC_LEN + 1] = {0}; + unsigned char buff[MX_ALLOC_LEN + 1] = {0}; + int len; if (fd < 0) return 1; - if (0 == do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN, 0)) { - memcpy(vendor, buff + 8, 8); - vendor[8] = '\0'; - strchop(vendor); - memcpy(product, buff + 16, 16); - product[16] = '\0'; - strchop(product); - memcpy(rev, buff + 32, 4); - rev[4] = '\0'; - strchop(rev); - return 0; + if (0 != do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN)) + return 1; + + /* Check peripheral qualifier */ + if ((buff[0] >> 5) != 0) { + int pqual = (buff[0] >> 5); + switch (pqual) { + case 1: + condlog(3, "%s: INQUIRY failed, LU not connected", dev); + break; + case 3: + condlog(3, "%s: INQUIRY failed, LU not supported", dev); + break; + default: + condlog(3, "%s: INQUIRY failed, Invalid PQ %x", + dev, pqual); + break; + } + + return 1; } - return 1; + + len = buff[4] + 4; + + if (len < 8) { + condlog(3, "%s: INQUIRY response too short (len %d)", + dev, len); + return 1; + } + + len -= 8; + memset(vendor, 0x0, 8); + memcpy(vendor, buff + 8, len > 8 ? 8 : len); + vendor[8] = '\0'; + strchop(vendor); + if (len <= 8) + return 0; + + len -= 8; + + memset(product, 0x0, 16); + memcpy(product, buff + 16, len > 16 ? 16 : len); + product[16] = '\0'; + strchop(product); + if (len <= 16) + return 0; + + len -= 16; + + memset(rev, 0x0, 4); + memcpy(rev, buff + 32, 4); + rev[4] = '\0'; + strchop(rev); + + return 0; } static int @@ -549,13 +592,16 @@ sysfs_pathinfo(struct path * pp) if (!strncmp(parent->kernel, "block",5)) parent = sysfs_device_get_parent(parent); + if (!strncmp(pp->dev,"cciss",5)) + strcpy(parent->subsystem,"cciss"); + condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem); if (!strncmp(parent->subsystem, "scsi",4)) pp->bus = SYSFS_BUS_SCSI; if (!strncmp(parent->subsystem, "ccw",3)) pp->bus = SYSFS_BUS_CCW; - if (!strncmp(pp->dev,"cciss",5)) + if (!strncmp(parent->subsystem,"cciss",5)) pp->bus = SYSFS_BUS_CCISS; if (pp->bus == SYSFS_BUS_UNDEF) @@ -587,8 +633,14 @@ scsi_ioctl_pathinfo (struct path * pp, int mask) static int cciss_ioctl_pathinfo (struct path * pp, int mask) { + int ret; + if (mask & DI_SYSFS) { - get_inq(pp->vendor_id, pp->product_id, pp->rev, pp->fd); + ret = get_inq(pp->dev, pp->vendor_id, pp->product_id, + pp->rev, pp->fd); + if (ret) + return ret; + condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); condlog(3, "%s: product = %s", pp->dev, pp->product_id); condlog(3, "%s: revision = %s", pp->dev, pp->rev);