xref: /qemu/hw/s390x/virtio-ccw.c (revision c908ea10)
1a5cf2bb4SCornelia Huck /*
2a5cf2bb4SCornelia Huck  * virtio ccw target implementation
3a5cf2bb4SCornelia Huck  *
4a5cf2bb4SCornelia Huck  * Copyright 2012 IBM Corp.
5a5cf2bb4SCornelia Huck  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6a5cf2bb4SCornelia Huck  *
7a5cf2bb4SCornelia Huck  * This work is licensed under the terms of the GNU GPL, version 2 or (at
8a5cf2bb4SCornelia Huck  * your option) any later version. See the COPYING file in the top-level
9a5cf2bb4SCornelia Huck  * directory.
10a5cf2bb4SCornelia Huck  */
11a5cf2bb4SCornelia Huck 
12a5cf2bb4SCornelia Huck #include "hw/hw.h"
13a5cf2bb4SCornelia Huck #include "block/block.h"
14a5cf2bb4SCornelia Huck #include "sysemu/blockdev.h"
15a5cf2bb4SCornelia Huck #include "sysemu/sysemu.h"
16a5cf2bb4SCornelia Huck #include "net/net.h"
17a5cf2bb4SCornelia Huck #include "monitor/monitor.h"
18a5cf2bb4SCornelia Huck #include "hw/virtio.h"
19a5cf2bb4SCornelia Huck #include "hw/virtio-serial.h"
20a5cf2bb4SCornelia Huck #include "hw/virtio-net.h"
21a5cf2bb4SCornelia Huck #include "hw/sysbus.h"
22a5cf2bb4SCornelia Huck #include "qemu/bitops.h"
23a5cf2bb4SCornelia Huck #include "hw/virtio-bus.h"
24a5cf2bb4SCornelia Huck 
25a5cf2bb4SCornelia Huck #include "ioinst.h"
26a5cf2bb4SCornelia Huck #include "css.h"
27a5cf2bb4SCornelia Huck #include "virtio-ccw.h"
28a5cf2bb4SCornelia Huck #include "trace.h"
29a5cf2bb4SCornelia Huck 
30a5cf2bb4SCornelia Huck static int virtual_css_bus_reset(BusState *qbus)
31a5cf2bb4SCornelia Huck {
32a5cf2bb4SCornelia Huck     /* This should actually be modelled via the generic css */
33a5cf2bb4SCornelia Huck     css_reset();
34a5cf2bb4SCornelia Huck 
35a5cf2bb4SCornelia Huck     /* we dont traverse ourself, return 0 */
36a5cf2bb4SCornelia Huck     return 0;
37a5cf2bb4SCornelia Huck }
38a5cf2bb4SCornelia Huck 
39a5cf2bb4SCornelia Huck 
40a5cf2bb4SCornelia Huck static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
41a5cf2bb4SCornelia Huck {
42a5cf2bb4SCornelia Huck     BusClass *k = BUS_CLASS(klass);
43a5cf2bb4SCornelia Huck 
44a5cf2bb4SCornelia Huck     k->reset = virtual_css_bus_reset;
45a5cf2bb4SCornelia Huck }
46a5cf2bb4SCornelia Huck 
47a5cf2bb4SCornelia Huck static const TypeInfo virtual_css_bus_info = {
48a5cf2bb4SCornelia Huck     .name = TYPE_VIRTUAL_CSS_BUS,
49a5cf2bb4SCornelia Huck     .parent = TYPE_BUS,
50a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtualCssBus),
51a5cf2bb4SCornelia Huck     .class_init = virtual_css_bus_class_init,
52a5cf2bb4SCornelia Huck };
53a5cf2bb4SCornelia Huck 
54a5cf2bb4SCornelia Huck static const VirtIOBindings virtio_ccw_bindings;
55a5cf2bb4SCornelia Huck 
56a5cf2bb4SCornelia Huck VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
57a5cf2bb4SCornelia Huck {
58a5cf2bb4SCornelia Huck     VirtIODevice *vdev = NULL;
59a5cf2bb4SCornelia Huck 
60a5cf2bb4SCornelia Huck     if (sch->driver_data) {
61a5cf2bb4SCornelia Huck         vdev = ((VirtioCcwDevice *)sch->driver_data)->vdev;
62a5cf2bb4SCornelia Huck     }
63a5cf2bb4SCornelia Huck     return vdev;
64a5cf2bb4SCornelia Huck }
65a5cf2bb4SCornelia Huck 
66a5cf2bb4SCornelia Huck VirtualCssBus *virtual_css_bus_init(void)
67a5cf2bb4SCornelia Huck {
68a5cf2bb4SCornelia Huck     VirtualCssBus *cbus;
69a5cf2bb4SCornelia Huck     BusState *bus;
70a5cf2bb4SCornelia Huck     DeviceState *dev;
71a5cf2bb4SCornelia Huck 
72a5cf2bb4SCornelia Huck     /* Create bridge device */
73a5cf2bb4SCornelia Huck     dev = qdev_create(NULL, "virtual-css-bridge");
74a5cf2bb4SCornelia Huck     qdev_init_nofail(dev);
75a5cf2bb4SCornelia Huck 
76a5cf2bb4SCornelia Huck     /* Create bus on bridge device */
77a5cf2bb4SCornelia Huck     bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
78a5cf2bb4SCornelia Huck     cbus = VIRTUAL_CSS_BUS(bus);
79a5cf2bb4SCornelia Huck 
80a5cf2bb4SCornelia Huck     /* Enable hotplugging */
81a5cf2bb4SCornelia Huck     bus->allow_hotplug = 1;
82a5cf2bb4SCornelia Huck 
83a5cf2bb4SCornelia Huck     return cbus;
84a5cf2bb4SCornelia Huck }
85a5cf2bb4SCornelia Huck 
86a5cf2bb4SCornelia Huck /* Communication blocks used by several channel commands. */
87a5cf2bb4SCornelia Huck typedef struct VqInfoBlock {
88a5cf2bb4SCornelia Huck     uint64_t queue;
89a5cf2bb4SCornelia Huck     uint32_t align;
90a5cf2bb4SCornelia Huck     uint16_t index;
91a5cf2bb4SCornelia Huck     uint16_t num;
92a5cf2bb4SCornelia Huck } QEMU_PACKED VqInfoBlock;
93a5cf2bb4SCornelia Huck 
94a5cf2bb4SCornelia Huck typedef struct VqConfigBlock {
95a5cf2bb4SCornelia Huck     uint16_t index;
96a5cf2bb4SCornelia Huck     uint16_t num_max;
97a5cf2bb4SCornelia Huck } QEMU_PACKED VqConfigBlock;
98a5cf2bb4SCornelia Huck 
99a5cf2bb4SCornelia Huck typedef struct VirtioFeatDesc {
100a5cf2bb4SCornelia Huck     uint32_t features;
101a5cf2bb4SCornelia Huck     uint8_t index;
102a5cf2bb4SCornelia Huck } QEMU_PACKED VirtioFeatDesc;
103a5cf2bb4SCornelia Huck 
104a5cf2bb4SCornelia Huck /* Specify where the virtqueues for the subchannel are in guest memory. */
105a5cf2bb4SCornelia Huck static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
106a5cf2bb4SCornelia Huck                               uint16_t index, uint16_t num)
107a5cf2bb4SCornelia Huck {
108a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = sch->driver_data;
109a5cf2bb4SCornelia Huck 
110a5cf2bb4SCornelia Huck     if (index > VIRTIO_PCI_QUEUE_MAX) {
111a5cf2bb4SCornelia Huck         return -EINVAL;
112a5cf2bb4SCornelia Huck     }
113a5cf2bb4SCornelia Huck 
114a5cf2bb4SCornelia Huck     /* Current code in virtio.c relies on 4K alignment. */
115a5cf2bb4SCornelia Huck     if (addr && (align != 4096)) {
116a5cf2bb4SCornelia Huck         return -EINVAL;
117a5cf2bb4SCornelia Huck     }
118a5cf2bb4SCornelia Huck 
119a5cf2bb4SCornelia Huck     if (!dev) {
120a5cf2bb4SCornelia Huck         return -EINVAL;
121a5cf2bb4SCornelia Huck     }
122a5cf2bb4SCornelia Huck 
123a5cf2bb4SCornelia Huck     virtio_queue_set_addr(dev->vdev, index, addr);
124a5cf2bb4SCornelia Huck     if (!addr) {
125a5cf2bb4SCornelia Huck         virtio_queue_set_vector(dev->vdev, index, 0);
126a5cf2bb4SCornelia Huck     } else {
127a5cf2bb4SCornelia Huck         /* Fail if we don't have a big enough queue. */
128a5cf2bb4SCornelia Huck         /* TODO: Add interface to handle vring.num changing */
129a5cf2bb4SCornelia Huck         if (virtio_queue_get_num(dev->vdev, index) > num) {
130a5cf2bb4SCornelia Huck             return -EINVAL;
131a5cf2bb4SCornelia Huck         }
132a5cf2bb4SCornelia Huck         virtio_queue_set_vector(dev->vdev, index, index);
133a5cf2bb4SCornelia Huck     }
134a5cf2bb4SCornelia Huck     /* tell notify handler in case of config change */
135a5cf2bb4SCornelia Huck     dev->vdev->config_vector = VIRTIO_PCI_QUEUE_MAX;
136a5cf2bb4SCornelia Huck     return 0;
137a5cf2bb4SCornelia Huck }
138a5cf2bb4SCornelia Huck 
139a5cf2bb4SCornelia Huck static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
140a5cf2bb4SCornelia Huck {
141a5cf2bb4SCornelia Huck     int ret;
142a5cf2bb4SCornelia Huck     VqInfoBlock info;
143a5cf2bb4SCornelia Huck     uint8_t status;
144a5cf2bb4SCornelia Huck     VirtioFeatDesc features;
145a5cf2bb4SCornelia Huck     void *config;
146a5cf2bb4SCornelia Huck     hwaddr indicators;
147a5cf2bb4SCornelia Huck     VqConfigBlock vq_config;
148a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = sch->driver_data;
149a5cf2bb4SCornelia Huck     bool check_len;
150a5cf2bb4SCornelia Huck     int len;
151a5cf2bb4SCornelia Huck     hwaddr hw_len;
152a5cf2bb4SCornelia Huck 
153a5cf2bb4SCornelia Huck     if (!dev) {
154a5cf2bb4SCornelia Huck         return -EINVAL;
155a5cf2bb4SCornelia Huck     }
156a5cf2bb4SCornelia Huck 
157a5cf2bb4SCornelia Huck     trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid,
158a5cf2bb4SCornelia Huck                                    ccw.cmd_code);
159a5cf2bb4SCornelia Huck     check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));
160a5cf2bb4SCornelia Huck 
161a5cf2bb4SCornelia Huck     /* Look at the command. */
162a5cf2bb4SCornelia Huck     switch (ccw.cmd_code) {
163a5cf2bb4SCornelia Huck     case CCW_CMD_SET_VQ:
164a5cf2bb4SCornelia Huck         if (check_len) {
165a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(info)) {
166a5cf2bb4SCornelia Huck                 ret = -EINVAL;
167a5cf2bb4SCornelia Huck                 break;
168a5cf2bb4SCornelia Huck             }
169a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(info)) {
170a5cf2bb4SCornelia Huck             /* Can't execute command. */
171a5cf2bb4SCornelia Huck             ret = -EINVAL;
172a5cf2bb4SCornelia Huck             break;
173a5cf2bb4SCornelia Huck         }
174a5cf2bb4SCornelia Huck         if (!ccw.cda) {
175a5cf2bb4SCornelia Huck             ret = -EFAULT;
176a5cf2bb4SCornelia Huck         } else {
177a5cf2bb4SCornelia Huck             info.queue = ldq_phys(ccw.cda);
178a5cf2bb4SCornelia Huck             info.align = ldl_phys(ccw.cda + sizeof(info.queue));
179a5cf2bb4SCornelia Huck             info.index = lduw_phys(ccw.cda + sizeof(info.queue)
180a5cf2bb4SCornelia Huck                                    + sizeof(info.align));
181a5cf2bb4SCornelia Huck             info.num = lduw_phys(ccw.cda + sizeof(info.queue)
182a5cf2bb4SCornelia Huck                                  + sizeof(info.align)
183a5cf2bb4SCornelia Huck                                  + sizeof(info.index));
184a5cf2bb4SCornelia Huck             ret = virtio_ccw_set_vqs(sch, info.queue, info.align, info.index,
185a5cf2bb4SCornelia Huck                                      info.num);
186a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = 0;
187a5cf2bb4SCornelia Huck         }
188a5cf2bb4SCornelia Huck         break;
189a5cf2bb4SCornelia Huck     case CCW_CMD_VDEV_RESET:
190a5cf2bb4SCornelia Huck         virtio_reset(dev->vdev);
191a5cf2bb4SCornelia Huck         ret = 0;
192a5cf2bb4SCornelia Huck         break;
193a5cf2bb4SCornelia Huck     case CCW_CMD_READ_FEAT:
194a5cf2bb4SCornelia Huck         if (check_len) {
195a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(features)) {
196a5cf2bb4SCornelia Huck                 ret = -EINVAL;
197a5cf2bb4SCornelia Huck                 break;
198a5cf2bb4SCornelia Huck             }
199a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(features)) {
200a5cf2bb4SCornelia Huck             /* Can't execute command. */
201a5cf2bb4SCornelia Huck             ret = -EINVAL;
202a5cf2bb4SCornelia Huck             break;
203a5cf2bb4SCornelia Huck         }
204a5cf2bb4SCornelia Huck         if (!ccw.cda) {
205a5cf2bb4SCornelia Huck             ret = -EFAULT;
206a5cf2bb4SCornelia Huck         } else {
207a5cf2bb4SCornelia Huck             features.index = ldub_phys(ccw.cda + sizeof(features.features));
208a5cf2bb4SCornelia Huck             if (features.index < ARRAY_SIZE(dev->host_features)) {
209a5cf2bb4SCornelia Huck                 features.features = dev->host_features[features.index];
210a5cf2bb4SCornelia Huck             } else {
211a5cf2bb4SCornelia Huck                 /* Return zeroes if the guest supports more feature bits. */
212a5cf2bb4SCornelia Huck                 features.features = 0;
213a5cf2bb4SCornelia Huck             }
214a5cf2bb4SCornelia Huck             stl_le_phys(ccw.cda, features.features);
215a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(features);
216a5cf2bb4SCornelia Huck             ret = 0;
217a5cf2bb4SCornelia Huck         }
218a5cf2bb4SCornelia Huck         break;
219a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_FEAT:
220a5cf2bb4SCornelia Huck         if (check_len) {
221a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(features)) {
222a5cf2bb4SCornelia Huck                 ret = -EINVAL;
223a5cf2bb4SCornelia Huck                 break;
224a5cf2bb4SCornelia Huck             }
225a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(features)) {
226a5cf2bb4SCornelia Huck             /* Can't execute command. */
227a5cf2bb4SCornelia Huck             ret = -EINVAL;
228a5cf2bb4SCornelia Huck             break;
229a5cf2bb4SCornelia Huck         }
230a5cf2bb4SCornelia Huck         if (!ccw.cda) {
231a5cf2bb4SCornelia Huck             ret = -EFAULT;
232a5cf2bb4SCornelia Huck         } else {
233a5cf2bb4SCornelia Huck             features.index = ldub_phys(ccw.cda + sizeof(features.features));
234a5cf2bb4SCornelia Huck             features.features = ldl_le_phys(ccw.cda);
235a5cf2bb4SCornelia Huck             if (features.index < ARRAY_SIZE(dev->host_features)) {
236a5cf2bb4SCornelia Huck                 if (dev->vdev->set_features) {
237a5cf2bb4SCornelia Huck                     dev->vdev->set_features(dev->vdev, features.features);
238a5cf2bb4SCornelia Huck                 }
239a5cf2bb4SCornelia Huck                 dev->vdev->guest_features = features.features;
240a5cf2bb4SCornelia Huck             } else {
241a5cf2bb4SCornelia Huck                 /*
242a5cf2bb4SCornelia Huck                  * If the guest supports more feature bits, assert that it
243a5cf2bb4SCornelia Huck                  * passes us zeroes for those we don't support.
244a5cf2bb4SCornelia Huck                  */
245a5cf2bb4SCornelia Huck                 if (features.features) {
246a5cf2bb4SCornelia Huck                     fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",
247a5cf2bb4SCornelia Huck                             features.index, features.features);
248a5cf2bb4SCornelia Huck                     /* XXX: do a unit check here? */
249a5cf2bb4SCornelia Huck                 }
250a5cf2bb4SCornelia Huck             }
251a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(features);
252a5cf2bb4SCornelia Huck             ret = 0;
253a5cf2bb4SCornelia Huck         }
254a5cf2bb4SCornelia Huck         break;
255a5cf2bb4SCornelia Huck     case CCW_CMD_READ_CONF:
256a5cf2bb4SCornelia Huck         if (check_len) {
257a5cf2bb4SCornelia Huck             if (ccw.count > dev->vdev->config_len) {
258a5cf2bb4SCornelia Huck                 ret = -EINVAL;
259a5cf2bb4SCornelia Huck                 break;
260a5cf2bb4SCornelia Huck             }
261a5cf2bb4SCornelia Huck         }
262a5cf2bb4SCornelia Huck         len = MIN(ccw.count, dev->vdev->config_len);
263a5cf2bb4SCornelia Huck         if (!ccw.cda) {
264a5cf2bb4SCornelia Huck             ret = -EFAULT;
265a5cf2bb4SCornelia Huck         } else {
266a5cf2bb4SCornelia Huck             dev->vdev->get_config(dev->vdev, dev->vdev->config);
267a5cf2bb4SCornelia Huck             /* XXX config space endianness */
268a5cf2bb4SCornelia Huck             cpu_physical_memory_write(ccw.cda, dev->vdev->config, len);
269a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - len;
270a5cf2bb4SCornelia Huck             ret = 0;
271a5cf2bb4SCornelia Huck         }
272a5cf2bb4SCornelia Huck         break;
273a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_CONF:
274a5cf2bb4SCornelia Huck         if (check_len) {
275a5cf2bb4SCornelia Huck             if (ccw.count > dev->vdev->config_len) {
276a5cf2bb4SCornelia Huck                 ret = -EINVAL;
277a5cf2bb4SCornelia Huck                 break;
278a5cf2bb4SCornelia Huck             }
279a5cf2bb4SCornelia Huck         }
280a5cf2bb4SCornelia Huck         len = MIN(ccw.count, dev->vdev->config_len);
281a5cf2bb4SCornelia Huck         hw_len = len;
282a5cf2bb4SCornelia Huck         if (!ccw.cda) {
283a5cf2bb4SCornelia Huck             ret = -EFAULT;
284a5cf2bb4SCornelia Huck         } else {
285a5cf2bb4SCornelia Huck             config = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
286a5cf2bb4SCornelia Huck             if (!config) {
287a5cf2bb4SCornelia Huck                 ret = -EFAULT;
288a5cf2bb4SCornelia Huck             } else {
289a5cf2bb4SCornelia Huck                 len = hw_len;
290a5cf2bb4SCornelia Huck                 /* XXX config space endianness */
291a5cf2bb4SCornelia Huck                 memcpy(dev->vdev->config, config, len);
292a5cf2bb4SCornelia Huck                 cpu_physical_memory_unmap(config, hw_len, 0, hw_len);
293a5cf2bb4SCornelia Huck                 if (dev->vdev->set_config) {
294a5cf2bb4SCornelia Huck                     dev->vdev->set_config(dev->vdev, dev->vdev->config);
295a5cf2bb4SCornelia Huck                 }
296a5cf2bb4SCornelia Huck                 sch->curr_status.scsw.count = ccw.count - len;
297a5cf2bb4SCornelia Huck                 ret = 0;
298a5cf2bb4SCornelia Huck             }
299a5cf2bb4SCornelia Huck         }
300a5cf2bb4SCornelia Huck         break;
301a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_STATUS:
302a5cf2bb4SCornelia Huck         if (check_len) {
303a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(status)) {
304a5cf2bb4SCornelia Huck                 ret = -EINVAL;
305a5cf2bb4SCornelia Huck                 break;
306a5cf2bb4SCornelia Huck             }
307a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(status)) {
308a5cf2bb4SCornelia Huck             /* Can't execute command. */
309a5cf2bb4SCornelia Huck             ret = -EINVAL;
310a5cf2bb4SCornelia Huck             break;
311a5cf2bb4SCornelia Huck         }
312a5cf2bb4SCornelia Huck         if (!ccw.cda) {
313a5cf2bb4SCornelia Huck             ret = -EFAULT;
314a5cf2bb4SCornelia Huck         } else {
315a5cf2bb4SCornelia Huck             status = ldub_phys(ccw.cda);
316a5cf2bb4SCornelia Huck             virtio_set_status(dev->vdev, status);
317a5cf2bb4SCornelia Huck             if (dev->vdev->status == 0) {
318a5cf2bb4SCornelia Huck                 virtio_reset(dev->vdev);
319a5cf2bb4SCornelia Huck             }
320a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(status);
321a5cf2bb4SCornelia Huck             ret = 0;
322a5cf2bb4SCornelia Huck         }
323a5cf2bb4SCornelia Huck         break;
324a5cf2bb4SCornelia Huck     case CCW_CMD_SET_IND:
325a5cf2bb4SCornelia Huck         if (check_len) {
326a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(indicators)) {
327a5cf2bb4SCornelia Huck                 ret = -EINVAL;
328a5cf2bb4SCornelia Huck                 break;
329a5cf2bb4SCornelia Huck             }
330a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(indicators)) {
331a5cf2bb4SCornelia Huck             /* Can't execute command. */
332a5cf2bb4SCornelia Huck             ret = -EINVAL;
333a5cf2bb4SCornelia Huck             break;
334a5cf2bb4SCornelia Huck         }
335a5cf2bb4SCornelia Huck         indicators = ldq_phys(ccw.cda);
336a5cf2bb4SCornelia Huck         if (!indicators) {
337a5cf2bb4SCornelia Huck             ret = -EFAULT;
338a5cf2bb4SCornelia Huck         } else {
339a5cf2bb4SCornelia Huck             dev->indicators = indicators;
340a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
341a5cf2bb4SCornelia Huck             ret = 0;
342a5cf2bb4SCornelia Huck         }
343a5cf2bb4SCornelia Huck         break;
344a5cf2bb4SCornelia Huck     case CCW_CMD_SET_CONF_IND:
345a5cf2bb4SCornelia Huck         if (check_len) {
346a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(indicators)) {
347a5cf2bb4SCornelia Huck                 ret = -EINVAL;
348a5cf2bb4SCornelia Huck                 break;
349a5cf2bb4SCornelia Huck             }
350a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(indicators)) {
351a5cf2bb4SCornelia Huck             /* Can't execute command. */
352a5cf2bb4SCornelia Huck             ret = -EINVAL;
353a5cf2bb4SCornelia Huck             break;
354a5cf2bb4SCornelia Huck         }
355a5cf2bb4SCornelia Huck         indicators = ldq_phys(ccw.cda);
356a5cf2bb4SCornelia Huck         if (!indicators) {
357a5cf2bb4SCornelia Huck             ret = -EFAULT;
358a5cf2bb4SCornelia Huck         } else {
359a5cf2bb4SCornelia Huck             dev->indicators2 = indicators;
360a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
361a5cf2bb4SCornelia Huck             ret = 0;
362a5cf2bb4SCornelia Huck         }
363a5cf2bb4SCornelia Huck         break;
364a5cf2bb4SCornelia Huck     case CCW_CMD_READ_VQ_CONF:
365a5cf2bb4SCornelia Huck         if (check_len) {
366a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(vq_config)) {
367a5cf2bb4SCornelia Huck                 ret = -EINVAL;
368a5cf2bb4SCornelia Huck                 break;
369a5cf2bb4SCornelia Huck             }
370a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(vq_config)) {
371a5cf2bb4SCornelia Huck             /* Can't execute command. */
372a5cf2bb4SCornelia Huck             ret = -EINVAL;
373a5cf2bb4SCornelia Huck             break;
374a5cf2bb4SCornelia Huck         }
375a5cf2bb4SCornelia Huck         if (!ccw.cda) {
376a5cf2bb4SCornelia Huck             ret = -EFAULT;
377a5cf2bb4SCornelia Huck         } else {
378a5cf2bb4SCornelia Huck             vq_config.index = lduw_phys(ccw.cda);
379a5cf2bb4SCornelia Huck             vq_config.num_max = virtio_queue_get_num(dev->vdev,
380a5cf2bb4SCornelia Huck                                                      vq_config.index);
381a5cf2bb4SCornelia Huck             stw_phys(ccw.cda + sizeof(vq_config.index), vq_config.num_max);
382a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
383a5cf2bb4SCornelia Huck             ret = 0;
384a5cf2bb4SCornelia Huck         }
385a5cf2bb4SCornelia Huck         break;
386a5cf2bb4SCornelia Huck     default:
3878d034a6fSCornelia Huck         ret = -ENOSYS;
388a5cf2bb4SCornelia Huck         break;
389a5cf2bb4SCornelia Huck     }
390a5cf2bb4SCornelia Huck     return ret;
391a5cf2bb4SCornelia Huck }
392a5cf2bb4SCornelia Huck 
393a5cf2bb4SCornelia Huck static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
394a5cf2bb4SCornelia Huck {
395a5cf2bb4SCornelia Huck     unsigned int cssid = 0;
396a5cf2bb4SCornelia Huck     unsigned int ssid = 0;
397a5cf2bb4SCornelia Huck     unsigned int schid;
398a5cf2bb4SCornelia Huck     unsigned int devno;
399a5cf2bb4SCornelia Huck     bool have_devno = false;
400a5cf2bb4SCornelia Huck     bool found = false;
401a5cf2bb4SCornelia Huck     SubchDev *sch;
402a5cf2bb4SCornelia Huck     int ret;
403a5cf2bb4SCornelia Huck     int num;
404a5cf2bb4SCornelia Huck     DeviceState *parent = DEVICE(dev);
405a5cf2bb4SCornelia Huck 
406a5cf2bb4SCornelia Huck     sch = g_malloc0(sizeof(SubchDev));
407a5cf2bb4SCornelia Huck 
408a5cf2bb4SCornelia Huck     sch->driver_data = dev;
409a5cf2bb4SCornelia Huck     dev->sch = sch;
410a5cf2bb4SCornelia Huck 
411a5cf2bb4SCornelia Huck     dev->vdev = vdev;
412a5cf2bb4SCornelia Huck     dev->indicators = 0;
413a5cf2bb4SCornelia Huck 
414a5cf2bb4SCornelia Huck     /* Initialize subchannel structure. */
415a5cf2bb4SCornelia Huck     sch->channel_prog = 0x0;
416a5cf2bb4SCornelia Huck     sch->last_cmd_valid = false;
417a5cf2bb4SCornelia Huck     sch->orb = NULL;
418a5cf2bb4SCornelia Huck     /*
419a5cf2bb4SCornelia Huck      * Use a device number if provided. Otherwise, fall back to subchannel
420a5cf2bb4SCornelia Huck      * number.
421a5cf2bb4SCornelia Huck      */
422a5cf2bb4SCornelia Huck     if (dev->bus_id) {
423a5cf2bb4SCornelia Huck         num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
424a5cf2bb4SCornelia Huck         if (num == 3) {
425a5cf2bb4SCornelia Huck             if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
426a5cf2bb4SCornelia Huck                 ret = -EINVAL;
427a5cf2bb4SCornelia Huck                 error_report("Invalid cssid or ssid: cssid %x, ssid %x",
428a5cf2bb4SCornelia Huck                              cssid, ssid);
429a5cf2bb4SCornelia Huck                 goto out_err;
430a5cf2bb4SCornelia Huck             }
431a5cf2bb4SCornelia Huck             /* Enforce use of virtual cssid. */
432a5cf2bb4SCornelia Huck             if (cssid != VIRTUAL_CSSID) {
433a5cf2bb4SCornelia Huck                 ret = -EINVAL;
434a5cf2bb4SCornelia Huck                 error_report("cssid %x not valid for virtio devices", cssid);
435a5cf2bb4SCornelia Huck                 goto out_err;
436a5cf2bb4SCornelia Huck             }
437a5cf2bb4SCornelia Huck             if (css_devno_used(cssid, ssid, devno)) {
438a5cf2bb4SCornelia Huck                 ret = -EEXIST;
439a5cf2bb4SCornelia Huck                 error_report("Device %x.%x.%04x already exists", cssid, ssid,
440a5cf2bb4SCornelia Huck                              devno);
441a5cf2bb4SCornelia Huck                 goto out_err;
442a5cf2bb4SCornelia Huck             }
443a5cf2bb4SCornelia Huck             sch->cssid = cssid;
444a5cf2bb4SCornelia Huck             sch->ssid = ssid;
445a5cf2bb4SCornelia Huck             sch->devno = devno;
446a5cf2bb4SCornelia Huck             have_devno = true;
447a5cf2bb4SCornelia Huck         } else {
448a5cf2bb4SCornelia Huck             ret = -EINVAL;
449a5cf2bb4SCornelia Huck             error_report("Malformed devno parameter '%s'", dev->bus_id);
450a5cf2bb4SCornelia Huck             goto out_err;
451a5cf2bb4SCornelia Huck         }
452a5cf2bb4SCornelia Huck     }
453a5cf2bb4SCornelia Huck 
454a5cf2bb4SCornelia Huck     /* Find the next free id. */
455a5cf2bb4SCornelia Huck     if (have_devno) {
456a5cf2bb4SCornelia Huck         for (schid = 0; schid <= MAX_SCHID; schid++) {
457a5cf2bb4SCornelia Huck             if (!css_find_subch(1, cssid, ssid, schid)) {
458a5cf2bb4SCornelia Huck                 sch->schid = schid;
459a5cf2bb4SCornelia Huck                 css_subch_assign(cssid, ssid, schid, devno, sch);
460a5cf2bb4SCornelia Huck                 found = true;
461a5cf2bb4SCornelia Huck                 break;
462a5cf2bb4SCornelia Huck             }
463a5cf2bb4SCornelia Huck         }
464a5cf2bb4SCornelia Huck         if (!found) {
465a5cf2bb4SCornelia Huck             ret = -ENODEV;
466a5cf2bb4SCornelia Huck             error_report("No free subchannel found for %x.%x.%04x", cssid, ssid,
467a5cf2bb4SCornelia Huck                          devno);
468a5cf2bb4SCornelia Huck             goto out_err;
469a5cf2bb4SCornelia Huck         }
470a5cf2bb4SCornelia Huck         trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
471a5cf2bb4SCornelia Huck                                     "user-configured");
472a5cf2bb4SCornelia Huck     } else {
473a5cf2bb4SCornelia Huck         cssid = VIRTUAL_CSSID;
474a5cf2bb4SCornelia Huck         for (ssid = 0; ssid <= MAX_SSID; ssid++) {
475a5cf2bb4SCornelia Huck             for (schid = 0; schid <= MAX_SCHID; schid++) {
476a5cf2bb4SCornelia Huck                 if (!css_find_subch(1, cssid, ssid, schid)) {
477a5cf2bb4SCornelia Huck                     sch->cssid = cssid;
478a5cf2bb4SCornelia Huck                     sch->ssid = ssid;
479a5cf2bb4SCornelia Huck                     sch->schid = schid;
480a5cf2bb4SCornelia Huck                     devno = schid;
481a5cf2bb4SCornelia Huck                     /*
482a5cf2bb4SCornelia Huck                      * If the devno is already taken, look further in this
483a5cf2bb4SCornelia Huck                      * subchannel set.
484a5cf2bb4SCornelia Huck                      */
485a5cf2bb4SCornelia Huck                     while (css_devno_used(cssid, ssid, devno)) {
486a5cf2bb4SCornelia Huck                         if (devno == MAX_SCHID) {
487a5cf2bb4SCornelia Huck                             devno = 0;
488a5cf2bb4SCornelia Huck                         } else if (devno == schid - 1) {
489a5cf2bb4SCornelia Huck                             ret = -ENODEV;
490a5cf2bb4SCornelia Huck                             error_report("No free devno found");
491a5cf2bb4SCornelia Huck                             goto out_err;
492a5cf2bb4SCornelia Huck                         } else {
493a5cf2bb4SCornelia Huck                             devno++;
494a5cf2bb4SCornelia Huck                         }
495a5cf2bb4SCornelia Huck                     }
496a5cf2bb4SCornelia Huck                     sch->devno = devno;
497a5cf2bb4SCornelia Huck                     css_subch_assign(cssid, ssid, schid, devno, sch);
498a5cf2bb4SCornelia Huck                     found = true;
499a5cf2bb4SCornelia Huck                     break;
500a5cf2bb4SCornelia Huck                 }
501a5cf2bb4SCornelia Huck             }
502a5cf2bb4SCornelia Huck             if (found) {
503a5cf2bb4SCornelia Huck                 break;
504a5cf2bb4SCornelia Huck             }
505a5cf2bb4SCornelia Huck         }
506a5cf2bb4SCornelia Huck         if (!found) {
507a5cf2bb4SCornelia Huck             ret = -ENODEV;
508a5cf2bb4SCornelia Huck             error_report("Virtual channel subsystem is full!");
509a5cf2bb4SCornelia Huck             goto out_err;
510a5cf2bb4SCornelia Huck         }
511a5cf2bb4SCornelia Huck         trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
512a5cf2bb4SCornelia Huck                                     "auto-configured");
513a5cf2bb4SCornelia Huck     }
514a5cf2bb4SCornelia Huck 
515a5cf2bb4SCornelia Huck     /* Build initial schib. */
516a5cf2bb4SCornelia Huck     css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE);
517a5cf2bb4SCornelia Huck 
518a5cf2bb4SCornelia Huck     sch->ccw_cb = virtio_ccw_cb;
519a5cf2bb4SCornelia Huck 
520a5cf2bb4SCornelia Huck     /* Build senseid data. */
521a5cf2bb4SCornelia Huck     memset(&sch->id, 0, sizeof(SenseId));
522a5cf2bb4SCornelia Huck     sch->id.reserved = 0xff;
523a5cf2bb4SCornelia Huck     sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
524a5cf2bb4SCornelia Huck     sch->id.cu_model = dev->vdev->device_id;
525a5cf2bb4SCornelia Huck 
526a5cf2bb4SCornelia Huck     virtio_bind_device(vdev, &virtio_ccw_bindings, DEVICE(dev));
527a5cf2bb4SCornelia Huck     /* Only the first 32 feature bits are used. */
528a5cf2bb4SCornelia Huck     dev->host_features[0] = vdev->get_features(vdev, dev->host_features[0]);
529a5cf2bb4SCornelia Huck     dev->host_features[0] |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
530a5cf2bb4SCornelia Huck     dev->host_features[0] |= 0x1 << VIRTIO_F_BAD_FEATURE;
531a5cf2bb4SCornelia Huck 
532a5cf2bb4SCornelia Huck     css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
533a5cf2bb4SCornelia Huck                           parent->hotplugged, 1);
534a5cf2bb4SCornelia Huck     return 0;
535a5cf2bb4SCornelia Huck 
536a5cf2bb4SCornelia Huck out_err:
537a5cf2bb4SCornelia Huck     dev->sch = NULL;
538a5cf2bb4SCornelia Huck     g_free(sch);
539a5cf2bb4SCornelia Huck     return ret;
540a5cf2bb4SCornelia Huck }
541a5cf2bb4SCornelia Huck 
542a5cf2bb4SCornelia Huck static int virtio_ccw_exit(VirtioCcwDevice *dev)
543a5cf2bb4SCornelia Huck {
544a5cf2bb4SCornelia Huck     SubchDev *sch = dev->sch;
545a5cf2bb4SCornelia Huck 
546a5cf2bb4SCornelia Huck     if (sch) {
547a5cf2bb4SCornelia Huck         css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
548a5cf2bb4SCornelia Huck         g_free(sch);
549a5cf2bb4SCornelia Huck     }
550a5cf2bb4SCornelia Huck     dev->indicators = 0;
551a5cf2bb4SCornelia Huck     return 0;
552a5cf2bb4SCornelia Huck }
553a5cf2bb4SCornelia Huck 
554a5cf2bb4SCornelia Huck static int virtio_ccw_net_init(VirtioCcwDevice *dev)
555a5cf2bb4SCornelia Huck {
556a5cf2bb4SCornelia Huck     VirtIODevice *vdev;
557a5cf2bb4SCornelia Huck 
5581e89ad5bSAnthony Liguori     vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net,
5591e89ad5bSAnthony Liguori                            dev->host_features[0]);
560a5cf2bb4SCornelia Huck     if (!vdev) {
561a5cf2bb4SCornelia Huck         return -1;
562a5cf2bb4SCornelia Huck     }
563a5cf2bb4SCornelia Huck 
564a5cf2bb4SCornelia Huck     return virtio_ccw_device_init(dev, vdev);
565a5cf2bb4SCornelia Huck }
566a5cf2bb4SCornelia Huck 
567a5cf2bb4SCornelia Huck static int virtio_ccw_net_exit(VirtioCcwDevice *dev)
568a5cf2bb4SCornelia Huck {
569a5cf2bb4SCornelia Huck     virtio_net_exit(dev->vdev);
570a5cf2bb4SCornelia Huck     return virtio_ccw_exit(dev);
571a5cf2bb4SCornelia Huck }
572a5cf2bb4SCornelia Huck 
5733400c455SKONRAD Frederic static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
574a5cf2bb4SCornelia Huck {
5753400c455SKONRAD Frederic     VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
5763400c455SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
5773400c455SKONRAD Frederic     virtio_blk_set_conf(vdev, &(dev->blk));
5783400c455SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
5793400c455SKONRAD Frederic     if (qdev_init(vdev) < 0) {
580a5cf2bb4SCornelia Huck         return -1;
581a5cf2bb4SCornelia Huck     }
582a5cf2bb4SCornelia Huck 
5833400c455SKONRAD Frederic     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
584a5cf2bb4SCornelia Huck }
585a5cf2bb4SCornelia Huck 
5863400c455SKONRAD Frederic static void virtio_ccw_blk_instance_init(Object *obj)
587a5cf2bb4SCornelia Huck {
5883400c455SKONRAD Frederic     VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj);
5893400c455SKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK);
5903400c455SKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
591a5cf2bb4SCornelia Huck }
592a5cf2bb4SCornelia Huck 
593a5cf2bb4SCornelia Huck static int virtio_ccw_serial_init(VirtioCcwDevice *dev)
594a5cf2bb4SCornelia Huck {
595a5cf2bb4SCornelia Huck     VirtIODevice *vdev;
596a5cf2bb4SCornelia Huck 
597a5cf2bb4SCornelia Huck     vdev = virtio_serial_init((DeviceState *)dev, &dev->serial);
598a5cf2bb4SCornelia Huck     if (!vdev) {
599a5cf2bb4SCornelia Huck         return -1;
600a5cf2bb4SCornelia Huck     }
601a5cf2bb4SCornelia Huck 
602a5cf2bb4SCornelia Huck     return virtio_ccw_device_init(dev, vdev);
603a5cf2bb4SCornelia Huck }
604a5cf2bb4SCornelia Huck 
605a5cf2bb4SCornelia Huck static int virtio_ccw_serial_exit(VirtioCcwDevice *dev)
606a5cf2bb4SCornelia Huck {
607a5cf2bb4SCornelia Huck     virtio_serial_exit(dev->vdev);
608a5cf2bb4SCornelia Huck     return virtio_ccw_exit(dev);
609a5cf2bb4SCornelia Huck }
610a5cf2bb4SCornelia Huck 
611a5cf2bb4SCornelia Huck static int virtio_ccw_balloon_init(VirtioCcwDevice *dev)
612a5cf2bb4SCornelia Huck {
613a5cf2bb4SCornelia Huck     VirtIODevice *vdev;
614a5cf2bb4SCornelia Huck 
615a5cf2bb4SCornelia Huck     vdev = virtio_balloon_init((DeviceState *)dev);
616a5cf2bb4SCornelia Huck     if (!vdev) {
617a5cf2bb4SCornelia Huck         return -1;
618a5cf2bb4SCornelia Huck     }
619a5cf2bb4SCornelia Huck 
620a5cf2bb4SCornelia Huck     return virtio_ccw_device_init(dev, vdev);
621a5cf2bb4SCornelia Huck }
622a5cf2bb4SCornelia Huck 
623a5cf2bb4SCornelia Huck static int virtio_ccw_balloon_exit(VirtioCcwDevice *dev)
624a5cf2bb4SCornelia Huck {
625a5cf2bb4SCornelia Huck     virtio_balloon_exit(dev->vdev);
626a5cf2bb4SCornelia Huck     return virtio_ccw_exit(dev);
627a5cf2bb4SCornelia Huck }
628a5cf2bb4SCornelia Huck 
629*c908ea10SKONRAD Frederic static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
630a5cf2bb4SCornelia Huck {
631*c908ea10SKONRAD Frederic     VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev);
632*c908ea10SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
633a5cf2bb4SCornelia Huck 
634*c908ea10SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
635*c908ea10SKONRAD Frederic     if (qdev_init(vdev) < 0) {
636a5cf2bb4SCornelia Huck         return -1;
637a5cf2bb4SCornelia Huck     }
638a5cf2bb4SCornelia Huck 
639*c908ea10SKONRAD Frederic     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
640a5cf2bb4SCornelia Huck }
641a5cf2bb4SCornelia Huck 
642*c908ea10SKONRAD Frederic static void virtio_ccw_scsi_instance_init(Object *obj)
643a5cf2bb4SCornelia Huck {
644*c908ea10SKONRAD Frederic     VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj);
645*c908ea10SKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SCSI);
646*c908ea10SKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
647a5cf2bb4SCornelia Huck }
648a5cf2bb4SCornelia Huck 
6492362ecc5SCornelia Huck static int virtio_ccw_rng_init(VirtioCcwDevice *dev)
6502362ecc5SCornelia Huck {
6512362ecc5SCornelia Huck     VirtIODevice *vdev;
6522362ecc5SCornelia Huck 
6532362ecc5SCornelia Huck     if (dev->rng.rng == NULL) {
6542362ecc5SCornelia Huck         dev->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
6552362ecc5SCornelia Huck         object_property_add_child(OBJECT(dev), "default-backend",
6562362ecc5SCornelia Huck                                   OBJECT(dev->rng.default_backend), NULL);
6572362ecc5SCornelia Huck         object_property_set_link(OBJECT(dev), OBJECT(dev->rng.default_backend),
6582362ecc5SCornelia Huck                                  "rng", NULL);
6592362ecc5SCornelia Huck     }
6602362ecc5SCornelia Huck     vdev = virtio_rng_init((DeviceState *)dev, &dev->rng);
6612362ecc5SCornelia Huck     if (!vdev) {
6622362ecc5SCornelia Huck         return -1;
6632362ecc5SCornelia Huck     }
6642362ecc5SCornelia Huck     return virtio_ccw_device_init(dev, vdev);
6652362ecc5SCornelia Huck }
6662362ecc5SCornelia Huck 
6672362ecc5SCornelia Huck static int virtio_ccw_rng_exit(VirtioCcwDevice *dev)
6682362ecc5SCornelia Huck {
6692362ecc5SCornelia Huck     virtio_rng_exit(dev->vdev);
6702362ecc5SCornelia Huck     return virtio_ccw_exit(dev);
6712362ecc5SCornelia Huck }
6722362ecc5SCornelia Huck 
673a5cf2bb4SCornelia Huck /* DeviceState to VirtioCcwDevice. Note: used on datapath,
674a5cf2bb4SCornelia Huck  * be careful and test performance if you change this.
675a5cf2bb4SCornelia Huck  */
676a5cf2bb4SCornelia Huck static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
677a5cf2bb4SCornelia Huck {
678a5cf2bb4SCornelia Huck     return container_of(d, VirtioCcwDevice, parent_obj);
679a5cf2bb4SCornelia Huck }
680a5cf2bb4SCornelia Huck 
681a5cf2bb4SCornelia Huck static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
682a5cf2bb4SCornelia Huck {
683a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d);
684a5cf2bb4SCornelia Huck     SubchDev *sch = dev->sch;
685a5cf2bb4SCornelia Huck     uint64_t indicators;
686a5cf2bb4SCornelia Huck 
687a5cf2bb4SCornelia Huck     if (vector >= 128) {
688a5cf2bb4SCornelia Huck         return;
689a5cf2bb4SCornelia Huck     }
690a5cf2bb4SCornelia Huck 
691a5cf2bb4SCornelia Huck     if (vector < VIRTIO_PCI_QUEUE_MAX) {
692a5cf2bb4SCornelia Huck         indicators = ldq_phys(dev->indicators);
69319380b1bSCornelia Huck         indicators |= 1ULL << vector;
694a5cf2bb4SCornelia Huck         stq_phys(dev->indicators, indicators);
695a5cf2bb4SCornelia Huck     } else {
696a5cf2bb4SCornelia Huck         vector = 0;
697a5cf2bb4SCornelia Huck         indicators = ldq_phys(dev->indicators2);
69819380b1bSCornelia Huck         indicators |= 1ULL << vector;
699a5cf2bb4SCornelia Huck         stq_phys(dev->indicators2, indicators);
700a5cf2bb4SCornelia Huck     }
701a5cf2bb4SCornelia Huck 
702a5cf2bb4SCornelia Huck     css_conditional_io_interrupt(sch);
703a5cf2bb4SCornelia Huck 
704a5cf2bb4SCornelia Huck }
705a5cf2bb4SCornelia Huck 
706a5cf2bb4SCornelia Huck static unsigned virtio_ccw_get_features(DeviceState *d)
707a5cf2bb4SCornelia Huck {
708a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
709a5cf2bb4SCornelia Huck 
710a5cf2bb4SCornelia Huck     /* Only the first 32 feature bits are used. */
711a5cf2bb4SCornelia Huck     return dev->host_features[0];
712a5cf2bb4SCornelia Huck }
713a5cf2bb4SCornelia Huck 
714a5cf2bb4SCornelia Huck static void virtio_ccw_reset(DeviceState *d)
715a5cf2bb4SCornelia Huck {
716a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
717a5cf2bb4SCornelia Huck 
718a5cf2bb4SCornelia Huck     virtio_reset(dev->vdev);
719a5cf2bb4SCornelia Huck     css_reset_sch(dev->sch);
720a5cf2bb4SCornelia Huck }
721a5cf2bb4SCornelia Huck 
722a5cf2bb4SCornelia Huck /**************** Virtio-ccw Bus Device Descriptions *******************/
723a5cf2bb4SCornelia Huck 
724a5cf2bb4SCornelia Huck static const VirtIOBindings virtio_ccw_bindings = {
725a5cf2bb4SCornelia Huck     .notify = virtio_ccw_notify,
726a5cf2bb4SCornelia Huck     .get_features = virtio_ccw_get_features,
727a5cf2bb4SCornelia Huck };
728a5cf2bb4SCornelia Huck 
729a5cf2bb4SCornelia Huck static Property virtio_ccw_net_properties[] = {
730a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
731a5cf2bb4SCornelia Huck     DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
732a5cf2bb4SCornelia Huck     DEFINE_NIC_PROPERTIES(VirtioCcwDevice, nic),
733a5cf2bb4SCornelia Huck     DEFINE_PROP_UINT32("x-txtimer", VirtioCcwDevice,
734a5cf2bb4SCornelia Huck                        net.txtimer, TX_TIMER_INTERVAL),
735a5cf2bb4SCornelia Huck     DEFINE_PROP_INT32("x-txburst", VirtioCcwDevice,
736a5cf2bb4SCornelia Huck                       net.txburst, TX_BURST),
737a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("tx", VirtioCcwDevice, net.tx),
738a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
739a5cf2bb4SCornelia Huck };
740a5cf2bb4SCornelia Huck 
741a5cf2bb4SCornelia Huck static void virtio_ccw_net_class_init(ObjectClass *klass, void *data)
742a5cf2bb4SCornelia Huck {
743a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
744a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
745a5cf2bb4SCornelia Huck 
746a5cf2bb4SCornelia Huck     k->init = virtio_ccw_net_init;
747a5cf2bb4SCornelia Huck     k->exit = virtio_ccw_net_exit;
748a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
749a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_net_properties;
750a5cf2bb4SCornelia Huck }
751a5cf2bb4SCornelia Huck 
752a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_net = {
753a5cf2bb4SCornelia Huck     .name          = "virtio-net-ccw",
754a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
755a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwDevice),
756a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_net_class_init,
757a5cf2bb4SCornelia Huck };
758a5cf2bb4SCornelia Huck 
759a5cf2bb4SCornelia Huck static Property virtio_ccw_blk_properties[] = {
760a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
761a5cf2bb4SCornelia Huck     DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]),
762fe42d7fbSCornelia Huck     DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk),
763a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
764a5cf2bb4SCornelia Huck };
765a5cf2bb4SCornelia Huck 
766a5cf2bb4SCornelia Huck static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data)
767a5cf2bb4SCornelia Huck {
768a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
769a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
770a5cf2bb4SCornelia Huck 
771a5cf2bb4SCornelia Huck     k->init = virtio_ccw_blk_init;
7723400c455SKONRAD Frederic     k->exit = virtio_ccw_exit;
773a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
774a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_blk_properties;
775a5cf2bb4SCornelia Huck }
776a5cf2bb4SCornelia Huck 
777a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_blk = {
7783400c455SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_CCW,
779a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
7803400c455SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkCcw),
7813400c455SKONRAD Frederic     .instance_init = virtio_ccw_blk_instance_init,
782a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_blk_class_init,
783a5cf2bb4SCornelia Huck };
784a5cf2bb4SCornelia Huck 
785a5cf2bb4SCornelia Huck static Property virtio_ccw_serial_properties[] = {
786a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
787a5cf2bb4SCornelia Huck     DEFINE_PROP_UINT32("max_ports", VirtioCcwDevice,
788a5cf2bb4SCornelia Huck                        serial.max_virtserial_ports, 31),
789a5cf2bb4SCornelia Huck     DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
790a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
791a5cf2bb4SCornelia Huck };
792a5cf2bb4SCornelia Huck 
793a5cf2bb4SCornelia Huck static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data)
794a5cf2bb4SCornelia Huck {
795a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
796a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
797a5cf2bb4SCornelia Huck 
798a5cf2bb4SCornelia Huck     k->init = virtio_ccw_serial_init;
799a5cf2bb4SCornelia Huck     k->exit = virtio_ccw_serial_exit;
800a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
801a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_serial_properties;
802a5cf2bb4SCornelia Huck }
803a5cf2bb4SCornelia Huck 
804a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_serial = {
805a5cf2bb4SCornelia Huck     .name          = "virtio-serial-ccw",
806a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
807a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwDevice),
808a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_serial_class_init,
809a5cf2bb4SCornelia Huck };
810a5cf2bb4SCornelia Huck 
811a5cf2bb4SCornelia Huck static Property virtio_ccw_balloon_properties[] = {
812a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
813a5cf2bb4SCornelia Huck     DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
814a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
815a5cf2bb4SCornelia Huck };
816a5cf2bb4SCornelia Huck 
817a5cf2bb4SCornelia Huck static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data)
818a5cf2bb4SCornelia Huck {
819a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
820a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
821a5cf2bb4SCornelia Huck 
822a5cf2bb4SCornelia Huck     k->init = virtio_ccw_balloon_init;
823a5cf2bb4SCornelia Huck     k->exit = virtio_ccw_balloon_exit;
824a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
825a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_balloon_properties;
826a5cf2bb4SCornelia Huck }
827a5cf2bb4SCornelia Huck 
828a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_balloon = {
829a5cf2bb4SCornelia Huck     .name          = "virtio-balloon-ccw",
830a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
831a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwDevice),
832a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_balloon_class_init,
833a5cf2bb4SCornelia Huck };
834a5cf2bb4SCornelia Huck 
835a5cf2bb4SCornelia Huck static Property virtio_ccw_scsi_properties[] = {
836a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
837*c908ea10SKONRAD Frederic     DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.conf),
8384bfeb18aSKONRAD Frederic     DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
839a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
840a5cf2bb4SCornelia Huck };
841a5cf2bb4SCornelia Huck 
842a5cf2bb4SCornelia Huck static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data)
843a5cf2bb4SCornelia Huck {
844a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
845a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
846a5cf2bb4SCornelia Huck 
847a5cf2bb4SCornelia Huck     k->init = virtio_ccw_scsi_init;
848*c908ea10SKONRAD Frederic     k->exit = virtio_ccw_exit;
849a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
850a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_scsi_properties;
851a5cf2bb4SCornelia Huck }
852a5cf2bb4SCornelia Huck 
853a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_scsi = {
854*c908ea10SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_CCW,
855a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
856*c908ea10SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSICcw),
857*c908ea10SKONRAD Frederic     .instance_init = virtio_ccw_scsi_instance_init,
858a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_scsi_class_init,
859a5cf2bb4SCornelia Huck };
860a5cf2bb4SCornelia Huck 
8612362ecc5SCornelia Huck static void virtio_ccw_rng_initfn(Object *obj)
8622362ecc5SCornelia Huck {
8632362ecc5SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(obj);
8642362ecc5SCornelia Huck 
8652362ecc5SCornelia Huck     object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
8662362ecc5SCornelia Huck                              (Object **)&dev->rng.rng, NULL);
8672362ecc5SCornelia Huck }
8682362ecc5SCornelia Huck 
8692362ecc5SCornelia Huck static Property virtio_ccw_rng_properties[] = {
8702362ecc5SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
8712362ecc5SCornelia Huck     DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
8722362ecc5SCornelia Huck     DEFINE_PROP_UINT64("max-bytes", VirtioCcwDevice, rng.max_bytes, INT64_MAX),
8732362ecc5SCornelia Huck     DEFINE_PROP_UINT32("period", VirtioCcwDevice, rng.period_ms, 1 << 16),
8742362ecc5SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
8752362ecc5SCornelia Huck };
8762362ecc5SCornelia Huck 
8772362ecc5SCornelia Huck static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data)
8782362ecc5SCornelia Huck {
8792362ecc5SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
8802362ecc5SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
8812362ecc5SCornelia Huck 
8822362ecc5SCornelia Huck     k->init = virtio_ccw_rng_init;
8832362ecc5SCornelia Huck     k->exit = virtio_ccw_rng_exit;
8842362ecc5SCornelia Huck     dc->reset = virtio_ccw_reset;
8852362ecc5SCornelia Huck     dc->props = virtio_ccw_rng_properties;
8862362ecc5SCornelia Huck }
8872362ecc5SCornelia Huck 
8882362ecc5SCornelia Huck static const TypeInfo virtio_ccw_rng = {
8892362ecc5SCornelia Huck     .name          = "virtio-rng-ccw",
8902362ecc5SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
8912362ecc5SCornelia Huck     .instance_size = sizeof(VirtioCcwDevice),
8922362ecc5SCornelia Huck     .instance_init = virtio_ccw_rng_initfn,
8932362ecc5SCornelia Huck     .class_init    = virtio_ccw_rng_class_init,
8942362ecc5SCornelia Huck };
8952362ecc5SCornelia Huck 
896a5cf2bb4SCornelia Huck static int virtio_ccw_busdev_init(DeviceState *dev)
897a5cf2bb4SCornelia Huck {
898a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
899a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
900a5cf2bb4SCornelia Huck 
901a5cf2bb4SCornelia Huck     virtio_ccw_bus_new(&_dev->bus, _dev);
902a5cf2bb4SCornelia Huck 
903a5cf2bb4SCornelia Huck     return _info->init(_dev);
904a5cf2bb4SCornelia Huck }
905a5cf2bb4SCornelia Huck 
906a5cf2bb4SCornelia Huck static int virtio_ccw_busdev_exit(DeviceState *dev)
907a5cf2bb4SCornelia Huck {
908a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
909a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
910a5cf2bb4SCornelia Huck 
911a5cf2bb4SCornelia Huck     return _info->exit(_dev);
912a5cf2bb4SCornelia Huck }
913a5cf2bb4SCornelia Huck 
914a5cf2bb4SCornelia Huck static int virtio_ccw_busdev_unplug(DeviceState *dev)
915a5cf2bb4SCornelia Huck {
916a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
917a5cf2bb4SCornelia Huck     SubchDev *sch = _dev->sch;
918a5cf2bb4SCornelia Huck 
919a5cf2bb4SCornelia Huck     /*
920a5cf2bb4SCornelia Huck      * We should arrive here only for device_del, since we don't support
921a5cf2bb4SCornelia Huck      * direct hot(un)plug of channels, but only through virtio.
922a5cf2bb4SCornelia Huck      */
923a5cf2bb4SCornelia Huck     assert(sch != NULL);
924a5cf2bb4SCornelia Huck     /* Subchannel is now disabled and no longer valid. */
925a5cf2bb4SCornelia Huck     sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA |
926a5cf2bb4SCornelia Huck                                      PMCW_FLAGS_MASK_DNV);
927a5cf2bb4SCornelia Huck 
928a5cf2bb4SCornelia Huck     css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
929a5cf2bb4SCornelia Huck 
930a5cf2bb4SCornelia Huck     qdev_free(dev);
931a5cf2bb4SCornelia Huck     return 0;
932a5cf2bb4SCornelia Huck }
933a5cf2bb4SCornelia Huck 
934a5cf2bb4SCornelia Huck static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
935a5cf2bb4SCornelia Huck {
936a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
937a5cf2bb4SCornelia Huck 
938a5cf2bb4SCornelia Huck     dc->init = virtio_ccw_busdev_init;
939a5cf2bb4SCornelia Huck     dc->exit = virtio_ccw_busdev_exit;
940a5cf2bb4SCornelia Huck     dc->unplug = virtio_ccw_busdev_unplug;
941a5cf2bb4SCornelia Huck     dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
942a5cf2bb4SCornelia Huck 
943a5cf2bb4SCornelia Huck }
944a5cf2bb4SCornelia Huck 
945a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_device_info = {
946a5cf2bb4SCornelia Huck     .name = TYPE_VIRTIO_CCW_DEVICE,
947a5cf2bb4SCornelia Huck     .parent = TYPE_DEVICE,
948a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwDevice),
949a5cf2bb4SCornelia Huck     .class_init = virtio_ccw_device_class_init,
950a5cf2bb4SCornelia Huck     .class_size = sizeof(VirtIOCCWDeviceClass),
951a5cf2bb4SCornelia Huck     .abstract = true,
952a5cf2bb4SCornelia Huck };
953a5cf2bb4SCornelia Huck 
954a5cf2bb4SCornelia Huck /***************** Virtual-css Bus Bridge Device ********************/
955a5cf2bb4SCornelia Huck /* Only required to have the virtio bus as child in the system bus */
956a5cf2bb4SCornelia Huck 
957a5cf2bb4SCornelia Huck static int virtual_css_bridge_init(SysBusDevice *dev)
958a5cf2bb4SCornelia Huck {
959a5cf2bb4SCornelia Huck     /* nothing */
960a5cf2bb4SCornelia Huck     return 0;
961a5cf2bb4SCornelia Huck }
962a5cf2bb4SCornelia Huck 
963a5cf2bb4SCornelia Huck static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
964a5cf2bb4SCornelia Huck {
965a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
966a5cf2bb4SCornelia Huck     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
967a5cf2bb4SCornelia Huck 
968a5cf2bb4SCornelia Huck     k->init = virtual_css_bridge_init;
969a5cf2bb4SCornelia Huck     dc->no_user = 1;
970a5cf2bb4SCornelia Huck }
971a5cf2bb4SCornelia Huck 
972a5cf2bb4SCornelia Huck static const TypeInfo virtual_css_bridge_info = {
973a5cf2bb4SCornelia Huck     .name          = "virtual-css-bridge",
974a5cf2bb4SCornelia Huck     .parent        = TYPE_SYS_BUS_DEVICE,
975a5cf2bb4SCornelia Huck     .instance_size = sizeof(SysBusDevice),
976a5cf2bb4SCornelia Huck     .class_init    = virtual_css_bridge_class_init,
977a5cf2bb4SCornelia Huck };
978a5cf2bb4SCornelia Huck 
979a5cf2bb4SCornelia Huck /* virtio-ccw-bus */
980a5cf2bb4SCornelia Huck 
981a5cf2bb4SCornelia Huck void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev)
982a5cf2bb4SCornelia Huck {
983a5cf2bb4SCornelia Huck     DeviceState *qdev = DEVICE(dev);
984a5cf2bb4SCornelia Huck     BusState *qbus;
985a5cf2bb4SCornelia Huck 
986a5cf2bb4SCornelia Huck     qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_CCW_BUS, qdev, NULL);
987a5cf2bb4SCornelia Huck     qbus = BUS(bus);
988cbd19063SKONRAD Frederic     qbus->allow_hotplug = 1;
989a5cf2bb4SCornelia Huck }
990a5cf2bb4SCornelia Huck 
991a5cf2bb4SCornelia Huck static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
992a5cf2bb4SCornelia Huck {
993a5cf2bb4SCornelia Huck     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
994a5cf2bb4SCornelia Huck     BusClass *bus_class = BUS_CLASS(klass);
995a5cf2bb4SCornelia Huck 
996a5cf2bb4SCornelia Huck     bus_class->max_dev = 1;
997a5cf2bb4SCornelia Huck     k->notify = virtio_ccw_notify;
998a5cf2bb4SCornelia Huck     k->get_features = virtio_ccw_get_features;
999a5cf2bb4SCornelia Huck }
1000a5cf2bb4SCornelia Huck 
1001a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_bus_info = {
1002a5cf2bb4SCornelia Huck     .name = TYPE_VIRTIO_CCW_BUS,
1003a5cf2bb4SCornelia Huck     .parent = TYPE_VIRTIO_BUS,
1004a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwBusState),
1005a5cf2bb4SCornelia Huck     .class_init = virtio_ccw_bus_class_init,
1006a5cf2bb4SCornelia Huck };
1007a5cf2bb4SCornelia Huck 
1008a5cf2bb4SCornelia Huck static void virtio_ccw_register(void)
1009a5cf2bb4SCornelia Huck {
1010a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_bus_info);
1011a5cf2bb4SCornelia Huck     type_register_static(&virtual_css_bus_info);
1012a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_device_info);
1013a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_serial);
1014a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_blk);
1015a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_net);
1016a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_balloon);
1017a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_scsi);
10182362ecc5SCornelia Huck     type_register_static(&virtio_ccw_rng);
1019a5cf2bb4SCornelia Huck     type_register_static(&virtual_css_bridge_info);
1020a5cf2bb4SCornelia Huck }
1021a5cf2bb4SCornelia Huck 
1022a5cf2bb4SCornelia Huck type_init(virtio_ccw_register)
1023