diff options
author | Bart Van Assche <bvanassche@acm.org> | 2013-06-28 08:51:26 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2013-07-01 13:40:07 -0400 |
commit | 96fc248a4c6fe1e5ffac4903b39d2dd5cbe2dc9a (patch) | |
tree | 53f84bcd15b51bfc415f9b74331753eb1850bdeb /drivers/infiniband/ulp/srp | |
parent | 99e1c1398f44a056b16e78122133988c82b66d97 (diff) |
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>
Diffstat (limited to 'drivers/infiniband/ulp/srp')
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 1f331011653e..830ef0037087 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c | |||
@@ -542,11 +542,11 @@ static void srp_remove_work(struct work_struct *work) | |||
542 | 542 | ||
543 | WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); | 543 | WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); |
544 | 544 | ||
545 | srp_remove_target(target); | ||
546 | |||
545 | spin_lock(&target->srp_host->target_lock); | 547 | spin_lock(&target->srp_host->target_lock); |
546 | list_del(&target->list); | 548 | list_del(&target->list); |
547 | spin_unlock(&target->srp_host->target_lock); | 549 | spin_unlock(&target->srp_host->target_lock); |
548 | |||
549 | srp_remove_target(target); | ||
550 | } | 550 | } |
551 | 551 | ||
552 | static void srp_rport_delete(struct srp_rport *rport) | 552 | static void srp_rport_delete(struct srp_rport *rport) |
@@ -2009,6 +2009,36 @@ static struct class srp_class = { | |||
2009 | .dev_release = srp_release_dev | 2009 | .dev_release = srp_release_dev |
2010 | }; | 2010 | }; |
2011 | 2011 | ||
2012 | /** | ||
2013 | * srp_conn_unique() - check whether the connection to a target is unique | ||
2014 | */ | ||
2015 | static bool srp_conn_unique(struct srp_host *host, | ||
2016 | struct srp_target_port *target) | ||
2017 | { | ||
2018 | struct srp_target_port *t; | ||
2019 | bool ret = false; | ||
2020 | |||
2021 | if (target->state == SRP_TARGET_REMOVED) | ||
2022 | goto out; | ||
2023 | |||
2024 | ret = true; | ||
2025 | |||
2026 | spin_lock(&host->target_lock); | ||
2027 | list_for_each_entry(t, &host->target_list, list) { | ||
2028 | if (t != target && | ||
2029 | target->id_ext == t->id_ext && | ||
2030 | target->ioc_guid == t->ioc_guid && | ||
2031 | target->initiator_ext == t->initiator_ext) { | ||
2032 | ret = false; | ||
2033 | break; | ||
2034 | } | ||
2035 | } | ||
2036 | spin_unlock(&host->target_lock); | ||
2037 | |||
2038 | out: | ||
2039 | return ret; | ||
2040 | } | ||
2041 | |||
2012 | /* | 2042 | /* |
2013 | * Target ports are added by writing | 2043 | * Target ports are added by writing |
2014 | * | 2044 | * |
@@ -2265,6 +2295,16 @@ static ssize_t srp_create_target(struct device *dev, | |||
2265 | if (ret) | 2295 | if (ret) |
2266 | goto err; | 2296 | goto err; |
2267 | 2297 | ||
2298 | if (!srp_conn_unique(target->srp_host, target)) { | ||
2299 | shost_printk(KERN_INFO, target->scsi_host, | ||
2300 | PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n", | ||
2301 | be64_to_cpu(target->id_ext), | ||
2302 | be64_to_cpu(target->ioc_guid), | ||
2303 | be64_to_cpu(target->initiator_ext)); | ||
2304 | ret = -EEXIST; | ||
2305 | goto err; | ||
2306 | } | ||
2307 | |||
2268 | if (!host->srp_dev->fmr_pool && !target->allow_ext_sg && | 2308 | if (!host->srp_dev->fmr_pool && !target->allow_ext_sg && |
2269 | target->cmd_sg_cnt < target->sg_tablesize) { | 2309 | target->cmd_sg_cnt < target->sg_tablesize) { |
2270 | pr_warn("No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); | 2310 | pr_warn("No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); |