Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6aa2677a authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

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: default avatarPeter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 69db3b5e
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -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;

	do {
	spin_lock_irq(sch->lock);
		ret = cio_disable_subchannel(sch);
	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 {
		ret = cio_disable_subchannel(sch);
	} while (ret == -EBUSY);

	spin_unlock_irq(sch->lock);
}

static int eadm_subchannel_remove(struct subchannel *sch)
+3 −1
Original line number Diff line number Diff line
#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))