xref: /qemu/hw/s390x/virtio-ccw.c (revision d49b6836)
1a5cf2bb4SCornelia Huck /*
2a5cf2bb4SCornelia Huck  * virtio ccw target implementation
3a5cf2bb4SCornelia Huck  *
4de6a9218SPierre Morel  * Copyright 2012,2015 IBM Corp.
5a5cf2bb4SCornelia Huck  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6de6a9218SPierre Morel  *            Pierre Morel <pmorel@linux.vnet.ibm.com>
7a5cf2bb4SCornelia Huck  *
8a5cf2bb4SCornelia Huck  * This work is licensed under the terms of the GNU GPL, version 2 or (at
9a5cf2bb4SCornelia Huck  * your option) any later version. See the COPYING file in the top-level
10a5cf2bb4SCornelia Huck  * directory.
11a5cf2bb4SCornelia Huck  */
12a5cf2bb4SCornelia Huck 
13a5cf2bb4SCornelia Huck #include "hw/hw.h"
144be74634SMarkus Armbruster #include "sysemu/block-backend.h"
15a5cf2bb4SCornelia Huck #include "sysemu/blockdev.h"
16a5cf2bb4SCornelia Huck #include "sysemu/sysemu.h"
17a5cf2bb4SCornelia Huck #include "net/net.h"
18a5cf2bb4SCornelia Huck #include "monitor/monitor.h"
190d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
200d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h"
210d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
22a5cf2bb4SCornelia Huck #include "hw/sysbus.h"
23a5cf2bb4SCornelia Huck #include "qemu/bitops.h"
24*d49b6836SMarkus Armbruster #include "qemu/error-report.h"
250d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h"
26d426d9fbSCornelia Huck #include "hw/s390x/adapter.h"
27d426d9fbSCornelia Huck #include "hw/s390x/s390_flic.h"
28a5cf2bb4SCornelia Huck 
29a5cf2bb4SCornelia Huck #include "ioinst.h"
30a5cf2bb4SCornelia Huck #include "css.h"
31a5cf2bb4SCornelia Huck #include "virtio-ccw.h"
32a5cf2bb4SCornelia Huck #include "trace.h"
33a5cf2bb4SCornelia Huck 
347bca3892SCornelia Huck static QTAILQ_HEAD(, IndAddr) indicator_addresses =
357bca3892SCornelia Huck     QTAILQ_HEAD_INITIALIZER(indicator_addresses);
367bca3892SCornelia Huck 
377bca3892SCornelia Huck static IndAddr *get_indicator(hwaddr ind_addr, int len)
387bca3892SCornelia Huck {
397bca3892SCornelia Huck     IndAddr *indicator;
407bca3892SCornelia Huck 
417bca3892SCornelia Huck     QTAILQ_FOREACH(indicator, &indicator_addresses, sibling) {
427bca3892SCornelia Huck         if (indicator->addr == ind_addr) {
437bca3892SCornelia Huck             indicator->refcnt++;
447bca3892SCornelia Huck             return indicator;
457bca3892SCornelia Huck         }
467bca3892SCornelia Huck     }
477bca3892SCornelia Huck     indicator = g_new0(IndAddr, 1);
487bca3892SCornelia Huck     indicator->addr = ind_addr;
497bca3892SCornelia Huck     indicator->len = len;
507bca3892SCornelia Huck     indicator->refcnt = 1;
517bca3892SCornelia Huck     QTAILQ_INSERT_TAIL(&indicator_addresses, indicator, sibling);
527bca3892SCornelia Huck     return indicator;
537bca3892SCornelia Huck }
547bca3892SCornelia Huck 
55d426d9fbSCornelia Huck static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
56d426d9fbSCornelia Huck                                bool do_map)
57d426d9fbSCornelia Huck {
58d426d9fbSCornelia Huck     S390FLICState *fs = s390_get_flic();
59d426d9fbSCornelia Huck     S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
60d426d9fbSCornelia Huck 
61d426d9fbSCornelia Huck     return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
62d426d9fbSCornelia Huck }
63d426d9fbSCornelia Huck 
64d426d9fbSCornelia Huck static void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
657bca3892SCornelia Huck {
667bca3892SCornelia Huck     assert(indicator->refcnt > 0);
677bca3892SCornelia Huck     indicator->refcnt--;
687bca3892SCornelia Huck     if (indicator->refcnt > 0) {
697bca3892SCornelia Huck         return;
707bca3892SCornelia Huck     }
717bca3892SCornelia Huck     QTAILQ_REMOVE(&indicator_addresses, indicator, sibling);
72d426d9fbSCornelia Huck     if (indicator->map) {
73d426d9fbSCornelia Huck         s390_io_adapter_map(adapter, indicator->map, false);
74d426d9fbSCornelia Huck     }
757bca3892SCornelia Huck     g_free(indicator);
767bca3892SCornelia Huck }
777bca3892SCornelia Huck 
78d426d9fbSCornelia Huck static int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
79d426d9fbSCornelia Huck {
80d426d9fbSCornelia Huck     int ret;
81d426d9fbSCornelia Huck 
82d426d9fbSCornelia Huck     if (indicator->map) {
83d426d9fbSCornelia Huck         return 0; /* already mapped is not an error */
84d426d9fbSCornelia Huck     }
85d426d9fbSCornelia Huck     indicator->map = indicator->addr;
86d426d9fbSCornelia Huck     ret = s390_io_adapter_map(adapter, indicator->map, true);
87d426d9fbSCornelia Huck     if ((ret != 0) && (ret != -ENOSYS)) {
88d426d9fbSCornelia Huck         goto out_err;
89d426d9fbSCornelia Huck     }
90d426d9fbSCornelia Huck     return 0;
91d426d9fbSCornelia Huck 
92d426d9fbSCornelia Huck out_err:
93d426d9fbSCornelia Huck     indicator->map = 0;
94d426d9fbSCornelia Huck     return ret;
95d426d9fbSCornelia Huck }
96d426d9fbSCornelia Huck 
971bf4d7aaSAndreas Färber static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
981bf4d7aaSAndreas Färber                                VirtioCcwDevice *dev);
99d51fcfacSKONRAD Frederic 
100dcc20931SPaolo Bonzini static void virtual_css_bus_reset(BusState *qbus)
101a5cf2bb4SCornelia Huck {
102a5cf2bb4SCornelia Huck     /* This should actually be modelled via the generic css */
103a5cf2bb4SCornelia Huck     css_reset();
104a5cf2bb4SCornelia Huck }
105a5cf2bb4SCornelia Huck 
106a5cf2bb4SCornelia Huck 
107a5cf2bb4SCornelia Huck static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
108a5cf2bb4SCornelia Huck {
109a5cf2bb4SCornelia Huck     BusClass *k = BUS_CLASS(klass);
110a5cf2bb4SCornelia Huck 
111a5cf2bb4SCornelia Huck     k->reset = virtual_css_bus_reset;
112a5cf2bb4SCornelia Huck }
113a5cf2bb4SCornelia Huck 
114a5cf2bb4SCornelia Huck static const TypeInfo virtual_css_bus_info = {
115a5cf2bb4SCornelia Huck     .name = TYPE_VIRTUAL_CSS_BUS,
116a5cf2bb4SCornelia Huck     .parent = TYPE_BUS,
117a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtualCssBus),
118a5cf2bb4SCornelia Huck     .class_init = virtual_css_bus_class_init,
119a5cf2bb4SCornelia Huck };
120a5cf2bb4SCornelia Huck 
121a5cf2bb4SCornelia Huck VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
122a5cf2bb4SCornelia Huck {
123a5cf2bb4SCornelia Huck     VirtIODevice *vdev = NULL;
124f24a6840SPaolo Bonzini     VirtioCcwDevice *dev = sch->driver_data;
125a5cf2bb4SCornelia Huck 
126f24a6840SPaolo Bonzini     if (dev) {
127f24a6840SPaolo Bonzini         vdev = virtio_bus_get_device(&dev->bus);
128a5cf2bb4SCornelia Huck     }
129a5cf2bb4SCornelia Huck     return vdev;
130a5cf2bb4SCornelia Huck }
131a5cf2bb4SCornelia Huck 
132b4436a0bSCornelia Huck static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n,
133b4436a0bSCornelia Huck                                               bool assign, bool set_handler)
134b4436a0bSCornelia Huck {
135f24a6840SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
136f24a6840SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
137b4436a0bSCornelia Huck     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
138b4436a0bSCornelia Huck     int r = 0;
139b4436a0bSCornelia Huck     SubchDev *sch = dev->sch;
140b4436a0bSCornelia Huck     uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid;
141b4436a0bSCornelia Huck 
142b4436a0bSCornelia Huck     if (assign) {
143b4436a0bSCornelia Huck         r = event_notifier_init(notifier, 1);
144b4436a0bSCornelia Huck         if (r < 0) {
145b4436a0bSCornelia Huck             error_report("%s: unable to init event notifier: %d", __func__, r);
146b4436a0bSCornelia Huck             return r;
147b4436a0bSCornelia Huck         }
148b4436a0bSCornelia Huck         virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
149cc3ac9c4SCornelia Huck         r = s390_assign_subch_ioeventfd(notifier, sch_id, n, assign);
150b4436a0bSCornelia Huck         if (r < 0) {
151b4436a0bSCornelia Huck             error_report("%s: unable to assign ioeventfd: %d", __func__, r);
152b4436a0bSCornelia Huck             virtio_queue_set_host_notifier_fd_handler(vq, false, false);
153b4436a0bSCornelia Huck             event_notifier_cleanup(notifier);
154b4436a0bSCornelia Huck             return r;
155b4436a0bSCornelia Huck         }
156b4436a0bSCornelia Huck     } else {
157b4436a0bSCornelia Huck         virtio_queue_set_host_notifier_fd_handler(vq, false, false);
158cc3ac9c4SCornelia Huck         s390_assign_subch_ioeventfd(notifier, sch_id, n, assign);
159b4436a0bSCornelia Huck         event_notifier_cleanup(notifier);
160b4436a0bSCornelia Huck     }
161b4436a0bSCornelia Huck     return r;
162b4436a0bSCornelia Huck }
163b4436a0bSCornelia Huck 
164b4436a0bSCornelia Huck static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
165b4436a0bSCornelia Huck {
166f24a6840SPaolo Bonzini     VirtIODevice *vdev;
167b4436a0bSCornelia Huck     int n, r;
168b4436a0bSCornelia Huck 
169b4436a0bSCornelia Huck     if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) ||
170320ce850SCornelia Huck         dev->ioeventfd_disabled ||
171b4436a0bSCornelia Huck         dev->ioeventfd_started) {
172b4436a0bSCornelia Huck         return;
173b4436a0bSCornelia Huck     }
174f24a6840SPaolo Bonzini     vdev = virtio_bus_get_device(&dev->bus);
1758dfbaa6aSJason Wang     for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) {
176f24a6840SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
177b4436a0bSCornelia Huck             continue;
178b4436a0bSCornelia Huck         }
179b4436a0bSCornelia Huck         r = virtio_ccw_set_guest2host_notifier(dev, n, true, true);
180b4436a0bSCornelia Huck         if (r < 0) {
181b4436a0bSCornelia Huck             goto assign_error;
182b4436a0bSCornelia Huck         }
183b4436a0bSCornelia Huck     }
184b4436a0bSCornelia Huck     dev->ioeventfd_started = true;
185b4436a0bSCornelia Huck     return;
186b4436a0bSCornelia Huck 
187b4436a0bSCornelia Huck   assign_error:
188b4436a0bSCornelia Huck     while (--n >= 0) {
189f24a6840SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
190b4436a0bSCornelia Huck             continue;
191b4436a0bSCornelia Huck         }
192b4436a0bSCornelia Huck         r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
193b4436a0bSCornelia Huck         assert(r >= 0);
194b4436a0bSCornelia Huck     }
195b4436a0bSCornelia Huck     dev->ioeventfd_started = false;
196b4436a0bSCornelia Huck     /* Disable ioeventfd for this device. */
197b4436a0bSCornelia Huck     dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
198b4436a0bSCornelia Huck     error_report("%s: failed. Fallback to userspace (slower).", __func__);
199b4436a0bSCornelia Huck }
200b4436a0bSCornelia Huck 
201b4436a0bSCornelia Huck static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev)
202b4436a0bSCornelia Huck {
203f24a6840SPaolo Bonzini     VirtIODevice *vdev;
204b4436a0bSCornelia Huck     int n, r;
205b4436a0bSCornelia Huck 
206b4436a0bSCornelia Huck     if (!dev->ioeventfd_started) {
207b4436a0bSCornelia Huck         return;
208b4436a0bSCornelia Huck     }
209f24a6840SPaolo Bonzini     vdev = virtio_bus_get_device(&dev->bus);
2108dfbaa6aSJason Wang     for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) {
211f24a6840SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
212b4436a0bSCornelia Huck             continue;
213b4436a0bSCornelia Huck         }
214b4436a0bSCornelia Huck         r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
215b4436a0bSCornelia Huck         assert(r >= 0);
216b4436a0bSCornelia Huck     }
217b4436a0bSCornelia Huck     dev->ioeventfd_started = false;
218b4436a0bSCornelia Huck }
219b4436a0bSCornelia Huck 
220a5cf2bb4SCornelia Huck VirtualCssBus *virtual_css_bus_init(void)
221a5cf2bb4SCornelia Huck {
222a5cf2bb4SCornelia Huck     VirtualCssBus *cbus;
223a5cf2bb4SCornelia Huck     BusState *bus;
224a5cf2bb4SCornelia Huck     DeviceState *dev;
225a5cf2bb4SCornelia Huck 
226a5cf2bb4SCornelia Huck     /* Create bridge device */
227a5cf2bb4SCornelia Huck     dev = qdev_create(NULL, "virtual-css-bridge");
228a5cf2bb4SCornelia Huck     qdev_init_nofail(dev);
229a5cf2bb4SCornelia Huck 
230a5cf2bb4SCornelia Huck     /* Create bus on bridge device */
231a5cf2bb4SCornelia Huck     bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
232a5cf2bb4SCornelia Huck     cbus = VIRTUAL_CSS_BUS(bus);
233a5cf2bb4SCornelia Huck 
234a5cf2bb4SCornelia Huck     /* Enable hotplugging */
235277bc95eSIgor Mammedov     qbus_set_hotplug_handler(bus, dev, &error_abort);
236a5cf2bb4SCornelia Huck 
237a5cf2bb4SCornelia Huck     return cbus;
238a5cf2bb4SCornelia Huck }
239a5cf2bb4SCornelia Huck 
240a5cf2bb4SCornelia Huck /* Communication blocks used by several channel commands. */
241a5cf2bb4SCornelia Huck typedef struct VqInfoBlock {
242a5cf2bb4SCornelia Huck     uint64_t queue;
243a5cf2bb4SCornelia Huck     uint32_t align;
244a5cf2bb4SCornelia Huck     uint16_t index;
245a5cf2bb4SCornelia Huck     uint16_t num;
246a5cf2bb4SCornelia Huck } QEMU_PACKED VqInfoBlock;
247a5cf2bb4SCornelia Huck 
248a5cf2bb4SCornelia Huck typedef struct VqConfigBlock {
249a5cf2bb4SCornelia Huck     uint16_t index;
250a5cf2bb4SCornelia Huck     uint16_t num_max;
251a5cf2bb4SCornelia Huck } QEMU_PACKED VqConfigBlock;
252a5cf2bb4SCornelia Huck 
253a5cf2bb4SCornelia Huck typedef struct VirtioFeatDesc {
254a5cf2bb4SCornelia Huck     uint32_t features;
255a5cf2bb4SCornelia Huck     uint8_t index;
256a5cf2bb4SCornelia Huck } QEMU_PACKED VirtioFeatDesc;
257a5cf2bb4SCornelia Huck 
2587e749462SCornelia Huck typedef struct VirtioThinintInfo {
2597e749462SCornelia Huck     hwaddr summary_indicator;
2607e749462SCornelia Huck     hwaddr device_indicator;
2617e749462SCornelia Huck     uint64_t ind_bit;
2627e749462SCornelia Huck     uint8_t isc;
2637e749462SCornelia Huck } QEMU_PACKED VirtioThinintInfo;
2647e749462SCornelia Huck 
265a5cf2bb4SCornelia Huck /* Specify where the virtqueues for the subchannel are in guest memory. */
266a5cf2bb4SCornelia Huck static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
267a5cf2bb4SCornelia Huck                               uint16_t index, uint16_t num)
268a5cf2bb4SCornelia Huck {
269f24a6840SPaolo Bonzini     VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
270a5cf2bb4SCornelia Huck 
2718dfbaa6aSJason Wang     if (index >= VIRTIO_CCW_QUEUE_MAX) {
272a5cf2bb4SCornelia Huck         return -EINVAL;
273a5cf2bb4SCornelia Huck     }
274a5cf2bb4SCornelia Huck 
275a5cf2bb4SCornelia Huck     /* Current code in virtio.c relies on 4K alignment. */
276a5cf2bb4SCornelia Huck     if (addr && (align != 4096)) {
277a5cf2bb4SCornelia Huck         return -EINVAL;
278a5cf2bb4SCornelia Huck     }
279a5cf2bb4SCornelia Huck 
280f24a6840SPaolo Bonzini     if (!vdev) {
281a5cf2bb4SCornelia Huck         return -EINVAL;
282a5cf2bb4SCornelia Huck     }
283a5cf2bb4SCornelia Huck 
284f24a6840SPaolo Bonzini     virtio_queue_set_addr(vdev, index, addr);
285a5cf2bb4SCornelia Huck     if (!addr) {
286955cc8c9SJason Wang         virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR);
287a5cf2bb4SCornelia Huck     } else {
288a5cf2bb4SCornelia Huck         /* Fail if we don't have a big enough queue. */
289a5cf2bb4SCornelia Huck         /* TODO: Add interface to handle vring.num changing */
290f24a6840SPaolo Bonzini         if (virtio_queue_get_num(vdev, index) > num) {
291a5cf2bb4SCornelia Huck             return -EINVAL;
292a5cf2bb4SCornelia Huck         }
293f24a6840SPaolo Bonzini         virtio_queue_set_vector(vdev, index, index);
294a5cf2bb4SCornelia Huck     }
295a5cf2bb4SCornelia Huck     /* tell notify handler in case of config change */
2968dfbaa6aSJason Wang     vdev->config_vector = VIRTIO_CCW_QUEUE_MAX;
297a5cf2bb4SCornelia Huck     return 0;
298a5cf2bb4SCornelia Huck }
299a5cf2bb4SCornelia Huck 
300a5cf2bb4SCornelia Huck static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
301a5cf2bb4SCornelia Huck {
302a5cf2bb4SCornelia Huck     int ret;
303a5cf2bb4SCornelia Huck     VqInfoBlock info;
304a5cf2bb4SCornelia Huck     uint8_t status;
305a5cf2bb4SCornelia Huck     VirtioFeatDesc features;
306a5cf2bb4SCornelia Huck     void *config;
307a5cf2bb4SCornelia Huck     hwaddr indicators;
308a5cf2bb4SCornelia Huck     VqConfigBlock vq_config;
309a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = sch->driver_data;
310f24a6840SPaolo Bonzini     VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
311a5cf2bb4SCornelia Huck     bool check_len;
312a5cf2bb4SCornelia Huck     int len;
313a5cf2bb4SCornelia Huck     hwaddr hw_len;
3147e749462SCornelia Huck     VirtioThinintInfo *thinint;
315a5cf2bb4SCornelia Huck 
316a5cf2bb4SCornelia Huck     if (!dev) {
317a5cf2bb4SCornelia Huck         return -EINVAL;
318a5cf2bb4SCornelia Huck     }
319a5cf2bb4SCornelia Huck 
320a5cf2bb4SCornelia Huck     trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid,
321a5cf2bb4SCornelia Huck                                    ccw.cmd_code);
322a5cf2bb4SCornelia Huck     check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));
323a5cf2bb4SCornelia Huck 
324a5cf2bb4SCornelia Huck     /* Look at the command. */
325a5cf2bb4SCornelia Huck     switch (ccw.cmd_code) {
326a5cf2bb4SCornelia Huck     case CCW_CMD_SET_VQ:
327a5cf2bb4SCornelia Huck         if (check_len) {
328a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(info)) {
329a5cf2bb4SCornelia Huck                 ret = -EINVAL;
330a5cf2bb4SCornelia Huck                 break;
331a5cf2bb4SCornelia Huck             }
332a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(info)) {
333a5cf2bb4SCornelia Huck             /* Can't execute command. */
334a5cf2bb4SCornelia Huck             ret = -EINVAL;
335a5cf2bb4SCornelia Huck             break;
336a5cf2bb4SCornelia Huck         }
337a5cf2bb4SCornelia Huck         if (!ccw.cda) {
338a5cf2bb4SCornelia Huck             ret = -EFAULT;
339a5cf2bb4SCornelia Huck         } else {
34042874d3aSPeter Maydell             info.queue = address_space_ldq(&address_space_memory, ccw.cda,
34142874d3aSPeter Maydell                                            MEMTXATTRS_UNSPECIFIED, NULL);
34242874d3aSPeter Maydell             info.align = address_space_ldl(&address_space_memory,
34342874d3aSPeter Maydell                                            ccw.cda + sizeof(info.queue),
34442874d3aSPeter Maydell                                            MEMTXATTRS_UNSPECIFIED,
34542874d3aSPeter Maydell                                            NULL);
34642874d3aSPeter Maydell             info.index = address_space_lduw(&address_space_memory,
34741701aa4SEdgar E. Iglesias                                             ccw.cda + sizeof(info.queue)
34842874d3aSPeter Maydell                                             + sizeof(info.align),
34942874d3aSPeter Maydell                                             MEMTXATTRS_UNSPECIFIED,
35042874d3aSPeter Maydell                                             NULL);
35142874d3aSPeter Maydell             info.num = address_space_lduw(&address_space_memory,
35241701aa4SEdgar E. Iglesias                                           ccw.cda + sizeof(info.queue)
353a5cf2bb4SCornelia Huck                                           + sizeof(info.align)
35442874d3aSPeter Maydell                                           + sizeof(info.index),
35542874d3aSPeter Maydell                                           MEMTXATTRS_UNSPECIFIED,
35642874d3aSPeter Maydell                                           NULL);
357a5cf2bb4SCornelia Huck             ret = virtio_ccw_set_vqs(sch, info.queue, info.align, info.index,
358a5cf2bb4SCornelia Huck                                      info.num);
359a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = 0;
360a5cf2bb4SCornelia Huck         }
361a5cf2bb4SCornelia Huck         break;
362a5cf2bb4SCornelia Huck     case CCW_CMD_VDEV_RESET:
363b4436a0bSCornelia Huck         virtio_ccw_stop_ioeventfd(dev);
364f24a6840SPaolo Bonzini         virtio_reset(vdev);
365a5cf2bb4SCornelia Huck         ret = 0;
366a5cf2bb4SCornelia Huck         break;
367a5cf2bb4SCornelia Huck     case CCW_CMD_READ_FEAT:
368a5cf2bb4SCornelia Huck         if (check_len) {
369a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(features)) {
370a5cf2bb4SCornelia Huck                 ret = -EINVAL;
371a5cf2bb4SCornelia Huck                 break;
372a5cf2bb4SCornelia Huck             }
373a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(features)) {
374a5cf2bb4SCornelia Huck             /* Can't execute command. */
375a5cf2bb4SCornelia Huck             ret = -EINVAL;
376a5cf2bb4SCornelia Huck             break;
377a5cf2bb4SCornelia Huck         }
378a5cf2bb4SCornelia Huck         if (!ccw.cda) {
379a5cf2bb4SCornelia Huck             ret = -EFAULT;
380a5cf2bb4SCornelia Huck         } else {
38142874d3aSPeter Maydell             features.index = address_space_ldub(&address_space_memory,
38242874d3aSPeter Maydell                                                 ccw.cda
38342874d3aSPeter Maydell                                                 + sizeof(features.features),
38442874d3aSPeter Maydell                                                 MEMTXATTRS_UNSPECIFIED,
38542874d3aSPeter Maydell                                                 NULL);
3866b8f1020SCornelia Huck             if (features.index == 0) {
3876b8f1020SCornelia Huck                 features.features = vdev->host_features;
388a5cf2bb4SCornelia Huck             } else {
389a5cf2bb4SCornelia Huck                 /* Return zeroes if the guest supports more feature bits. */
390a5cf2bb4SCornelia Huck                 features.features = 0;
391a5cf2bb4SCornelia Huck             }
39242874d3aSPeter Maydell             address_space_stl_le(&address_space_memory, ccw.cda,
39342874d3aSPeter Maydell                                  features.features, MEMTXATTRS_UNSPECIFIED,
39442874d3aSPeter Maydell                                  NULL);
395a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(features);
396a5cf2bb4SCornelia Huck             ret = 0;
397a5cf2bb4SCornelia Huck         }
398a5cf2bb4SCornelia Huck         break;
399a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_FEAT:
400a5cf2bb4SCornelia Huck         if (check_len) {
401a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(features)) {
402a5cf2bb4SCornelia Huck                 ret = -EINVAL;
403a5cf2bb4SCornelia Huck                 break;
404a5cf2bb4SCornelia Huck             }
405a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(features)) {
406a5cf2bb4SCornelia Huck             /* Can't execute command. */
407a5cf2bb4SCornelia Huck             ret = -EINVAL;
408a5cf2bb4SCornelia Huck             break;
409a5cf2bb4SCornelia Huck         }
410a5cf2bb4SCornelia Huck         if (!ccw.cda) {
411a5cf2bb4SCornelia Huck             ret = -EFAULT;
412a5cf2bb4SCornelia Huck         } else {
41342874d3aSPeter Maydell             features.index = address_space_ldub(&address_space_memory,
41442874d3aSPeter Maydell                                                 ccw.cda
41542874d3aSPeter Maydell                                                 + sizeof(features.features),
41642874d3aSPeter Maydell                                                 MEMTXATTRS_UNSPECIFIED,
41742874d3aSPeter Maydell                                                 NULL);
41842874d3aSPeter Maydell             features.features = address_space_ldl_le(&address_space_memory,
41942874d3aSPeter Maydell                                                      ccw.cda,
42042874d3aSPeter Maydell                                                      MEMTXATTRS_UNSPECIFIED,
42142874d3aSPeter Maydell                                                      NULL);
4226b8f1020SCornelia Huck             if (features.index == 0) {
423a590fd5bSCornelia Huck                 virtio_set_features(vdev, features.features);
424a5cf2bb4SCornelia Huck             } else {
425a5cf2bb4SCornelia Huck                 /*
426a5cf2bb4SCornelia Huck                  * If the guest supports more feature bits, assert that it
427a5cf2bb4SCornelia Huck                  * passes us zeroes for those we don't support.
428a5cf2bb4SCornelia Huck                  */
429a5cf2bb4SCornelia Huck                 if (features.features) {
430a5cf2bb4SCornelia Huck                     fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",
431a5cf2bb4SCornelia Huck                             features.index, features.features);
432a5cf2bb4SCornelia Huck                     /* XXX: do a unit check here? */
433a5cf2bb4SCornelia Huck                 }
434a5cf2bb4SCornelia Huck             }
435a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(features);
436a5cf2bb4SCornelia Huck             ret = 0;
437a5cf2bb4SCornelia Huck         }
438a5cf2bb4SCornelia Huck         break;
439a5cf2bb4SCornelia Huck     case CCW_CMD_READ_CONF:
440a5cf2bb4SCornelia Huck         if (check_len) {
441f24a6840SPaolo Bonzini             if (ccw.count > vdev->config_len) {
442a5cf2bb4SCornelia Huck                 ret = -EINVAL;
443a5cf2bb4SCornelia Huck                 break;
444a5cf2bb4SCornelia Huck             }
445a5cf2bb4SCornelia Huck         }
446f24a6840SPaolo Bonzini         len = MIN(ccw.count, vdev->config_len);
447a5cf2bb4SCornelia Huck         if (!ccw.cda) {
448a5cf2bb4SCornelia Huck             ret = -EFAULT;
449a5cf2bb4SCornelia Huck         } else {
450f24a6840SPaolo Bonzini             virtio_bus_get_vdev_config(&dev->bus, vdev->config);
451a5cf2bb4SCornelia Huck             /* XXX config space endianness */
452f24a6840SPaolo Bonzini             cpu_physical_memory_write(ccw.cda, vdev->config, len);
453a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - len;
454a5cf2bb4SCornelia Huck             ret = 0;
455a5cf2bb4SCornelia Huck         }
456a5cf2bb4SCornelia Huck         break;
457a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_CONF:
458a5cf2bb4SCornelia Huck         if (check_len) {
459f24a6840SPaolo Bonzini             if (ccw.count > vdev->config_len) {
460a5cf2bb4SCornelia Huck                 ret = -EINVAL;
461a5cf2bb4SCornelia Huck                 break;
462a5cf2bb4SCornelia Huck             }
463a5cf2bb4SCornelia Huck         }
464f24a6840SPaolo Bonzini         len = MIN(ccw.count, vdev->config_len);
465a5cf2bb4SCornelia Huck         hw_len = len;
466a5cf2bb4SCornelia Huck         if (!ccw.cda) {
467a5cf2bb4SCornelia Huck             ret = -EFAULT;
468a5cf2bb4SCornelia Huck         } else {
469a5cf2bb4SCornelia Huck             config = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
470a5cf2bb4SCornelia Huck             if (!config) {
471a5cf2bb4SCornelia Huck                 ret = -EFAULT;
472a5cf2bb4SCornelia Huck             } else {
473a5cf2bb4SCornelia Huck                 len = hw_len;
474a5cf2bb4SCornelia Huck                 /* XXX config space endianness */
475f24a6840SPaolo Bonzini                 memcpy(vdev->config, config, len);
476a5cf2bb4SCornelia Huck                 cpu_physical_memory_unmap(config, hw_len, 0, hw_len);
477f24a6840SPaolo Bonzini                 virtio_bus_set_vdev_config(&dev->bus, vdev->config);
478a5cf2bb4SCornelia Huck                 sch->curr_status.scsw.count = ccw.count - len;
479a5cf2bb4SCornelia Huck                 ret = 0;
480a5cf2bb4SCornelia Huck             }
481a5cf2bb4SCornelia Huck         }
482a5cf2bb4SCornelia Huck         break;
483a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_STATUS:
484a5cf2bb4SCornelia Huck         if (check_len) {
485a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(status)) {
486a5cf2bb4SCornelia Huck                 ret = -EINVAL;
487a5cf2bb4SCornelia Huck                 break;
488a5cf2bb4SCornelia Huck             }
489a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(status)) {
490a5cf2bb4SCornelia Huck             /* Can't execute command. */
491a5cf2bb4SCornelia Huck             ret = -EINVAL;
492a5cf2bb4SCornelia Huck             break;
493a5cf2bb4SCornelia Huck         }
494a5cf2bb4SCornelia Huck         if (!ccw.cda) {
495a5cf2bb4SCornelia Huck             ret = -EFAULT;
496a5cf2bb4SCornelia Huck         } else {
49742874d3aSPeter Maydell             status = address_space_ldub(&address_space_memory, ccw.cda,
49842874d3aSPeter Maydell                                         MEMTXATTRS_UNSPECIFIED, NULL);
499b4436a0bSCornelia Huck             if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
500b4436a0bSCornelia Huck                 virtio_ccw_stop_ioeventfd(dev);
501b4436a0bSCornelia Huck             }
5020b352fd6SCornelia Huck             if (virtio_set_status(vdev, status) == 0) {
503f24a6840SPaolo Bonzini                 if (vdev->status == 0) {
504f24a6840SPaolo Bonzini                     virtio_reset(vdev);
505a5cf2bb4SCornelia Huck                 }
506b4436a0bSCornelia Huck                 if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
507b4436a0bSCornelia Huck                     virtio_ccw_start_ioeventfd(dev);
508b4436a0bSCornelia Huck                 }
509a5cf2bb4SCornelia Huck                 sch->curr_status.scsw.count = ccw.count - sizeof(status);
510a5cf2bb4SCornelia Huck                 ret = 0;
5110b352fd6SCornelia Huck             } else {
5120b352fd6SCornelia Huck                 /* Trigger a command reject. */
5130b352fd6SCornelia Huck                 ret = -ENOSYS;
5140b352fd6SCornelia Huck             }
515a5cf2bb4SCornelia Huck         }
516a5cf2bb4SCornelia Huck         break;
517a5cf2bb4SCornelia Huck     case CCW_CMD_SET_IND:
518a5cf2bb4SCornelia Huck         if (check_len) {
519a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(indicators)) {
520a5cf2bb4SCornelia Huck                 ret = -EINVAL;
521a5cf2bb4SCornelia Huck                 break;
522a5cf2bb4SCornelia Huck             }
523a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(indicators)) {
524a5cf2bb4SCornelia Huck             /* Can't execute command. */
525a5cf2bb4SCornelia Huck             ret = -EINVAL;
526a5cf2bb4SCornelia Huck             break;
527a5cf2bb4SCornelia Huck         }
5287e749462SCornelia Huck         if (sch->thinint_active) {
5297e749462SCornelia Huck             /* Trigger a command reject. */
5307e749462SCornelia Huck             ret = -ENOSYS;
5317e749462SCornelia Huck             break;
5327e749462SCornelia Huck         }
533d1db1fa8SCornelia Huck         if (!ccw.cda) {
534a5cf2bb4SCornelia Huck             ret = -EFAULT;
535a5cf2bb4SCornelia Huck         } else {
53642874d3aSPeter Maydell             indicators = address_space_ldq_be(&address_space_memory, ccw.cda,
53742874d3aSPeter Maydell                                               MEMTXATTRS_UNSPECIFIED, NULL);
5387bca3892SCornelia Huck             dev->indicators = get_indicator(indicators, sizeof(uint64_t));
539a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
540a5cf2bb4SCornelia Huck             ret = 0;
541a5cf2bb4SCornelia Huck         }
542a5cf2bb4SCornelia Huck         break;
543a5cf2bb4SCornelia Huck     case CCW_CMD_SET_CONF_IND:
544a5cf2bb4SCornelia Huck         if (check_len) {
545a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(indicators)) {
546a5cf2bb4SCornelia Huck                 ret = -EINVAL;
547a5cf2bb4SCornelia Huck                 break;
548a5cf2bb4SCornelia Huck             }
549a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(indicators)) {
550a5cf2bb4SCornelia Huck             /* Can't execute command. */
551a5cf2bb4SCornelia Huck             ret = -EINVAL;
552a5cf2bb4SCornelia Huck             break;
553a5cf2bb4SCornelia Huck         }
554d1db1fa8SCornelia Huck         if (!ccw.cda) {
555a5cf2bb4SCornelia Huck             ret = -EFAULT;
556a5cf2bb4SCornelia Huck         } else {
55742874d3aSPeter Maydell             indicators = address_space_ldq_be(&address_space_memory, ccw.cda,
55842874d3aSPeter Maydell                                               MEMTXATTRS_UNSPECIFIED, NULL);
5597bca3892SCornelia Huck             dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
560a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
561a5cf2bb4SCornelia Huck             ret = 0;
562a5cf2bb4SCornelia Huck         }
563a5cf2bb4SCornelia Huck         break;
564a5cf2bb4SCornelia Huck     case CCW_CMD_READ_VQ_CONF:
565a5cf2bb4SCornelia Huck         if (check_len) {
566a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(vq_config)) {
567a5cf2bb4SCornelia Huck                 ret = -EINVAL;
568a5cf2bb4SCornelia Huck                 break;
569a5cf2bb4SCornelia Huck             }
570a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(vq_config)) {
571a5cf2bb4SCornelia Huck             /* Can't execute command. */
572a5cf2bb4SCornelia Huck             ret = -EINVAL;
573a5cf2bb4SCornelia Huck             break;
574a5cf2bb4SCornelia Huck         }
575a5cf2bb4SCornelia Huck         if (!ccw.cda) {
576a5cf2bb4SCornelia Huck             ret = -EFAULT;
577a5cf2bb4SCornelia Huck         } else {
57842874d3aSPeter Maydell             vq_config.index = address_space_lduw_be(&address_space_memory,
57942874d3aSPeter Maydell                                                     ccw.cda,
58042874d3aSPeter Maydell                                                     MEMTXATTRS_UNSPECIFIED,
58142874d3aSPeter Maydell                                                     NULL);
5828dfbaa6aSJason Wang             if (vq_config.index >= VIRTIO_CCW_QUEUE_MAX) {
583d03a3630SCornelia Huck                 ret = -EINVAL;
584d03a3630SCornelia Huck                 break;
585d03a3630SCornelia Huck             }
586f24a6840SPaolo Bonzini             vq_config.num_max = virtio_queue_get_num(vdev,
587a5cf2bb4SCornelia Huck                                                      vq_config.index);
58842874d3aSPeter Maydell             address_space_stw_be(&address_space_memory,
58942874d3aSPeter Maydell                                  ccw.cda + sizeof(vq_config.index),
59042874d3aSPeter Maydell                                  vq_config.num_max,
59142874d3aSPeter Maydell                                  MEMTXATTRS_UNSPECIFIED,
59242874d3aSPeter Maydell                                  NULL);
593a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
594a5cf2bb4SCornelia Huck             ret = 0;
595a5cf2bb4SCornelia Huck         }
596a5cf2bb4SCornelia Huck         break;
5977e749462SCornelia Huck     case CCW_CMD_SET_IND_ADAPTER:
5987e749462SCornelia Huck         if (check_len) {
5997e749462SCornelia Huck             if (ccw.count != sizeof(*thinint)) {
6007e749462SCornelia Huck                 ret = -EINVAL;
6017e749462SCornelia Huck                 break;
6027e749462SCornelia Huck             }
6037e749462SCornelia Huck         } else if (ccw.count < sizeof(*thinint)) {
6047e749462SCornelia Huck             /* Can't execute command. */
6057e749462SCornelia Huck             ret = -EINVAL;
6067e749462SCornelia Huck             break;
6077e749462SCornelia Huck         }
6087e749462SCornelia Huck         len = sizeof(*thinint);
6097e749462SCornelia Huck         hw_len = len;
6107e749462SCornelia Huck         if (!ccw.cda) {
6117e749462SCornelia Huck             ret = -EFAULT;
6127e749462SCornelia Huck         } else if (dev->indicators && !sch->thinint_active) {
6137e749462SCornelia Huck             /* Trigger a command reject. */
6147e749462SCornelia Huck             ret = -ENOSYS;
6157e749462SCornelia Huck         } else {
6167e749462SCornelia Huck             thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
6177e749462SCornelia Huck             if (!thinint) {
6187e749462SCornelia Huck                 ret = -EFAULT;
6197e749462SCornelia Huck             } else {
6207d45285fSCornelia Huck                 uint64_t ind_bit = ldq_be_p(&thinint->ind_bit);
6217d45285fSCornelia Huck 
6227e749462SCornelia Huck                 len = hw_len;
6237bca3892SCornelia Huck                 dev->summary_indicator =
6247d45285fSCornelia Huck                     get_indicator(ldq_be_p(&thinint->summary_indicator),
6257d45285fSCornelia Huck                                   sizeof(uint8_t));
6267d45285fSCornelia Huck                 dev->indicators =
6277d45285fSCornelia Huck                     get_indicator(ldq_be_p(&thinint->device_indicator),
6287d45285fSCornelia Huck                                   ind_bit / 8 + 1);
6297e749462SCornelia Huck                 dev->thinint_isc = thinint->isc;
6307d45285fSCornelia Huck                 dev->routes.adapter.ind_offset = ind_bit;
631d426d9fbSCornelia Huck                 dev->routes.adapter.summary_offset = 7;
6327e749462SCornelia Huck                 cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
63303cf077aSCornelia Huck                 ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
63403cf077aSCornelia Huck                                               dev->thinint_isc, true, false,
635d426d9fbSCornelia Huck                                               &dev->routes.adapter.adapter_id);
63603cf077aSCornelia Huck                 assert(ret == 0);
6377bca3892SCornelia Huck                 sch->thinint_active = ((dev->indicators != NULL) &&
6387bca3892SCornelia Huck                                        (dev->summary_indicator != NULL));
6397e749462SCornelia Huck                 sch->curr_status.scsw.count = ccw.count - len;
6407e749462SCornelia Huck                 ret = 0;
6417e749462SCornelia Huck             }
6427e749462SCornelia Huck         }
6437e749462SCornelia Huck         break;
644a5cf2bb4SCornelia Huck     default:
6458d034a6fSCornelia Huck         ret = -ENOSYS;
646a5cf2bb4SCornelia Huck         break;
647a5cf2bb4SCornelia Huck     }
648a5cf2bb4SCornelia Huck     return ret;
649a5cf2bb4SCornelia Huck }
650a5cf2bb4SCornelia Huck 
6511fa75523SCornelia Huck static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
652a5cf2bb4SCornelia Huck {
653a5cf2bb4SCornelia Huck     unsigned int cssid = 0;
654a5cf2bb4SCornelia Huck     unsigned int ssid = 0;
655a5cf2bb4SCornelia Huck     unsigned int schid;
656a5cf2bb4SCornelia Huck     unsigned int devno;
657a5cf2bb4SCornelia Huck     bool have_devno = false;
658a5cf2bb4SCornelia Huck     bool found = false;
659a5cf2bb4SCornelia Huck     SubchDev *sch;
660a5cf2bb4SCornelia Huck     int num;
6611fa75523SCornelia Huck     Error *err = NULL;
6621fa75523SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
663a5cf2bb4SCornelia Huck 
664a5cf2bb4SCornelia Huck     sch = g_malloc0(sizeof(SubchDev));
665a5cf2bb4SCornelia Huck 
666a5cf2bb4SCornelia Huck     sch->driver_data = dev;
667a5cf2bb4SCornelia Huck     dev->sch = sch;
668a5cf2bb4SCornelia Huck 
6697bca3892SCornelia Huck     dev->indicators = NULL;
670a5cf2bb4SCornelia Huck 
671a5cf2bb4SCornelia Huck     /* Initialize subchannel structure. */
672a5cf2bb4SCornelia Huck     sch->channel_prog = 0x0;
673a5cf2bb4SCornelia Huck     sch->last_cmd_valid = false;
6747e749462SCornelia Huck     sch->thinint_active = false;
675a5cf2bb4SCornelia Huck     /*
676a5cf2bb4SCornelia Huck      * Use a device number if provided. Otherwise, fall back to subchannel
677a5cf2bb4SCornelia Huck      * number.
678a5cf2bb4SCornelia Huck      */
679a5cf2bb4SCornelia Huck     if (dev->bus_id) {
680a5cf2bb4SCornelia Huck         num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
681a5cf2bb4SCornelia Huck         if (num == 3) {
682a5cf2bb4SCornelia Huck             if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
6835e5ced38SMarkus Armbruster                 error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
684a5cf2bb4SCornelia Huck                            cssid, ssid);
685a5cf2bb4SCornelia Huck                 goto out_err;
686a5cf2bb4SCornelia Huck             }
687a5cf2bb4SCornelia Huck             /* Enforce use of virtual cssid. */
688a5cf2bb4SCornelia Huck             if (cssid != VIRTUAL_CSSID) {
6895e5ced38SMarkus Armbruster                 error_setg(errp, "cssid %x not valid for virtio devices",
6905e5ced38SMarkus Armbruster                            cssid);
691a5cf2bb4SCornelia Huck                 goto out_err;
692a5cf2bb4SCornelia Huck             }
693a5cf2bb4SCornelia Huck             if (css_devno_used(cssid, ssid, devno)) {
6945e5ced38SMarkus Armbruster                 error_setg(errp, "Device %x.%x.%04x already exists",
6955e5ced38SMarkus Armbruster                            cssid, ssid, devno);
696a5cf2bb4SCornelia Huck                 goto out_err;
697a5cf2bb4SCornelia Huck             }
698a5cf2bb4SCornelia Huck             sch->cssid = cssid;
699a5cf2bb4SCornelia Huck             sch->ssid = ssid;
700a5cf2bb4SCornelia Huck             sch->devno = devno;
701a5cf2bb4SCornelia Huck             have_devno = true;
702a5cf2bb4SCornelia Huck         } else {
7035e5ced38SMarkus Armbruster             error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id);
704a5cf2bb4SCornelia Huck             goto out_err;
705a5cf2bb4SCornelia Huck         }
706a5cf2bb4SCornelia Huck     }
707a5cf2bb4SCornelia Huck 
708a5cf2bb4SCornelia Huck     /* Find the next free id. */
709a5cf2bb4SCornelia Huck     if (have_devno) {
710a5cf2bb4SCornelia Huck         for (schid = 0; schid <= MAX_SCHID; schid++) {
711a5cf2bb4SCornelia Huck             if (!css_find_subch(1, cssid, ssid, schid)) {
712a5cf2bb4SCornelia Huck                 sch->schid = schid;
713a5cf2bb4SCornelia Huck                 css_subch_assign(cssid, ssid, schid, devno, sch);
714a5cf2bb4SCornelia Huck                 found = true;
715a5cf2bb4SCornelia Huck                 break;
716a5cf2bb4SCornelia Huck             }
717a5cf2bb4SCornelia Huck         }
718a5cf2bb4SCornelia Huck         if (!found) {
7195e5ced38SMarkus Armbruster             error_setg(errp, "No free subchannel found for %x.%x.%04x",
7205e5ced38SMarkus Armbruster                        cssid, ssid, devno);
721a5cf2bb4SCornelia Huck             goto out_err;
722a5cf2bb4SCornelia Huck         }
723a5cf2bb4SCornelia Huck         trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
724a5cf2bb4SCornelia Huck                                     "user-configured");
725a5cf2bb4SCornelia Huck     } else {
726a5cf2bb4SCornelia Huck         cssid = VIRTUAL_CSSID;
727a5cf2bb4SCornelia Huck         for (ssid = 0; ssid <= MAX_SSID; ssid++) {
728a5cf2bb4SCornelia Huck             for (schid = 0; schid <= MAX_SCHID; schid++) {
729a5cf2bb4SCornelia Huck                 if (!css_find_subch(1, cssid, ssid, schid)) {
730a5cf2bb4SCornelia Huck                     sch->cssid = cssid;
731a5cf2bb4SCornelia Huck                     sch->ssid = ssid;
732a5cf2bb4SCornelia Huck                     sch->schid = schid;
733a5cf2bb4SCornelia Huck                     devno = schid;
734a5cf2bb4SCornelia Huck                     /*
735a5cf2bb4SCornelia Huck                      * If the devno is already taken, look further in this
736a5cf2bb4SCornelia Huck                      * subchannel set.
737a5cf2bb4SCornelia Huck                      */
738a5cf2bb4SCornelia Huck                     while (css_devno_used(cssid, ssid, devno)) {
739a5cf2bb4SCornelia Huck                         if (devno == MAX_SCHID) {
740a5cf2bb4SCornelia Huck                             devno = 0;
741a5cf2bb4SCornelia Huck                         } else if (devno == schid - 1) {
7425e5ced38SMarkus Armbruster                             error_setg(errp, "No free devno found");
743a5cf2bb4SCornelia Huck                             goto out_err;
744a5cf2bb4SCornelia Huck                         } else {
745a5cf2bb4SCornelia Huck                             devno++;
746a5cf2bb4SCornelia Huck                         }
747a5cf2bb4SCornelia Huck                     }
748a5cf2bb4SCornelia Huck                     sch->devno = devno;
749a5cf2bb4SCornelia Huck                     css_subch_assign(cssid, ssid, schid, devno, sch);
750a5cf2bb4SCornelia Huck                     found = true;
751a5cf2bb4SCornelia Huck                     break;
752a5cf2bb4SCornelia Huck                 }
753a5cf2bb4SCornelia Huck             }
754a5cf2bb4SCornelia Huck             if (found) {
755a5cf2bb4SCornelia Huck                 break;
756a5cf2bb4SCornelia Huck             }
757a5cf2bb4SCornelia Huck         }
758a5cf2bb4SCornelia Huck         if (!found) {
7595e5ced38SMarkus Armbruster             error_setg(errp, "Virtual channel subsystem is full!");
760a5cf2bb4SCornelia Huck             goto out_err;
761a5cf2bb4SCornelia Huck         }
762a5cf2bb4SCornelia Huck         trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
763a5cf2bb4SCornelia Huck                                     "auto-configured");
764a5cf2bb4SCornelia Huck     }
765a5cf2bb4SCornelia Huck 
766a5cf2bb4SCornelia Huck     /* Build initial schib. */
767a5cf2bb4SCornelia Huck     css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE);
768a5cf2bb4SCornelia Huck 
769a5cf2bb4SCornelia Huck     sch->ccw_cb = virtio_ccw_cb;
770a5cf2bb4SCornelia Huck 
771a5cf2bb4SCornelia Huck     /* Build senseid data. */
772a5cf2bb4SCornelia Huck     memset(&sch->id, 0, sizeof(SenseId));
773a5cf2bb4SCornelia Huck     sch->id.reserved = 0xff;
774a5cf2bb4SCornelia Huck     sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
7751fa75523SCornelia Huck 
7761fa75523SCornelia Huck     if (k->realize) {
7771fa75523SCornelia Huck         k->realize(dev, &err);
7781fa75523SCornelia Huck     }
7791fa75523SCornelia Huck     if (err) {
7801fa75523SCornelia Huck         error_propagate(errp, err);
7811fa75523SCornelia Huck         css_subch_assign(cssid, ssid, schid, devno, NULL);
7821fa75523SCornelia Huck         goto out_err;
7831fa75523SCornelia Huck     }
7841fa75523SCornelia Huck 
7855e5ced38SMarkus Armbruster     return;
786a5cf2bb4SCornelia Huck 
787a5cf2bb4SCornelia Huck out_err:
788a5cf2bb4SCornelia Huck     dev->sch = NULL;
789a5cf2bb4SCornelia Huck     g_free(sch);
790a5cf2bb4SCornelia Huck }
791a5cf2bb4SCornelia Huck 
792a5cf2bb4SCornelia Huck static int virtio_ccw_exit(VirtioCcwDevice *dev)
793a5cf2bb4SCornelia Huck {
794a5cf2bb4SCornelia Huck     SubchDev *sch = dev->sch;
795a5cf2bb4SCornelia Huck 
796a5cf2bb4SCornelia Huck     if (sch) {
797a5cf2bb4SCornelia Huck         css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
798a5cf2bb4SCornelia Huck         g_free(sch);
799a5cf2bb4SCornelia Huck     }
8007bca3892SCornelia Huck     if (dev->indicators) {
801d426d9fbSCornelia Huck         release_indicator(&dev->routes.adapter, dev->indicators);
8027bca3892SCornelia Huck         dev->indicators = NULL;
8037bca3892SCornelia Huck     }
804a5cf2bb4SCornelia Huck     return 0;
805a5cf2bb4SCornelia Huck }
806a5cf2bb4SCornelia Huck 
8075e5ced38SMarkus Armbruster static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp)
808a5cf2bb4SCornelia Huck {
809800ced8cSKONRAD Frederic     DeviceState *qdev = DEVICE(ccw_dev);
81089334c8bSKONRAD Frederic     VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev);
81189334c8bSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
8125e5ced38SMarkus Armbruster     Error *err = NULL;
813a5cf2bb4SCornelia Huck 
814800ced8cSKONRAD Frederic     virtio_net_set_netclient_name(&dev->vdev, qdev->id,
815800ced8cSKONRAD Frederic                                   object_get_typename(OBJECT(qdev)));
81689334c8bSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
8175e5ced38SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
8185e5ced38SMarkus Armbruster     if (err) {
8195e5ced38SMarkus Armbruster         error_propagate(errp, err);
820a5cf2bb4SCornelia Huck     }
821a5cf2bb4SCornelia Huck }
822a5cf2bb4SCornelia Huck 
82389334c8bSKONRAD Frederic static void virtio_ccw_net_instance_init(Object *obj)
824a5cf2bb4SCornelia Huck {
82589334c8bSKONRAD Frederic     VirtIONetCcw *dev = VIRTIO_NET_CCW(obj);
826c8075cafSGonglei 
827c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
828c8075cafSGonglei                                 TYPE_VIRTIO_NET);
8290cf63c3eSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
8300cf63c3eSGonglei                               "bootindex", &error_abort);
831a5cf2bb4SCornelia Huck }
832a5cf2bb4SCornelia Huck 
8335e5ced38SMarkus Armbruster static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp)
834a5cf2bb4SCornelia Huck {
8353400c455SKONRAD Frederic     VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
8363400c455SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
8375e5ced38SMarkus Armbruster     Error *err = NULL;
8385e5ced38SMarkus Armbruster 
8393400c455SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
8405e5ced38SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
8415e5ced38SMarkus Armbruster     if (err) {
8425e5ced38SMarkus Armbruster         error_propagate(errp, err);
843a5cf2bb4SCornelia Huck     }
844a5cf2bb4SCornelia Huck }
845a5cf2bb4SCornelia Huck 
8463400c455SKONRAD Frederic static void virtio_ccw_blk_instance_init(Object *obj)
847a5cf2bb4SCornelia Huck {
8483400c455SKONRAD Frederic     VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj);
849c8075cafSGonglei 
850c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
851c8075cafSGonglei                                 TYPE_VIRTIO_BLK);
852467b3f33SStefan Hajnoczi     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
853467b3f33SStefan Hajnoczi                               &error_abort);
854aeb98ddcSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
855aeb98ddcSGonglei                               "bootindex", &error_abort);
856a5cf2bb4SCornelia Huck }
857a5cf2bb4SCornelia Huck 
8585e5ced38SMarkus Armbruster static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp)
859a5cf2bb4SCornelia Huck {
8606acf69cdSKONRAD Frederic     VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev);
8616acf69cdSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
86280270a19SKONRAD Frederic     DeviceState *proxy = DEVICE(ccw_dev);
8635e5ced38SMarkus Armbruster     Error *err = NULL;
86480270a19SKONRAD Frederic     char *bus_name;
86580270a19SKONRAD Frederic 
86680270a19SKONRAD Frederic     /*
86780270a19SKONRAD Frederic      * For command line compatibility, this sets the virtio-serial-device bus
86880270a19SKONRAD Frederic      * name as before.
86980270a19SKONRAD Frederic      */
87080270a19SKONRAD Frederic     if (proxy->id) {
87180270a19SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
87280270a19SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
87380270a19SKONRAD Frederic         g_free(bus_name);
87480270a19SKONRAD Frederic     }
875a5cf2bb4SCornelia Huck 
8766acf69cdSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
8775e5ced38SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
8785e5ced38SMarkus Armbruster     if (err) {
8795e5ced38SMarkus Armbruster         error_propagate(errp, err);
880a5cf2bb4SCornelia Huck     }
881a5cf2bb4SCornelia Huck }
882a5cf2bb4SCornelia Huck 
8836acf69cdSKONRAD Frederic 
8846acf69cdSKONRAD Frederic static void virtio_ccw_serial_instance_init(Object *obj)
885a5cf2bb4SCornelia Huck {
8866acf69cdSKONRAD Frederic     VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj);
887c8075cafSGonglei 
888c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
889c8075cafSGonglei                                 TYPE_VIRTIO_SERIAL);
890a5cf2bb4SCornelia Huck }
891a5cf2bb4SCornelia Huck 
8925e5ced38SMarkus Armbruster static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp)
893a5cf2bb4SCornelia Huck {
89430bff6a0SKONRAD Frederic     VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev);
89530bff6a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
8965e5ced38SMarkus Armbruster     Error *err = NULL;
897a5cf2bb4SCornelia Huck 
89830bff6a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
8995e5ced38SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
9005e5ced38SMarkus Armbruster     if (err) {
9015e5ced38SMarkus Armbruster         error_propagate(errp, err);
902a5cf2bb4SCornelia Huck     }
903a5cf2bb4SCornelia Huck }
904a5cf2bb4SCornelia Huck 
90530bff6a0SKONRAD Frederic static void virtio_ccw_balloon_instance_init(Object *obj)
906a5cf2bb4SCornelia Huck {
90730bff6a0SKONRAD Frederic     VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj);
908ecfa60e3SShannon Zhao 
909a6027b0fSDenis V. Lunev     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
910a6027b0fSDenis V. Lunev                                 TYPE_VIRTIO_BALLOON);
911ecfa60e3SShannon Zhao     object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
912ecfa60e3SShannon Zhao                               "guest-stats", &error_abort);
913ecfa60e3SShannon Zhao     object_property_add_alias(obj, "guest-stats-polling-interval",
914ecfa60e3SShannon Zhao                               OBJECT(&dev->vdev),
915ecfa60e3SShannon Zhao                               "guest-stats-polling-interval", &error_abort);
916a5cf2bb4SCornelia Huck }
917a5cf2bb4SCornelia Huck 
9185e5ced38SMarkus Armbruster static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
919a5cf2bb4SCornelia Huck {
920c908ea10SKONRAD Frederic     VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev);
921c908ea10SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
9226f32a6b4SKONRAD Frederic     DeviceState *qdev = DEVICE(ccw_dev);
9235e5ced38SMarkus Armbruster     Error *err = NULL;
9246f32a6b4SKONRAD Frederic     char *bus_name;
9256f32a6b4SKONRAD Frederic 
9266f32a6b4SKONRAD Frederic     /*
9276f32a6b4SKONRAD Frederic      * For command line compatibility, this sets the virtio-scsi-device bus
9286f32a6b4SKONRAD Frederic      * name as before.
9296f32a6b4SKONRAD Frederic      */
9306f32a6b4SKONRAD Frederic     if (qdev->id) {
9316f32a6b4SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", qdev->id);
9326f32a6b4SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
9336f32a6b4SKONRAD Frederic         g_free(bus_name);
9346f32a6b4SKONRAD Frederic     }
935a5cf2bb4SCornelia Huck 
936c908ea10SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
9375e5ced38SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
9385e5ced38SMarkus Armbruster     if (err) {
9395e5ced38SMarkus Armbruster         error_propagate(errp, err);
940a5cf2bb4SCornelia Huck     }
941a5cf2bb4SCornelia Huck }
942a5cf2bb4SCornelia Huck 
943c908ea10SKONRAD Frederic static void virtio_ccw_scsi_instance_init(Object *obj)
944a5cf2bb4SCornelia Huck {
945c908ea10SKONRAD Frederic     VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj);
946c8075cafSGonglei 
947c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
948c8075cafSGonglei                                 TYPE_VIRTIO_SCSI);
94919d339f1SFam Zheng     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
95019d339f1SFam Zheng                               &error_abort);
951a5cf2bb4SCornelia Huck }
952a5cf2bb4SCornelia Huck 
953ccf6916cSPaolo Bonzini #ifdef CONFIG_VHOST_SCSI
9545e5ced38SMarkus Armbruster static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
955ccf6916cSPaolo Bonzini {
956ccf6916cSPaolo Bonzini     VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev);
957ccf6916cSPaolo Bonzini     DeviceState *vdev = DEVICE(&dev->vdev);
9585e5ced38SMarkus Armbruster     Error *err = NULL;
959ccf6916cSPaolo Bonzini 
960ccf6916cSPaolo Bonzini     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
9615e5ced38SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
9625e5ced38SMarkus Armbruster     if (err) {
9635e5ced38SMarkus Armbruster         error_propagate(errp, err);
964ccf6916cSPaolo Bonzini     }
965ccf6916cSPaolo Bonzini }
966ccf6916cSPaolo Bonzini 
967ccf6916cSPaolo Bonzini static void vhost_ccw_scsi_instance_init(Object *obj)
968ccf6916cSPaolo Bonzini {
969ccf6916cSPaolo Bonzini     VHostSCSICcw *dev = VHOST_SCSI_CCW(obj);
970c8075cafSGonglei 
971c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
972c8075cafSGonglei                                 TYPE_VHOST_SCSI);
973ccf6916cSPaolo Bonzini }
974ccf6916cSPaolo Bonzini #endif
975ccf6916cSPaolo Bonzini 
9765e5ced38SMarkus Armbruster static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp)
9772362ecc5SCornelia Huck {
9782db26d4cSKONRAD Frederic     VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev);
9792db26d4cSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
9805e5ced38SMarkus Armbruster     Error *err = NULL;
9812362ecc5SCornelia Huck 
9822db26d4cSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
9835e5ced38SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
9845e5ced38SMarkus Armbruster     if (err) {
9855e5ced38SMarkus Armbruster         error_propagate(errp, err);
9865e5ced38SMarkus Armbruster         return;
9872362ecc5SCornelia Huck     }
9882362ecc5SCornelia Huck 
9892db26d4cSKONRAD Frederic     object_property_set_link(OBJECT(dev),
9905b456438SCole Robinson                              OBJECT(dev->vdev.conf.rng), "rng",
9912db26d4cSKONRAD Frederic                              NULL);
9922362ecc5SCornelia Huck }
9932362ecc5SCornelia Huck 
994a5cf2bb4SCornelia Huck /* DeviceState to VirtioCcwDevice. Note: used on datapath,
995a5cf2bb4SCornelia Huck  * be careful and test performance if you change this.
996a5cf2bb4SCornelia Huck  */
997a5cf2bb4SCornelia Huck static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
998a5cf2bb4SCornelia Huck {
999a5cf2bb4SCornelia Huck     return container_of(d, VirtioCcwDevice, parent_obj);
1000a5cf2bb4SCornelia Huck }
1001a5cf2bb4SCornelia Huck 
10027e749462SCornelia Huck static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
10037e749462SCornelia Huck                                      uint8_t to_be_set)
10047e749462SCornelia Huck {
10057e749462SCornelia Huck     uint8_t ind_old, ind_new;
10067e749462SCornelia Huck     hwaddr len = 1;
10077e749462SCornelia Huck     uint8_t *ind_addr;
10087e749462SCornelia Huck 
10097e749462SCornelia Huck     ind_addr = cpu_physical_memory_map(ind_loc, &len, 1);
10107e749462SCornelia Huck     if (!ind_addr) {
10117e749462SCornelia Huck         error_report("%s(%x.%x.%04x): unable to access indicator",
10127e749462SCornelia Huck                      __func__, sch->cssid, sch->ssid, sch->schid);
10137e749462SCornelia Huck         return -1;
10147e749462SCornelia Huck     }
10157e749462SCornelia Huck     do {
10167e749462SCornelia Huck         ind_old = *ind_addr;
10177e749462SCornelia Huck         ind_new = ind_old | to_be_set;
10187e749462SCornelia Huck     } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
10197e749462SCornelia Huck     cpu_physical_memory_unmap(ind_addr, len, 1, len);
10207e749462SCornelia Huck 
10217e749462SCornelia Huck     return ind_old;
10227e749462SCornelia Huck }
10237e749462SCornelia Huck 
1024a5cf2bb4SCornelia Huck static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
1025a5cf2bb4SCornelia Huck {
1026a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d);
1027a5cf2bb4SCornelia Huck     SubchDev *sch = dev->sch;
1028a5cf2bb4SCornelia Huck     uint64_t indicators;
1029a5cf2bb4SCornelia Huck 
1030a5cf2bb4SCornelia Huck     if (vector >= 128) {
1031a5cf2bb4SCornelia Huck         return;
1032a5cf2bb4SCornelia Huck     }
1033a5cf2bb4SCornelia Huck 
10348dfbaa6aSJason Wang     if (vector < VIRTIO_CCW_QUEUE_MAX) {
10357c486976SCornelia Huck         if (!dev->indicators) {
10367c486976SCornelia Huck             return;
10377c486976SCornelia Huck         }
10387e749462SCornelia Huck         if (sch->thinint_active) {
10397e749462SCornelia Huck             /*
10407e749462SCornelia Huck              * In the adapter interrupt case, indicators points to a
10417e749462SCornelia Huck              * memory area that may be (way) larger than 64 bit and
10427e749462SCornelia Huck              * ind_bit indicates the start of the indicators in a big
10437e749462SCornelia Huck              * endian notation.
10447e749462SCornelia Huck              */
1045d426d9fbSCornelia Huck             uint64_t ind_bit = dev->routes.adapter.ind_offset;
1046d426d9fbSCornelia Huck 
10477bca3892SCornelia Huck             virtio_set_ind_atomic(sch, dev->indicators->addr +
1048d426d9fbSCornelia Huck                                   (ind_bit + vector) / 8,
1049d426d9fbSCornelia Huck                                   0x80 >> ((ind_bit + vector) % 8));
10507bca3892SCornelia Huck             if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr,
10517e749462SCornelia Huck                                        0x01)) {
10527e749462SCornelia Huck                 css_adapter_interrupt(dev->thinint_isc);
10537e749462SCornelia Huck             }
10547e749462SCornelia Huck         } else {
105542874d3aSPeter Maydell             indicators = address_space_ldq(&address_space_memory,
105642874d3aSPeter Maydell                                            dev->indicators->addr,
105742874d3aSPeter Maydell                                            MEMTXATTRS_UNSPECIFIED,
105842874d3aSPeter Maydell                                            NULL);
105919380b1bSCornelia Huck             indicators |= 1ULL << vector;
106042874d3aSPeter Maydell             address_space_stq(&address_space_memory, dev->indicators->addr,
106142874d3aSPeter Maydell                               indicators, MEMTXATTRS_UNSPECIFIED, NULL);
10627e749462SCornelia Huck             css_conditional_io_interrupt(sch);
10637e749462SCornelia Huck         }
1064a5cf2bb4SCornelia Huck     } else {
10657c486976SCornelia Huck         if (!dev->indicators2) {
10667c486976SCornelia Huck             return;
10677c486976SCornelia Huck         }
1068a5cf2bb4SCornelia Huck         vector = 0;
106942874d3aSPeter Maydell         indicators = address_space_ldq(&address_space_memory,
107042874d3aSPeter Maydell                                        dev->indicators2->addr,
107142874d3aSPeter Maydell                                        MEMTXATTRS_UNSPECIFIED,
107242874d3aSPeter Maydell                                        NULL);
107319380b1bSCornelia Huck         indicators |= 1ULL << vector;
107442874d3aSPeter Maydell         address_space_stq(&address_space_memory, dev->indicators2->addr,
107542874d3aSPeter Maydell                           indicators, MEMTXATTRS_UNSPECIFIED, NULL);
1076a5cf2bb4SCornelia Huck         css_conditional_io_interrupt(sch);
10777e749462SCornelia Huck     }
1078a5cf2bb4SCornelia Huck }
1079a5cf2bb4SCornelia Huck 
1080a5cf2bb4SCornelia Huck static void virtio_ccw_reset(DeviceState *d)
1081a5cf2bb4SCornelia Huck {
1082a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1083f24a6840SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1084a5cf2bb4SCornelia Huck 
1085b4436a0bSCornelia Huck     virtio_ccw_stop_ioeventfd(dev);
1086f24a6840SPaolo Bonzini     virtio_reset(vdev);
1087a5cf2bb4SCornelia Huck     css_reset_sch(dev->sch);
10887bca3892SCornelia Huck     if (dev->indicators) {
1089d426d9fbSCornelia Huck         release_indicator(&dev->routes.adapter, dev->indicators);
10907bca3892SCornelia Huck         dev->indicators = NULL;
10917bca3892SCornelia Huck     }
10927bca3892SCornelia Huck     if (dev->indicators2) {
1093d426d9fbSCornelia Huck         release_indicator(&dev->routes.adapter, dev->indicators2);
10947bca3892SCornelia Huck         dev->indicators2 = NULL;
10957bca3892SCornelia Huck     }
10967bca3892SCornelia Huck     if (dev->summary_indicator) {
1097d426d9fbSCornelia Huck         release_indicator(&dev->routes.adapter, dev->summary_indicator);
10987bca3892SCornelia Huck         dev->summary_indicator = NULL;
10997bca3892SCornelia Huck     }
1100a5cf2bb4SCornelia Huck }
1101a5cf2bb4SCornelia Huck 
1102b4436a0bSCornelia Huck static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
1103b4436a0bSCornelia Huck {
1104b4436a0bSCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1105b4436a0bSCornelia Huck 
1106b4436a0bSCornelia Huck     if (running) {
1107b4436a0bSCornelia Huck         virtio_ccw_start_ioeventfd(dev);
1108b4436a0bSCornelia Huck     } else {
1109b4436a0bSCornelia Huck         virtio_ccw_stop_ioeventfd(dev);
1110b4436a0bSCornelia Huck     }
1111b4436a0bSCornelia Huck }
1112b4436a0bSCornelia Huck 
1113320ce850SCornelia Huck static bool virtio_ccw_query_guest_notifiers(DeviceState *d)
1114320ce850SCornelia Huck {
1115320ce850SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1116320ce850SCornelia Huck 
1117320ce850SCornelia Huck     return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA);
1118320ce850SCornelia Huck }
1119320ce850SCornelia Huck 
1120320ce850SCornelia Huck static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign)
1121320ce850SCornelia Huck {
1122320ce850SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1123320ce850SCornelia Huck 
1124320ce850SCornelia Huck     /* Stop using the generic ioeventfd, we are doing eventfd handling
1125320ce850SCornelia Huck      * ourselves below */
1126320ce850SCornelia Huck     dev->ioeventfd_disabled = assign;
1127320ce850SCornelia Huck     if (assign) {
1128320ce850SCornelia Huck         virtio_ccw_stop_ioeventfd(dev);
1129320ce850SCornelia Huck     }
1130320ce850SCornelia Huck     return virtio_ccw_set_guest2host_notifier(dev, n, assign, false);
1131320ce850SCornelia Huck }
1132320ce850SCornelia Huck 
1133d426d9fbSCornelia Huck static int virtio_ccw_get_mappings(VirtioCcwDevice *dev)
1134d426d9fbSCornelia Huck {
1135d426d9fbSCornelia Huck     int r;
1136d426d9fbSCornelia Huck 
1137d426d9fbSCornelia Huck     if (!dev->sch->thinint_active) {
1138d426d9fbSCornelia Huck         return -EINVAL;
1139d426d9fbSCornelia Huck     }
1140d426d9fbSCornelia Huck 
1141d426d9fbSCornelia Huck     r = map_indicator(&dev->routes.adapter, dev->summary_indicator);
1142d426d9fbSCornelia Huck     if (r) {
1143d426d9fbSCornelia Huck         return r;
1144d426d9fbSCornelia Huck     }
1145d426d9fbSCornelia Huck     r = map_indicator(&dev->routes.adapter, dev->indicators);
1146d426d9fbSCornelia Huck     if (r) {
1147d426d9fbSCornelia Huck         return r;
1148d426d9fbSCornelia Huck     }
1149d426d9fbSCornelia Huck     dev->routes.adapter.summary_addr = dev->summary_indicator->map;
1150d426d9fbSCornelia Huck     dev->routes.adapter.ind_addr = dev->indicators->map;
1151d426d9fbSCornelia Huck 
1152d426d9fbSCornelia Huck     return 0;
1153d426d9fbSCornelia Huck }
1154d426d9fbSCornelia Huck 
1155d426d9fbSCornelia Huck static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs)
1156d426d9fbSCornelia Huck {
1157d426d9fbSCornelia Huck     int i;
1158d426d9fbSCornelia Huck     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1159d426d9fbSCornelia Huck     int ret;
1160d426d9fbSCornelia Huck     S390FLICState *fs = s390_get_flic();
1161d426d9fbSCornelia Huck     S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
1162d426d9fbSCornelia Huck 
1163d426d9fbSCornelia Huck     ret = virtio_ccw_get_mappings(dev);
1164d426d9fbSCornelia Huck     if (ret) {
1165d426d9fbSCornelia Huck         return ret;
1166d426d9fbSCornelia Huck     }
1167d426d9fbSCornelia Huck     for (i = 0; i < nvqs; i++) {
1168d426d9fbSCornelia Huck         if (!virtio_queue_get_num(vdev, i)) {
1169d426d9fbSCornelia Huck             break;
1170d426d9fbSCornelia Huck         }
1171d426d9fbSCornelia Huck     }
1172d426d9fbSCornelia Huck     dev->routes.num_routes = i;
1173d426d9fbSCornelia Huck     return fsc->add_adapter_routes(fs, &dev->routes);
1174d426d9fbSCornelia Huck }
1175d426d9fbSCornelia Huck 
1176d426d9fbSCornelia Huck static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs)
1177d426d9fbSCornelia Huck {
1178d426d9fbSCornelia Huck     S390FLICState *fs = s390_get_flic();
1179d426d9fbSCornelia Huck     S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
1180d426d9fbSCornelia Huck 
1181d426d9fbSCornelia Huck     fsc->release_adapter_routes(fs, &dev->routes);
1182d426d9fbSCornelia Huck }
1183d426d9fbSCornelia Huck 
1184d426d9fbSCornelia Huck static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n)
1185d426d9fbSCornelia Huck {
1186d426d9fbSCornelia Huck     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1187d426d9fbSCornelia Huck     VirtQueue *vq = virtio_get_queue(vdev, n);
1188d426d9fbSCornelia Huck     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
1189d426d9fbSCornelia Huck 
1190d426d9fbSCornelia Huck     return kvm_irqchip_add_irqfd_notifier(kvm_state, notifier, NULL,
1191d426d9fbSCornelia Huck                                           dev->routes.gsi[n]);
1192d426d9fbSCornelia Huck }
1193d426d9fbSCornelia Huck 
1194d426d9fbSCornelia Huck static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n)
1195d426d9fbSCornelia Huck {
1196d426d9fbSCornelia Huck     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1197d426d9fbSCornelia Huck     VirtQueue *vq = virtio_get_queue(vdev, n);
1198d426d9fbSCornelia Huck     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
1199d426d9fbSCornelia Huck     int ret;
1200d426d9fbSCornelia Huck 
1201d426d9fbSCornelia Huck     ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, notifier,
1202d426d9fbSCornelia Huck                                             dev->routes.gsi[n]);
1203d426d9fbSCornelia Huck     assert(ret == 0);
1204d426d9fbSCornelia Huck }
1205d426d9fbSCornelia Huck 
1206320ce850SCornelia Huck static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
1207320ce850SCornelia Huck                                          bool assign, bool with_irqfd)
1208320ce850SCornelia Huck {
1209f24a6840SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1210f24a6840SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
1211320ce850SCornelia Huck     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
1212f24a6840SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
1213320ce850SCornelia Huck 
1214320ce850SCornelia Huck     if (assign) {
1215320ce850SCornelia Huck         int r = event_notifier_init(notifier, 0);
1216320ce850SCornelia Huck 
1217320ce850SCornelia Huck         if (r < 0) {
1218320ce850SCornelia Huck             return r;
1219320ce850SCornelia Huck         }
1220320ce850SCornelia Huck         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
1221d426d9fbSCornelia Huck         if (with_irqfd) {
1222d426d9fbSCornelia Huck             r = virtio_ccw_add_irqfd(dev, n);
1223d426d9fbSCornelia Huck             if (r) {
1224d426d9fbSCornelia Huck                 virtio_queue_set_guest_notifier_fd_handler(vq, false,
1225d426d9fbSCornelia Huck                                                            with_irqfd);
1226d426d9fbSCornelia Huck                 return r;
1227d426d9fbSCornelia Huck             }
1228d426d9fbSCornelia Huck         }
1229d426d9fbSCornelia Huck         /*
1230d426d9fbSCornelia Huck          * We do not support individual masking for channel devices, so we
1231d426d9fbSCornelia Huck          * need to manually trigger any guest masking callbacks here.
1232320ce850SCornelia Huck          */
1233320ce850SCornelia Huck         if (k->guest_notifier_mask) {
1234f24a6840SPaolo Bonzini             k->guest_notifier_mask(vdev, n, false);
1235320ce850SCornelia Huck         }
1236320ce850SCornelia Huck         /* get lost events and re-inject */
1237320ce850SCornelia Huck         if (k->guest_notifier_pending &&
1238f24a6840SPaolo Bonzini             k->guest_notifier_pending(vdev, n)) {
1239320ce850SCornelia Huck             event_notifier_set(notifier);
1240320ce850SCornelia Huck         }
1241320ce850SCornelia Huck     } else {
1242320ce850SCornelia Huck         if (k->guest_notifier_mask) {
1243f24a6840SPaolo Bonzini             k->guest_notifier_mask(vdev, n, true);
1244320ce850SCornelia Huck         }
1245d426d9fbSCornelia Huck         if (with_irqfd) {
1246d426d9fbSCornelia Huck             virtio_ccw_remove_irqfd(dev, n);
1247d426d9fbSCornelia Huck         }
1248320ce850SCornelia Huck         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
1249320ce850SCornelia Huck         event_notifier_cleanup(notifier);
1250320ce850SCornelia Huck     }
1251320ce850SCornelia Huck     return 0;
1252320ce850SCornelia Huck }
1253320ce850SCornelia Huck 
1254320ce850SCornelia Huck static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs,
1255320ce850SCornelia Huck                                           bool assigned)
1256320ce850SCornelia Huck {
1257320ce850SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1258f24a6840SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1259d426d9fbSCornelia Huck     bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled();
1260320ce850SCornelia Huck     int r, n;
1261320ce850SCornelia Huck 
1262d426d9fbSCornelia Huck     if (with_irqfd && assigned) {
1263d426d9fbSCornelia Huck         /* irq routes need to be set up before assigning irqfds */
1264d426d9fbSCornelia Huck         r = virtio_ccw_setup_irqroutes(dev, nvqs);
1265d426d9fbSCornelia Huck         if (r < 0) {
1266d426d9fbSCornelia Huck             goto irqroute_error;
1267d426d9fbSCornelia Huck         }
1268d426d9fbSCornelia Huck     }
1269320ce850SCornelia Huck     for (n = 0; n < nvqs; n++) {
1270320ce850SCornelia Huck         if (!virtio_queue_get_num(vdev, n)) {
1271320ce850SCornelia Huck             break;
1272320ce850SCornelia Huck         }
1273d426d9fbSCornelia Huck         r = virtio_ccw_set_guest_notifier(dev, n, assigned, with_irqfd);
1274320ce850SCornelia Huck         if (r < 0) {
1275320ce850SCornelia Huck             goto assign_error;
1276320ce850SCornelia Huck         }
1277320ce850SCornelia Huck     }
1278d426d9fbSCornelia Huck     if (with_irqfd && !assigned) {
1279d426d9fbSCornelia Huck         /* release irq routes after irqfds have been released */
1280d426d9fbSCornelia Huck         virtio_ccw_release_irqroutes(dev, nvqs);
1281d426d9fbSCornelia Huck     }
1282320ce850SCornelia Huck     return 0;
1283320ce850SCornelia Huck 
1284320ce850SCornelia Huck assign_error:
1285320ce850SCornelia Huck     while (--n >= 0) {
1286320ce850SCornelia Huck         virtio_ccw_set_guest_notifier(dev, n, !assigned, false);
1287320ce850SCornelia Huck     }
1288d426d9fbSCornelia Huck irqroute_error:
1289d426d9fbSCornelia Huck     if (with_irqfd && assigned) {
1290d426d9fbSCornelia Huck         virtio_ccw_release_irqroutes(dev, nvqs);
1291d426d9fbSCornelia Huck     }
1292320ce850SCornelia Huck     return r;
1293320ce850SCornelia Huck }
1294320ce850SCornelia Huck 
1295bcb2b582SJens Freimann static void virtio_ccw_save_queue(DeviceState *d, int n, QEMUFile *f)
1296bcb2b582SJens Freimann {
1297bcb2b582SJens Freimann     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1298bcb2b582SJens Freimann     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1299bcb2b582SJens Freimann 
1300bcb2b582SJens Freimann     qemu_put_be16(f, virtio_queue_vector(vdev, n));
1301bcb2b582SJens Freimann }
1302bcb2b582SJens Freimann 
1303bcb2b582SJens Freimann static int virtio_ccw_load_queue(DeviceState *d, int n, QEMUFile *f)
1304bcb2b582SJens Freimann {
1305bcb2b582SJens Freimann     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1306bcb2b582SJens Freimann     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1307bcb2b582SJens Freimann     uint16_t vector;
1308bcb2b582SJens Freimann 
1309bcb2b582SJens Freimann     qemu_get_be16s(f, &vector);
1310bcb2b582SJens Freimann     virtio_queue_set_vector(vdev, n , vector);
1311bcb2b582SJens Freimann 
1312bcb2b582SJens Freimann     return 0;
1313bcb2b582SJens Freimann }
1314bcb2b582SJens Freimann 
1315bcb2b582SJens Freimann static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
1316bcb2b582SJens Freimann {
1317bcb2b582SJens Freimann     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1318bcb2b582SJens Freimann     SubchDev *s = dev->sch;
13192a72ea5fSJason J. Herne     VirtIODevice *vdev = virtio_ccw_get_vdev(s);
1320bcb2b582SJens Freimann 
1321bcb2b582SJens Freimann     subch_device_save(s, f);
1322bcb2b582SJens Freimann     if (dev->indicators != NULL) {
1323bcb2b582SJens Freimann         qemu_put_be32(f, dev->indicators->len);
1324bcb2b582SJens Freimann         qemu_put_be64(f, dev->indicators->addr);
1325bcb2b582SJens Freimann     } else {
1326bcb2b582SJens Freimann         qemu_put_be32(f, 0);
1327bcb2b582SJens Freimann         qemu_put_be64(f, 0UL);
1328bcb2b582SJens Freimann     }
1329bcb2b582SJens Freimann     if (dev->indicators2 != NULL) {
1330bcb2b582SJens Freimann         qemu_put_be32(f, dev->indicators2->len);
1331bcb2b582SJens Freimann         qemu_put_be64(f, dev->indicators2->addr);
1332bcb2b582SJens Freimann     } else {
1333bcb2b582SJens Freimann         qemu_put_be32(f, 0);
1334bcb2b582SJens Freimann         qemu_put_be64(f, 0UL);
1335bcb2b582SJens Freimann     }
1336bcb2b582SJens Freimann     if (dev->summary_indicator != NULL) {
1337bcb2b582SJens Freimann         qemu_put_be32(f, dev->summary_indicator->len);
1338bcb2b582SJens Freimann         qemu_put_be64(f, dev->summary_indicator->addr);
1339bcb2b582SJens Freimann     } else {
1340bcb2b582SJens Freimann         qemu_put_be32(f, 0);
1341bcb2b582SJens Freimann         qemu_put_be64(f, 0UL);
1342bcb2b582SJens Freimann     }
13432a72ea5fSJason J. Herne     qemu_put_be16(f, vdev->config_vector);
1344bcb2b582SJens Freimann     qemu_put_be64(f, dev->routes.adapter.ind_offset);
1345bcb2b582SJens Freimann     qemu_put_byte(f, dev->thinint_isc);
1346bcb2b582SJens Freimann }
1347bcb2b582SJens Freimann 
1348bcb2b582SJens Freimann static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
1349bcb2b582SJens Freimann {
1350bcb2b582SJens Freimann     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1351bcb2b582SJens Freimann     SubchDev *s = dev->sch;
13522a72ea5fSJason J. Herne     VirtIODevice *vdev = virtio_ccw_get_vdev(s);
1353bcb2b582SJens Freimann     int len;
1354bcb2b582SJens Freimann 
1355bcb2b582SJens Freimann     s->driver_data = dev;
1356bcb2b582SJens Freimann     subch_device_load(s, f);
1357bcb2b582SJens Freimann     len = qemu_get_be32(f);
1358bcb2b582SJens Freimann     if (len != 0) {
1359bcb2b582SJens Freimann         dev->indicators = get_indicator(qemu_get_be64(f), len);
1360bcb2b582SJens Freimann     } else {
1361bcb2b582SJens Freimann         qemu_get_be64(f);
1362bcb2b582SJens Freimann         dev->indicators = NULL;
1363bcb2b582SJens Freimann     }
1364bcb2b582SJens Freimann     len = qemu_get_be32(f);
1365bcb2b582SJens Freimann     if (len != 0) {
1366bcb2b582SJens Freimann         dev->indicators2 = get_indicator(qemu_get_be64(f), len);
1367bcb2b582SJens Freimann     } else {
1368bcb2b582SJens Freimann         qemu_get_be64(f);
1369bcb2b582SJens Freimann         dev->indicators2 = NULL;
1370bcb2b582SJens Freimann     }
1371bcb2b582SJens Freimann     len = qemu_get_be32(f);
1372bcb2b582SJens Freimann     if (len != 0) {
1373bcb2b582SJens Freimann         dev->summary_indicator = get_indicator(qemu_get_be64(f), len);
1374bcb2b582SJens Freimann     } else {
1375bcb2b582SJens Freimann         qemu_get_be64(f);
1376bcb2b582SJens Freimann         dev->summary_indicator = NULL;
1377bcb2b582SJens Freimann     }
13782a72ea5fSJason J. Herne     qemu_get_be16s(f, &vdev->config_vector);
1379bcb2b582SJens Freimann     dev->routes.adapter.ind_offset = qemu_get_be64(f);
1380bcb2b582SJens Freimann     dev->thinint_isc = qemu_get_byte(f);
1381bcb2b582SJens Freimann     if (s->thinint_active) {
1382bcb2b582SJens Freimann         return css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
1383bcb2b582SJens Freimann                                        dev->thinint_isc, true, false,
1384bcb2b582SJens Freimann                                        &dev->routes.adapter.adapter_id);
1385bcb2b582SJens Freimann     }
1386bcb2b582SJens Freimann 
1387bcb2b582SJens Freimann     return 0;
1388bcb2b582SJens Freimann }
1389bcb2b582SJens Freimann 
1390fb846a09SCornelia Huck /* This is called by virtio-bus just after the device is plugged. */
1391e8398045SJason Wang static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
1392fb846a09SCornelia Huck {
1393fb846a09SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
139410ceaa1eSJason Wang     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
1395fb846a09SCornelia Huck     SubchDev *sch = dev->sch;
139610ceaa1eSJason Wang     int n = virtio_get_num_queues(vdev);
139710ceaa1eSJason Wang 
139810ceaa1eSJason Wang     if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) {
139910ceaa1eSJason Wang         error_setg(errp, "The nubmer of virtqueues %d "
140010ceaa1eSJason Wang                    "exceeds ccw limit %d", n,
140110ceaa1eSJason Wang                    VIRTIO_CCW_QUEUE_MAX);
140210ceaa1eSJason Wang         return;
140310ceaa1eSJason Wang     }
1404fb846a09SCornelia Huck 
1405a499973fSAurelien Jarno     if (!kvm_eventfds_enabled()) {
1406a499973fSAurelien Jarno         dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
1407a499973fSAurelien Jarno     }
1408a499973fSAurelien Jarno 
1409fb846a09SCornelia Huck     sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
1410fb846a09SCornelia Huck 
1411fb846a09SCornelia Huck     css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
1412fb846a09SCornelia Huck                           d->hotplugged, 1);
1413fb846a09SCornelia Huck }
1414fb846a09SCornelia Huck 
1415fb846a09SCornelia Huck static void virtio_ccw_device_unplugged(DeviceState *d)
1416fb846a09SCornelia Huck {
1417fb846a09SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
1418fb846a09SCornelia Huck 
1419fb846a09SCornelia Huck     virtio_ccw_stop_ioeventfd(dev);
1420fb846a09SCornelia Huck }
1421a5cf2bb4SCornelia Huck /**************** Virtio-ccw Bus Device Descriptions *******************/
1422a5cf2bb4SCornelia Huck 
1423a5cf2bb4SCornelia Huck static Property virtio_ccw_net_properties[] = {
1424a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
1425b4436a0bSCornelia Huck     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
1426b4436a0bSCornelia Huck                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
1427a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
1428a5cf2bb4SCornelia Huck };
1429a5cf2bb4SCornelia Huck 
1430a5cf2bb4SCornelia Huck static void virtio_ccw_net_class_init(ObjectClass *klass, void *data)
1431a5cf2bb4SCornelia Huck {
1432a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1433a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
1434a5cf2bb4SCornelia Huck 
14355e5ced38SMarkus Armbruster     k->realize = virtio_ccw_net_realize;
143689334c8bSKONRAD Frederic     k->exit = virtio_ccw_exit;
1437a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
1438a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_net_properties;
1439cd20d616SCornelia Huck     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1440a5cf2bb4SCornelia Huck }
1441a5cf2bb4SCornelia Huck 
1442a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_net = {
144389334c8bSKONRAD Frederic     .name          = TYPE_VIRTIO_NET_CCW,
1444a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
144589334c8bSKONRAD Frederic     .instance_size = sizeof(VirtIONetCcw),
144689334c8bSKONRAD Frederic     .instance_init = virtio_ccw_net_instance_init,
1447a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_net_class_init,
1448a5cf2bb4SCornelia Huck };
1449a5cf2bb4SCornelia Huck 
1450a5cf2bb4SCornelia Huck static Property virtio_ccw_blk_properties[] = {
1451a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
1452b4436a0bSCornelia Huck     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
1453b4436a0bSCornelia Huck                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
1454a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
1455a5cf2bb4SCornelia Huck };
1456a5cf2bb4SCornelia Huck 
1457a5cf2bb4SCornelia Huck static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data)
1458a5cf2bb4SCornelia Huck {
1459a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1460a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
1461a5cf2bb4SCornelia Huck 
14625e5ced38SMarkus Armbruster     k->realize = virtio_ccw_blk_realize;
14633400c455SKONRAD Frederic     k->exit = virtio_ccw_exit;
1464a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
1465a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_blk_properties;
1466cd20d616SCornelia Huck     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1467a5cf2bb4SCornelia Huck }
1468a5cf2bb4SCornelia Huck 
1469a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_blk = {
14703400c455SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_CCW,
1471a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
14723400c455SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkCcw),
14733400c455SKONRAD Frederic     .instance_init = virtio_ccw_blk_instance_init,
1474a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_blk_class_init,
1475a5cf2bb4SCornelia Huck };
1476a5cf2bb4SCornelia Huck 
1477a5cf2bb4SCornelia Huck static Property virtio_ccw_serial_properties[] = {
1478a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
1479b4436a0bSCornelia Huck     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
1480b4436a0bSCornelia Huck                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
1481a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
1482a5cf2bb4SCornelia Huck };
1483a5cf2bb4SCornelia Huck 
1484a5cf2bb4SCornelia Huck static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data)
1485a5cf2bb4SCornelia Huck {
1486a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1487a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
1488a5cf2bb4SCornelia Huck 
14895e5ced38SMarkus Armbruster     k->realize = virtio_ccw_serial_realize;
14906acf69cdSKONRAD Frederic     k->exit = virtio_ccw_exit;
1491a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
1492a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_serial_properties;
1493cd20d616SCornelia Huck     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1494a5cf2bb4SCornelia Huck }
1495a5cf2bb4SCornelia Huck 
1496a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_serial = {
14976acf69cdSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_CCW,
1498a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
14996acf69cdSKONRAD Frederic     .instance_size = sizeof(VirtioSerialCcw),
15006acf69cdSKONRAD Frederic     .instance_init = virtio_ccw_serial_instance_init,
1501a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_serial_class_init,
1502a5cf2bb4SCornelia Huck };
1503a5cf2bb4SCornelia Huck 
1504a5cf2bb4SCornelia Huck static Property virtio_ccw_balloon_properties[] = {
1505a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
1506b4436a0bSCornelia Huck     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
1507b4436a0bSCornelia Huck                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
1508a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
1509a5cf2bb4SCornelia Huck };
1510a5cf2bb4SCornelia Huck 
1511a5cf2bb4SCornelia Huck static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data)
1512a5cf2bb4SCornelia Huck {
1513a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1514a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
1515a5cf2bb4SCornelia Huck 
15165e5ced38SMarkus Armbruster     k->realize = virtio_ccw_balloon_realize;
151730bff6a0SKONRAD Frederic     k->exit = virtio_ccw_exit;
1518a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
1519a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_balloon_properties;
1520cd20d616SCornelia Huck     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
1521a5cf2bb4SCornelia Huck }
1522a5cf2bb4SCornelia Huck 
1523a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_balloon = {
152430bff6a0SKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_CCW,
1525a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
152630bff6a0SKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonCcw),
152730bff6a0SKONRAD Frederic     .instance_init = virtio_ccw_balloon_instance_init,
1528a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_balloon_class_init,
1529a5cf2bb4SCornelia Huck };
1530a5cf2bb4SCornelia Huck 
1531a5cf2bb4SCornelia Huck static Property virtio_ccw_scsi_properties[] = {
1532a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
1533b4436a0bSCornelia Huck     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
1534b4436a0bSCornelia Huck                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
1535a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
1536a5cf2bb4SCornelia Huck };
1537a5cf2bb4SCornelia Huck 
1538a5cf2bb4SCornelia Huck static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data)
1539a5cf2bb4SCornelia Huck {
1540a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1541a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
1542a5cf2bb4SCornelia Huck 
15435e5ced38SMarkus Armbruster     k->realize = virtio_ccw_scsi_realize;
1544c908ea10SKONRAD Frederic     k->exit = virtio_ccw_exit;
1545a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
1546a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_scsi_properties;
1547cd20d616SCornelia Huck     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1548a5cf2bb4SCornelia Huck }
1549a5cf2bb4SCornelia Huck 
1550a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_scsi = {
1551c908ea10SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_CCW,
1552a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
1553c908ea10SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSICcw),
1554c908ea10SKONRAD Frederic     .instance_init = virtio_ccw_scsi_instance_init,
1555a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_scsi_class_init,
1556a5cf2bb4SCornelia Huck };
1557a5cf2bb4SCornelia Huck 
1558ccf6916cSPaolo Bonzini #ifdef CONFIG_VHOST_SCSI
1559ccf6916cSPaolo Bonzini static Property vhost_ccw_scsi_properties[] = {
1560ccf6916cSPaolo Bonzini     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
1561ccf6916cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
1562ccf6916cSPaolo Bonzini };
1563ccf6916cSPaolo Bonzini 
1564ccf6916cSPaolo Bonzini static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
1565ccf6916cSPaolo Bonzini {
1566ccf6916cSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
1567ccf6916cSPaolo Bonzini     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
1568ccf6916cSPaolo Bonzini 
15695e5ced38SMarkus Armbruster     k->realize = vhost_ccw_scsi_realize;
1570ccf6916cSPaolo Bonzini     k->exit = virtio_ccw_exit;
1571ccf6916cSPaolo Bonzini     dc->reset = virtio_ccw_reset;
1572ccf6916cSPaolo Bonzini     dc->props = vhost_ccw_scsi_properties;
1573cd20d616SCornelia Huck     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1574ccf6916cSPaolo Bonzini }
1575ccf6916cSPaolo Bonzini 
1576ccf6916cSPaolo Bonzini static const TypeInfo vhost_ccw_scsi = {
1577ccf6916cSPaolo Bonzini     .name          = TYPE_VHOST_SCSI_CCW,
1578ccf6916cSPaolo Bonzini     .parent        = TYPE_VIRTIO_CCW_DEVICE,
15794b7757baSCornelia Huck     .instance_size = sizeof(VHostSCSICcw),
1580ccf6916cSPaolo Bonzini     .instance_init = vhost_ccw_scsi_instance_init,
1581ccf6916cSPaolo Bonzini     .class_init    = vhost_ccw_scsi_class_init,
1582ccf6916cSPaolo Bonzini };
1583ccf6916cSPaolo Bonzini #endif
1584ccf6916cSPaolo Bonzini 
15852db26d4cSKONRAD Frederic static void virtio_ccw_rng_instance_init(Object *obj)
15862362ecc5SCornelia Huck {
15872db26d4cSKONRAD Frederic     VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj);
1588c8075cafSGonglei 
1589c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1590c8075cafSGonglei                                 TYPE_VIRTIO_RNG);
1591cbd5ac69SPaolo Bonzini     object_property_add_alias(obj, "rng", OBJECT(&dev->vdev),
1592cbd5ac69SPaolo Bonzini                               "rng", &error_abort);
15932362ecc5SCornelia Huck }
15942362ecc5SCornelia Huck 
15952362ecc5SCornelia Huck static Property virtio_ccw_rng_properties[] = {
15962362ecc5SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
1597b4436a0bSCornelia Huck     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
1598b4436a0bSCornelia Huck                     VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
15992362ecc5SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
16002362ecc5SCornelia Huck };
16012362ecc5SCornelia Huck 
16022362ecc5SCornelia Huck static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data)
16032362ecc5SCornelia Huck {
16042362ecc5SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
16052362ecc5SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
16062362ecc5SCornelia Huck 
16075e5ced38SMarkus Armbruster     k->realize = virtio_ccw_rng_realize;
16082db26d4cSKONRAD Frederic     k->exit = virtio_ccw_exit;
16092362ecc5SCornelia Huck     dc->reset = virtio_ccw_reset;
16102362ecc5SCornelia Huck     dc->props = virtio_ccw_rng_properties;
1611cd20d616SCornelia Huck     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
16122362ecc5SCornelia Huck }
16132362ecc5SCornelia Huck 
16142362ecc5SCornelia Huck static const TypeInfo virtio_ccw_rng = {
16152db26d4cSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_CCW,
16162362ecc5SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
16172db26d4cSKONRAD Frederic     .instance_size = sizeof(VirtIORNGCcw),
16182db26d4cSKONRAD Frederic     .instance_init = virtio_ccw_rng_instance_init,
16192362ecc5SCornelia Huck     .class_init    = virtio_ccw_rng_class_init,
16202362ecc5SCornelia Huck };
16212362ecc5SCornelia Huck 
16225e5ced38SMarkus Armbruster static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp)
1623a5cf2bb4SCornelia Huck {
1624a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
1625a5cf2bb4SCornelia Huck 
16261bf4d7aaSAndreas Färber     virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
16271fa75523SCornelia Huck     virtio_ccw_device_realize(_dev, errp);
1628a5cf2bb4SCornelia Huck }
1629a5cf2bb4SCornelia Huck 
1630a5cf2bb4SCornelia Huck static int virtio_ccw_busdev_exit(DeviceState *dev)
1631a5cf2bb4SCornelia Huck {
1632a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
1633a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
1634a5cf2bb4SCornelia Huck 
1635a5cf2bb4SCornelia Huck     return _info->exit(_dev);
1636a5cf2bb4SCornelia Huck }
1637a5cf2bb4SCornelia Huck 
1638277bc95eSIgor Mammedov static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
1639277bc95eSIgor Mammedov                                      DeviceState *dev, Error **errp)
1640a5cf2bb4SCornelia Huck {
1641a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
1642a5cf2bb4SCornelia Huck     SubchDev *sch = _dev->sch;
1643a5cf2bb4SCornelia Huck 
16440b81c1efSPaolo Bonzini     virtio_ccw_stop_ioeventfd(_dev);
16450b81c1efSPaolo Bonzini 
1646a5cf2bb4SCornelia Huck     /*
1647a5cf2bb4SCornelia Huck      * We should arrive here only for device_del, since we don't support
1648a5cf2bb4SCornelia Huck      * direct hot(un)plug of channels, but only through virtio.
1649a5cf2bb4SCornelia Huck      */
1650a5cf2bb4SCornelia Huck     assert(sch != NULL);
1651a5cf2bb4SCornelia Huck     /* Subchannel is now disabled and no longer valid. */
1652a5cf2bb4SCornelia Huck     sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA |
1653a5cf2bb4SCornelia Huck                                      PMCW_FLAGS_MASK_DNV);
1654a5cf2bb4SCornelia Huck 
1655a5cf2bb4SCornelia Huck     css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
1656a5cf2bb4SCornelia Huck 
165702a5c4c9SStefan Hajnoczi     object_unparent(OBJECT(dev));
1658a5cf2bb4SCornelia Huck }
1659a5cf2bb4SCornelia Huck 
1660a5cf2bb4SCornelia Huck static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
1661a5cf2bb4SCornelia Huck {
1662a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1663a5cf2bb4SCornelia Huck 
16645e5ced38SMarkus Armbruster     dc->realize = virtio_ccw_busdev_realize;
1665a5cf2bb4SCornelia Huck     dc->exit = virtio_ccw_busdev_exit;
1666a5cf2bb4SCornelia Huck     dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
1667a5cf2bb4SCornelia Huck }
1668a5cf2bb4SCornelia Huck 
1669a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_device_info = {
1670a5cf2bb4SCornelia Huck     .name = TYPE_VIRTIO_CCW_DEVICE,
1671a5cf2bb4SCornelia Huck     .parent = TYPE_DEVICE,
1672a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwDevice),
1673a5cf2bb4SCornelia Huck     .class_init = virtio_ccw_device_class_init,
1674a5cf2bb4SCornelia Huck     .class_size = sizeof(VirtIOCCWDeviceClass),
1675a5cf2bb4SCornelia Huck     .abstract = true,
1676a5cf2bb4SCornelia Huck };
1677a5cf2bb4SCornelia Huck 
1678a5cf2bb4SCornelia Huck /***************** Virtual-css Bus Bridge Device ********************/
1679a5cf2bb4SCornelia Huck /* Only required to have the virtio bus as child in the system bus */
1680a5cf2bb4SCornelia Huck 
1681a5cf2bb4SCornelia Huck static int virtual_css_bridge_init(SysBusDevice *dev)
1682a5cf2bb4SCornelia Huck {
1683a5cf2bb4SCornelia Huck     /* nothing */
1684a5cf2bb4SCornelia Huck     return 0;
1685a5cf2bb4SCornelia Huck }
1686a5cf2bb4SCornelia Huck 
1687a5cf2bb4SCornelia Huck static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
1688a5cf2bb4SCornelia Huck {
1689a5cf2bb4SCornelia Huck     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
1690277bc95eSIgor Mammedov     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
1691cd20d616SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1692a5cf2bb4SCornelia Huck 
1693a5cf2bb4SCornelia Huck     k->init = virtual_css_bridge_init;
1694277bc95eSIgor Mammedov     hc->unplug = virtio_ccw_busdev_unplug;
1695cd20d616SCornelia Huck     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
1696a5cf2bb4SCornelia Huck }
1697a5cf2bb4SCornelia Huck 
1698a5cf2bb4SCornelia Huck static const TypeInfo virtual_css_bridge_info = {
1699a5cf2bb4SCornelia Huck     .name          = "virtual-css-bridge",
1700a5cf2bb4SCornelia Huck     .parent        = TYPE_SYS_BUS_DEVICE,
1701a5cf2bb4SCornelia Huck     .instance_size = sizeof(SysBusDevice),
1702a5cf2bb4SCornelia Huck     .class_init    = virtual_css_bridge_class_init,
1703277bc95eSIgor Mammedov     .interfaces = (InterfaceInfo[]) {
1704277bc95eSIgor Mammedov         { TYPE_HOTPLUG_HANDLER },
1705277bc95eSIgor Mammedov         { }
1706277bc95eSIgor Mammedov     }
1707a5cf2bb4SCornelia Huck };
1708a5cf2bb4SCornelia Huck 
1709a5cf2bb4SCornelia Huck /* virtio-ccw-bus */
1710a5cf2bb4SCornelia Huck 
17111bf4d7aaSAndreas Färber static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
17121bf4d7aaSAndreas Färber                                VirtioCcwDevice *dev)
1713a5cf2bb4SCornelia Huck {
1714a5cf2bb4SCornelia Huck     DeviceState *qdev = DEVICE(dev);
1715f4dd69aaSKONRAD Frederic     char virtio_bus_name[] = "virtio-bus";
1716a5cf2bb4SCornelia Huck 
1717fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS,
1718fb17dfe0SAndreas Färber                         qdev, virtio_bus_name);
1719a5cf2bb4SCornelia Huck }
1720a5cf2bb4SCornelia Huck 
1721a5cf2bb4SCornelia Huck static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
1722a5cf2bb4SCornelia Huck {
1723a5cf2bb4SCornelia Huck     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
1724a5cf2bb4SCornelia Huck     BusClass *bus_class = BUS_CLASS(klass);
1725a5cf2bb4SCornelia Huck 
1726a5cf2bb4SCornelia Huck     bus_class->max_dev = 1;
1727a5cf2bb4SCornelia Huck     k->notify = virtio_ccw_notify;
1728b4436a0bSCornelia Huck     k->vmstate_change = virtio_ccw_vmstate_change;
1729320ce850SCornelia Huck     k->query_guest_notifiers = virtio_ccw_query_guest_notifiers;
1730320ce850SCornelia Huck     k->set_host_notifier = virtio_ccw_set_host_notifier;
1731320ce850SCornelia Huck     k->set_guest_notifiers = virtio_ccw_set_guest_notifiers;
1732bcb2b582SJens Freimann     k->save_queue = virtio_ccw_save_queue;
1733bcb2b582SJens Freimann     k->load_queue = virtio_ccw_load_queue;
1734bcb2b582SJens Freimann     k->save_config = virtio_ccw_save_config;
1735bcb2b582SJens Freimann     k->load_config = virtio_ccw_load_config;
1736fb846a09SCornelia Huck     k->device_plugged = virtio_ccw_device_plugged;
1737fb846a09SCornelia Huck     k->device_unplugged = virtio_ccw_device_unplugged;
1738a5cf2bb4SCornelia Huck }
1739a5cf2bb4SCornelia Huck 
1740a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_bus_info = {
1741a5cf2bb4SCornelia Huck     .name = TYPE_VIRTIO_CCW_BUS,
1742a5cf2bb4SCornelia Huck     .parent = TYPE_VIRTIO_BUS,
1743a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwBusState),
1744a5cf2bb4SCornelia Huck     .class_init = virtio_ccw_bus_class_init,
1745a5cf2bb4SCornelia Huck };
1746a5cf2bb4SCornelia Huck 
1747de6a9218SPierre Morel #ifdef CONFIG_VIRTFS
1748de6a9218SPierre Morel static Property virtio_ccw_9p_properties[] = {
1749de6a9218SPierre Morel     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
1750de6a9218SPierre Morel     DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
1751de6a9218SPierre Morel             VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
1752de6a9218SPierre Morel     DEFINE_PROP_END_OF_LIST(),
1753de6a9218SPierre Morel };
1754de6a9218SPierre Morel 
1755de6a9218SPierre Morel static void virtio_ccw_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp)
1756de6a9218SPierre Morel {
1757de6a9218SPierre Morel     V9fsCCWState *dev = VIRTIO_9P_CCW(ccw_dev);
1758de6a9218SPierre Morel     DeviceState *vdev = DEVICE(&dev->vdev);
1759de6a9218SPierre Morel     Error *err = NULL;
1760de6a9218SPierre Morel 
1761de6a9218SPierre Morel     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
1762de6a9218SPierre Morel     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
1763de6a9218SPierre Morel     if (err) {
1764de6a9218SPierre Morel         error_propagate(errp, err);
1765de6a9218SPierre Morel     }
1766de6a9218SPierre Morel }
1767de6a9218SPierre Morel 
1768de6a9218SPierre Morel static void virtio_ccw_9p_class_init(ObjectClass *klass, void *data)
1769de6a9218SPierre Morel {
1770de6a9218SPierre Morel     DeviceClass *dc = DEVICE_CLASS(klass);
1771de6a9218SPierre Morel     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
1772de6a9218SPierre Morel 
1773de6a9218SPierre Morel     k->exit = virtio_ccw_exit;
1774de6a9218SPierre Morel     k->realize = virtio_ccw_9p_realize;
1775de6a9218SPierre Morel     dc->reset = virtio_ccw_reset;
1776de6a9218SPierre Morel     dc->props = virtio_ccw_9p_properties;
1777de6a9218SPierre Morel     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1778de6a9218SPierre Morel }
1779de6a9218SPierre Morel 
1780de6a9218SPierre Morel static void virtio_ccw_9p_instance_init(Object *obj)
1781de6a9218SPierre Morel {
1782de6a9218SPierre Morel     V9fsCCWState *dev = VIRTIO_9P_CCW(obj);
1783de6a9218SPierre Morel 
1784de6a9218SPierre Morel     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1785de6a9218SPierre Morel                                 TYPE_VIRTIO_9P);
1786de6a9218SPierre Morel }
1787de6a9218SPierre Morel 
1788de6a9218SPierre Morel static const TypeInfo virtio_ccw_9p_info = {
1789de6a9218SPierre Morel     .name          = TYPE_VIRTIO_9P_CCW,
1790de6a9218SPierre Morel     .parent        = TYPE_VIRTIO_CCW_DEVICE,
1791de6a9218SPierre Morel     .instance_size = sizeof(V9fsCCWState),
1792de6a9218SPierre Morel     .instance_init = virtio_ccw_9p_instance_init,
1793de6a9218SPierre Morel     .class_init    = virtio_ccw_9p_class_init,
1794de6a9218SPierre Morel };
1795de6a9218SPierre Morel #endif
1796de6a9218SPierre Morel 
1797a5cf2bb4SCornelia Huck static void virtio_ccw_register(void)
1798a5cf2bb4SCornelia Huck {
1799a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_bus_info);
1800a5cf2bb4SCornelia Huck     type_register_static(&virtual_css_bus_info);
1801a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_device_info);
1802a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_serial);
1803a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_blk);
1804a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_net);
1805a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_balloon);
1806a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_scsi);
1807b702d2aeSEd Maste #ifdef CONFIG_VHOST_SCSI
1808ccf6916cSPaolo Bonzini     type_register_static(&vhost_ccw_scsi);
1809b702d2aeSEd Maste #endif
18102362ecc5SCornelia Huck     type_register_static(&virtio_ccw_rng);
1811a5cf2bb4SCornelia Huck     type_register_static(&virtual_css_bridge_info);
1812de6a9218SPierre Morel #ifdef CONFIG_VIRTFS
1813de6a9218SPierre Morel     type_register_static(&virtio_ccw_9p_info);
1814de6a9218SPierre Morel #endif
1815a5cf2bb4SCornelia Huck }
1816a5cf2bb4SCornelia Huck 
1817a5cf2bb4SCornelia Huck type_init(virtio_ccw_register)
1818