multipath-tools/multipath-tools-check-get_inq-return-values

153 lines
3.8 KiB
Plaintext

commit 08a140c02f9010f356e5b18dc7b7652cc15fc79d
Author: Hannes Reinecke <hare@suse.de>
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 <hare@suse.de>
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);