aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorBart Van Assche <bvanassche@acm.org>2011-12-26 11:49:18 -0500
committerRoland Dreier <roland@purestorage.com>2012-11-30 20:40:31 -0500
commitef6c49d87c3418c442a22e55e3ce2f91b163d69e (patch)
treec1348935f77b750c3f82caa847db6c944aeb4961 /drivers/infiniband
parentee12d6a80cfcd08b862ed3c8e109442e466b0302 (diff)
IB/srp: Eliminate state SRP_TARGET_DEAD
Only queue removal work after having changed the target state into SRP_TARGET_REMOVED and not if that state was already equal to SRP_TARGET_REMOVED. That allows us to remove the state SRP_TARGET_DEAD. Add a call to srp_disconnect_target() in srp_remove_target() -- due to previous changes it is now safe to invoke that function even if the IB connection has already been disconnected. This change allows us to replace the target removal code in srp_remove_one() by an (indirect) call to srp_remove_target(). Rename srp_target_port.work into srp_target_port.remove_work to reflect its usage. Signed-off-by: Bart Van Assche <bvanassche@acm.org> Acked-by: David Dillow <dillowda@ornl.gov> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c83
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h5
2 files changed, 32 insertions, 56 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index beb68786001e..95590a38e88a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -428,6 +428,23 @@ static int srp_send_req(struct srp_target_port *target)
428 return status; 428 return status;
429} 429}
430 430
431static bool srp_queue_remove_work(struct srp_target_port *target)
432{
433 bool changed = false;
434
435 spin_lock_irq(&target->lock);
436 if (target->state != SRP_TARGET_REMOVED) {
437 target->state = SRP_TARGET_REMOVED;
438 changed = true;
439 }
440 spin_unlock_irq(&target->lock);
441
442 if (changed)
443 queue_work(system_long_wq, &target->remove_work);
444
445 return changed;
446}
447
431static bool srp_change_conn_state(struct srp_target_port *target, 448static bool srp_change_conn_state(struct srp_target_port *target,
432 bool connected) 449 bool connected)
433{ 450{
@@ -458,21 +475,6 @@ static void srp_disconnect_target(struct srp_target_port *target)
458 } 475 }
459} 476}
460 477
461static bool srp_change_state(struct srp_target_port *target,
462 enum srp_target_state old,
463 enum srp_target_state new)
464{
465 bool changed = false;
466
467 spin_lock_irq(&target->lock);
468 if (target->state == old) {
469 target->state = new;
470 changed = true;
471 }
472 spin_unlock_irq(&target->lock);
473 return changed;
474}
475
476static void srp_free_req_data(struct srp_target_port *target) 478static void srp_free_req_data(struct srp_target_port *target)
477{ 479{
478 struct ib_device *ibdev = target->srp_host->srp_dev->dev; 480 struct ib_device *ibdev = target->srp_host->srp_dev->dev;
@@ -508,9 +510,12 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost)
508 510
509static void srp_remove_target(struct srp_target_port *target) 511static void srp_remove_target(struct srp_target_port *target)
510{ 512{
513 WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
514
511 srp_del_scsi_host_attr(target->scsi_host); 515 srp_del_scsi_host_attr(target->scsi_host);
512 srp_remove_host(target->scsi_host); 516 srp_remove_host(target->scsi_host);
513 scsi_remove_host(target->scsi_host); 517 scsi_remove_host(target->scsi_host);
518 srp_disconnect_target(target);
514 ib_destroy_cm_id(target->cm_id); 519 ib_destroy_cm_id(target->cm_id);
515 srp_free_target_ib(target); 520 srp_free_target_ib(target);
516 srp_free_req_data(target); 521 srp_free_req_data(target);
@@ -520,10 +525,9 @@ static void srp_remove_target(struct srp_target_port *target)
520static void srp_remove_work(struct work_struct *work) 525static void srp_remove_work(struct work_struct *work)
521{ 526{
522 struct srp_target_port *target = 527 struct srp_target_port *target =
523 container_of(work, struct srp_target_port, work); 528 container_of(work, struct srp_target_port, remove_work);
524 529
525 if (!srp_change_state(target, SRP_TARGET_DEAD, SRP_TARGET_REMOVED)) 530 WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
526 return;
527 531
528 spin_lock(&target->srp_host->target_lock); 532 spin_lock(&target->srp_host->target_lock);
529 list_del(&target->list); 533 list_del(&target->list);
@@ -738,17 +742,8 @@ err:
738 * However, we have to defer the real removal because we 742 * However, we have to defer the real removal because we
739 * are in the context of the SCSI error handler now, which 743 * are in the context of the SCSI error handler now, which
740 * will deadlock if we call scsi_remove_host(). 744 * will deadlock if we call scsi_remove_host().
741 *
742 * Schedule our work inside the lock to avoid a race with
743 * the flush_scheduled_work() in srp_remove_one().
744 */ 745 */
745 spin_lock_irq(&target->lock); 746 srp_queue_remove_work(target);
746 if (target->state == SRP_TARGET_LIVE) {
747 target->state = SRP_TARGET_DEAD;
748 INIT_WORK(&target->work, srp_remove_work);
749 queue_work(ib_wq, &target->work);
750 }
751 spin_unlock_irq(&target->lock);
752 747
753 return ret; 748 return ret;
754} 749}
@@ -2258,6 +2253,7 @@ static ssize_t srp_create_target(struct device *dev,
2258 sizeof (struct srp_indirect_buf) + 2253 sizeof (struct srp_indirect_buf) +
2259 target->cmd_sg_cnt * sizeof (struct srp_direct_buf); 2254 target->cmd_sg_cnt * sizeof (struct srp_direct_buf);
2260 2255
2256 INIT_WORK(&target->remove_work, srp_remove_work);
2261 spin_lock_init(&target->lock); 2257 spin_lock_init(&target->lock);
2262 INIT_LIST_HEAD(&target->free_tx); 2258 INIT_LIST_HEAD(&target->free_tx);
2263 INIT_LIST_HEAD(&target->free_reqs); 2259 INIT_LIST_HEAD(&target->free_reqs);
@@ -2491,8 +2487,7 @@ static void srp_remove_one(struct ib_device *device)
2491{ 2487{
2492 struct srp_device *srp_dev; 2488 struct srp_device *srp_dev;
2493 struct srp_host *host, *tmp_host; 2489 struct srp_host *host, *tmp_host;
2494 LIST_HEAD(target_list); 2490 struct srp_target_port *target;
2495 struct srp_target_port *target, *tmp_target;
2496 2491
2497 srp_dev = ib_get_client_data(device, &srp_client); 2492 srp_dev = ib_get_client_data(device, &srp_client);
2498 2493
@@ -2505,35 +2500,17 @@ static void srp_remove_one(struct ib_device *device)
2505 wait_for_completion(&host->released); 2500 wait_for_completion(&host->released);
2506 2501
2507 /* 2502 /*
2508 * Mark all target ports as removed, so we stop queueing 2503 * Remove all target ports.
2509 * commands and don't try to reconnect.
2510 */ 2504 */
2511 spin_lock(&host->target_lock); 2505 spin_lock(&host->target_lock);
2512 list_for_each_entry(target, &host->target_list, list) { 2506 list_for_each_entry(target, &host->target_list, list)
2513 spin_lock_irq(&target->lock); 2507 srp_queue_remove_work(target);
2514 target->state = SRP_TARGET_REMOVED;
2515 spin_unlock_irq(&target->lock);
2516 }
2517 spin_unlock(&host->target_lock); 2508 spin_unlock(&host->target_lock);
2518 2509
2519 /* 2510 /*
2520 * Wait for any reconnection tasks that may have 2511 * Wait for target port removal tasks.
2521 * started before we marked our target ports as
2522 * removed, and any target port removal tasks.
2523 */ 2512 */
2524 flush_workqueue(ib_wq); 2513 flush_workqueue(system_long_wq);
2525
2526 list_for_each_entry_safe(target, tmp_target,
2527 &host->target_list, list) {
2528 srp_del_scsi_host_attr(target->scsi_host);
2529 srp_remove_host(target->scsi_host);
2530 scsi_remove_host(target->scsi_host);
2531 srp_disconnect_target(target);
2532 ib_destroy_cm_id(target->cm_id);
2533 srp_free_target_ib(target);
2534 srp_free_req_data(target);
2535 scsi_host_put(target->scsi_host);
2536 }
2537 2514
2538 kfree(host); 2515 kfree(host);
2539 } 2516 }
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index ef95fa4ca3ef..de2d0b3c0bfe 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -80,8 +80,7 @@ enum {
80 80
81enum srp_target_state { 81enum srp_target_state {
82 SRP_TARGET_LIVE, 82 SRP_TARGET_LIVE,
83 SRP_TARGET_DEAD, 83 SRP_TARGET_REMOVED,
84 SRP_TARGET_REMOVED
85}; 84};
86 85
87enum srp_iu_type { 86enum srp_iu_type {
@@ -175,7 +174,7 @@ struct srp_target_port {
175 struct srp_iu *rx_ring[SRP_RQ_SIZE]; 174 struct srp_iu *rx_ring[SRP_RQ_SIZE];
176 struct srp_request req_ring[SRP_CMD_SQ_SIZE]; 175 struct srp_request req_ring[SRP_CMD_SQ_SIZE];
177 176
178 struct work_struct work; 177 struct work_struct remove_work;
179 178
180 struct list_head list; 179 struct list_head list;
181 struct completion done; 180 struct completion done;