|
@@ -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)
|