This patch is a modified version of a patch from Karandeep Chahal that was posted on May 29, 2012 on the linux-rdma mailing list (http://www.mail-archive.com/[email protected]/msg11796.html).
Cc: David Dillow <[email protected]> Cc: Roland Dreier <[email protected]> Cc: Karandeep Chahal <[email protected]> Signed-off-by: Bart Van Assche <[email protected]> --- drivers/infiniband/ulp/srp/ib_srp.c | 68 +++++++++++++++++++++++++++-------- drivers/infiniband/ulp/srp/ib_srp.h | 1 + 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 7ed0c26..91f86ea 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -451,13 +451,14 @@ static bool srp_change_state(struct srp_target_port *target, static bool srp_queue_remove_work(struct srp_target_port *target) { bool changed = false; + unsigned long flags; - spin_lock_irq(&target->lock); + spin_lock_irqsave(&target->lock, flags); if (target->state != SRP_TARGET_REMOVED) { target->state = SRP_TARGET_REMOVED; changed = true; } - spin_unlock_irq(&target->lock); + spin_unlock_irqrestore(&target->lock, flags); if (changed) queue_work(system_long_wq, &target->remove_work); @@ -630,9 +631,9 @@ static void srp_remove_work(struct work_struct *work) WARN_ON(target->state != SRP_TARGET_REMOVED); - spin_lock(&target->srp_host->target_lock); + spin_lock_irq(&target->srp_host->target_lock); list_del(&target->list); - spin_unlock(&target->srp_host->target_lock); + spin_unlock_irq(&target->srp_host->target_lock); srp_remove_target(target); } @@ -653,7 +654,7 @@ static bool srp_conn_unique(struct srp_host *host, struct srp_target_port *t; bool ret = true; - spin_lock(&host->target_lock); + spin_lock_irq(&host->target_lock); list_for_each_entry(t, &host->target_list, list) { if (t != target && target->id_ext == t->id_ext && @@ -663,7 +664,7 @@ static bool srp_conn_unique(struct srp_host *host, break; } } - spin_unlock(&host->target_lock); + spin_unlock_irq(&host->target_lock); return ret; } @@ -2487,9 +2488,9 @@ static ssize_t srp_create_target(struct device *dev, target->scsi_host_added = false; mutex_lock(&target->mutex); - spin_lock(&host->target_lock); + spin_lock_irq(&host->target_lock); list_add_tail(&target->list, &host->target_list); - spin_unlock(&host->target_lock); + spin_unlock_irq(&host->target_lock); if (!srp_change_state(target, SRP_TARGET_CONNECTING, SRP_TARGET_LIVE)) { ret = -ENOENT; @@ -2600,13 +2601,48 @@ free_host: return NULL; } +static void srp_host_remove_all(struct srp_host *host) +{ + struct srp_target_port *target; + unsigned long flags; + + spin_lock_irqsave(&host->target_lock, flags); + list_for_each_entry(target, &host->target_list, list) + srp_queue_remove_work(target); + spin_unlock_irqrestore(&host->target_lock, flags); +} + +static void srp_event_handler(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct srp_device *srp_dev = container_of(handler, struct srp_device, + event_handler); + u8 port; + struct srp_host *host; + + switch (event->event) { + case IB_EVENT_DEVICE_FATAL: + case IB_EVENT_PORT_ERR: + port = event->element.port_num; + pr_info("an error occurred on port %s-%d\n", srp_dev->dev->name, + port); + + list_for_each_entry(host, &srp_dev->dev_list, list) + if (host->port == port) + srp_host_remove_all(host); + break; + default: + break; + } +} + static void srp_add_one(struct ib_device *device) { struct srp_device *srp_dev; struct ib_device_attr *dev_attr; struct ib_fmr_pool_param fmr_param; struct srp_host *host; - int max_pages_per_fmr, fmr_page_shift, s, e, p; + int max_pages_per_fmr, fmr_page_shift, s, e, p, ret; dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); if (!dev_attr) @@ -2680,6 +2716,12 @@ static void srp_add_one(struct ib_device *device) list_add_tail(&host->list, &srp_dev->dev_list); } + INIT_IB_EVENT_HANDLER(&srp_dev->event_handler, device, + srp_event_handler); + ret = ib_register_event_handler(&srp_dev->event_handler); + if (ret) + pr_err("ib_register_event_handler() failed: %d", ret); + ib_set_client_data(device, &srp_client, srp_dev); goto free_attr; @@ -2698,10 +2740,11 @@ static void srp_remove_one(struct ib_device *device) { struct srp_device *srp_dev; struct srp_host *host, *tmp_host; - struct srp_target_port *target; srp_dev = ib_get_client_data(device, &srp_client); + ib_unregister_event_handler(&srp_dev->event_handler); + list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { device_unregister(&host->dev); /* @@ -2713,10 +2756,7 @@ static void srp_remove_one(struct ib_device *device) /* * Remove all target ports. */ - spin_lock(&host->target_lock); - list_for_each_entry(target, &host->target_list, list) - srp_queue_remove_work(target); - spin_unlock(&host->target_lock); + srp_host_remove_all(host); /* * Wait for target port removal tasks. diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 99485a3..f7841c8 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -107,6 +107,7 @@ struct srp_device { struct ib_pd *pd; struct ib_mr *mr; struct ib_fmr_pool *fmr_pool; + struct ib_event_handler event_handler; u64 fmr_page_mask; int fmr_page_size; int fmr_max_size; -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
