From abc8657987dd2f94bc31670b74e607c032b0a11f Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 9 May 2011 16:04:05 -0400
Subject: [PATCH 5/6] Evaluate TGPS setting for device handler detection

For correct ALUA support we should evaluate the TPGS setting
of the device and only attach the alua device handler to it
if not zero.
---
 drivers/scsi/device_handler/scsi_dh.c       |   25 ++++++++-
 drivers/scsi/device_handler/scsi_dh_alua.c  |   74 ++++-----------------------
 drivers/scsi/device_handler/scsi_dh_emc.c   |    8 ++--
 drivers/scsi/device_handler/scsi_dh_hp_sw.c |   10 ++--
 drivers/scsi/device_handler/scsi_dh_rdac.c  |   64 ++++++++++++------------
 drivers/scsi/scsi_sysfs.c                   |    7 ++-
 include/linux/mod_devicetable.h             |    6 ++
 include/scsi/scsi_device.h                  |    1 +
 scripts/mod/file2alias.c                    |    2 +
 9 files changed, 88 insertions(+), 109 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index c6770ad..af523af 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -74,10 +74,27 @@ device_handler_match(struct scsi_device_handler *scsi_dh,
 {
 	struct scsi_device_handler *found_dh = NULL;
 	int idx;
+	int tpgs = scsi_device_tpgs(sdev);
 
-	idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model,
-					  SCSI_DEVINFO_DH);
-	found_dh = get_device_handler_by_idx(idx);
+	/* If there are tpgs flags set, try ALUA as first among equals. */
+	if (tpgs) {
+		idx = scsi_get_device_flags_keyed(sdev, "linux", "alua",
+						  SCSI_DEVINFO_DH);
+		found_dh = get_device_handler_by_idx(idx);
+		/*
+		 * If ALUA claims not to support the tpgs this device needs,
+		 * treat it as any other device.  Currently this is a formality
+		 * only, since ALUA supports all nonzero TPGS values.
+		 */
+		if ((tpgs & found_dh->tpgs) == 0)
+			found_dh = NULL;
+	}
+
+	if (!found_dh) {
+		idx = scsi_get_device_flags_keyed(sdev, sdev->vendor,
+						sdev->model, SCSI_DEVINFO_DH);
+		found_dh = get_device_handler_by_idx(idx);
+	}
 
 	if (scsi_dh && found_dh != scsi_dh)
 		found_dh = NULL;
@@ -327,6 +344,8 @@ static inline int scsi_dh_list_end(const struct scsi_dh_device_id *id)
 		return 0;
 	if (id->model[0] != '\0')
 		return 0;
+	if (id->tpgs != 0)
+		return 0;
 	return 1;
 }
 
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index b565db4..b6b3ec6 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -128,43 +128,6 @@ static struct request *get_alua_req(struct scsi_device *sdev,
 }
 
 /*
- * submit_std_inquiry - Issue a standard INQUIRY command
- * @sdev: sdev the command should be send to
- */
-static int submit_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
-{
-	struct request *rq;
-	int err = SCSI_DH_RES_TEMP_UNAVAIL;
-
-	rq = get_alua_req(sdev, h->inq, ALUA_INQUIRY_SIZE, READ);
-	if (!rq)
-		goto done;
-
-	/* Prepare the command. */
-	rq->cmd[0] = INQUIRY;
-	rq->cmd[1] = 0;
-	rq->cmd[2] = 0;
-	rq->cmd[4] = ALUA_INQUIRY_SIZE;
-	rq->cmd_len = COMMAND_SIZE(INQUIRY);
-
-	rq->sense = h->sense;
-	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-	rq->sense_len = h->senselen = 0;
-
-	err = blk_execute_rq(rq->q, NULL, rq, 1);
-	if (err == -EIO) {
-		sdev_printk(KERN_INFO, sdev,
-			    "%s: std inquiry failed with %x\n",
-			    ALUA_DH_NAME, rq->errors);
-		h->senselen = rq->sense_len;
-		err = SCSI_DH_IO;
-	}
-	blk_put_request(rq);
-done:
-	return err;
-}
-
-/*
  * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
  * @sdev: sdev the command should be sent to
  */
@@ -338,23 +301,19 @@ static unsigned submit_stpg(struct alua_dh_data *h)
 }
 
 /*
- * alua_std_inquiry - Evaluate standard INQUIRY command
+ * alua_check_tpgs - Evaluate TPGS setting
  * @sdev: device to be checked
  *
- * Just extract the TPGS setting to find out if ALUA
+ * Just examine the TPGS setting of the device to find out if ALUA
  * is supported.
  */
-static int alua_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
 {
-	int err;
-
-	err = submit_std_inquiry(sdev, h);
-
-	if (err != SCSI_DH_OK)
-		return err;
+	int err = SCSI_DH_OK;
 
 	/* Check TPGS setting */
-	h->tpgs = (h->inq[5] >> 4) & 0x3;
+	h->tpgs = scsi_device_tpgs(sdev);
+
 	switch (h->tpgs) {
 	case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
 		sdev_printk(KERN_INFO, sdev,
@@ -642,7 +601,7 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
 {
 	int err;
 
-	err = alua_std_inquiry(sdev, h);
+	err = alua_check_tpgs(sdev, h);
 	if (err != SCSI_DH_OK)
 		goto out;
 
@@ -721,21 +680,9 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
 }
 
 static const struct scsi_dh_device_id alua_dev_list[] = {
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "HP", "MSA VOLUME" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "HP", "HSV101" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "HP", "HSV111" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "HP", "HSV200" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "HP", "HSV210" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "HP", "HSV300" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "2107900" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "2145" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "Pillar", "Axiom" },
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "Intel", "Multi-Flex"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "NETAPP", "LUN"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "NETAPP", "LUN C-Mode"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "AIX", "NVDISK"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "Promise", "VTrak"},
-	{0, 0, "", ""}
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "linux", "alua",
+		SCSI_DH_ALUA_IMPLICIT|SCSI_DH_ALUA_EXPLICIT },
+	{0, 0, "", "", 0}
 };
 
 MODULE_DEVICE_TABLE(scsi_dh, alua_dev_list);
@@ -752,6 +699,7 @@ static struct scsi_device_handler alua_dh = {
 	.prep_fn = alua_prep_fn,
 	.check_sense = alua_check_sense,
 	.activate = alua_activate,
+	.tpgs = SCSI_DH_ALUA_IMPLICIT|SCSI_DH_ALUA_EXPLICIT,
 };
 
 /*
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index 913f254..27f31cf2 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -622,10 +622,10 @@ done:
 }
 
 static const struct scsi_dh_device_id clariion_dev_list[] = {
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DGC", "RAID"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DGC", "DISK"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DGC", "VRAID"},
-	{0, 0, "", ""},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DGC", "RAID", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DGC", "DISK", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DGC", "VRAID", SCSI_DH_ALUA_NONE},
+	{0, 0, "", "", 0},
 };
 
 MODULE_DEVICE_TABLE(scsi_dh, clariion_dev_list);
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index c8bdcdc..ba7be87 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -312,11 +312,11 @@ static int hp_sw_activate(struct scsi_device *sdev,
 }
 
 static const struct scsi_dh_device_id hp_sw_dh_data_list[] = {
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "COMPAQ", "MSA1000 VOLUME"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "COMPAQ", "HSV110"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "HP", "HSV100"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DEC", "HSG80"},
-	{0, 0, "", ""},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "COMPAQ", "MSA1000 VOLUME", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "COMPAQ", "HSV110", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "HP", "HSV100", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DEC", "HSG80", SCSI_DH_ALUA_NONE},
+	{0, 0, "", "", 0},
 };
 
 MODULE_DEVICE_TABLE(scsi_dh, hp_sw_dh_data_list);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 8053fad..3d738a5 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -783,38 +783,38 @@ static int rdac_check_sense(struct scsi_device *sdev,
 }
 
 static const struct scsi_dh_device_id rdac_dev_list[] = {
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1722"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1724"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1726"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1742"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1745"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1746"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1814"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1815"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1818"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "3526"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SGI", "TP9400"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SGI", "TP9500"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SGI", "IS"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "STK", "OPENstorage D280"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "CSM200_R"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "LCSM100_I"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "LCSM100_S"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "LCSM100_E"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "LCSM100_F"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD3000"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD3000i"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD32xx"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD32xxi"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD36xxi"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD36xxf"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "LSI", "INF-01-00"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "ENGENIO", "INF-01-00"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "STK", "FLEXLINE 380"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "CSM100_R_FC"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "STK6580_6780"},
-	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "SUN_6180"},
-	{0, 0, "", ""},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1722", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1724", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1726", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1742", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1745", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1746", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1814", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1815", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "1818", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "IBM", "3526", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SGI", "TP9400", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SGI", "TP9500", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SGI", "IS", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "STK", "OPENstorage D280", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "CSM200_R", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "LCSM100_I", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "LCSM100_S", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "LCSM100_E", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "LCSM100_F", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD3000", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD3000i", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD32xx", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD32xxi", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD36xxi", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "DELL", "MD36xxf", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "LSI", "INF-01-00", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "ENGENIO", "INF-01-00", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "STK", "FLEXLINE 380", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "CSM100_R_FC", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "STK6580_6780", SCSI_DH_ALUA_NONE},
+	{TYPE_DISK, SCSI_DEVICE_ANY_TYPE, "SUN", "SUN_6180", SCSI_DH_ALUA_NONE},
+	{0, 0, "", "", 0},
 };
 
 MODULE_DEVICE_TABLE(scsi_dh, rdac_dev_list);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index a61c784..4c1b8ad 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -370,6 +370,7 @@ static ssize_t format_scsi_modalias(struct scsi_device *sdev, char *buffer,
 	char model[17];
 	char *hex_model;
 	int i;
+	unsigned char tpgs = scsi_device_tpgs(sdev);
 
 	strncpy(vendor, sdev->vendor, 8);
 	vendor[8] = '\0';
@@ -395,8 +396,10 @@ static ssize_t format_scsi_modalias(struct scsi_device *sdev, char *buffer,
 		return -ENOMEM;
 	}
 
-	i = snprintf(buffer, len, "scsi:t-0x%02Xv%.16sm%.32s\n", sdev->type,
-		 hex_vendor, hex_model);
+	i = snprintf(buffer, len, "scsi:t-0x%02Xv%.16sm%.32sti%02Xte%02X\n",
+		     sdev->type, hex_vendor, hex_model,
+		     tpgs & SCSI_DH_ALUA_IMPLICIT,
+		     (tpgs & SCSI_DH_ALUA_EXPLICIT) >> 1);
 	kfree(hex_vendor);
 	kfree(hex_model);
 	return i;
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 57291e6..04ca98b 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -534,11 +534,17 @@ struct isapnp_device_id {
 };
 
 #define SCSI_DEVICE_ANY_TYPE 1
+
+#define SCSI_DH_ALUA_NONE	0
+#define SCSI_DH_ALUA_IMPLICIT	1
+#define SCSI_DH_ALUA_EXPLICIT	2
+
 struct scsi_dh_device_id {
 	unsigned char type;
 	unsigned char flags;
 	char vendor[9];
 	char model[17];
+	unsigned char tpgs;
 };
 
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index b23c705..8e22e06 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -193,6 +193,7 @@ struct scsi_device_handler {
 	int (*activate)(struct scsi_device *, activate_complete, void *);
 	int (*prep_fn)(struct scsi_device *, struct request *);
 	int (*set_params)(struct scsi_device *, const char *);
+	unsigned char tpgs;
 };
 
 struct scsi_dh_data {
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 9202cc0..8b7283c 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -887,6 +887,8 @@ static int do_scsi_entry(const char *filename,
 	}
 	ADD_HEX_STR(alias, "v", id->vendor[0] != '\0', id->vendor);
 	ADD_HEX_STR(alias, "m", id->model[0] != '\0', id->model);
+	ADD(alias, "ti", id->tpgs & SCSI_DH_ALUA_IMPLICIT, (char)1);
+	ADD(alias, "te", id->tpgs & SCSI_DH_ALUA_EXPLICIT, (char)1);
 
 	add_wildcard(alias);
 	return 1;
-- 
1.7.6.4

