DECLARE_COMPLETION_ONSTACK(completion);
        int iretry, ret = 0;
 
-       spin_lock_irq(sch->lock);
-       if (!sch->schib.pmcw.ena)
-               goto out_unlock;
-       ret = cio_disable_subchannel(sch);
-       if (ret != -EBUSY)
-               goto out_unlock;
-
        iretry = 255;
        do {
 
                spin_lock_irq(sch->lock);
                ret = cio_disable_subchannel(sch);
        } while (ret == -EBUSY);
-out_unlock:
-       private->state = VFIO_CCW_STATE_NOT_OPER;
-       spin_unlock_irq(sch->lock);
+
        return ret;
 }
 
 {
        struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
 
-       vfio_ccw_sch_quiesce(sch);
+       vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
        mdev_unregister_device(&sch->dev);
 
        dev_set_drvdata(&sch->dev, NULL);
 
 static void vfio_ccw_sch_shutdown(struct subchannel *sch)
 {
-       vfio_ccw_sch_quiesce(sch);
+       struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
+
+       vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
 }
 
 /**
 
        spin_unlock_irq(sch->lock);
 }
 
+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 out_unlock;
+
+       ret = cio_disable_subchannel(sch);
+       if (ret == -EBUSY)
+               vfio_ccw_sch_quiesce(sch);
+
+out_unlock:
+       private->state = VFIO_CCW_STATE_NOT_OPER;
+       spin_unlock_irq(sch->lock);
+       cp_free(&private->cp);
+}
+
 /*
  * Device statemachine
  */
                [VFIO_CCW_EVENT_ASYNC_REQ]      = fsm_async_error,
                [VFIO_CCW_EVENT_INTERRUPT]      = fsm_disabled_irq,
                [VFIO_CCW_EVENT_OPEN]           = fsm_open,
+               [VFIO_CCW_EVENT_CLOSE]          = fsm_nop,
        },
        [VFIO_CCW_STATE_STANDBY] = {
                [VFIO_CCW_EVENT_NOT_OPER]       = fsm_notoper,
                [VFIO_CCW_EVENT_ASYNC_REQ]      = fsm_async_error,
                [VFIO_CCW_EVENT_INTERRUPT]      = fsm_irq,
                [VFIO_CCW_EVENT_OPEN]           = fsm_notoper,
+               [VFIO_CCW_EVENT_CLOSE]          = fsm_close,
        },
        [VFIO_CCW_STATE_IDLE] = {
                [VFIO_CCW_EVENT_NOT_OPER]       = fsm_notoper,
                [VFIO_CCW_EVENT_ASYNC_REQ]      = fsm_async_request,
                [VFIO_CCW_EVENT_INTERRUPT]      = fsm_irq,
                [VFIO_CCW_EVENT_OPEN]           = fsm_notoper,
+               [VFIO_CCW_EVENT_CLOSE]          = fsm_close,
        },
        [VFIO_CCW_STATE_CP_PROCESSING] = {
                [VFIO_CCW_EVENT_NOT_OPER]       = fsm_notoper,
                [VFIO_CCW_EVENT_ASYNC_REQ]      = fsm_async_retry,
                [VFIO_CCW_EVENT_INTERRUPT]      = fsm_irq,
                [VFIO_CCW_EVENT_OPEN]           = fsm_notoper,
+               [VFIO_CCW_EVENT_CLOSE]          = fsm_close,
        },
        [VFIO_CCW_STATE_CP_PENDING] = {
                [VFIO_CCW_EVENT_NOT_OPER]       = fsm_notoper,
                [VFIO_CCW_EVENT_ASYNC_REQ]      = fsm_async_request,
                [VFIO_CCW_EVENT_INTERRUPT]      = fsm_irq,
                [VFIO_CCW_EVENT_OPEN]           = fsm_notoper,
+               [VFIO_CCW_EVENT_CLOSE]          = fsm_close,
        },
 };
 
         * There are still a lot more instructions need to be handled. We
         * should come back here later.
         */
-       ret = vfio_ccw_sch_quiesce(sch);
-       if (ret)
-               return ret;
+       vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
 
        ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
        if (!ret)
                if (vfio_ccw_mdev_reset(private))
                        return NOTIFY_BAD;
 
-               cp_free(&private->cp);
                return NOTIFY_OK;
        }
 
 
        vfio_unregister_group_dev(&private->vdev);
 
-       if ((private->state != VFIO_CCW_STATE_NOT_OPER) &&
-           (private->state != VFIO_CCW_STATE_STANDBY)) {
-               if (!vfio_ccw_sch_quiesce(private->sch))
-                       private->state = VFIO_CCW_STATE_STANDBY;
-               /* The state will be NOT_OPER on error. */
-       }
+       vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
 
        vfio_uninit_group_dev(&private->vdev);
-       cp_free(&private->cp);
        atomic_inc(&private->avail);
 }
 
                /* The state will be NOT_OPER on error. */
        }
 
-       cp_free(&private->cp);
        vfio_ccw_unregister_dev_regions(private);
        vfio_unregister_notifier(vdev, VFIO_IOMMU_NOTIFY, &private->nb);
 }