cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

scsi_pm.c (6124B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *	scsi_pm.c	Copyright (C) 2010 Alan Stern
      4 *
      5 *	SCSI dynamic Power Management
      6 *		Initial version: Alan Stern <stern@rowland.harvard.edu>
      7 */
      8
      9#include <linux/pm_runtime.h>
     10#include <linux/export.h>
     11#include <linux/blk-pm.h>
     12
     13#include <scsi/scsi.h>
     14#include <scsi/scsi_device.h>
     15#include <scsi/scsi_driver.h>
     16#include <scsi/scsi_host.h>
     17
     18#include "scsi_priv.h"
     19
     20#ifdef CONFIG_PM_SLEEP
     21
     22static int do_scsi_suspend(struct device *dev, const struct dev_pm_ops *pm)
     23{
     24	return pm && pm->suspend ? pm->suspend(dev) : 0;
     25}
     26
     27static int do_scsi_freeze(struct device *dev, const struct dev_pm_ops *pm)
     28{
     29	return pm && pm->freeze ? pm->freeze(dev) : 0;
     30}
     31
     32static int do_scsi_poweroff(struct device *dev, const struct dev_pm_ops *pm)
     33{
     34	return pm && pm->poweroff ? pm->poweroff(dev) : 0;
     35}
     36
     37static int do_scsi_resume(struct device *dev, const struct dev_pm_ops *pm)
     38{
     39	return pm && pm->resume ? pm->resume(dev) : 0;
     40}
     41
     42static int do_scsi_thaw(struct device *dev, const struct dev_pm_ops *pm)
     43{
     44	return pm && pm->thaw ? pm->thaw(dev) : 0;
     45}
     46
     47static int do_scsi_restore(struct device *dev, const struct dev_pm_ops *pm)
     48{
     49	return pm && pm->restore ? pm->restore(dev) : 0;
     50}
     51
     52static int scsi_dev_type_suspend(struct device *dev,
     53		int (*cb)(struct device *, const struct dev_pm_ops *))
     54{
     55	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
     56	int err;
     57
     58	err = scsi_device_quiesce(to_scsi_device(dev));
     59	if (err == 0) {
     60		err = cb(dev, pm);
     61		if (err)
     62			scsi_device_resume(to_scsi_device(dev));
     63	}
     64	dev_dbg(dev, "scsi suspend: %d\n", err);
     65	return err;
     66}
     67
     68static int
     69scsi_bus_suspend_common(struct device *dev,
     70		int (*cb)(struct device *, const struct dev_pm_ops *))
     71{
     72	if (!scsi_is_sdev_device(dev))
     73		return 0;
     74
     75	return scsi_dev_type_suspend(dev, cb);
     76}
     77
     78static int scsi_bus_resume_common(struct device *dev,
     79		int (*cb)(struct device *, const struct dev_pm_ops *))
     80{
     81	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
     82	int err;
     83
     84	if (!scsi_is_sdev_device(dev))
     85		return 0;
     86
     87	err = cb(dev, pm);
     88	scsi_device_resume(to_scsi_device(dev));
     89	dev_dbg(dev, "scsi resume: %d\n", err);
     90
     91	return err;
     92}
     93
     94static int scsi_bus_prepare(struct device *dev)
     95{
     96	if (scsi_is_host_device(dev)) {
     97		/* Wait until async scanning is finished */
     98		scsi_complete_async_scans();
     99	}
    100	return 0;
    101}
    102
    103static int scsi_bus_suspend(struct device *dev)
    104{
    105	return scsi_bus_suspend_common(dev, do_scsi_suspend);
    106}
    107
    108static int scsi_bus_resume(struct device *dev)
    109{
    110	return scsi_bus_resume_common(dev, do_scsi_resume);
    111}
    112
    113static int scsi_bus_freeze(struct device *dev)
    114{
    115	return scsi_bus_suspend_common(dev, do_scsi_freeze);
    116}
    117
    118static int scsi_bus_thaw(struct device *dev)
    119{
    120	return scsi_bus_resume_common(dev, do_scsi_thaw);
    121}
    122
    123static int scsi_bus_poweroff(struct device *dev)
    124{
    125	return scsi_bus_suspend_common(dev, do_scsi_poweroff);
    126}
    127
    128static int scsi_bus_restore(struct device *dev)
    129{
    130	return scsi_bus_resume_common(dev, do_scsi_restore);
    131}
    132
    133#else /* CONFIG_PM_SLEEP */
    134
    135#define scsi_bus_prepare		NULL
    136#define scsi_bus_suspend		NULL
    137#define scsi_bus_resume			NULL
    138#define scsi_bus_freeze			NULL
    139#define scsi_bus_thaw			NULL
    140#define scsi_bus_poweroff		NULL
    141#define scsi_bus_restore		NULL
    142
    143#endif /* CONFIG_PM_SLEEP */
    144
    145static int sdev_runtime_suspend(struct device *dev)
    146{
    147	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
    148	struct scsi_device *sdev = to_scsi_device(dev);
    149	int err = 0;
    150
    151	err = blk_pre_runtime_suspend(sdev->request_queue);
    152	if (err)
    153		return err;
    154	if (pm && pm->runtime_suspend)
    155		err = pm->runtime_suspend(dev);
    156	blk_post_runtime_suspend(sdev->request_queue, err);
    157
    158	return err;
    159}
    160
    161static int scsi_runtime_suspend(struct device *dev)
    162{
    163	int err = 0;
    164
    165	dev_dbg(dev, "scsi_runtime_suspend\n");
    166	if (scsi_is_sdev_device(dev))
    167		err = sdev_runtime_suspend(dev);
    168
    169	/* Insert hooks here for targets, hosts, and transport classes */
    170
    171	return err;
    172}
    173
    174static int sdev_runtime_resume(struct device *dev)
    175{
    176	struct scsi_device *sdev = to_scsi_device(dev);
    177	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
    178	int err = 0;
    179
    180	blk_pre_runtime_resume(sdev->request_queue);
    181	if (pm && pm->runtime_resume)
    182		err = pm->runtime_resume(dev);
    183	blk_post_runtime_resume(sdev->request_queue);
    184
    185	return err;
    186}
    187
    188static int scsi_runtime_resume(struct device *dev)
    189{
    190	int err = 0;
    191
    192	dev_dbg(dev, "scsi_runtime_resume\n");
    193	if (scsi_is_sdev_device(dev))
    194		err = sdev_runtime_resume(dev);
    195
    196	/* Insert hooks here for targets, hosts, and transport classes */
    197
    198	return err;
    199}
    200
    201static int scsi_runtime_idle(struct device *dev)
    202{
    203	dev_dbg(dev, "scsi_runtime_idle\n");
    204
    205	/* Insert hooks here for targets, hosts, and transport classes */
    206
    207	if (scsi_is_sdev_device(dev)) {
    208		pm_runtime_mark_last_busy(dev);
    209		pm_runtime_autosuspend(dev);
    210		return -EBUSY;
    211	}
    212
    213	return 0;
    214}
    215
    216int scsi_autopm_get_device(struct scsi_device *sdev)
    217{
    218	int	err;
    219
    220	err = pm_runtime_get_sync(&sdev->sdev_gendev);
    221	if (err < 0 && err !=-EACCES)
    222		pm_runtime_put_sync(&sdev->sdev_gendev);
    223	else
    224		err = 0;
    225	return err;
    226}
    227EXPORT_SYMBOL_GPL(scsi_autopm_get_device);
    228
    229void scsi_autopm_put_device(struct scsi_device *sdev)
    230{
    231	pm_runtime_put_sync(&sdev->sdev_gendev);
    232}
    233EXPORT_SYMBOL_GPL(scsi_autopm_put_device);
    234
    235void scsi_autopm_get_target(struct scsi_target *starget)
    236{
    237	pm_runtime_get_sync(&starget->dev);
    238}
    239
    240void scsi_autopm_put_target(struct scsi_target *starget)
    241{
    242	pm_runtime_put_sync(&starget->dev);
    243}
    244
    245int scsi_autopm_get_host(struct Scsi_Host *shost)
    246{
    247	int	err;
    248
    249	err = pm_runtime_get_sync(&shost->shost_gendev);
    250	if (err < 0 && err !=-EACCES)
    251		pm_runtime_put_sync(&shost->shost_gendev);
    252	else
    253		err = 0;
    254	return err;
    255}
    256
    257void scsi_autopm_put_host(struct Scsi_Host *shost)
    258{
    259	pm_runtime_put_sync(&shost->shost_gendev);
    260}
    261
    262const struct dev_pm_ops scsi_bus_pm_ops = {
    263	.prepare =		scsi_bus_prepare,
    264	.suspend =		scsi_bus_suspend,
    265	.resume =		scsi_bus_resume,
    266	.freeze =		scsi_bus_freeze,
    267	.thaw =			scsi_bus_thaw,
    268	.poweroff =		scsi_bus_poweroff,
    269	.restore =		scsi_bus_restore,
    270	.runtime_suspend =	scsi_runtime_suspend,
    271	.runtime_resume =	scsi_runtime_resume,
    272	.runtime_idle =		scsi_runtime_idle,
    273};