aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2009-06-16 04:30:20 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-06-16 04:31:08 -0400
commit823d494ac11111064cf39abd4178ce299414c771 (patch)
treeede15540ad89c3412f16c24770408a4c34cc032c /drivers/s390
parent03347e2592078a90df818670fddf97a33eec70fb (diff)
[S390] pm: ccw bus power management callbacks
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/cmf.c5
-rw-r--r--drivers/s390/cio/device.c237
-rw-r--r--drivers/s390/cio/device.h3
-rw-r--r--drivers/s390/cio/device_fsm.c96
-rw-r--r--drivers/s390/cio/device_ops.c26
-rw-r--r--drivers/s390/cio/io_sch.h1
6 files changed, 308 insertions, 60 deletions
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index dc98b2c63862..30f516111307 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev,
1204 1204
1205DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); 1205DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
1206 1206
1207int ccw_set_cmf(struct ccw_device *cdev, int enable)
1208{
1209 return cmbops->set(cdev, enable ? 2 : 0);
1210}
1211
1207/** 1212/**
1208 * enable_cmf() - switch on the channel measurement for a specific device 1213 * enable_cmf() - switch on the channel measurement for a specific device
1209 * @cdev: The ccw device to be enabled 1214 * @cdev: The ccw device to be enabled
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 35441fa16be1..228a6c314d84 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1895,6 +1895,242 @@ static void ccw_device_shutdown(struct device *dev)
1895 disable_cmf(cdev); 1895 disable_cmf(cdev);
1896} 1896}
1897 1897
1898static int ccw_device_pm_prepare(struct device *dev)
1899{
1900 struct ccw_device *cdev = to_ccwdev(dev);
1901
1902 if (work_pending(&cdev->private->kick_work))
1903 return -EAGAIN;
1904 /* Fail while device is being set online/offline. */
1905 if (atomic_read(&cdev->private->onoff))
1906 return -EAGAIN;
1907
1908 if (cdev->online && cdev->drv && cdev->drv->prepare)
1909 return cdev->drv->prepare(cdev);
1910
1911 return 0;
1912}
1913
1914static void ccw_device_pm_complete(struct device *dev)
1915{
1916 struct ccw_device *cdev = to_ccwdev(dev);
1917
1918 if (cdev->online && cdev->drv && cdev->drv->complete)
1919 cdev->drv->complete(cdev);
1920}
1921
1922static int ccw_device_pm_freeze(struct device *dev)
1923{
1924 struct ccw_device *cdev = to_ccwdev(dev);
1925 struct subchannel *sch = to_subchannel(cdev->dev.parent);
1926 int ret, cm_enabled;
1927
1928 /* Fail suspend while device is in transistional state. */
1929 if (!dev_fsm_final_state(cdev))
1930 return -EAGAIN;
1931 if (!cdev->online)
1932 return 0;
1933 if (cdev->drv && cdev->drv->freeze) {
1934 ret = cdev->drv->freeze(cdev);
1935 if (ret)
1936 return ret;
1937 }
1938
1939 spin_lock_irq(sch->lock);
1940 cm_enabled = cdev->private->cmb != NULL;
1941 spin_unlock_irq(sch->lock);
1942 if (cm_enabled) {
1943 /* Don't have the css write on memory. */
1944 ret = ccw_set_cmf(cdev, 0);
1945 if (ret)
1946 return ret;
1947 }
1948 /* From here on, disallow device driver I/O. */
1949 spin_lock_irq(sch->lock);
1950 ret = cio_disable_subchannel(sch);
1951 spin_unlock_irq(sch->lock);
1952
1953 return ret;
1954}
1955
1956static int ccw_device_pm_thaw(struct device *dev)
1957{
1958 struct ccw_device *cdev = to_ccwdev(dev);
1959 struct subchannel *sch = to_subchannel(cdev->dev.parent);
1960 int ret, cm_enabled;
1961
1962 if (!cdev->online)
1963 return 0;
1964
1965 spin_lock_irq(sch->lock);
1966 /* Allow device driver I/O again. */
1967 ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
1968 cm_enabled = cdev->private->cmb != NULL;
1969 spin_unlock_irq(sch->lock);
1970 if (ret)
1971 return ret;
1972
1973 if (cm_enabled) {
1974 ret = ccw_set_cmf(cdev, 1);
1975 if (ret)
1976 return ret;
1977 }
1978
1979 if (cdev->drv && cdev->drv->thaw)
1980 ret = cdev->drv->thaw(cdev);
1981
1982 return ret;
1983}
1984
1985static void __ccw_device_pm_restore(struct ccw_device *cdev)
1986{
1987 struct subchannel *sch = to_subchannel(cdev->dev.parent);
1988 int ret;
1989
1990 if (cio_is_console(sch->schid))
1991 goto out;
1992 /*
1993 * While we were sleeping, devices may have gone or become
1994 * available again. Kick re-detection.
1995 */
1996 spin_lock_irq(sch->lock);
1997 cdev->private->flags.resuming = 1;
1998 ret = ccw_device_recognition(cdev);
1999 spin_unlock_irq(sch->lock);
2000 if (ret) {
2001 CIO_MSG_EVENT(0, "Couldn't start recognition for device "
2002 "%s (ret=%d)\n", dev_name(&cdev->dev), ret);
2003 spin_lock_irq(sch->lock);
2004 cdev->private->state = DEV_STATE_DISCONNECTED;
2005 spin_unlock_irq(sch->lock);
2006 /* notify driver after the resume cb */
2007 goto out;
2008 }
2009 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
2010 cdev->private->state == DEV_STATE_DISCONNECTED);
2011
2012out:
2013 cdev->private->flags.resuming = 0;
2014}
2015
2016static int resume_handle_boxed(struct ccw_device *cdev)
2017{
2018 cdev->private->state = DEV_STATE_BOXED;
2019 if (ccw_device_notify(cdev, CIO_BOXED))
2020 return 0;
2021 ccw_device_schedule_sch_unregister(cdev);
2022 return -ENODEV;
2023}
2024
2025static int resume_handle_disc(struct ccw_device *cdev)
2026{
2027 cdev->private->state = DEV_STATE_DISCONNECTED;
2028 if (ccw_device_notify(cdev, CIO_GONE))
2029 return 0;
2030 ccw_device_schedule_sch_unregister(cdev);
2031 return -ENODEV;
2032}
2033
2034static int ccw_device_pm_restore(struct device *dev)
2035{
2036 struct ccw_device *cdev = to_ccwdev(dev);
2037 struct subchannel *sch = to_subchannel(cdev->dev.parent);
2038 int ret = 0, cm_enabled;
2039
2040 __ccw_device_pm_restore(cdev);
2041 spin_lock_irq(sch->lock);
2042 if (cio_is_console(sch->schid)) {
2043 cio_enable_subchannel(sch, (u32)(addr_t)sch);
2044 spin_unlock_irq(sch->lock);
2045 goto out_restore;
2046 }
2047 cdev->private->flags.donotify = 0;
2048 /* check recognition results */
2049 switch (cdev->private->state) {
2050 case DEV_STATE_OFFLINE:
2051 break;
2052 case DEV_STATE_BOXED:
2053 ret = resume_handle_boxed(cdev);
2054 spin_unlock_irq(sch->lock);
2055 if (ret)
2056 goto out;
2057 goto out_restore;
2058 case DEV_STATE_DISCONNECTED:
2059 goto out_disc_unlock;
2060 default:
2061 goto out_unreg_unlock;
2062 }
2063 /* check if the device id has changed */
2064 if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
2065 CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from "
2066 "%04x to %04x)\n", dev_name(&sch->dev),
2067 cdev->private->dev_id.devno,
2068 sch->schib.pmcw.dev);
2069 goto out_unreg_unlock;
2070 }
2071 /* check if the device type has changed */
2072 if (!ccw_device_test_sense_data(cdev)) {
2073 ccw_device_update_sense_data(cdev);
2074 PREPARE_WORK(&cdev->private->kick_work,
2075 ccw_device_do_unbind_bind);
2076 queue_work(ccw_device_work, &cdev->private->kick_work);
2077 ret = -ENODEV;
2078 goto out_unlock;
2079 }
2080 if (!cdev->online) {
2081 ret = 0;
2082 goto out_unlock;
2083 }
2084 ret = ccw_device_online(cdev);
2085 if (ret)
2086 goto out_disc_unlock;
2087
2088 cm_enabled = cdev->private->cmb != NULL;
2089 spin_unlock_irq(sch->lock);
2090
2091 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
2092 if (cdev->private->state != DEV_STATE_ONLINE) {
2093 spin_lock_irq(sch->lock);
2094 goto out_disc_unlock;
2095 }
2096 if (cm_enabled) {
2097 ret = ccw_set_cmf(cdev, 1);
2098 if (ret) {
2099 CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed "
2100 "(rc=%d)\n", dev_name(&cdev->dev), ret);
2101 ret = 0;
2102 }
2103 }
2104
2105out_restore:
2106 if (cdev->online && cdev->drv && cdev->drv->restore)
2107 ret = cdev->drv->restore(cdev);
2108out:
2109 return ret;
2110
2111out_disc_unlock:
2112 ret = resume_handle_disc(cdev);
2113 spin_unlock_irq(sch->lock);
2114 if (ret)
2115 return ret;
2116 goto out_restore;
2117
2118out_unreg_unlock:
2119 ccw_device_schedule_sch_unregister(cdev);
2120 ret = -ENODEV;
2121out_unlock:
2122 spin_unlock_irq(sch->lock);
2123 return ret;
2124}
2125
2126static struct dev_pm_ops ccw_pm_ops = {
2127 .prepare = ccw_device_pm_prepare,
2128 .complete = ccw_device_pm_complete,
2129 .freeze = ccw_device_pm_freeze,
2130 .thaw = ccw_device_pm_thaw,
2131 .restore = ccw_device_pm_restore,
2132};
2133
1898struct bus_type ccw_bus_type = { 2134struct bus_type ccw_bus_type = {
1899 .name = "ccw", 2135 .name = "ccw",
1900 .match = ccw_bus_match, 2136 .match = ccw_bus_match,
@@ -1902,6 +2138,7 @@ struct bus_type ccw_bus_type = {
1902 .probe = ccw_device_probe, 2138 .probe = ccw_device_probe,
1903 .remove = ccw_device_remove, 2139 .remove = ccw_device_remove,
1904 .shutdown = ccw_device_shutdown, 2140 .shutdown = ccw_device_shutdown,
2141 .pm = &ccw_pm_ops,
1905}; 2142};
1906 2143
1907/** 2144/**
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index f1cbbd94ad4e..e3975107a578 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *);
87int ccw_device_recognition(struct ccw_device *); 87int ccw_device_recognition(struct ccw_device *);
88int ccw_device_online(struct ccw_device *); 88int ccw_device_online(struct ccw_device *);
89int ccw_device_offline(struct ccw_device *); 89int ccw_device_offline(struct ccw_device *);
90void ccw_device_update_sense_data(struct ccw_device *);
91int ccw_device_test_sense_data(struct ccw_device *);
90void ccw_device_schedule_sch_unregister(struct ccw_device *); 92void ccw_device_schedule_sch_unregister(struct ccw_device *);
91int ccw_purge_blacklisted(void); 93int ccw_purge_blacklisted(void);
92 94
@@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type;
133void retry_set_schib(struct ccw_device *cdev); 135void retry_set_schib(struct ccw_device *cdev);
134void cmf_retry_copy_block(struct ccw_device *); 136void cmf_retry_copy_block(struct ccw_device *);
135int cmf_reenable(struct ccw_device *); 137int cmf_reenable(struct ccw_device *);
138int ccw_set_cmf(struct ccw_device *cdev, int enable);
136extern struct device_attribute dev_attr_cmb_enable; 139extern struct device_attribute dev_attr_cmb_enable;
137#endif 140#endif
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index e46049261561..3db88c52d287 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
177 panic("Can't stop i/o on subchannel.\n"); 177 panic("Can't stop i/o on subchannel.\n");
178} 178}
179 179
180static int 180void ccw_device_update_sense_data(struct ccw_device *cdev)
181ccw_device_handle_oper(struct ccw_device *cdev)
182{ 181{
183 struct subchannel *sch; 182 memset(&cdev->id, 0, sizeof(cdev->id));
183 cdev->id.cu_type = cdev->private->senseid.cu_type;
184 cdev->id.cu_model = cdev->private->senseid.cu_model;
185 cdev->id.dev_type = cdev->private->senseid.dev_type;
186 cdev->id.dev_model = cdev->private->senseid.dev_model;
187}
184 188
185 sch = to_subchannel(cdev->dev.parent); 189int ccw_device_test_sense_data(struct ccw_device *cdev)
186 cdev->private->flags.recog_done = 1; 190{
187 /* 191 return cdev->id.cu_type == cdev->private->senseid.cu_type &&
188 * Check if cu type and device type still match. If 192 cdev->id.cu_model == cdev->private->senseid.cu_model &&
189 * not, it is certainly another device and we have to 193 cdev->id.dev_type == cdev->private->senseid.dev_type &&
190 * de- and re-register. 194 cdev->id.dev_model == cdev->private->senseid.dev_model;
191 */
192 if (cdev->id.cu_type != cdev->private->senseid.cu_type ||
193 cdev->id.cu_model != cdev->private->senseid.cu_model ||
194 cdev->id.dev_type != cdev->private->senseid.dev_type ||
195 cdev->id.dev_model != cdev->private->senseid.dev_model) {
196 PREPARE_WORK(&cdev->private->kick_work,
197 ccw_device_do_unbind_bind);
198 queue_work(ccw_device_work, &cdev->private->kick_work);
199 return 0;
200 }
201 cdev->private->flags.donotify = 1;
202 return 1;
203} 195}
204 196
205/* 197/*
@@ -233,7 +225,7 @@ static void
233ccw_device_recog_done(struct ccw_device *cdev, int state) 225ccw_device_recog_done(struct ccw_device *cdev, int state)
234{ 226{
235 struct subchannel *sch; 227 struct subchannel *sch;
236 int notify, old_lpm, same_dev; 228 int old_lpm;
237 229
238 sch = to_subchannel(cdev->dev.parent); 230 sch = to_subchannel(cdev->dev.parent);
239 231
@@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
263 wake_up(&cdev->private->wait_q); 255 wake_up(&cdev->private->wait_q);
264 return; 256 return;
265 } 257 }
266 notify = 0; 258 if (cdev->private->flags.resuming) {
267 same_dev = 0; /* Keep the compiler quiet... */ 259 cdev->private->state = state;
260 cdev->private->flags.recog_done = 1;
261 wake_up(&cdev->private->wait_q);
262 return;
263 }
268 switch (state) { 264 switch (state) {
269 case DEV_STATE_NOT_OPER: 265 case DEV_STATE_NOT_OPER:
270 CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " 266 CIO_MSG_EVENT(2, "SenseID : unknown device %04x on "
@@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
273 sch->schid.ssid, sch->schid.sch_no); 269 sch->schid.ssid, sch->schid.sch_no);
274 break; 270 break;
275 case DEV_STATE_OFFLINE: 271 case DEV_STATE_OFFLINE:
276 if (cdev->online) { 272 if (!cdev->online) {
277 same_dev = ccw_device_handle_oper(cdev); 273 ccw_device_update_sense_data(cdev);
278 notify = 1; 274 /* Issue device info message. */
275 CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
276 "CU Type/Mod = %04X/%02X, Dev Type/Mod "
277 "= %04X/%02X\n",
278 cdev->private->dev_id.ssid,
279 cdev->private->dev_id.devno,
280 cdev->id.cu_type, cdev->id.cu_model,
281 cdev->id.dev_type, cdev->id.dev_model);
282 break;
279 } 283 }
280 /* fill out sense information */ 284 cdev->private->state = DEV_STATE_OFFLINE;
281 memset(&cdev->id, 0, sizeof(cdev->id)); 285 cdev->private->flags.recog_done = 1;
282 cdev->id.cu_type = cdev->private->senseid.cu_type; 286 if (ccw_device_test_sense_data(cdev)) {
283 cdev->id.cu_model = cdev->private->senseid.cu_model; 287 cdev->private->flags.donotify = 1;
284 cdev->id.dev_type = cdev->private->senseid.dev_type; 288 ccw_device_online(cdev);
285 cdev->id.dev_model = cdev->private->senseid.dev_model; 289 wake_up(&cdev->private->wait_q);
286 if (notify) { 290 } else {
287 cdev->private->state = DEV_STATE_OFFLINE; 291 ccw_device_update_sense_data(cdev);
288 if (same_dev) { 292 PREPARE_WORK(&cdev->private->kick_work,
289 /* Get device online again. */ 293 ccw_device_do_unbind_bind);
290 ccw_device_online(cdev); 294 queue_work(ccw_device_work, &cdev->private->kick_work);
291 wake_up(&cdev->private->wait_q);
292 }
293 return;
294 } 295 }
295 /* Issue device info message. */ 296 return;
296 CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
297 "CU Type/Mod = %04X/%02X, Dev Type/Mod = "
298 "%04X/%02X\n",
299 cdev->private->dev_id.ssid,
300 cdev->private->dev_id.devno,
301 cdev->id.cu_type, cdev->id.cu_model,
302 cdev->id.dev_type, cdev->id.dev_model);
303 break;
304 case DEV_STATE_BOXED: 297 case DEV_STATE_BOXED:
305 CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " 298 CIO_MSG_EVENT(0, "SenseID : boxed device %04x on "
306 " subchannel 0.%x.%04x\n", 299 " subchannel 0.%x.%04x\n",
@@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev)
502 struct subchannel *sch; 495 struct subchannel *sch;
503 int ret; 496 int ret;
504 497
505 if ((cdev->private->state != DEV_STATE_NOT_OPER) &&
506 (cdev->private->state != DEV_STATE_BOXED))
507 return -EINVAL;
508 sch = to_subchannel(cdev->dev.parent); 498 sch = to_subchannel(cdev->dev.parent);
509 ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); 499 ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
510 if (ret != 0) 500 if (ret != 0)
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index bf0a24af39a0..2d0efee8a290 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -1,10 +1,8 @@
1/* 1/*
2 * drivers/s390/cio/device_ops.c 2 * Copyright IBM Corp. 2002, 2009
3 * 3 *
4 * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, 4 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
5 * IBM Corporation 5 * Cornelia Huck (cornelia.huck@de.ibm.com)
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
7 * Cornelia Huck (cornelia.huck@de.ibm.com)
8 */ 6 */
9#include <linux/module.h> 7#include <linux/module.h>
10#include <linux/init.h> 8#include <linux/init.h>
@@ -116,12 +114,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
116 114
117 if (!cdev || !cdev->dev.parent) 115 if (!cdev || !cdev->dev.parent)
118 return -ENODEV; 116 return -ENODEV;
117 sch = to_subchannel(cdev->dev.parent);
118 if (!sch->schib.pmcw.ena)
119 return -EINVAL;
119 if (cdev->private->state == DEV_STATE_NOT_OPER) 120 if (cdev->private->state == DEV_STATE_NOT_OPER)
120 return -ENODEV; 121 return -ENODEV;
121 if (cdev->private->state != DEV_STATE_ONLINE && 122 if (cdev->private->state != DEV_STATE_ONLINE &&
122 cdev->private->state != DEV_STATE_W4SENSE) 123 cdev->private->state != DEV_STATE_W4SENSE)
123 return -EINVAL; 124 return -EINVAL;
124 sch = to_subchannel(cdev->dev.parent); 125
125 ret = cio_clear(sch); 126 ret = cio_clear(sch);
126 if (ret == 0) 127 if (ret == 0)
127 cdev->private->intparm = intparm; 128 cdev->private->intparm = intparm;
@@ -162,6 +163,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
162 if (!cdev || !cdev->dev.parent) 163 if (!cdev || !cdev->dev.parent)
163 return -ENODEV; 164 return -ENODEV;
164 sch = to_subchannel(cdev->dev.parent); 165 sch = to_subchannel(cdev->dev.parent);
166 if (!sch->schib.pmcw.ena)
167 return -EINVAL;
165 if (cdev->private->state == DEV_STATE_NOT_OPER) 168 if (cdev->private->state == DEV_STATE_NOT_OPER)
166 return -ENODEV; 169 return -ENODEV;
167 if (cdev->private->state == DEV_STATE_VERIFY || 170 if (cdev->private->state == DEV_STATE_VERIFY ||
@@ -337,12 +340,15 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
337 340
338 if (!cdev || !cdev->dev.parent) 341 if (!cdev || !cdev->dev.parent)
339 return -ENODEV; 342 return -ENODEV;
343 sch = to_subchannel(cdev->dev.parent);
344 if (!sch->schib.pmcw.ena)
345 return -EINVAL;
340 if (cdev->private->state == DEV_STATE_NOT_OPER) 346 if (cdev->private->state == DEV_STATE_NOT_OPER)
341 return -ENODEV; 347 return -ENODEV;
342 if (cdev->private->state != DEV_STATE_ONLINE && 348 if (cdev->private->state != DEV_STATE_ONLINE &&
343 cdev->private->state != DEV_STATE_W4SENSE) 349 cdev->private->state != DEV_STATE_W4SENSE)
344 return -EINVAL; 350 return -EINVAL;
345 sch = to_subchannel(cdev->dev.parent); 351
346 ret = cio_halt(sch); 352 ret = cio_halt(sch);
347 if (ret == 0) 353 if (ret == 0)
348 cdev->private->intparm = intparm; 354 cdev->private->intparm = intparm;
@@ -369,6 +375,8 @@ int ccw_device_resume(struct ccw_device *cdev)
369 if (!cdev || !cdev->dev.parent) 375 if (!cdev || !cdev->dev.parent)
370 return -ENODEV; 376 return -ENODEV;
371 sch = to_subchannel(cdev->dev.parent); 377 sch = to_subchannel(cdev->dev.parent);
378 if (!sch->schib.pmcw.ena)
379 return -EINVAL;
372 if (cdev->private->state == DEV_STATE_NOT_OPER) 380 if (cdev->private->state == DEV_STATE_NOT_OPER)
373 return -ENODEV; 381 return -ENODEV;
374 if (cdev->private->state != DEV_STATE_ONLINE || 382 if (cdev->private->state != DEV_STATE_ONLINE ||
@@ -580,6 +588,8 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
580 int rc; 588 int rc;
581 589
582 sch = to_subchannel(cdev->dev.parent); 590 sch = to_subchannel(cdev->dev.parent);
591 if (!sch->schib.pmcw.ena)
592 return -EINVAL;
583 if (cdev->private->state != DEV_STATE_ONLINE) 593 if (cdev->private->state != DEV_STATE_ONLINE)
584 return -EIO; 594 return -EIO;
585 /* Adjust requested path mask to excluded varied off paths. */ 595 /* Adjust requested path mask to excluded varied off paths. */
@@ -669,6 +679,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev)
669{ 679{
670 struct subchannel *sch = to_subchannel(cdev->dev.parent); 680 struct subchannel *sch = to_subchannel(cdev->dev.parent);
671 681
682 if (!sch->schib.pmcw.ena)
683 return -EINVAL;
672 if (cdev->private->state != DEV_STATE_ONLINE) 684 if (cdev->private->state != DEV_STATE_ONLINE)
673 return -EIO; 685 return -EIO;
674 if (!scsw_is_tm(&sch->schib.scsw) || 686 if (!scsw_is_tm(&sch->schib.scsw) ||
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index c4f3e7c9a854..0b8f381bd20e 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -107,6 +107,7 @@ struct ccw_device_private {
107 unsigned int recog_done:1; /* dev. recog. complete */ 107 unsigned int recog_done:1; /* dev. recog. complete */
108 unsigned int fake_irb:1; /* deliver faked irb */ 108 unsigned int fake_irb:1; /* deliver faked irb */
109 unsigned int intretry:1; /* retry internal operation */ 109 unsigned int intretry:1; /* retry internal operation */
110 unsigned int resuming:1; /* recognition while resume */
110 } __attribute__((packed)) flags; 111 } __attribute__((packed)) flags;
111 unsigned long intparm; /* user interruption parameter */ 112 unsigned long intparm; /* user interruption parameter */
112 struct qdio_irq *qdio_data; 113 struct qdio_irq *qdio_data;