On Mon, Sep 13, 2021 at 04:31:54PM -0400, Eric Farman wrote:
> > I rebased it and fixed it up here:
> > 
> > https://github.com/jgunthorpe/linux/tree/vfio_ccw
> > 
> > Can you try again?
> 
> That does address the crash, but then why is it processing a BROKEN
> event? Seems problematic. 

The stuff related to the NOT_OPER looked really wonky to me. I'm
guessing this is the issue - not sure about the pmcw.ena either..

diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index 5ea392959c0711..0d4d4f425befac 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -380,29 +380,19 @@ static void fsm_open(struct vfio_ccw_private *private,
        spin_unlock_irq(sch->lock);
 }
 
-static void fsm_close(struct vfio_ccw_private *private,
-                     enum vfio_ccw_event event)
+static int flush_sch(struct vfio_ccw_private *private)
 {
        struct subchannel *sch = private->sch;
        DECLARE_COMPLETION_ONSTACK(completion);
        int iretry, ret = 0;
 
-       spin_lock_irq(sch->lock);
-       if (!sch->schib.pmcw.ena)
-               goto err_unlock;
-       ret = cio_disable_subchannel(sch);
-       if (ret != -EBUSY)
-               goto err_unlock;
-
        iretry = 255;
        do {
-
                ret = cio_cancel_halt_clear(sch, &iretry);
-
                if (ret == -EIO) {
                        pr_err("vfio_ccw: could not quiesce subchannel 
0.%x.%04x!\n",
                               sch->schid.ssid, sch->schid.sch_no);
-                       break;
+                       return ret;
                }
 
                /*
@@ -413,13 +403,28 @@ static void fsm_close(struct vfio_ccw_private *private,
                spin_unlock_irq(sch->lock);
 
                if (ret == -EBUSY)
-                       wait_for_completion_timeout(&completion, 3*HZ);
+                       wait_for_completion_timeout(&completion, 3 * HZ);
 
                private->completion = NULL;
                flush_workqueue(vfio_ccw_work_q);
                spin_lock_irq(sch->lock);
                ret = cio_disable_subchannel(sch);
        } while (ret == -EBUSY);
+       return ret;
+}
+
+static void fsm_close(struct vfio_ccw_private *private,
+                     enum vfio_ccw_event event)
+{
+       struct subchannel *sch = private->sch;
+       int ret;
+
+       spin_lock_irq(sch->lock);
+       if (!sch->schib.pmcw.ena)
+               goto err_unlock;
+       ret = cio_disable_subchannel(sch);
+       if (ret == -EBUSY)
+               ret = flush_sch(private);
        if (ret)
                goto err_unlock;
        private->state = VFIO_CCW_STATE_CLOSED;

Reply via email to