diff mbox

[PULL,08/25] s390x/css: Unplug handler of virtual css bridge

Message ID 20160711080912.13947-9-cornelia.huck@de.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Cornelia Huck July 11, 2016, 8:08 a.m. UTC
From: Jing Liu <liujbjl@linux.vnet.ibm.com>

The previous patch moved virtual css bridge and bus out from
virtio-ccw, but kept the direct reference of virtio-ccw specific
unplug function inside css-bridge.c.

To make the virtual css bus and bridge useful for non-virtio devices,
this introduces a common unplug function pointer "unplug" to call
specific virtio-ccw unplug parts. Thus, the tight coupling to
virtio-ccw can be removed.

This unplug pointer is a member of CCWDeviceClass, which is introduced
as an abstract device layer called "ccw-device". This layer is between
DeviceState and specific devices which are plugged in virtual css bus,
like virtio-ccw device. The specific unplug handlers should be assigned
to "unplug" during initialization.

Signed-off-by: Jing Liu <liujbjl@linux.vnet.ibm.com>
Reviewed-by: Sascha Silbe <silbe@linux.vnet.ibm.com>
Reviewed-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
Reviewed-by: Yi Min Zhao <zyimin@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
 hw/s390x/Makefile.objs |  1 +
 hw/s390x/ccw-device.c  | 27 ++++++++++++++++
 hw/s390x/ccw-device.h  | 43 +++++++++++++++++++++++++
 hw/s390x/css-bridge.c  | 39 +++++++++++++++++++++--
 hw/s390x/ipl.c         | 14 ++++----
 hw/s390x/virtio-ccw.c  | 86 ++++++++++++++++++++++++++------------------------
 hw/s390x/virtio-ccw.h  | 11 +++----
 7 files changed, 164 insertions(+), 57 deletions(-)
 create mode 100644 hw/s390x/ccw-device.c
 create mode 100644 hw/s390x/ccw-device.h
diff mbox

Patch

diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 141ce1a..41ac4ec 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -9,6 +9,7 @@  obj-y += css.o
 obj-y += s390-virtio-ccw.o
 obj-y += virtio-ccw.o
 obj-y += css-bridge.o
+obj-y += ccw-device.o
 obj-y += s390-pci-bus.o s390-pci-inst.o
 obj-y += s390-skeys.o
 obj-$(CONFIG_KVM) += s390-skeys-kvm.o
diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c
new file mode 100644
index 0000000..28ea204
--- /dev/null
+++ b/hw/s390x/ccw-device.c
@@ -0,0 +1,27 @@ 
+/*
+ * Common device infrastructure for devices in the virtual css
+ *
+ * Copyright 2016 IBM Corp.
+ * Author(s): Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+#include "qemu/osdep.h"
+#include "ccw-device.h"
+
+static const TypeInfo ccw_device_info = {
+    .name = TYPE_CCW_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(CcwDevice),
+    .class_size = sizeof(CCWDeviceClass),
+    .abstract = true,
+};
+
+static void ccw_device_register(void)
+{
+    type_register_static(&ccw_device_info);
+}
+
+type_init(ccw_device_register)
diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h
new file mode 100644
index 0000000..59ba01b
--- /dev/null
+++ b/hw/s390x/ccw-device.h
@@ -0,0 +1,43 @@ 
+/*
+ * Common device infrastructure for devices in the virtual css
+ *
+ * Copyright 2016 IBM Corp.
+ * Author(s): Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef HW_S390X_CCW_DEVICE_H
+#define HW_S390X_CCW_DEVICE_H
+#include "qom/object.h"
+#include "hw/qdev-core.h"
+#include "hw/s390x/css.h"
+
+typedef struct CcwDevice {
+    DeviceState parent_obj;
+    SubchDev *sch;
+    /* <cssid>.<ssid>.<device number> */
+    CssDevId bus_id;
+} CcwDevice;
+
+typedef struct CCWDeviceClass {
+    DeviceClass parent_class;
+    void (*unplug)(HotplugHandler *, DeviceState *, Error **);
+} CCWDeviceClass;
+
+static inline CcwDevice *to_ccw_dev_fast(DeviceState *d)
+{
+    return container_of(d, CcwDevice, parent_obj);
+}
+
+#define TYPE_CCW_DEVICE "ccw-device"
+
+#define CCW_DEVICE(obj) OBJECT_CHECK(CcwDevice, (obj), TYPE_CCW_DEVICE)
+#define CCW_DEVICE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(CCWDeviceClass, (obj), TYPE_CCW_DEVICE)
+#define CCW_DEVICE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(CCWDeviceClass, (klass), TYPE_CCW_DEVICE)
+
+#endif
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index e74cc1c..e4c24e2 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -11,13 +11,48 @@ 
  */
 #include "qemu/osdep.h"
 #include "qapi/error.h"
-#include "virtio-ccw.h"
 #include "hw/hotplug.h"
 #include "hw/sysbus.h"
 #include "qemu/bitops.h"
 #include "hw/s390x/css.h"
+#include "ccw-device.h"
 #include "hw/s390x/css-bridge.h"
 
+/*
+ * Invoke device-specific unplug handler, disable the subchannel
+ * (including sending a channel report to the guest) and remove the
+ * device from the virtual css bus.
+ */
+static void ccw_device_unplug(HotplugHandler *hotplug_dev,
+                              DeviceState *dev, Error **errp)
+{
+    CcwDevice *ccw_dev = CCW_DEVICE(dev);
+    CCWDeviceClass *k = CCW_DEVICE_GET_CLASS(ccw_dev);
+    SubchDev *sch = ccw_dev->sch;
+    Error *err = NULL;
+
+    if (k->unplug) {
+        k->unplug(hotplug_dev, dev, &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+    }
+
+    /*
+     * We should arrive here only for device_del, since we don't support
+     * direct hot(un)plug of channels.
+     */
+    assert(sch != NULL);
+    /* Subchannel is now disabled and no longer valid. */
+    sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA |
+                                     PMCW_FLAGS_MASK_DNV);
+
+    css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
+
+    object_unparent(OBJECT(dev));
+}
+
 static void virtual_css_bus_reset(BusState *qbus)
 {
     /* This should actually be modelled via the generic css */
@@ -65,7 +100,7 @@  static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
 
-    hc->unplug = virtio_ccw_busdev_unplug;
+    hc->unplug = ccw_device_unplug;
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 }
 
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index a54284c..2e2664f 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -221,12 +221,14 @@  static bool s390_gen_initial_iplb(S390IPLState *ipl)
 
     dev_st = get_boot_device(0);
     if (dev_st) {
-        VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast(
-            OBJECT(qdev_get_parent_bus(dev_st)->parent),
+        VirtioCcwDevice *virtio_ccw_dev = (VirtioCcwDevice *)
+            object_dynamic_cast(OBJECT(qdev_get_parent_bus(dev_st)->parent),
                 TYPE_VIRTIO_CCW_DEVICE);
         SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
                                                             TYPE_SCSI_DEVICE);
-        if (ccw_dev) {
+        if (virtio_ccw_dev) {
+            CcwDevice *ccw_dev = CCW_DEVICE(virtio_ccw_dev);
+
             ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
             ipl->iplb.blk0_len =
                 cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
@@ -238,7 +240,7 @@  static bool s390_gen_initial_iplb(S390IPLState *ipl)
             SCSIBus *bus = scsi_bus_from_device(sd);
             VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
             VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
-            VirtioCcwDevice *ccw = &scsi_ccw->parent_obj;
+            CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw);
 
             ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
             ipl->iplb.blk0_len =
@@ -247,8 +249,8 @@  static bool s390_gen_initial_iplb(S390IPLState *ipl)
             ipl->iplb.scsi.lun = cpu_to_be32(sd->lun);
             ipl->iplb.scsi.target = cpu_to_be16(sd->id);
             ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
-            ipl->iplb.scsi.devno = cpu_to_be16(ccw->sch->devno);
-            ipl->iplb.scsi.ssid = ccw->sch->ssid & 3;
+            ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
+            ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
             return true;
         }
     }
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 8f1a0e8..a554a24 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -97,7 +97,8 @@  static int virtio_ccw_ioeventfd_assign(DeviceState *d, EventNotifier *notifier,
                                        int n, bool assign)
 {
     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
-    SubchDev *sch = dev->sch;
+    CcwDevice *ccw_dev = CCW_DEVICE(dev);
+    SubchDev *sch = ccw_dev->sch;
     uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid;
 
     return s390_assign_subch_ioeventfd(notifier, sch_id, n, assign);
@@ -194,6 +195,8 @@  static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
 
 static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev)
 {
+    CcwDevice *ccw_dev = CCW_DEVICE(dev);
+
     virtio_ccw_stop_ioeventfd(dev);
     virtio_reset(vdev);
     if (dev->indicators) {
@@ -208,7 +211,7 @@  static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev)
         release_indicator(&dev->routes.adapter, dev->summary_indicator);
         dev->summary_indicator = NULL;
     }
-    dev->sch->thinint_active = false;
+    ccw_dev->sch->thinint_active = false;
 }
 
 static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len,
@@ -664,7 +667,8 @@  static void virtio_sch_disable_cb(SubchDev *sch)
 static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
 {
     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
-    SubchDev *sch = css_create_virtual_sch(dev->bus_id, errp);
+    CcwDevice *ccw_dev = CCW_DEVICE(dev);
+    SubchDev *sch = css_create_virtual_sch(ccw_dev->bus_id, errp);
     Error *err = NULL;
 
     if (!sch) {
@@ -676,14 +680,14 @@  static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
     sch->disable_cb = virtio_sch_disable_cb;
     sch->id.reserved = 0xff;
     sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
-    dev->sch = sch;
+    ccw_dev->sch = sch;
     dev->indicators = NULL;
     dev->revision = -1;
     css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE);
 
     trace_virtio_ccw_new_device(
         sch->cssid, sch->ssid, sch->schid, sch->devno,
-        dev->bus_id.valid ? "user-configured" : "auto-configured");
+        ccw_dev->bus_id.valid ? "user-configured" : "auto-configured");
 
     if (k->realize) {
         k->realize(dev, &err);
@@ -691,14 +695,15 @@  static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
     if (err) {
         error_propagate(errp, err);
         css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
-        dev->sch = NULL;
+        ccw_dev->sch = NULL;
         g_free(sch);
     }
 }
 
 static int virtio_ccw_exit(VirtioCcwDevice *dev)
 {
-    SubchDev *sch = dev->sch;
+    CcwDevice *ccw_dev = CCW_DEVICE(dev);
+    SubchDev *sch = ccw_dev->sch;
 
     if (sch) {
         css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
@@ -879,7 +884,9 @@  static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp)
  */
 static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
 {
-    return container_of(d, VirtioCcwDevice, parent_obj);
+    CcwDevice *ccw_dev = to_ccw_dev_fast(d);
+
+    return container_of(ccw_dev, VirtioCcwDevice, parent_obj);
 }
 
 static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
@@ -908,7 +915,8 @@  static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
 static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
 {
     VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d);
-    SubchDev *sch = dev->sch;
+    CcwDevice *ccw_dev = to_ccw_dev_fast(d);
+    SubchDev *sch = ccw_dev->sch;
     uint64_t indicators;
 
     /* queue indicators + secondary indicators */
@@ -966,9 +974,10 @@  static void virtio_ccw_reset(DeviceState *d)
 {
     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
+    CcwDevice *ccw_dev = CCW_DEVICE(d);
 
     virtio_ccw_reset_virtio(dev, vdev);
-    css_reset_sch(dev->sch);
+    css_reset_sch(ccw_dev->sch);
 }
 
 static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
@@ -984,7 +993,7 @@  static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
 
 static bool virtio_ccw_query_guest_notifiers(DeviceState *d)
 {
-    VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+    CcwDevice *dev = CCW_DEVICE(d);
 
     return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA);
 }
@@ -992,8 +1001,9 @@  static bool virtio_ccw_query_guest_notifiers(DeviceState *d)
 static int virtio_ccw_get_mappings(VirtioCcwDevice *dev)
 {
     int r;
+    CcwDevice *ccw_dev = CCW_DEVICE(dev);
 
-    if (!dev->sch->thinint_active) {
+    if (!ccw_dev->sch->thinint_active) {
         return -EINVAL;
     }
 
@@ -1115,7 +1125,8 @@  static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs,
 {
     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
-    bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled();
+    CcwDevice *ccw_dev = CCW_DEVICE(d);
+    bool with_irqfd = ccw_dev->sch->thinint_active && kvm_irqfds_enabled();
     int r, n;
 
     if (with_irqfd && assigned) {
@@ -1174,7 +1185,8 @@  static int virtio_ccw_load_queue(DeviceState *d, int n, QEMUFile *f)
 static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
 {
     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
-    SubchDev *s = dev->sch;
+    CcwDevice *ccw_dev = CCW_DEVICE(d);
+    SubchDev *s = ccw_dev->sch;
     VirtIODevice *vdev = virtio_ccw_get_vdev(s);
 
     subch_device_save(s, f);
@@ -1208,7 +1220,8 @@  static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
 static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
 {
     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
-    SubchDev *s = dev->sch;
+    CcwDevice *ccw_dev = CCW_DEVICE(d);
+    SubchDev *s = ccw_dev->sch;
     VirtIODevice *vdev = virtio_ccw_get_vdev(s);
     int len;
 
@@ -1253,7 +1266,8 @@  static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
 {
     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
-    SubchDev *sch = dev->sch;
+    CcwDevice *ccw_dev = CCW_DEVICE(d);
+    SubchDev *sch = ccw_dev->sch;
     int n = virtio_get_num_queues(vdev);
 
     if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) {
@@ -1297,7 +1311,7 @@  static void virtio_ccw_device_unplugged(DeviceState *d)
 /**************** Virtio-ccw Bus Device Descriptions *******************/
 
 static Property virtio_ccw_net_properties[] = {
-    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
+    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
     DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1326,7 +1340,7 @@  static const TypeInfo virtio_ccw_net = {
 };
 
 static Property virtio_ccw_blk_properties[] = {
-    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
+    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
     DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1355,7 +1369,7 @@  static const TypeInfo virtio_ccw_blk = {
 };
 
 static Property virtio_ccw_serial_properties[] = {
-    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
+    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
     DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1384,7 +1398,7 @@  static const TypeInfo virtio_ccw_serial = {
 };
 
 static Property virtio_ccw_balloon_properties[] = {
-    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
+    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
     DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1413,7 +1427,7 @@  static const TypeInfo virtio_ccw_balloon = {
 };
 
 static Property virtio_ccw_scsi_properties[] = {
-    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
+    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
     DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1443,7 +1457,7 @@  static const TypeInfo virtio_ccw_scsi = {
 
 #ifdef CONFIG_VHOST_SCSI
 static Property vhost_ccw_scsi_properties[] = {
-    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
+    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
     DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
                        VIRTIO_CCW_MAX_REV),
     DEFINE_PROP_END_OF_LIST(),
@@ -1481,7 +1495,7 @@  static void virtio_ccw_rng_instance_init(Object *obj)
 }
 
 static Property virtio_ccw_rng_properties[] = {
-    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
+    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
     DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1525,32 +1539,20 @@  static int virtio_ccw_busdev_exit(DeviceState *dev)
     return _info->exit(_dev);
 }
 
-void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
-                              DeviceState *dev, Error **errp)
+static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
+                                     DeviceState *dev, Error **errp)
 {
-    VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
-    SubchDev *sch = _dev->sch;
+    VirtioCcwDevice *_dev = to_virtio_ccw_dev_fast(dev);
 
     virtio_ccw_stop_ioeventfd(_dev);
-
-    /*
-     * We should arrive here only for device_del, since we don't support
-     * direct hot(un)plug of channels, but only through virtio.
-     */
-    assert(sch != NULL);
-    /* Subchannel is now disabled and no longer valid. */
-    sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA |
-                                     PMCW_FLAGS_MASK_DNV);
-
-    css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
-
-    object_unparent(OBJECT(dev));
 }
 
 static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    CCWDeviceClass *k = CCW_DEVICE_CLASS(dc);
 
+    k->unplug = virtio_ccw_busdev_unplug;
     dc->realize = virtio_ccw_busdev_realize;
     dc->exit = virtio_ccw_busdev_exit;
     dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
@@ -1558,7 +1560,7 @@  static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
 
 static const TypeInfo virtio_ccw_device_info = {
     .name = TYPE_VIRTIO_CCW_DEVICE,
-    .parent = TYPE_DEVICE,
+    .parent = TYPE_CCW_DEVICE,
     .instance_size = sizeof(VirtioCcwDevice),
     .class_init = virtio_ccw_device_class_init,
     .class_size = sizeof(VirtIOCCWDeviceClass),
@@ -1610,7 +1612,7 @@  static const TypeInfo virtio_ccw_bus_info = {
 
 #ifdef CONFIG_VIRTFS
 static Property virtio_ccw_9p_properties[] = {
-    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
+    DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id),
     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
             VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
     DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 11023aa..3f76443 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -26,6 +26,8 @@ 
 
 #include <hw/s390x/s390_flic.h>
 #include <hw/s390x/css.h>
+#include "ccw-device.h"
+#include "hw/s390x/css-bridge.h"
 
 #define VIRTIO_CCW_CU_TYPE 0x3832
 #define VIRTIO_CCW_CHPID_TYPE 0x32
@@ -65,7 +67,7 @@  typedef struct VirtioBusClass VirtioCcwBusClass;
 typedef struct VirtioCcwDevice VirtioCcwDevice;
 
 typedef struct VirtIOCCWDeviceClass {
-    DeviceClass parent_class;
+    CCWDeviceClass parent_class;
     void (*realize)(VirtioCcwDevice *dev, Error **errp);
     int (*exit)(VirtioCcwDevice *dev);
 } VirtIOCCWDeviceClass;
@@ -76,9 +78,7 @@  typedef struct VirtIOCCWDeviceClass {
 #define VIRTIO_CCW_FLAG_USE_IOEVENTFD   (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT)
 
 struct VirtioCcwDevice {
-    DeviceState parent_obj;
-    SubchDev *sch;
-    CssDevId bus_id;
+    CcwDevice parent_obj;
     int revision;
     uint32_t max_rev;
     VirtioBusState bus;
@@ -101,9 +101,6 @@  static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev)
     return dev->max_rev;
 }
 
-void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
-                              DeviceState *dev, Error **errp);
-
 /* virtio-scsi-ccw */
 
 #define TYPE_VIRTIO_SCSI_CCW "virtio-scsi-ccw"