summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r--drivers/scsi/scsi_scan.c86
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);