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);
}
EXPORT_SYMBOL(scsi_remove_host);
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) {
static void scsi_target_dev_release(struct device *dev)
{
struct device *parent = dev->parent;
+ struct Scsi_Host *shost = dev_to_shost(parent);
struct scsi_target *starget = to_scsi_target(dev);
kfree(starget);
+
+ if (atomic_dec_return(&shost->target_count) == 0)
+ wake_up(&shost->targets_wq);
+
put_device(parent);
}
starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED;
init_waitqueue_head(&starget->sdev_wq);
+ atomic_inc(&shost->target_count);
+
retry:
spin_lock_irqsave(shost->host_lock, flags);
/* ldm bits */
struct device shost_gendev, shost_dev;
+ atomic_t target_count;
+ wait_queue_head_t targets_wq;
+
/*
* Points to the transport data (if any) which is allocated
* separately