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.c63
1 files changed, 36 insertions, 27 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 4bc8b77a2ef..3d0a1e6e9c4 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -33,6 +33,7 @@
#include <linux/kthread.h>
#include <linux/spinlock.h>
#include <linux/async.h>
+#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -458,8 +459,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
found_target->reap_ref++;
spin_unlock_irqrestore(shost->host_lock, flags);
if (found_target->state != STARGET_DEL) {
- put_device(parent);
- kfree(starget);
+ put_device(dev);
return found_target;
}
/* Unfortunately, we found a dying target; need to
@@ -492,19 +492,20 @@ void scsi_target_reap(struct scsi_target *starget)
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
enum scsi_target_state state;
- int empty;
+ int empty = 0;
spin_lock_irqsave(shost->host_lock, flags);
state = starget->state;
- empty = --starget->reap_ref == 0 &&
- list_empty(&starget->devices) ? 1 : 0;
+ if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
+ empty = 1;
+ starget->state = STARGET_DEL;
+ }
spin_unlock_irqrestore(shost->host_lock, flags);
if (!empty)
return;
BUG_ON(state == STARGET_DEL);
- starget->state = STARGET_DEL;
if (state == STARGET_CREATED)
scsi_target_destroy(starget);
else
@@ -1220,7 +1221,7 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget,
}
/**
- * scsilun_to_int: convert a scsi_lun to an int
+ * scsilun_to_int - convert a scsi_lun to an int
* @scsilun: struct scsi_lun to be converted.
*
* Description:
@@ -1252,7 +1253,7 @@ int scsilun_to_int(struct scsi_lun *scsilun)
EXPORT_SYMBOL(scsilun_to_int);
/**
- * int_to_scsilun: reverts an int into a scsi_lun
+ * int_to_scsilun - reverts an int into a scsi_lun
* @lun: integer to be reverted
* @scsilun: struct scsi_lun to be set.
*
@@ -1512,14 +1513,18 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
starget = scsi_alloc_target(parent, channel, id);
if (!starget)
return ERR_PTR(-ENOMEM);
+ scsi_autopm_get_target(starget);
mutex_lock(&shost->scan_mutex);
if (!shost->async_scan)
scsi_complete_async_scans();
- if (scsi_host_scan_allowed(shost))
+ if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
+ scsi_autopm_put_host(shost);
+ }
mutex_unlock(&shost->scan_mutex);
+ scsi_autopm_put_target(starget);
scsi_target_reap(starget);
put_device(&starget->dev);
@@ -1573,6 +1578,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
starget = scsi_alloc_target(parent, channel, id);
if (!starget)
return;
+ scsi_autopm_get_target(starget);
if (lun != SCAN_WILD_CARD) {
/*
@@ -1598,6 +1604,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
}
out_reap:
+ scsi_autopm_put_target(starget);
/* now determine if the target has any children at all
* and if not, nuke it */
scsi_target_reap(starget);
@@ -1632,8 +1639,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
if (!shost->async_scan)
scsi_complete_async_scans();
- if (scsi_host_scan_allowed(shost))
+ if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
__scsi_scan_target(parent, channel, id, lun, rescan);
+ scsi_autopm_put_host(shost);
+ }
mutex_unlock(&shost->scan_mutex);
}
EXPORT_SYMBOL(scsi_scan_target);
@@ -1685,7 +1694,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
if (!shost->async_scan)
scsi_complete_async_scans();
- if (scsi_host_scan_allowed(shost)) {
+ if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
if (channel == SCAN_WILD_CARD)
for (channel = 0; channel <= shost->max_channel;
channel++)
@@ -1693,6 +1702,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
rescan);
else
scsi_scan_channel(shost, channel, id, lun, rescan);
+ scsi_autopm_put_host(shost);
}
mutex_unlock(&shost->scan_mutex);
@@ -1830,8 +1840,11 @@ static void do_scsi_scan_host(struct Scsi_Host *shost)
static int do_scan_async(void *_data)
{
struct async_scan_data *data = _data;
- do_scsi_scan_host(data->shost);
+ struct Scsi_Host *shost = data->shost;
+
+ do_scsi_scan_host(shost);
scsi_finish_async_scan(data);
+ scsi_autopm_put_host(shost);
return 0;
}
@@ -1846,16 +1859,20 @@ void scsi_scan_host(struct Scsi_Host *shost)
if (strncmp(scsi_scan_type, "none", 4) == 0)
return;
+ if (scsi_autopm_get_host(shost) < 0)
+ return;
data = scsi_prep_async_scan(shost);
if (!data) {
do_scsi_scan_host(shost);
+ scsi_autopm_put_host(shost);
return;
}
p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
if (IS_ERR(p))
do_scan_async(data);
+ /* scsi_autopm_put_host(shost) is called in do_scan_async() */
}
EXPORT_SYMBOL(scsi_scan_host);
@@ -1876,12 +1893,9 @@ void scsi_forget_host(struct Scsi_Host *shost)
spin_unlock_irqrestore(shost->host_lock, flags);
}
-/*
- * Function: scsi_get_host_dev()
- *
- * Purpose: Create a scsi_device that points to the host adapter itself.
- *
- * Arguments: SHpnt - Host that needs a scsi_device
+/**
+ * scsi_get_host_dev - Create a scsi_device that points to the host adapter itself
+ * @shost: Host that needs a scsi_device
*
* Lock status: None assumed.
*
@@ -1894,7 +1908,7 @@ void scsi_forget_host(struct Scsi_Host *shost)
*
* Note - this device is not accessible from any high-level
* drivers (including generics), which is probably not
- * optimal. We can add hooks later to attach
+ * optimal. We can add hooks later to attach.
*/
struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
{
@@ -1920,18 +1934,13 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
}
EXPORT_SYMBOL(scsi_get_host_dev);
-/*
- * Function: scsi_free_host_dev()
- *
- * Purpose: Free a scsi_device that points to the host adapter itself.
- *
- * Arguments: SHpnt - Host that needs a scsi_device
+/**
+ * scsi_free_host_dev - Free a scsi_device that points to the host adapter itself
+ * @sdev: Host device to be freed
*
* Lock status: None assumed.
*
* Returns: Nothing
- *
- * Notes:
*/
void scsi_free_host_dev(struct scsi_device *sdev)
{