2010-07-07 11:12:45 +00:00
|
|
|
Subject: Add TGPS setting to scsi devices
|
|
|
|
From: Hannes Reinecke <hare@suse.de>
|
|
|
|
Patch-mainline: Not yet
|
|
|
|
|
|
|
|
Some multipath-capable storage arrays are capable of running
|
|
|
|
in compatible mode, ie supporting both the original vendor-specific
|
|
|
|
failover mode and the SPC-3 compliant ALUA mode.
|
|
|
|
This patch stores the TGPS setting in the sdev so that we can directly
|
|
|
|
match onto it and select the correct device handler automatically.
|
|
|
|
And we can save code in the ALUA device handler.
|
|
|
|
|
|
|
|
Signed-off-by: Hannes Reinecke <hare@suse.de>
|
|
|
|
|
|
|
|
---
|
|
|
|
drivers/scsi/device_handler/scsi_dh.c | 9 ++-
|
|
|
|
drivers/scsi/device_handler/scsi_dh_alua.c | 70 +++-------------------------
|
|
|
|
drivers/scsi/device_handler/scsi_dh_emc.c | 8 +--
|
|
|
|
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 10 ++--
|
2011-04-19 20:09:59 +00:00
|
|
|
drivers/scsi/device_handler/scsi_dh_rdac.c | 58 +++++++++++------------
|
2010-07-07 11:12:45 +00:00
|
|
|
drivers/scsi/scsi_scan.c | 1
|
|
|
|
drivers/scsi/scsi_sysfs.c | 2
|
|
|
|
include/scsi/scsi_device.h | 4 +
|
2011-04-19 20:09:59 +00:00
|
|
|
8 files changed, 60 insertions(+), 102 deletions(-)
|
2010-07-07 11:12:45 +00:00
|
|
|
|
|
|
|
--- a/drivers/scsi/device_handler/scsi_dh.c
|
|
|
|
+++ b/drivers/scsi/device_handler/scsi_dh.c
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -29,6 +29,7 @@ struct scsi_dh_devinfo_list {
|
2010-07-07 11:12:45 +00:00
|
|
|
struct list_head node;
|
|
|
|
char vendor[9];
|
|
|
|
char model[17];
|
|
|
|
+ char tgps;
|
|
|
|
struct scsi_device_handler *handler;
|
|
|
|
};
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -61,7 +62,8 @@ scsi_dh_cache_lookup(struct scsi_device
|
2010-07-07 11:12:45 +00:00
|
|
|
spin_lock(&list_lock);
|
|
|
|
list_for_each_entry(tmp, &scsi_dh_dev_list, node) {
|
|
|
|
if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) &&
|
|
|
|
- !strncmp(sdev->model, tmp->model, strlen(tmp->model))) {
|
|
|
|
+ !strncmp(sdev->model, tmp->model, strlen(tmp->model)) &&
|
|
|
|
+ (!tmp->tgps || (sdev->tgps & tmp->tgps) != 0)) {
|
|
|
|
found_dh = tmp->handler;
|
|
|
|
break;
|
|
|
|
}
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -80,7 +82,9 @@ static int scsi_dh_handler_lookup(struct
|
2010-07-07 11:12:45 +00:00
|
|
|
if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor,
|
|
|
|
strlen(scsi_dh->devlist[i].vendor)) &&
|
|
|
|
!strncmp(sdev->model, scsi_dh->devlist[i].model,
|
|
|
|
- strlen(scsi_dh->devlist[i].model))) {
|
|
|
|
+ strlen(scsi_dh->devlist[i].model)) &&
|
|
|
|
+ (!scsi_dh->devlist[i].tgps ||
|
|
|
|
+ (sdev->tgps & scsi_dh->devlist[i].tgps) != 0)) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -129,6 +133,7 @@ device_handler_match(struct scsi_device_
|
2010-07-07 11:12:45 +00:00
|
|
|
strncpy(tmp->model, sdev->model, 16);
|
|
|
|
tmp->vendor[8] = '\0';
|
|
|
|
tmp->model[16] = '\0';
|
|
|
|
+ tmp->tgps = sdev->tgps;
|
|
|
|
tmp->handler = found_dh;
|
|
|
|
spin_lock(&list_lock);
|
|
|
|
list_add(&tmp->node, &scsi_dh_dev_list);
|
|
|
|
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
|
|
|
|
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -125,43 +125,6 @@ static struct request *get_alua_req(stru
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
- * 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
|
|
|
|
*/
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -333,23 +296,19 @@ static unsigned submit_stpg(struct alua_
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
- * alua_std_inquiry - Evaluate standard INQUIRY command
|
|
|
|
+ * alua_check_tgps - Evaluate TGPS 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_tgps(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 = sdev->tgps;
|
|
|
|
+
|
|
|
|
switch (h->tpgs) {
|
|
|
|
case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
|
|
|
|
sdev_printk(KERN_INFO, sdev,
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -611,7 +570,7 @@ static int alua_initialize(struct scsi_d
|
2010-07-07 11:12:45 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
- err = alua_std_inquiry(sdev, h);
|
|
|
|
+ err = alua_check_tgps(sdev, h);
|
|
|
|
if (err != SCSI_DH_OK)
|
|
|
|
goto out;
|
|
|
|
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -685,19 +644,8 @@ static int alua_prep_fn(struct scsi_devi
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct scsi_dh_devlist alua_dev_list[] = {
|
|
|
|
- {"HP", "MSA VOLUME" },
|
|
|
|
- {"HP", "HSV101" },
|
|
|
|
- {"HP", "HSV111" },
|
|
|
|
- {"HP", "HSV200" },
|
|
|
|
- {"HP", "HSV210" },
|
|
|
|
- {"HP", "HSV300" },
|
|
|
|
- {"IBM", "2107900" },
|
|
|
|
- {"IBM", "2145" },
|
|
|
|
- {"Pillar", "Axiom" },
|
|
|
|
- {"Intel", "Multi-Flex"},
|
|
|
|
- {"NETAPP", "LUN"},
|
|
|
|
- {"AIX", "NVDISK"},
|
|
|
|
- {NULL, NULL}
|
|
|
|
+ {"", "", 3 },
|
|
|
|
+ {NULL, NULL, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int alua_bus_attach(struct scsi_device *sdev);
|
|
|
|
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
|
|
|
|
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -622,10 +622,10 @@ done:
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct scsi_dh_devlist clariion_dev_list[] = {
|
|
|
|
- {"DGC", "RAID"},
|
|
|
|
- {"DGC", "DISK"},
|
|
|
|
- {"DGC", "VRAID"},
|
|
|
|
- {NULL, NULL},
|
|
|
|
+ {"DGC", "RAID", 0},
|
|
|
|
+ {"DGC", "DISK", 0},
|
|
|
|
+ {"DGC", "VRAID", 0},
|
|
|
|
+ {NULL, NULL, 0},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int clariion_bus_attach(struct scsi_device *sdev);
|
|
|
|
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
|
|
|
|
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -311,11 +311,11 @@ static int hp_sw_activate(struct scsi_de
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
|
|
|
|
- {"COMPAQ", "MSA1000 VOLUME"},
|
|
|
|
- {"COMPAQ", "HSV110"},
|
|
|
|
- {"HP", "HSV100"},
|
|
|
|
- {"DEC", "HSG80"},
|
|
|
|
- {NULL, NULL},
|
|
|
|
+ {"COMPAQ", "MSA1000 VOLUME", 0},
|
|
|
|
+ {"COMPAQ", "HSV110", 0},
|
|
|
|
+ {"HP", "HSV100", 0},
|
|
|
|
+ {"DEC", "HSG80", 0},
|
|
|
|
+ {NULL, NULL, 0},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int hp_sw_bus_attach(struct scsi_device *sdev);
|
|
|
|
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
|
|
|
|
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -745,37 +745,37 @@ static int rdac_check_sense(struct scsi_
|
2010-07-07 11:12:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct scsi_dh_devlist rdac_dev_list[] = {
|
|
|
|
- {"IBM", "1722"},
|
|
|
|
- {"IBM", "1724"},
|
|
|
|
- {"IBM", "1726"},
|
|
|
|
- {"IBM", "1742"},
|
|
|
|
- {"IBM", "1745"},
|
|
|
|
- {"IBM", "1746"},
|
|
|
|
- {"IBM", "1814"},
|
|
|
|
- {"IBM", "1815"},
|
|
|
|
- {"IBM", "1818"},
|
|
|
|
- {"IBM", "3526"},
|
|
|
|
- {"SGI", "TP9400"},
|
|
|
|
- {"SGI", "TP9500"},
|
|
|
|
- {"SGI", "IS"},
|
|
|
|
- {"STK", "OPENstorage D280"},
|
|
|
|
- {"SUN", "CSM200_R"},
|
|
|
|
- {"SUN", "LCSM100_I"},
|
|
|
|
- {"SUN", "LCSM100_S"},
|
|
|
|
- {"SUN", "LCSM100_E"},
|
|
|
|
- {"SUN", "LCSM100_F"},
|
|
|
|
- {"DELL", "MD3000"},
|
|
|
|
- {"DELL", "MD3000i"},
|
|
|
|
- {"DELL", "MD32xx"},
|
|
|
|
- {"DELL", "MD32xxi"},
|
2011-04-19 20:09:59 +00:00
|
|
|
- {"DELL", "MD36xxi"},
|
2010-07-07 11:12:45 +00:00
|
|
|
- {"LSI", "INF-01-00"},
|
|
|
|
- {"ENGENIO", "INF-01-00"},
|
|
|
|
- {"STK", "FLEXLINE 380"},
|
|
|
|
- {"SUN", "CSM100_R_FC"},
|
2011-04-19 20:09:59 +00:00
|
|
|
- {"SUN", "STK6580_6780"},
|
|
|
|
- {"SUN", "SUN_6180"},
|
2010-07-07 11:12:45 +00:00
|
|
|
- {NULL, NULL},
|
|
|
|
+ {"IBM", "1722", 0},
|
|
|
|
+ {"IBM", "1724", 0},
|
|
|
|
+ {"IBM", "1726", 0},
|
|
|
|
+ {"IBM", "1742", 0},
|
|
|
|
+ {"IBM", "1745", 0},
|
|
|
|
+ {"IBM", "1746", 0},
|
|
|
|
+ {"IBM", "1814", 0},
|
|
|
|
+ {"IBM", "1815", 0},
|
|
|
|
+ {"IBM", "1818", 0},
|
|
|
|
+ {"IBM", "3526", 0},
|
|
|
|
+ {"SGI", "TP9400", 0},
|
|
|
|
+ {"SGI", "TP9500", 0},
|
|
|
|
+ {"SGI", "IS", 0},
|
|
|
|
+ {"STK", "OPENstorage D280", 0},
|
|
|
|
+ {"SUN", "CSM200_R", 0},
|
|
|
|
+ {"SUN", "LCSM100_I", 0},
|
|
|
|
+ {"SUN", "LCSM100_S", 0},
|
|
|
|
+ {"SUN", "LCSM100_E", 0},
|
|
|
|
+ {"SUN", "LCSM100_F", 0},
|
|
|
|
+ {"DELL", "MD3000", 0},
|
|
|
|
+ {"DELL", "MD3000i", 0},
|
|
|
|
+ {"DELL", "MD32xx", 0},
|
|
|
|
+ {"DELL", "MD32xxi", 0},
|
2011-04-19 20:09:59 +00:00
|
|
|
+ {"DELL", "MD36xxi", 0},
|
2010-07-07 11:12:45 +00:00
|
|
|
+ {"LSI", "INF-01-00", 0},
|
|
|
|
+ {"ENGENIO", "INF-01-00", 0},
|
|
|
|
+ {"STK", "FLEXLINE 380", 0},
|
|
|
|
+ {"SUN", "CSM100_R_FC", 0},
|
2011-04-19 20:09:59 +00:00
|
|
|
+ {"SUN", "STK6580_6780", 0},
|
|
|
|
+ {"SUN", "SUN_6180", 0},
|
2010-07-07 11:12:45 +00:00
|
|
|
+ {NULL, NULL, 0},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int rdac_bus_attach(struct scsi_device *sdev);
|
|
|
|
--- a/drivers/scsi/scsi_scan.c
|
|
|
|
+++ b/drivers/scsi/scsi_scan.c
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -838,6 +838,7 @@ static int scsi_add_lun(struct scsi_devi
|
2010-07-07 11:12:45 +00:00
|
|
|
sdev->inq_periph_qual = (inq_result[0] >> 5) & 7;
|
|
|
|
sdev->lockable = sdev->removable;
|
|
|
|
sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
|
|
|
|
+ sdev->tgps = (inq_result[5] >> 4) & 3;
|
|
|
|
|
|
|
|
if (sdev->scsi_level >= SCSI_3 ||
|
|
|
|
(sdev->inquiry_len > 56 && inq_result[56] & 0x04))
|
|
|
|
--- a/drivers/scsi/scsi_sysfs.c
|
|
|
|
+++ b/drivers/scsi/scsi_sysfs.c
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -501,6 +501,7 @@ sdev_rd_attr (scsi_level, "%d\n");
|
2010-07-07 11:12:45 +00:00
|
|
|
sdev_rd_attr (vendor, "%.8s\n");
|
|
|
|
sdev_rd_attr (model, "%.16s\n");
|
|
|
|
sdev_rd_attr (rev, "%.4s\n");
|
|
|
|
+sdev_rd_attr (tgps, "%d\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: can we make these symlinks to the block layer ones?
|
2011-04-19 20:09:59 +00:00
|
|
|
@@ -686,6 +687,7 @@ static struct attribute *scsi_sdev_attrs
|
2010-07-07 11:12:45 +00:00
|
|
|
&dev_attr_vendor.attr,
|
|
|
|
&dev_attr_model.attr,
|
|
|
|
&dev_attr_rev.attr,
|
|
|
|
+ &dev_attr_tgps.attr,
|
|
|
|
&dev_attr_rescan.attr,
|
|
|
|
&dev_attr_delete.attr,
|
|
|
|
&dev_attr_state.attr,
|
|
|
|
--- a/include/scsi/scsi_device.h
|
|
|
|
+++ b/include/scsi/scsi_device.h
|
|
|
|
@@ -99,7 +99,8 @@ struct scsi_device {
|
|
|
|
void *hostdata; /* available to low-level driver */
|
|
|
|
char type;
|
|
|
|
char scsi_level;
|
|
|
|
- char inq_periph_qual; /* PQ from INQUIRY data */
|
|
|
|
+ char inq_periph_qual; /* PQ from INQUIRY data */
|
|
|
|
+ char tgps; /* Target port group support */
|
|
|
|
unsigned char inquiry_len; /* valid bytes in 'inquiry' */
|
|
|
|
unsigned char * inquiry; /* INQUIRY response data */
|
|
|
|
const char * vendor; /* [back_compat] point into 'inquiry' ... */
|
|
|
|
@@ -176,6 +177,7 @@ struct scsi_device {
|
|
|
|
struct scsi_dh_devlist {
|
|
|
|
char *vendor;
|
|
|
|
char *model;
|
|
|
|
+ char tgps;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef void (*activate_complete)(void *, int);
|