Use scsi_vpd_lun_id() to assign a unique device identification
to the alua port group structure.
Signed-off-by: Hannes Reinecke
---
drivers/scsi/device_handler/scsi_dh_alua.c | 64 --
1 file changed, 61 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c
b/drivers/scsi/device_handler/scsi_dh_alua.c
index ca6322d..688e0f7 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -70,6 +70,8 @@ static DEFINE_SPINLOCK(port_group_lock);
struct alua_port_group {
struct kref kref;
struct list_headnode;
+ unsigned char device_id_str[256];
+ int device_id_len;
int group_id;
int tpgs;
int state;
@@ -162,6 +164,25 @@ static int submit_stpg(struct scsi_device *sdev, int
group_id,
ALUA_FAILOVER_RETRIES, NULL, req_flags);
}
+struct alua_port_group *alua_lookup_pg(char *id_str, size_t id_size,
+ int group_id)
+{
+ struct alua_port_group *pg = NULL;
+
+ list_for_each_entry(pg, &port_group_list, node) {
+ if (pg->group_id != group_id)
+ continue;
+ if (pg->device_id_len != id_size)
+ continue;
+ if (strncmp(pg->device_id_str, id_str, id_size))
+ continue;
+ kref_get(&pg->kref);
+ return pg;
+ }
+
+ return NULL;
+}
+
/*
* alua_get_pg - Allocate a new port_group structure
* @sdev: scsi device
@@ -172,19 +193,37 @@ static int submit_stpg(struct scsi_device *sdev, int
group_id,
* device.
*/
struct alua_port_group *alua_get_pg(struct scsi_device *sdev,
- int group_id, int tpgs)
+ int group_id, int tpgs,
+ char *id_str, size_t id_size)
{
- struct alua_port_group *pg = NULL;
+ struct alua_port_group *pg = NULL, *tmp_pg;
+
+ spin_lock(&port_group_lock);
+ pg = alua_lookup_pg(id_str, id_size, group_id);
+ spin_unlock(&port_group_lock);
+ if (pg)
+ return pg;
pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
if (!pg)
return NULL;
+ strncpy(pg->device_id_str, id_str, sizeof(pg->device_id_str));
+
+ pg->device_id_len = id_size;
pg->group_id = group_id;
pg->tpgs = tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
kref_init(&pg->kref);
+
+ /* Re-check list again to catch concurrent updates */
spin_lock(&port_group_lock);
+ tmp_pg = alua_lookup_pg(id_str, id_size, group_id);
+ if (tmp_pg) {
+ spin_unlock(&port_group_lock);
+ kfree(pg);
+ return tmp_pg;
+ }
list_add(&pg->node, &port_group_list);
spin_unlock(&port_group_lock);
@@ -592,6 +631,8 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct
alua_port_group *pg)
static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
{
int err = SCSI_DH_DEV_UNSUPP, tpgs;
+ char device_id_str[256];
+ int device_id_len;
tpgs = alua_check_tpgs(sdev);
if (tpgs == TPGS_MODE_NONE)
@@ -601,7 +642,24 @@ static int alua_initialize(struct scsi_device *sdev,
struct alua_dh_data *h)
if (err != SCSI_DH_OK)
goto out;
- h->pg = alua_get_pg(sdev, h->group_id, tpgs);
+ device_id_len = scsi_vpd_lun_id(sdev, device_id_str,
+ sizeof(device_id_str));
+ if (device_id_len <= 0) {
+ /*
+* Internal error: TPGS supported but no device
+* identifcation found. Disable ALUA support.
+*/
+ sdev_printk(KERN_INFO, sdev,
+ "%s: No device descriptors found\n",
+ ALUA_DH_NAME);
+ goto out;
+ }
+ sdev_printk(KERN_INFO, sdev,
+ "%s: device %s port group %02x rel port %02x\n",
+ ALUA_DH_NAME, device_id_str, h->group_id, h->rel_port);
+
+ h->pg = alua_get_pg(sdev, h->group_id, tpgs,
+ device_id_str, device_id_len);
if (!h->pg) {
err = SCSI_DH_NOMEM;
goto out;
--
1.8.5.6
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html