Commit 96fc248a authored by Bart Van Assche's avatar Bart Van Assche Committed by Roland Dreier

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: default avatarBart Van Assche <bvanassche@acm.org>
Signed-off-by: default avatarSebastian Riemer <sebastian.riemer@profitbricks.com>
Acked-by: default avatarDavid Dillow <dillowda@ornl.gov>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent 99e1c139
...@@ -542,11 +542,11 @@ static void srp_remove_work(struct work_struct *work) ...@@ -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 = { ...@@ -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, ...@@ -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");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment