aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2013-09-25 06:29:05 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-10-24 11:16:58 -0400
commit6aa2677a57fdd8964ccd44766cdc06cdd9c5db5b (patch)
tree6da34df3a028e8ce177a4b41f09ad3f6158e4d50 /drivers/s390
parent69db3b5e850d0cac543d8523cbde17a4729f8990 (diff)
s390/eadm_sch: improve quiesce handling
When quiescing an eadm subchannel make sure that outstanding IO is cleared and potential timeout handlers are canceled. Reviewed-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> 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/eadm_sch.c27
-rw-r--r--drivers/s390/cio/eadm_sch.h4
2 files changed, 28 insertions, 3 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
164static struct subchannel *eadm_get_idle_sch(void) 168static struct subchannel *eadm_get_idle_sch(void)
@@ -255,13 +259,32 @@ out:
255 259
256static void eadm_quiesce(struct subchannel *sch) 260static 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
281disable:
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
267static int eadm_subchannel_remove(struct subchannel *sch) 290static int eadm_subchannel_remove(struct subchannel *sch)
diff --git a/drivers/s390/cio/eadm_sch.h b/drivers/s390/cio/eadm_sch.h
index 2779be093982..9664e4653f98 100644
--- a/drivers/s390/cio/eadm_sch.h
+++ b/drivers/s390/cio/eadm_sch.h
@@ -1,6 +1,7 @@
1#ifndef EADM_SCH_H 1#ifndef EADM_SCH_H
2#define EADM_SCH_H 2#define EADM_SCH_H
3 3
4#include <linux/completion.h>
4#include <linux/device.h> 5#include <linux/device.h>
5#include <linux/timer.h> 6#include <linux/timer.h>
6#include <linux/list.h> 7#include <linux/list.h>
@@ -9,9 +10,10 @@
9struct eadm_private { 10struct eadm_private {
10 union orb orb; 11 union orb orb;
11 enum {EADM_IDLE, EADM_BUSY, EADM_NOT_OPER} state; 12 enum {EADM_IDLE, EADM_BUSY, EADM_NOT_OPER} state;
13 struct completion *completion;
14 struct subchannel *sch;
12 struct timer_list timer; 15 struct timer_list timer;
13 struct list_head head; 16 struct list_head head;
14 struct subchannel *sch;
15} __aligned(8); 17} __aligned(8);
16 18
17#define get_eadm_private(n) ((struct eadm_private *)dev_get_drvdata(&n->dev)) 19#define get_eadm_private(n) ((struct eadm_private *)dev_get_drvdata(&n->dev))