scsi_dh_alua: use unique device id

Use scsi_vpd_lun_id() to assign a unique device identification
to the alua port group structure.

Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Hannes Reinecke 2016-02-19 09:17:05 +01:00 committed by Martin K. Petersen
parent 43394c67f8
commit 0047220c6c

View file

@ -70,6 +70,8 @@ static DEFINE_SPINLOCK(port_group_lock);
struct alua_port_group { struct alua_port_group {
struct kref kref; struct kref kref;
struct list_head node; struct list_head node;
unsigned char device_id_str[256];
int device_id_len;
int group_id; int group_id;
int tpgs; int tpgs;
int state; int state;
@ -162,6 +164,26 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
ALUA_FAILOVER_RETRIES, NULL, req_flags); ALUA_FAILOVER_RETRIES, NULL, req_flags);
} }
struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size,
int group_id)
{
struct alua_port_group *pg;
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;
if (!kref_get_unless_zero(&pg->kref))
continue;
return pg;
}
return NULL;
}
/* /*
* alua_alloc_pg - Allocate a new port_group structure * alua_alloc_pg - Allocate a new port_group structure
* @sdev: scsi device * @sdev: scsi device
@ -174,17 +196,39 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev, struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
int group_id, int tpgs) int group_id, int tpgs)
{ {
struct alua_port_group *pg; struct alua_port_group *pg, *tmp_pg;
pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL); pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
if (!pg) if (!pg)
return NULL; return ERR_PTR(-ENOMEM);
pg->device_id_len = scsi_vpd_lun_id(sdev, pg->device_id_str,
sizeof(pg->device_id_str));
if (pg->device_id_len <= 0) {
/*
* Internal error: TPGS supported but no device
* identifcation found. Disable ALUA support.
*/
kfree(pg);
sdev_printk(KERN_INFO, sdev,
"%s: No device descriptors found\n",
ALUA_DH_NAME);
return ERR_PTR(-ENXIO);
}
pg->group_id = group_id; pg->group_id = group_id;
pg->tpgs = tpgs; pg->tpgs = tpgs;
pg->state = TPGS_STATE_OPTIMIZED; pg->state = TPGS_STATE_OPTIMIZED;
kref_init(&pg->kref); kref_init(&pg->kref);
spin_lock(&port_group_lock); spin_lock(&port_group_lock);
tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
group_id);
if (tmp_pg) {
spin_unlock(&port_group_lock);
kfree(pg);
return tmp_pg;
}
list_add(&pg->node, &port_group_list); list_add(&pg->node, &port_group_list);
spin_unlock(&port_group_lock); spin_unlock(&port_group_lock);
@ -269,7 +313,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
h->group_id = group_id; h->group_id = group_id;
sdev_printk(KERN_INFO, sdev, sdev_printk(KERN_INFO, sdev,
"%s: port group %02x rel port %02x\n", "%s: port group %x rel port %x\n",
ALUA_DH_NAME, h->group_id, h->rel_port); ALUA_DH_NAME, h->group_id, h->rel_port);
return 0; return 0;
@ -597,8 +641,9 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
goto out; goto out;
h->pg = alua_alloc_pg(sdev, h->group_id, tpgs); h->pg = alua_alloc_pg(sdev, h->group_id, tpgs);
if (!h->pg) { if (IS_ERR(h->pg)) {
err = SCSI_DH_NOMEM; if (PTR_ERR(h->pg) == -ENOMEM)
err = SCSI_DH_NOMEM;
goto out; goto out;
} }
kref_get(&h->pg->kref); kref_get(&h->pg->kref);