IB/srp: Maintain a single connection per I_T nexus
An SRP target is required to maintain a single connection between initiator and target. This means that if the 'add_target' attribute is used to create a second connection to a target, the first connection will be logged out and that the SCSI error handler will kick in. The SCSI error handler will cause the SRP initiator to reconnect, which will cause I/O over the second connection to fail. Avoid such ping-pong behavior by disabling relogins. If reconnecting manually is necessary, that is possible by deleting and recreating an rport via sysfs. Signed-off-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Sebastian Riemer <sebastian.riemer@profitbricks.com> Acked-by: David Dillow <dillowda@ornl.gov> Signed-off-by: Roland Dreier <roland@purestorage.com>
This commit is contained in:
parent
99e1c1398f
commit
96fc248a4c
|
@ -542,11 +542,11 @@ static void srp_remove_work(struct work_struct *work)
|
||||||
|
|
||||||
WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
|
WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
|
||||||
|
|
||||||
|
srp_remove_target(target);
|
||||||
|
|
||||||
spin_lock(&target->srp_host->target_lock);
|
spin_lock(&target->srp_host->target_lock);
|
||||||
list_del(&target->list);
|
list_del(&target->list);
|
||||||
spin_unlock(&target->srp_host->target_lock);
|
spin_unlock(&target->srp_host->target_lock);
|
||||||
|
|
||||||
srp_remove_target(target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void srp_rport_delete(struct srp_rport *rport)
|
static void srp_rport_delete(struct srp_rport *rport)
|
||||||
|
@ -2009,6 +2009,36 @@ static struct class srp_class = {
|
||||||
.dev_release = srp_release_dev
|
.dev_release = srp_release_dev
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* srp_conn_unique() - check whether the connection to a target is unique
|
||||||
|
*/
|
||||||
|
static bool srp_conn_unique(struct srp_host *host,
|
||||||
|
struct srp_target_port *target)
|
||||||
|
{
|
||||||
|
struct srp_target_port *t;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (target->state == SRP_TARGET_REMOVED)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
spin_lock(&host->target_lock);
|
||||||
|
list_for_each_entry(t, &host->target_list, list) {
|
||||||
|
if (t != target &&
|
||||||
|
target->id_ext == t->id_ext &&
|
||||||
|
target->ioc_guid == t->ioc_guid &&
|
||||||
|
target->initiator_ext == t->initiator_ext) {
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&host->target_lock);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Target ports are added by writing
|
* Target ports are added by writing
|
||||||
*
|
*
|
||||||
|
@ -2265,6 +2295,16 @@ static ssize_t srp_create_target(struct device *dev,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
if (!srp_conn_unique(target->srp_host, target)) {
|
||||||
|
shost_printk(KERN_INFO, target->scsi_host,
|
||||||
|
PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n",
|
||||||
|
be64_to_cpu(target->id_ext),
|
||||||
|
be64_to_cpu(target->ioc_guid),
|
||||||
|
be64_to_cpu(target->initiator_ext));
|
||||||
|
ret = -EEXIST;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
if (!host->srp_dev->fmr_pool && !target->allow_ext_sg &&
|
if (!host->srp_dev->fmr_pool && !target->allow_ext_sg &&
|
||||||
target->cmd_sg_cnt < target->sg_tablesize) {
|
target->cmd_sg_cnt < target->sg_tablesize) {
|
||||||
pr_warn("No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n");
|
pr_warn("No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n");
|
||||||
|
|
Loading…
Reference in New Issue