mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 05:04:09 +08:00
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>
This commit is contained in:
parent
69db3b5e85
commit
6aa2677a57
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/device.h>
|
||||
@ -159,6 +160,9 @@ static void eadm_subchannel_irq(struct subchannel *sch)
|
||||
}
|
||||
scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error);
|
||||
private->state = EADM_IDLE;
|
||||
|
||||
if (private->completion)
|
||||
complete(private->completion);
|
||||
}
|
||||
|
||||
static struct subchannel *eadm_get_idle_sch(void)
|
||||
@ -255,13 +259,32 @@ out:
|
||||
|
||||
static void eadm_quiesce(struct subchannel *sch)
|
||||
{
|
||||
struct eadm_private *private = get_eadm_private(sch);
|
||||
DECLARE_COMPLETION_ONSTACK(completion);
|
||||
int ret;
|
||||
|
||||
spin_lock_irq(sch->lock);
|
||||
if (private->state != EADM_BUSY)
|
||||
goto disable;
|
||||
|
||||
if (eadm_subchannel_clear(sch))
|
||||
goto disable;
|
||||
|
||||
private->completion = &completion;
|
||||
spin_unlock_irq(sch->lock);
|
||||
|
||||
wait_for_completion_io(&completion);
|
||||
|
||||
spin_lock_irq(sch->lock);
|
||||
private->completion = NULL;
|
||||
|
||||
disable:
|
||||
eadm_subchannel_set_timeout(sch, 0);
|
||||
do {
|
||||
spin_lock_irq(sch->lock);
|
||||
ret = cio_disable_subchannel(sch);
|
||||
spin_unlock_irq(sch->lock);
|
||||
} while (ret == -EBUSY);
|
||||
|
||||
spin_unlock_irq(sch->lock);
|
||||
}
|
||||
|
||||
static int eadm_subchannel_remove(struct subchannel *sch)
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef EADM_SCH_H
|
||||
#define EADM_SCH_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/list.h>
|
||||
@ -9,9 +10,10 @@
|
||||
struct eadm_private {
|
||||
union orb orb;
|
||||
enum {EADM_IDLE, EADM_BUSY, EADM_NOT_OPER} state;
|
||||
struct completion *completion;
|
||||
struct subchannel *sch;
|
||||
struct timer_list timer;
|
||||
struct list_head head;
|
||||
struct subchannel *sch;
|
||||
} __aligned(8);
|
||||
|
||||
#define get_eadm_private(n) ((struct eadm_private *)dev_get_drvdata(&n->dev))
|
||||
|
Loading…
Reference in New Issue
Block a user