Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Sebastian Ott and committed by
Martin Schwidefsky
6aa2677a 69db3b5e

+28 -3
+25 -2
drivers/s390/cio/eadm_sch.c
··· 6 6 */ 7 7 8 8 #include <linux/kernel_stat.h> 9 + #include <linux/completion.h> 9 10 #include <linux/workqueue.h> 10 11 #include <linux/spinlock.h> 11 12 #include <linux/device.h> ··· 160 159 } 161 160 scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error); 162 161 private->state = EADM_IDLE; 162 + 163 + if (private->completion) 164 + complete(private->completion); 163 165 } 164 166 165 167 static struct subchannel *eadm_get_idle_sch(void) ··· 259 255 260 256 static void eadm_quiesce(struct subchannel *sch) 261 257 { 258 + struct eadm_private *private = get_eadm_private(sch); 259 + DECLARE_COMPLETION_ONSTACK(completion); 262 260 int ret; 263 261 262 + spin_lock_irq(sch->lock); 263 + if (private->state != EADM_BUSY) 264 + goto disable; 265 + 266 + if (eadm_subchannel_clear(sch)) 267 + goto disable; 268 + 269 + private->completion = &completion; 270 + spin_unlock_irq(sch->lock); 271 + 272 + wait_for_completion_io(&completion); 273 + 274 + spin_lock_irq(sch->lock); 275 + private->completion = NULL; 276 + 277 + disable: 278 + eadm_subchannel_set_timeout(sch, 0); 264 279 do { 265 - spin_lock_irq(sch->lock); 266 280 ret = cio_disable_subchannel(sch); 267 - spin_unlock_irq(sch->lock); 268 281 } while (ret == -EBUSY); 282 + 283 + spin_unlock_irq(sch->lock); 269 284 } 270 285 271 286 static int eadm_subchannel_remove(struct subchannel *sch)
+3 -1
drivers/s390/cio/eadm_sch.h
··· 1 1 #ifndef EADM_SCH_H 2 2 #define EADM_SCH_H 3 3 4 + #include <linux/completion.h> 4 5 #include <linux/device.h> 5 6 #include <linux/timer.h> 6 7 #include <linux/list.h> ··· 10 9 struct eadm_private { 11 10 union orb orb; 12 11 enum {EADM_IDLE, EADM_BUSY, EADM_NOT_OPER} state; 12 + struct completion *completion; 13 + struct subchannel *sch; 13 14 struct timer_list timer; 14 15 struct list_head head; 15 - struct subchannel *sch; 16 16 } __aligned(8); 17 17 18 18 #define get_eadm_private(n) ((struct eadm_private *)dev_get_drvdata(&n->dev))