Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[sfrench/cifs-2.6.git] / drivers / scsi / hosts.c
index 26bf3b1535959f177075961601a36f77191b61a1..0738238ed6cc40e7313adadbcaaa8757bc76b650 100644 (file)
@@ -190,6 +190,15 @@ void scsi_remove_host(struct Scsi_Host *shost)
        transport_unregister_device(&shost->shost_gendev);
        device_unregister(&shost->shost_dev);
        device_del(&shost->shost_gendev);
+
+       /*
+        * After scsi_remove_host() has returned the scsi LLD module can be
+        * unloaded and/or the host resources can be released. Hence wait until
+        * the dependent SCSI targets and devices are gone before returning.
+        */
+       wait_event(shost->targets_wq, atomic_read(&shost->target_count) == 0);
+
+       scsi_mq_destroy_tags(shost);
 }
 EXPORT_SYMBOL(scsi_remove_host);
 
@@ -300,8 +309,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
        return error;
 
        /*
-        * Any host allocation in this function will be freed in
-        * scsi_host_dev_release().
+        * Any resources associated with the SCSI host in this function except
+        * the tag set will be freed by scsi_host_dev_release().
         */
  out_del_dev:
        device_del(&shost->shost_dev);
@@ -317,6 +326,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
        pm_runtime_disable(&shost->shost_gendev);
        pm_runtime_set_suspended(&shost->shost_gendev);
        pm_runtime_put_noidle(&shost->shost_gendev);
+       scsi_mq_destroy_tags(shost);
  fail:
        return error;
 }
@@ -350,9 +360,6 @@ static void scsi_host_dev_release(struct device *dev)
                kfree(dev_name(&shost->shost_dev));
        }
 
-       if (shost->tag_set.tags)
-               scsi_mq_destroy_tags(shost);
-
        kfree(shost->shost_data);
 
        ida_free(&host_index_ida, shost->host_no);
@@ -399,6 +406,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        INIT_LIST_HEAD(&shost->starved_list);
        init_waitqueue_head(&shost->host_wait);
        mutex_init(&shost->scan_mutex);
+       init_waitqueue_head(&shost->targets_wq);
 
        index = ida_alloc(&host_index_ida, GFP_KERNEL);
        if (index < 0) {