*/
#include <linux/kernel_stat.h>
+#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h>
#include <linux/device.h>
}
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)
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)
#ifndef EADM_SCH_H
#define EADM_SCH_H
+#include <linux/completion.h>
#include <linux/device.h>
#include <linux/timer.h>
#include <linux/list.h>
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))