aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;