diff options
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 374853df9cc..752fb5da3de 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -74,7 +74,7 @@ #define SCSI_SCAN_TARGET_PRESENT 1 #define SCSI_SCAN_LUN_PRESENT 2 -static char *scsi_null_device_strs = "nullnullnullnull"; +static const char *scsi_null_device_strs = "nullnullnullnull"; #define MAX_SCSI_LUNS 512 @@ -266,8 +266,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, /* * if LLDD reports slave not present, don't clutter * console with alloc failure messages - - */ if (ret == -ENXIO) display_failure_msg = 0; @@ -279,7 +277,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, out_device_destroy: transport_destroy_device(&sdev->sdev_gendev); - scsi_free_queue(sdev->request_queue); put_device(&sdev->sdev_gendev); out: if (display_failure_msg) @@ -337,19 +334,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, struct scsi_target *starget; struct scsi_target *found_target; - /* - * Obtain the real parent from the transport. The transport - * is allowed to fail (no error) if there is nothing at that - * target id. - */ - if (shost->transportt->target_parent) { - spin_lock_irqsave(shost->host_lock, flags); - parent = shost->transportt->target_parent(shost, channel, id); - spin_unlock_irqrestore(shost->host_lock, flags); - if (!parent) - return NULL; - } - starget = kmalloc(size, GFP_KERNEL); if (!starget) { printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); @@ -403,6 +387,36 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, return found_target; } +struct work_queue_wrapper { + struct work_struct work; + struct scsi_target *starget; +}; + +static void scsi_target_reap_work(void *data) { + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct scsi_target *starget = wqw->starget; + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + unsigned long flags; + + kfree(wqw); + + spin_lock_irqsave(shost->host_lock, flags); + + if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { + list_del_init(&starget->siblings); + spin_unlock_irqrestore(shost->host_lock, flags); + transport_remove_device(&starget->dev); + device_del(&starget->dev); + transport_destroy_device(&starget->dev); + put_device(&starget->dev); + return; + + } + spin_unlock_irqrestore(shost->host_lock, flags); + + return; +} + /** * scsi_target_reap - check to see if target is in use and destroy if not * @@ -414,19 +428,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, */ void scsi_target_reap(struct scsi_target *starget) { - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - unsigned long flags; - spin_lock_irqsave(shost->host_lock, flags); + struct work_queue_wrapper *wqw = + kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); - if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { - list_del_init(&starget->siblings); - spin_unlock_irqrestore(shost->host_lock, flags); - device_del(&starget->dev); - transport_unregister_device(&starget->dev); - put_device(&starget->dev); + if (!wqw) { + starget_printk(KERN_ERR, starget, + "Failed to allocate memory in scsi_reap_target()\n"); return; } - spin_unlock_irqrestore(shost->host_lock, flags); + + INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); + wqw->starget = starget; + schedule_work(&wqw->work); } /** @@ -1257,20 +1270,21 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, struct scsi_device *sdev; struct device *parent = &shost->shost_gendev; int res; - struct scsi_target *starget = scsi_alloc_target(parent, channel, id); + struct scsi_target *starget; + starget = scsi_alloc_target(parent, channel, id); if (!starget) return ERR_PTR(-ENOMEM); get_device(&starget->dev); - down(&shost->scan_mutex); + mutex_lock(&shost->scan_mutex); if (scsi_host_scan_allowed(shost)) { res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); if (res != SCSI_SCAN_LUN_PRESENT) sdev = ERR_PTR(-ENODEV); } - up(&shost->scan_mutex); + mutex_unlock(&shost->scan_mutex); scsi_target_reap(starget); put_device(&starget->dev); @@ -1378,10 +1392,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel, { struct Scsi_Host *shost = dev_to_shost(parent); - down(&shost->scan_mutex); + mutex_lock(&shost->scan_mutex); if (scsi_host_scan_allowed(shost)) __scsi_scan_target(parent, channel, id, lun, rescan); - up(&shost->scan_mutex); + mutex_unlock(&shost->scan_mutex); } EXPORT_SYMBOL(scsi_scan_target); @@ -1428,7 +1442,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) return -EINVAL; - down(&shost->scan_mutex); + mutex_lock(&shost->scan_mutex); if (scsi_host_scan_allowed(shost)) { if (channel == SCAN_WILD_CARD) for (channel = 0; channel <= shost->max_channel; @@ -1438,7 +1452,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, else scsi_scan_channel(shost, channel, id, lun, rescan); } - up(&shost->scan_mutex); + mutex_unlock(&shost->scan_mutex); return 0; } @@ -1496,7 +1510,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) struct scsi_device *sdev = NULL; struct scsi_target *starget; - down(&shost->scan_mutex); + mutex_lock(&shost->scan_mutex); if (!scsi_host_scan_allowed(shost)) goto out; starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id); @@ -1510,7 +1524,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) } put_device(&starget->dev); out: - up(&shost->scan_mutex); + mutex_unlock(&shost->scan_mutex); return sdev; } EXPORT_SYMBOL(scsi_get_host_dev); |