Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 204305
b: refs/heads/master
c: bc4f240
h: refs/heads/master
i:
  204303: 4b0e497
v: v3
  • Loading branch information
Alan Stern authored and James Bottomley committed Jul 28, 2010
1 parent 8e2f372 commit 25a5520
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: db5bd1e0b505c54ff492172ce4abc245cf6cd639
refs/heads/master: bc4f24014de58f045f169742701a6598884d93db
10 changes: 8 additions & 2 deletions trunk/drivers/scsi/hosts.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/completion.h>
#include <linux/transport_class.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>

#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
Expand Down Expand Up @@ -156,6 +157,7 @@ EXPORT_SYMBOL(scsi_host_set_state);
void scsi_remove_host(struct Scsi_Host *shost)
{
unsigned long flags;

mutex_lock(&shost->scan_mutex);
spin_lock_irqsave(shost->host_lock, flags);
if (scsi_host_set_state(shost, SHOST_CANCEL))
Expand All @@ -165,6 +167,8 @@ void scsi_remove_host(struct Scsi_Host *shost)
return;
}
spin_unlock_irqrestore(shost->host_lock, flags);

scsi_autopm_get_host(shost);
scsi_forget_host(shost);
mutex_unlock(&shost->scan_mutex);
scsi_proc_host_rm(shost);
Expand Down Expand Up @@ -216,12 +220,14 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
shost->shost_gendev.parent = dev ? dev : &platform_bus;
shost->dma_dev = dma_dev;

device_enable_async_suspend(&shost->shost_gendev);

error = device_add(&shost->shost_gendev);
if (error)
goto out;

pm_runtime_set_active(&shost->shost_gendev);
pm_runtime_enable(&shost->shost_gendev);
device_enable_async_suspend(&shost->shost_gendev);

scsi_host_set_state(shost, SHOST_RUNNING);
get_device(shost->shost_gendev.parent);

Expand Down
16 changes: 15 additions & 1 deletion trunk/drivers/scsi/scsi_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,14 @@ int scsi_error_handler(void *data)
* what we need to do to get it up and online again (if we can).
* If we fail, we end up taking the thing offline.
*/
if (scsi_autopm_get_host(shost) != 0) {
SCSI_LOG_ERROR_RECOVERY(1,
printk(KERN_ERR "Error handler scsi_eh_%d "
"unable to autoresume\n",
shost->host_no));
continue;
}

if (shost->transportt->eh_strategy_handler)
shost->transportt->eh_strategy_handler(shost);
else
Expand All @@ -1788,6 +1796,7 @@ int scsi_error_handler(void *data)
* which are still online.
*/
scsi_restart_operations(shost);
scsi_autopm_put_host(shost);
set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
Expand Down Expand Up @@ -1885,12 +1894,16 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
int
scsi_reset_provider(struct scsi_device *dev, int flag)
{
struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
struct scsi_cmnd *scmd;
struct Scsi_Host *shost = dev->host;
struct request req;
unsigned long flags;
int rtn;

if (scsi_autopm_get_host(shost) < 0)
return FAILED;

scmd = scsi_get_command(dev, GFP_KERNEL);
blk_rq_init(NULL, &req);
scmd->request = &req;

Expand Down Expand Up @@ -1947,6 +1960,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scsi_run_host_queues(shost);

scsi_next_command(scmd);
scsi_autopm_put_host(shost);
return rtn;
}
EXPORT_SYMBOL(scsi_reset_provider);
Expand Down
110 changes: 110 additions & 0 deletions trunk/drivers/scsi/scsi_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ static int scsi_bus_resume_common(struct device *dev)

if (scsi_is_sdev_device(dev))
err = scsi_dev_type_resume(dev);

if (err == 0) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
}
return err;
}

Expand Down Expand Up @@ -86,11 +92,115 @@ static int scsi_bus_poweroff(struct device *dev)

#endif /* CONFIG_PM_SLEEP */

#ifdef CONFIG_PM_RUNTIME

static int scsi_runtime_suspend(struct device *dev)
{
int err = 0;

dev_dbg(dev, "scsi_runtime_suspend\n");
if (scsi_is_sdev_device(dev)) {
err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND);
if (err == -EAGAIN)
pm_schedule_suspend(dev, jiffies_to_msecs(
round_jiffies_up_relative(HZ/10)));
}

/* Insert hooks here for targets, hosts, and transport classes */

return err;
}

static int scsi_runtime_resume(struct device *dev)
{
int err = 0;

dev_dbg(dev, "scsi_runtime_resume\n");
if (scsi_is_sdev_device(dev))
err = scsi_dev_type_resume(dev);

/* Insert hooks here for targets, hosts, and transport classes */

return err;
}

static int scsi_runtime_idle(struct device *dev)
{
int err;

dev_dbg(dev, "scsi_runtime_idle\n");

/* Insert hooks here for targets, hosts, and transport classes */

if (scsi_is_sdev_device(dev))
err = pm_schedule_suspend(dev, 100);
else
err = pm_runtime_suspend(dev);
return err;
}

int scsi_autopm_get_device(struct scsi_device *sdev)
{
int err;

err = pm_runtime_get_sync(&sdev->sdev_gendev);
if (err < 0)
pm_runtime_put_sync(&sdev->sdev_gendev);
else if (err > 0)
err = 0;
return err;
}
EXPORT_SYMBOL_GPL(scsi_autopm_get_device);

void scsi_autopm_put_device(struct scsi_device *sdev)
{
pm_runtime_put_sync(&sdev->sdev_gendev);
}
EXPORT_SYMBOL_GPL(scsi_autopm_put_device);

void scsi_autopm_get_target(struct scsi_target *starget)
{
pm_runtime_get_sync(&starget->dev);
}

void scsi_autopm_put_target(struct scsi_target *starget)
{
pm_runtime_put_sync(&starget->dev);
}

int scsi_autopm_get_host(struct Scsi_Host *shost)
{
int err;

err = pm_runtime_get_sync(&shost->shost_gendev);
if (err < 0)
pm_runtime_put_sync(&shost->shost_gendev);
else if (err > 0)
err = 0;
return err;
}

void scsi_autopm_put_host(struct Scsi_Host *shost)
{
pm_runtime_put_sync(&shost->shost_gendev);
}

#else

#define scsi_runtime_suspend NULL
#define scsi_runtime_resume NULL
#define scsi_runtime_idle NULL

#endif /* CONFIG_PM_RUNTIME */

const struct dev_pm_ops scsi_bus_pm_ops = {
.suspend = scsi_bus_suspend,
.resume = scsi_bus_resume_common,
.freeze = scsi_bus_freeze,
.thaw = scsi_bus_resume_common,
.poweroff = scsi_bus_poweroff,
.restore = scsi_bus_resume_common,
.runtime_suspend = scsi_runtime_suspend,
.runtime_resume = scsi_runtime_resume,
.runtime_idle = scsi_runtime_idle,
};
14 changes: 13 additions & 1 deletion trunk/drivers/scsi/scsi_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ struct request_queue;
struct request;
struct scsi_cmnd;
struct scsi_device;
struct scsi_target;
struct scsi_host_template;
struct Scsi_Host;
struct scsi_nl_hdr;
Expand Down Expand Up @@ -147,9 +148,20 @@ static inline void scsi_netlink_exit(void) {}
/* scsi_pm.c */
#ifdef CONFIG_PM_OPS
extern const struct dev_pm_ops scsi_bus_pm_ops;
#else
#else /* CONFIG_PM_OPS */
#define scsi_bus_pm_ops (*NULL)
#endif
#ifdef CONFIG_PM_RUNTIME
extern void scsi_autopm_get_target(struct scsi_target *);
extern void scsi_autopm_put_target(struct scsi_target *);
extern int scsi_autopm_get_host(struct Scsi_Host *);
extern void scsi_autopm_put_host(struct Scsi_Host *);
#else
static inline void scsi_autopm_get_target(struct scsi_target *t) {}
static inline void scsi_autopm_put_target(struct scsi_target *t) {}
static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
#endif /* CONFIG_PM_RUNTIME */

/*
* internal scsi timeout functions: for use by mid-layer and transport
Expand Down
24 changes: 20 additions & 4 deletions trunk/drivers/scsi/scsi_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1513,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);

Expand Down Expand Up @@ -1574,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) {
/*
Expand All @@ -1599,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);
Expand Down Expand Up @@ -1633,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);
Expand Down Expand Up @@ -1686,14 +1694,15 @@ 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++)
scsi_scan_channel(shost, channel, id, lun,
rescan);
else
scsi_scan_channel(shost, channel, id, lun, rescan);
scsi_autopm_put_host(shost);
}
mutex_unlock(&shost->scan_mutex);

Expand Down Expand Up @@ -1831,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;
}

Expand All @@ -1847,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);

Expand Down
Loading

0 comments on commit 25a5520

Please sign in to comment.