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