diff options
Diffstat (limited to 'drivers/s390/cio/eadm_sch.c')
-rw-r--r-- | drivers/s390/cio/eadm_sch.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index 6b54d8a05cd4..aca7bfc113aa 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c | |||
@@ -6,6 +6,7 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/kernel_stat.h> | 8 | #include <linux/kernel_stat.h> |
9 | #include <linux/completion.h> | ||
9 | #include <linux/workqueue.h> | 10 | #include <linux/workqueue.h> |
10 | #include <linux/spinlock.h> | 11 | #include <linux/spinlock.h> |
11 | #include <linux/device.h> | 12 | #include <linux/device.h> |
@@ -159,6 +160,9 @@ static void eadm_subchannel_irq(struct subchannel *sch) | |||
159 | } | 160 | } |
160 | scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error); | 161 | scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error); |
161 | private->state = EADM_IDLE; | 162 | private->state = EADM_IDLE; |
163 | |||
164 | if (private->completion) | ||
165 | complete(private->completion); | ||
162 | } | 166 | } |
163 | 167 | ||
164 | static struct subchannel *eadm_get_idle_sch(void) | 168 | static struct subchannel *eadm_get_idle_sch(void) |
@@ -255,13 +259,32 @@ out: | |||
255 | 259 | ||
256 | static void eadm_quiesce(struct subchannel *sch) | 260 | static void eadm_quiesce(struct subchannel *sch) |
257 | { | 261 | { |
262 | struct eadm_private *private = get_eadm_private(sch); | ||
263 | DECLARE_COMPLETION_ONSTACK(completion); | ||
258 | int ret; | 264 | int ret; |
259 | 265 | ||
266 | spin_lock_irq(sch->lock); | ||
267 | if (private->state != EADM_BUSY) | ||
268 | goto disable; | ||
269 | |||
270 | if (eadm_subchannel_clear(sch)) | ||
271 | goto disable; | ||
272 | |||
273 | private->completion = &completion; | ||
274 | spin_unlock_irq(sch->lock); | ||
275 | |||
276 | wait_for_completion_io(&completion); | ||
277 | |||
278 | spin_lock_irq(sch->lock); | ||
279 | private->completion = NULL; | ||
280 | |||
281 | disable: | ||
282 | eadm_subchannel_set_timeout(sch, 0); | ||
260 | do { | 283 | do { |
261 | spin_lock_irq(sch->lock); | ||
262 | ret = cio_disable_subchannel(sch); | 284 | ret = cio_disable_subchannel(sch); |
263 | spin_unlock_irq(sch->lock); | ||
264 | } while (ret == -EBUSY); | 285 | } while (ret == -EBUSY); |
286 | |||
287 | spin_unlock_irq(sch->lock); | ||
265 | } | 288 | } |
266 | 289 | ||
267 | static int eadm_subchannel_remove(struct subchannel *sch) | 290 | static int eadm_subchannel_remove(struct subchannel *sch) |