xref: /qemu/hw/s390x/virtio-ccw-md.c (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
1 /*
2  * Virtio CCW support for abstract virtio based memory device
3  *
4  * Copyright (C) 2024 Red Hat, Inc.
5  *
6  * Authors:
7  *  David Hildenbrand <david@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.
10  * See the COPYING file in the top-level directory.
11  */
12 
13 #include "qemu/osdep.h"
14 #include "hw/s390x/virtio-ccw-md.h"
15 #include "hw/mem/memory-device.h"
16 #include "qapi/error.h"
17 #include "qemu/error-report.h"
18 
19 void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
20 {
21     DeviceState *dev = DEVICE(vmd);
22     HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
23     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
24     Error *local_err = NULL;
25 
26     if (!bus_handler && dev->hotplugged) {
27         /*
28          * Without a bus hotplug handler, we cannot control the plug/unplug
29          * order. We should never reach this point when hotplugging, but
30          * better add a safety net.
31          */
32         error_setg(errp, "hotplug of virtio based memory devices not supported"
33                    " on this bus.");
34         return;
35     }
36 
37     /*
38      * First, see if we can plug this memory device at all. If that
39      * succeeds, branch of to the actual hotplug handler.
40      */
41     memory_device_pre_plug(md, ms, &local_err);
42     if (!local_err && bus_handler) {
43         hotplug_handler_pre_plug(bus_handler, dev, &local_err);
44     }
45     error_propagate(errp, local_err);
46 }
47 
48 void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
49 {
50     DeviceState *dev = DEVICE(vmd);
51     HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
52     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
53     Error *local_err = NULL;
54 
55     /*
56      * Plug the memory device first and then branch off to the actual
57      * hotplug handler. If that one fails, we can easily undo the memory
58      * device bits.
59      */
60     memory_device_plug(md, ms);
61     if (bus_handler) {
62         hotplug_handler_plug(bus_handler, dev, &local_err);
63         if (local_err) {
64             memory_device_unplug(md, ms);
65         }
66     }
67     error_propagate(errp, local_err);
68 }
69 
70 void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
71                                   Error **errp)
72 {
73     VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd);
74     DeviceState *dev = DEVICE(vmd);
75     HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
76     HotplugHandlerClass *hdc;
77     Error *local_err = NULL;
78 
79     if (!vmdc->unplug_request_check) {
80         error_setg(errp,
81                    "this virtio based memory devices cannot be unplugged");
82         return;
83     }
84 
85     if (!bus_handler) {
86         error_setg(errp, "hotunplug of virtio based memory devices not"
87                    "supported on this bus");
88         return;
89     }
90 
91     vmdc->unplug_request_check(vmd, &local_err);
92     if (local_err) {
93         error_propagate(errp, local_err);
94         return;
95     }
96 
97     /*
98      * Forward the async request or turn it into a sync request (handling it
99      * like qdev_unplug()).
100      */
101     hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler);
102     if (hdc->unplug_request) {
103         hotplug_handler_unplug_request(bus_handler, dev, &local_err);
104     } else {
105         virtio_ccw_md_unplug(vmd, ms, &local_err);
106         if (!local_err) {
107             object_unparent(OBJECT(dev));
108         }
109     }
110 }
111 
112 void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
113 {
114     DeviceState *dev = DEVICE(vmd);
115     HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
116     MemoryDeviceState *md = MEMORY_DEVICE(vmd);
117     Error *local_err = NULL;
118 
119     /* Unplug the memory device while it is still realized. */
120     memory_device_unplug(md, ms);
121 
122     if (bus_handler) {
123         hotplug_handler_unplug(bus_handler, dev, &local_err);
124         if (local_err) {
125             /* Not expected to fail ... but still try to recover. */
126             memory_device_plug(md, ms);
127             error_propagate(errp, local_err);
128             return;
129         }
130     } else {
131         /* Very unexpected, but let's just try to do the right thing. */
132         warn_report("Unexpected unplug of virtio based memory device");
133         qdev_unrealize(dev);
134     }
135 }
136 
137 static const TypeInfo virtio_ccw_md_info = {
138     .name = TYPE_VIRTIO_MD_CCW,
139     .parent = TYPE_VIRTIO_CCW_DEVICE,
140     .instance_size = sizeof(VirtIOMDCcw),
141     .class_size = sizeof(VirtIOMDCcwClass),
142     .abstract = true,
143     .interfaces = (InterfaceInfo[]) {
144         { TYPE_MEMORY_DEVICE },
145         { }
146     },
147 };
148 
149 static void virtio_ccw_md_register(void)
150 {
151     type_register_static(&virtio_ccw_md_info);
152 }
153 type_init(virtio_ccw_md_register)
154