xref: /qemu/hw/s390x/virtio-ccw.c (revision d51fcfac)
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"
180d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
190d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h"
200d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
21a5cf2bb4SCornelia Huck #include "hw/sysbus.h"
22a5cf2bb4SCornelia Huck #include "qemu/bitops.h"
230d09e41aSPaolo Bonzini #include "hw/virtio/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 
30*d51fcfacSKONRAD Frederic static void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev);
31*d51fcfacSKONRAD Frederic 
32a5cf2bb4SCornelia Huck static int virtual_css_bus_reset(BusState *qbus)
33a5cf2bb4SCornelia Huck {
34a5cf2bb4SCornelia Huck     /* This should actually be modelled via the generic css */
35a5cf2bb4SCornelia Huck     css_reset();
36a5cf2bb4SCornelia Huck 
37a5cf2bb4SCornelia Huck     /* we dont traverse ourself, return 0 */
38a5cf2bb4SCornelia Huck     return 0;
39a5cf2bb4SCornelia Huck }
40a5cf2bb4SCornelia Huck 
41a5cf2bb4SCornelia Huck 
42a5cf2bb4SCornelia Huck static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
43a5cf2bb4SCornelia Huck {
44a5cf2bb4SCornelia Huck     BusClass *k = BUS_CLASS(klass);
45a5cf2bb4SCornelia Huck 
46a5cf2bb4SCornelia Huck     k->reset = virtual_css_bus_reset;
47a5cf2bb4SCornelia Huck }
48a5cf2bb4SCornelia Huck 
49a5cf2bb4SCornelia Huck static const TypeInfo virtual_css_bus_info = {
50a5cf2bb4SCornelia Huck     .name = TYPE_VIRTUAL_CSS_BUS,
51a5cf2bb4SCornelia Huck     .parent = TYPE_BUS,
52a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtualCssBus),
53a5cf2bb4SCornelia Huck     .class_init = virtual_css_bus_class_init,
54a5cf2bb4SCornelia Huck };
55a5cf2bb4SCornelia Huck 
56a5cf2bb4SCornelia Huck static const VirtIOBindings virtio_ccw_bindings;
57a5cf2bb4SCornelia Huck 
58a5cf2bb4SCornelia Huck VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
59a5cf2bb4SCornelia Huck {
60a5cf2bb4SCornelia Huck     VirtIODevice *vdev = NULL;
61a5cf2bb4SCornelia Huck 
62a5cf2bb4SCornelia Huck     if (sch->driver_data) {
63a5cf2bb4SCornelia Huck         vdev = ((VirtioCcwDevice *)sch->driver_data)->vdev;
64a5cf2bb4SCornelia Huck     }
65a5cf2bb4SCornelia Huck     return vdev;
66a5cf2bb4SCornelia Huck }
67a5cf2bb4SCornelia Huck 
68a5cf2bb4SCornelia Huck VirtualCssBus *virtual_css_bus_init(void)
69a5cf2bb4SCornelia Huck {
70a5cf2bb4SCornelia Huck     VirtualCssBus *cbus;
71a5cf2bb4SCornelia Huck     BusState *bus;
72a5cf2bb4SCornelia Huck     DeviceState *dev;
73a5cf2bb4SCornelia Huck 
74a5cf2bb4SCornelia Huck     /* Create bridge device */
75a5cf2bb4SCornelia Huck     dev = qdev_create(NULL, "virtual-css-bridge");
76a5cf2bb4SCornelia Huck     qdev_init_nofail(dev);
77a5cf2bb4SCornelia Huck 
78a5cf2bb4SCornelia Huck     /* Create bus on bridge device */
79a5cf2bb4SCornelia Huck     bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
80a5cf2bb4SCornelia Huck     cbus = VIRTUAL_CSS_BUS(bus);
81a5cf2bb4SCornelia Huck 
82a5cf2bb4SCornelia Huck     /* Enable hotplugging */
83a5cf2bb4SCornelia Huck     bus->allow_hotplug = 1;
84a5cf2bb4SCornelia Huck 
85a5cf2bb4SCornelia Huck     return cbus;
86a5cf2bb4SCornelia Huck }
87a5cf2bb4SCornelia Huck 
88a5cf2bb4SCornelia Huck /* Communication blocks used by several channel commands. */
89a5cf2bb4SCornelia Huck typedef struct VqInfoBlock {
90a5cf2bb4SCornelia Huck     uint64_t queue;
91a5cf2bb4SCornelia Huck     uint32_t align;
92a5cf2bb4SCornelia Huck     uint16_t index;
93a5cf2bb4SCornelia Huck     uint16_t num;
94a5cf2bb4SCornelia Huck } QEMU_PACKED VqInfoBlock;
95a5cf2bb4SCornelia Huck 
96a5cf2bb4SCornelia Huck typedef struct VqConfigBlock {
97a5cf2bb4SCornelia Huck     uint16_t index;
98a5cf2bb4SCornelia Huck     uint16_t num_max;
99a5cf2bb4SCornelia Huck } QEMU_PACKED VqConfigBlock;
100a5cf2bb4SCornelia Huck 
101a5cf2bb4SCornelia Huck typedef struct VirtioFeatDesc {
102a5cf2bb4SCornelia Huck     uint32_t features;
103a5cf2bb4SCornelia Huck     uint8_t index;
104a5cf2bb4SCornelia Huck } QEMU_PACKED VirtioFeatDesc;
105a5cf2bb4SCornelia Huck 
106a5cf2bb4SCornelia Huck /* Specify where the virtqueues for the subchannel are in guest memory. */
107a5cf2bb4SCornelia Huck static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
108a5cf2bb4SCornelia Huck                               uint16_t index, uint16_t num)
109a5cf2bb4SCornelia Huck {
110a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = sch->driver_data;
111a5cf2bb4SCornelia Huck 
112a5cf2bb4SCornelia Huck     if (index > VIRTIO_PCI_QUEUE_MAX) {
113a5cf2bb4SCornelia Huck         return -EINVAL;
114a5cf2bb4SCornelia Huck     }
115a5cf2bb4SCornelia Huck 
116a5cf2bb4SCornelia Huck     /* Current code in virtio.c relies on 4K alignment. */
117a5cf2bb4SCornelia Huck     if (addr && (align != 4096)) {
118a5cf2bb4SCornelia Huck         return -EINVAL;
119a5cf2bb4SCornelia Huck     }
120a5cf2bb4SCornelia Huck 
121a5cf2bb4SCornelia Huck     if (!dev) {
122a5cf2bb4SCornelia Huck         return -EINVAL;
123a5cf2bb4SCornelia Huck     }
124a5cf2bb4SCornelia Huck 
125a5cf2bb4SCornelia Huck     virtio_queue_set_addr(dev->vdev, index, addr);
126a5cf2bb4SCornelia Huck     if (!addr) {
127a5cf2bb4SCornelia Huck         virtio_queue_set_vector(dev->vdev, index, 0);
128a5cf2bb4SCornelia Huck     } else {
129a5cf2bb4SCornelia Huck         /* Fail if we don't have a big enough queue. */
130a5cf2bb4SCornelia Huck         /* TODO: Add interface to handle vring.num changing */
131a5cf2bb4SCornelia Huck         if (virtio_queue_get_num(dev->vdev, index) > num) {
132a5cf2bb4SCornelia Huck             return -EINVAL;
133a5cf2bb4SCornelia Huck         }
134a5cf2bb4SCornelia Huck         virtio_queue_set_vector(dev->vdev, index, index);
135a5cf2bb4SCornelia Huck     }
136a5cf2bb4SCornelia Huck     /* tell notify handler in case of config change */
137a5cf2bb4SCornelia Huck     dev->vdev->config_vector = VIRTIO_PCI_QUEUE_MAX;
138a5cf2bb4SCornelia Huck     return 0;
139a5cf2bb4SCornelia Huck }
140a5cf2bb4SCornelia Huck 
141a5cf2bb4SCornelia Huck static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
142a5cf2bb4SCornelia Huck {
143a5cf2bb4SCornelia Huck     int ret;
144a5cf2bb4SCornelia Huck     VqInfoBlock info;
145a5cf2bb4SCornelia Huck     uint8_t status;
146a5cf2bb4SCornelia Huck     VirtioFeatDesc features;
147a5cf2bb4SCornelia Huck     void *config;
148a5cf2bb4SCornelia Huck     hwaddr indicators;
149a5cf2bb4SCornelia Huck     VqConfigBlock vq_config;
150a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = sch->driver_data;
151a5cf2bb4SCornelia Huck     bool check_len;
152a5cf2bb4SCornelia Huck     int len;
153a5cf2bb4SCornelia Huck     hwaddr hw_len;
154a5cf2bb4SCornelia Huck 
155a5cf2bb4SCornelia Huck     if (!dev) {
156a5cf2bb4SCornelia Huck         return -EINVAL;
157a5cf2bb4SCornelia Huck     }
158a5cf2bb4SCornelia Huck 
159a5cf2bb4SCornelia Huck     trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid,
160a5cf2bb4SCornelia Huck                                    ccw.cmd_code);
161a5cf2bb4SCornelia Huck     check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));
162a5cf2bb4SCornelia Huck 
163a5cf2bb4SCornelia Huck     /* Look at the command. */
164a5cf2bb4SCornelia Huck     switch (ccw.cmd_code) {
165a5cf2bb4SCornelia Huck     case CCW_CMD_SET_VQ:
166a5cf2bb4SCornelia Huck         if (check_len) {
167a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(info)) {
168a5cf2bb4SCornelia Huck                 ret = -EINVAL;
169a5cf2bb4SCornelia Huck                 break;
170a5cf2bb4SCornelia Huck             }
171a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(info)) {
172a5cf2bb4SCornelia Huck             /* Can't execute command. */
173a5cf2bb4SCornelia Huck             ret = -EINVAL;
174a5cf2bb4SCornelia Huck             break;
175a5cf2bb4SCornelia Huck         }
176a5cf2bb4SCornelia Huck         if (!ccw.cda) {
177a5cf2bb4SCornelia Huck             ret = -EFAULT;
178a5cf2bb4SCornelia Huck         } else {
179a5cf2bb4SCornelia Huck             info.queue = ldq_phys(ccw.cda);
180a5cf2bb4SCornelia Huck             info.align = ldl_phys(ccw.cda + sizeof(info.queue));
181a5cf2bb4SCornelia Huck             info.index = lduw_phys(ccw.cda + sizeof(info.queue)
182a5cf2bb4SCornelia Huck                                    + sizeof(info.align));
183a5cf2bb4SCornelia Huck             info.num = lduw_phys(ccw.cda + sizeof(info.queue)
184a5cf2bb4SCornelia Huck                                  + sizeof(info.align)
185a5cf2bb4SCornelia Huck                                  + sizeof(info.index));
186a5cf2bb4SCornelia Huck             ret = virtio_ccw_set_vqs(sch, info.queue, info.align, info.index,
187a5cf2bb4SCornelia Huck                                      info.num);
188a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = 0;
189a5cf2bb4SCornelia Huck         }
190a5cf2bb4SCornelia Huck         break;
191a5cf2bb4SCornelia Huck     case CCW_CMD_VDEV_RESET:
192a5cf2bb4SCornelia Huck         virtio_reset(dev->vdev);
193a5cf2bb4SCornelia Huck         ret = 0;
194a5cf2bb4SCornelia Huck         break;
195a5cf2bb4SCornelia Huck     case CCW_CMD_READ_FEAT:
196a5cf2bb4SCornelia Huck         if (check_len) {
197a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(features)) {
198a5cf2bb4SCornelia Huck                 ret = -EINVAL;
199a5cf2bb4SCornelia Huck                 break;
200a5cf2bb4SCornelia Huck             }
201a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(features)) {
202a5cf2bb4SCornelia Huck             /* Can't execute command. */
203a5cf2bb4SCornelia Huck             ret = -EINVAL;
204a5cf2bb4SCornelia Huck             break;
205a5cf2bb4SCornelia Huck         }
206a5cf2bb4SCornelia Huck         if (!ccw.cda) {
207a5cf2bb4SCornelia Huck             ret = -EFAULT;
208a5cf2bb4SCornelia Huck         } else {
209a5cf2bb4SCornelia Huck             features.index = ldub_phys(ccw.cda + sizeof(features.features));
210a5cf2bb4SCornelia Huck             if (features.index < ARRAY_SIZE(dev->host_features)) {
211a5cf2bb4SCornelia Huck                 features.features = dev->host_features[features.index];
212a5cf2bb4SCornelia Huck             } else {
213a5cf2bb4SCornelia Huck                 /* Return zeroes if the guest supports more feature bits. */
214a5cf2bb4SCornelia Huck                 features.features = 0;
215a5cf2bb4SCornelia Huck             }
216a5cf2bb4SCornelia Huck             stl_le_phys(ccw.cda, features.features);
217a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(features);
218a5cf2bb4SCornelia Huck             ret = 0;
219a5cf2bb4SCornelia Huck         }
220a5cf2bb4SCornelia Huck         break;
221a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_FEAT:
222a5cf2bb4SCornelia Huck         if (check_len) {
223a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(features)) {
224a5cf2bb4SCornelia Huck                 ret = -EINVAL;
225a5cf2bb4SCornelia Huck                 break;
226a5cf2bb4SCornelia Huck             }
227a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(features)) {
228a5cf2bb4SCornelia Huck             /* Can't execute command. */
229a5cf2bb4SCornelia Huck             ret = -EINVAL;
230a5cf2bb4SCornelia Huck             break;
231a5cf2bb4SCornelia Huck         }
232a5cf2bb4SCornelia Huck         if (!ccw.cda) {
233a5cf2bb4SCornelia Huck             ret = -EFAULT;
234a5cf2bb4SCornelia Huck         } else {
235a5cf2bb4SCornelia Huck             features.index = ldub_phys(ccw.cda + sizeof(features.features));
236a5cf2bb4SCornelia Huck             features.features = ldl_le_phys(ccw.cda);
237a5cf2bb4SCornelia Huck             if (features.index < ARRAY_SIZE(dev->host_features)) {
238a5cf2bb4SCornelia Huck                 if (dev->vdev->set_features) {
239a5cf2bb4SCornelia Huck                     dev->vdev->set_features(dev->vdev, features.features);
240a5cf2bb4SCornelia Huck                 }
241a5cf2bb4SCornelia Huck                 dev->vdev->guest_features = features.features;
242a5cf2bb4SCornelia Huck             } else {
243a5cf2bb4SCornelia Huck                 /*
244a5cf2bb4SCornelia Huck                  * If the guest supports more feature bits, assert that it
245a5cf2bb4SCornelia Huck                  * passes us zeroes for those we don't support.
246a5cf2bb4SCornelia Huck                  */
247a5cf2bb4SCornelia Huck                 if (features.features) {
248a5cf2bb4SCornelia Huck                     fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",
249a5cf2bb4SCornelia Huck                             features.index, features.features);
250a5cf2bb4SCornelia Huck                     /* XXX: do a unit check here? */
251a5cf2bb4SCornelia Huck                 }
252a5cf2bb4SCornelia Huck             }
253a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(features);
254a5cf2bb4SCornelia Huck             ret = 0;
255a5cf2bb4SCornelia Huck         }
256a5cf2bb4SCornelia Huck         break;
257a5cf2bb4SCornelia Huck     case CCW_CMD_READ_CONF:
258a5cf2bb4SCornelia Huck         if (check_len) {
259a5cf2bb4SCornelia Huck             if (ccw.count > dev->vdev->config_len) {
260a5cf2bb4SCornelia Huck                 ret = -EINVAL;
261a5cf2bb4SCornelia Huck                 break;
262a5cf2bb4SCornelia Huck             }
263a5cf2bb4SCornelia Huck         }
264a5cf2bb4SCornelia Huck         len = MIN(ccw.count, dev->vdev->config_len);
265a5cf2bb4SCornelia Huck         if (!ccw.cda) {
266a5cf2bb4SCornelia Huck             ret = -EFAULT;
267a5cf2bb4SCornelia Huck         } else {
268a5cf2bb4SCornelia Huck             dev->vdev->get_config(dev->vdev, dev->vdev->config);
269a5cf2bb4SCornelia Huck             /* XXX config space endianness */
270a5cf2bb4SCornelia Huck             cpu_physical_memory_write(ccw.cda, dev->vdev->config, len);
271a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - len;
272a5cf2bb4SCornelia Huck             ret = 0;
273a5cf2bb4SCornelia Huck         }
274a5cf2bb4SCornelia Huck         break;
275a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_CONF:
276a5cf2bb4SCornelia Huck         if (check_len) {
277a5cf2bb4SCornelia Huck             if (ccw.count > dev->vdev->config_len) {
278a5cf2bb4SCornelia Huck                 ret = -EINVAL;
279a5cf2bb4SCornelia Huck                 break;
280a5cf2bb4SCornelia Huck             }
281a5cf2bb4SCornelia Huck         }
282a5cf2bb4SCornelia Huck         len = MIN(ccw.count, dev->vdev->config_len);
283a5cf2bb4SCornelia Huck         hw_len = len;
284a5cf2bb4SCornelia Huck         if (!ccw.cda) {
285a5cf2bb4SCornelia Huck             ret = -EFAULT;
286a5cf2bb4SCornelia Huck         } else {
287a5cf2bb4SCornelia Huck             config = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
288a5cf2bb4SCornelia Huck             if (!config) {
289a5cf2bb4SCornelia Huck                 ret = -EFAULT;
290a5cf2bb4SCornelia Huck             } else {
291a5cf2bb4SCornelia Huck                 len = hw_len;
292a5cf2bb4SCornelia Huck                 /* XXX config space endianness */
293a5cf2bb4SCornelia Huck                 memcpy(dev->vdev->config, config, len);
294a5cf2bb4SCornelia Huck                 cpu_physical_memory_unmap(config, hw_len, 0, hw_len);
295a5cf2bb4SCornelia Huck                 if (dev->vdev->set_config) {
296a5cf2bb4SCornelia Huck                     dev->vdev->set_config(dev->vdev, dev->vdev->config);
297a5cf2bb4SCornelia Huck                 }
298a5cf2bb4SCornelia Huck                 sch->curr_status.scsw.count = ccw.count - len;
299a5cf2bb4SCornelia Huck                 ret = 0;
300a5cf2bb4SCornelia Huck             }
301a5cf2bb4SCornelia Huck         }
302a5cf2bb4SCornelia Huck         break;
303a5cf2bb4SCornelia Huck     case CCW_CMD_WRITE_STATUS:
304a5cf2bb4SCornelia Huck         if (check_len) {
305a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(status)) {
306a5cf2bb4SCornelia Huck                 ret = -EINVAL;
307a5cf2bb4SCornelia Huck                 break;
308a5cf2bb4SCornelia Huck             }
309a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(status)) {
310a5cf2bb4SCornelia Huck             /* Can't execute command. */
311a5cf2bb4SCornelia Huck             ret = -EINVAL;
312a5cf2bb4SCornelia Huck             break;
313a5cf2bb4SCornelia Huck         }
314a5cf2bb4SCornelia Huck         if (!ccw.cda) {
315a5cf2bb4SCornelia Huck             ret = -EFAULT;
316a5cf2bb4SCornelia Huck         } else {
317a5cf2bb4SCornelia Huck             status = ldub_phys(ccw.cda);
318a5cf2bb4SCornelia Huck             virtio_set_status(dev->vdev, status);
319a5cf2bb4SCornelia Huck             if (dev->vdev->status == 0) {
320a5cf2bb4SCornelia Huck                 virtio_reset(dev->vdev);
321a5cf2bb4SCornelia Huck             }
322a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(status);
323a5cf2bb4SCornelia Huck             ret = 0;
324a5cf2bb4SCornelia Huck         }
325a5cf2bb4SCornelia Huck         break;
326a5cf2bb4SCornelia Huck     case CCW_CMD_SET_IND:
327a5cf2bb4SCornelia Huck         if (check_len) {
328a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(indicators)) {
329a5cf2bb4SCornelia Huck                 ret = -EINVAL;
330a5cf2bb4SCornelia Huck                 break;
331a5cf2bb4SCornelia Huck             }
332a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(indicators)) {
333a5cf2bb4SCornelia Huck             /* Can't execute command. */
334a5cf2bb4SCornelia Huck             ret = -EINVAL;
335a5cf2bb4SCornelia Huck             break;
336a5cf2bb4SCornelia Huck         }
337a5cf2bb4SCornelia Huck         indicators = ldq_phys(ccw.cda);
338a5cf2bb4SCornelia Huck         if (!indicators) {
339a5cf2bb4SCornelia Huck             ret = -EFAULT;
340a5cf2bb4SCornelia Huck         } else {
341a5cf2bb4SCornelia Huck             dev->indicators = indicators;
342a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
343a5cf2bb4SCornelia Huck             ret = 0;
344a5cf2bb4SCornelia Huck         }
345a5cf2bb4SCornelia Huck         break;
346a5cf2bb4SCornelia Huck     case CCW_CMD_SET_CONF_IND:
347a5cf2bb4SCornelia Huck         if (check_len) {
348a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(indicators)) {
349a5cf2bb4SCornelia Huck                 ret = -EINVAL;
350a5cf2bb4SCornelia Huck                 break;
351a5cf2bb4SCornelia Huck             }
352a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(indicators)) {
353a5cf2bb4SCornelia Huck             /* Can't execute command. */
354a5cf2bb4SCornelia Huck             ret = -EINVAL;
355a5cf2bb4SCornelia Huck             break;
356a5cf2bb4SCornelia Huck         }
357a5cf2bb4SCornelia Huck         indicators = ldq_phys(ccw.cda);
358a5cf2bb4SCornelia Huck         if (!indicators) {
359a5cf2bb4SCornelia Huck             ret = -EFAULT;
360a5cf2bb4SCornelia Huck         } else {
361a5cf2bb4SCornelia Huck             dev->indicators2 = indicators;
362a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
363a5cf2bb4SCornelia Huck             ret = 0;
364a5cf2bb4SCornelia Huck         }
365a5cf2bb4SCornelia Huck         break;
366a5cf2bb4SCornelia Huck     case CCW_CMD_READ_VQ_CONF:
367a5cf2bb4SCornelia Huck         if (check_len) {
368a5cf2bb4SCornelia Huck             if (ccw.count != sizeof(vq_config)) {
369a5cf2bb4SCornelia Huck                 ret = -EINVAL;
370a5cf2bb4SCornelia Huck                 break;
371a5cf2bb4SCornelia Huck             }
372a5cf2bb4SCornelia Huck         } else if (ccw.count < sizeof(vq_config)) {
373a5cf2bb4SCornelia Huck             /* Can't execute command. */
374a5cf2bb4SCornelia Huck             ret = -EINVAL;
375a5cf2bb4SCornelia Huck             break;
376a5cf2bb4SCornelia Huck         }
377a5cf2bb4SCornelia Huck         if (!ccw.cda) {
378a5cf2bb4SCornelia Huck             ret = -EFAULT;
379a5cf2bb4SCornelia Huck         } else {
380a5cf2bb4SCornelia Huck             vq_config.index = lduw_phys(ccw.cda);
381a5cf2bb4SCornelia Huck             vq_config.num_max = virtio_queue_get_num(dev->vdev,
382a5cf2bb4SCornelia Huck                                                      vq_config.index);
383a5cf2bb4SCornelia Huck             stw_phys(ccw.cda + sizeof(vq_config.index), vq_config.num_max);
384a5cf2bb4SCornelia Huck             sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
385a5cf2bb4SCornelia Huck             ret = 0;
386a5cf2bb4SCornelia Huck         }
387a5cf2bb4SCornelia Huck         break;
388a5cf2bb4SCornelia Huck     default:
3898d034a6fSCornelia Huck         ret = -ENOSYS;
390a5cf2bb4SCornelia Huck         break;
391a5cf2bb4SCornelia Huck     }
392a5cf2bb4SCornelia Huck     return ret;
393a5cf2bb4SCornelia Huck }
394a5cf2bb4SCornelia Huck 
395a5cf2bb4SCornelia Huck static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
396a5cf2bb4SCornelia Huck {
397a5cf2bb4SCornelia Huck     unsigned int cssid = 0;
398a5cf2bb4SCornelia Huck     unsigned int ssid = 0;
399a5cf2bb4SCornelia Huck     unsigned int schid;
400a5cf2bb4SCornelia Huck     unsigned int devno;
401a5cf2bb4SCornelia Huck     bool have_devno = false;
402a5cf2bb4SCornelia Huck     bool found = false;
403a5cf2bb4SCornelia Huck     SubchDev *sch;
404a5cf2bb4SCornelia Huck     int ret;
405a5cf2bb4SCornelia Huck     int num;
406a5cf2bb4SCornelia Huck     DeviceState *parent = DEVICE(dev);
407a5cf2bb4SCornelia Huck 
408a5cf2bb4SCornelia Huck     sch = g_malloc0(sizeof(SubchDev));
409a5cf2bb4SCornelia Huck 
410a5cf2bb4SCornelia Huck     sch->driver_data = dev;
411a5cf2bb4SCornelia Huck     dev->sch = sch;
412a5cf2bb4SCornelia Huck 
413a5cf2bb4SCornelia Huck     dev->vdev = vdev;
414a5cf2bb4SCornelia Huck     dev->indicators = 0;
415a5cf2bb4SCornelia Huck 
416a5cf2bb4SCornelia Huck     /* Initialize subchannel structure. */
417a5cf2bb4SCornelia Huck     sch->channel_prog = 0x0;
418a5cf2bb4SCornelia Huck     sch->last_cmd_valid = false;
419a5cf2bb4SCornelia Huck     sch->orb = NULL;
420a5cf2bb4SCornelia Huck     /*
421a5cf2bb4SCornelia Huck      * Use a device number if provided. Otherwise, fall back to subchannel
422a5cf2bb4SCornelia Huck      * number.
423a5cf2bb4SCornelia Huck      */
424a5cf2bb4SCornelia Huck     if (dev->bus_id) {
425a5cf2bb4SCornelia Huck         num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
426a5cf2bb4SCornelia Huck         if (num == 3) {
427a5cf2bb4SCornelia Huck             if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
428a5cf2bb4SCornelia Huck                 ret = -EINVAL;
429a5cf2bb4SCornelia Huck                 error_report("Invalid cssid or ssid: cssid %x, ssid %x",
430a5cf2bb4SCornelia Huck                              cssid, ssid);
431a5cf2bb4SCornelia Huck                 goto out_err;
432a5cf2bb4SCornelia Huck             }
433a5cf2bb4SCornelia Huck             /* Enforce use of virtual cssid. */
434a5cf2bb4SCornelia Huck             if (cssid != VIRTUAL_CSSID) {
435a5cf2bb4SCornelia Huck                 ret = -EINVAL;
436a5cf2bb4SCornelia Huck                 error_report("cssid %x not valid for virtio devices", cssid);
437a5cf2bb4SCornelia Huck                 goto out_err;
438a5cf2bb4SCornelia Huck             }
439a5cf2bb4SCornelia Huck             if (css_devno_used(cssid, ssid, devno)) {
440a5cf2bb4SCornelia Huck                 ret = -EEXIST;
441a5cf2bb4SCornelia Huck                 error_report("Device %x.%x.%04x already exists", cssid, ssid,
442a5cf2bb4SCornelia Huck                              devno);
443a5cf2bb4SCornelia Huck                 goto out_err;
444a5cf2bb4SCornelia Huck             }
445a5cf2bb4SCornelia Huck             sch->cssid = cssid;
446a5cf2bb4SCornelia Huck             sch->ssid = ssid;
447a5cf2bb4SCornelia Huck             sch->devno = devno;
448a5cf2bb4SCornelia Huck             have_devno = true;
449a5cf2bb4SCornelia Huck         } else {
450a5cf2bb4SCornelia Huck             ret = -EINVAL;
451a5cf2bb4SCornelia Huck             error_report("Malformed devno parameter '%s'", dev->bus_id);
452a5cf2bb4SCornelia Huck             goto out_err;
453a5cf2bb4SCornelia Huck         }
454a5cf2bb4SCornelia Huck     }
455a5cf2bb4SCornelia Huck 
456a5cf2bb4SCornelia Huck     /* Find the next free id. */
457a5cf2bb4SCornelia Huck     if (have_devno) {
458a5cf2bb4SCornelia Huck         for (schid = 0; schid <= MAX_SCHID; schid++) {
459a5cf2bb4SCornelia Huck             if (!css_find_subch(1, cssid, ssid, schid)) {
460a5cf2bb4SCornelia Huck                 sch->schid = schid;
461a5cf2bb4SCornelia Huck                 css_subch_assign(cssid, ssid, schid, devno, sch);
462a5cf2bb4SCornelia Huck                 found = true;
463a5cf2bb4SCornelia Huck                 break;
464a5cf2bb4SCornelia Huck             }
465a5cf2bb4SCornelia Huck         }
466a5cf2bb4SCornelia Huck         if (!found) {
467a5cf2bb4SCornelia Huck             ret = -ENODEV;
468a5cf2bb4SCornelia Huck             error_report("No free subchannel found for %x.%x.%04x", cssid, ssid,
469a5cf2bb4SCornelia Huck                          devno);
470a5cf2bb4SCornelia Huck             goto out_err;
471a5cf2bb4SCornelia Huck         }
472a5cf2bb4SCornelia Huck         trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
473a5cf2bb4SCornelia Huck                                     "user-configured");
474a5cf2bb4SCornelia Huck     } else {
475a5cf2bb4SCornelia Huck         cssid = VIRTUAL_CSSID;
476a5cf2bb4SCornelia Huck         for (ssid = 0; ssid <= MAX_SSID; ssid++) {
477a5cf2bb4SCornelia Huck             for (schid = 0; schid <= MAX_SCHID; schid++) {
478a5cf2bb4SCornelia Huck                 if (!css_find_subch(1, cssid, ssid, schid)) {
479a5cf2bb4SCornelia Huck                     sch->cssid = cssid;
480a5cf2bb4SCornelia Huck                     sch->ssid = ssid;
481a5cf2bb4SCornelia Huck                     sch->schid = schid;
482a5cf2bb4SCornelia Huck                     devno = schid;
483a5cf2bb4SCornelia Huck                     /*
484a5cf2bb4SCornelia Huck                      * If the devno is already taken, look further in this
485a5cf2bb4SCornelia Huck                      * subchannel set.
486a5cf2bb4SCornelia Huck                      */
487a5cf2bb4SCornelia Huck                     while (css_devno_used(cssid, ssid, devno)) {
488a5cf2bb4SCornelia Huck                         if (devno == MAX_SCHID) {
489a5cf2bb4SCornelia Huck                             devno = 0;
490a5cf2bb4SCornelia Huck                         } else if (devno == schid - 1) {
491a5cf2bb4SCornelia Huck                             ret = -ENODEV;
492a5cf2bb4SCornelia Huck                             error_report("No free devno found");
493a5cf2bb4SCornelia Huck                             goto out_err;
494a5cf2bb4SCornelia Huck                         } else {
495a5cf2bb4SCornelia Huck                             devno++;
496a5cf2bb4SCornelia Huck                         }
497a5cf2bb4SCornelia Huck                     }
498a5cf2bb4SCornelia Huck                     sch->devno = devno;
499a5cf2bb4SCornelia Huck                     css_subch_assign(cssid, ssid, schid, devno, sch);
500a5cf2bb4SCornelia Huck                     found = true;
501a5cf2bb4SCornelia Huck                     break;
502a5cf2bb4SCornelia Huck                 }
503a5cf2bb4SCornelia Huck             }
504a5cf2bb4SCornelia Huck             if (found) {
505a5cf2bb4SCornelia Huck                 break;
506a5cf2bb4SCornelia Huck             }
507a5cf2bb4SCornelia Huck         }
508a5cf2bb4SCornelia Huck         if (!found) {
509a5cf2bb4SCornelia Huck             ret = -ENODEV;
510a5cf2bb4SCornelia Huck             error_report("Virtual channel subsystem is full!");
511a5cf2bb4SCornelia Huck             goto out_err;
512a5cf2bb4SCornelia Huck         }
513a5cf2bb4SCornelia Huck         trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
514a5cf2bb4SCornelia Huck                                     "auto-configured");
515a5cf2bb4SCornelia Huck     }
516a5cf2bb4SCornelia Huck 
517a5cf2bb4SCornelia Huck     /* Build initial schib. */
518a5cf2bb4SCornelia Huck     css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE);
519a5cf2bb4SCornelia Huck 
520a5cf2bb4SCornelia Huck     sch->ccw_cb = virtio_ccw_cb;
521a5cf2bb4SCornelia Huck 
522a5cf2bb4SCornelia Huck     /* Build senseid data. */
523a5cf2bb4SCornelia Huck     memset(&sch->id, 0, sizeof(SenseId));
524a5cf2bb4SCornelia Huck     sch->id.reserved = 0xff;
525a5cf2bb4SCornelia Huck     sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
526a5cf2bb4SCornelia Huck     sch->id.cu_model = dev->vdev->device_id;
527a5cf2bb4SCornelia Huck 
528a5cf2bb4SCornelia Huck     virtio_bind_device(vdev, &virtio_ccw_bindings, DEVICE(dev));
529a5cf2bb4SCornelia Huck     /* Only the first 32 feature bits are used. */
530a5cf2bb4SCornelia Huck     dev->host_features[0] = vdev->get_features(vdev, dev->host_features[0]);
531a5cf2bb4SCornelia Huck     dev->host_features[0] |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
532a5cf2bb4SCornelia Huck     dev->host_features[0] |= 0x1 << VIRTIO_F_BAD_FEATURE;
533a5cf2bb4SCornelia Huck 
534a5cf2bb4SCornelia Huck     css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
535a5cf2bb4SCornelia Huck                           parent->hotplugged, 1);
536a5cf2bb4SCornelia Huck     return 0;
537a5cf2bb4SCornelia Huck 
538a5cf2bb4SCornelia Huck out_err:
539a5cf2bb4SCornelia Huck     dev->sch = NULL;
540a5cf2bb4SCornelia Huck     g_free(sch);
541a5cf2bb4SCornelia Huck     return ret;
542a5cf2bb4SCornelia Huck }
543a5cf2bb4SCornelia Huck 
544a5cf2bb4SCornelia Huck static int virtio_ccw_exit(VirtioCcwDevice *dev)
545a5cf2bb4SCornelia Huck {
546a5cf2bb4SCornelia Huck     SubchDev *sch = dev->sch;
547a5cf2bb4SCornelia Huck 
548a5cf2bb4SCornelia Huck     if (sch) {
549a5cf2bb4SCornelia Huck         css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
550a5cf2bb4SCornelia Huck         g_free(sch);
551a5cf2bb4SCornelia Huck     }
552a5cf2bb4SCornelia Huck     dev->indicators = 0;
553a5cf2bb4SCornelia Huck     return 0;
554a5cf2bb4SCornelia Huck }
555a5cf2bb4SCornelia Huck 
55689334c8bSKONRAD Frederic static int virtio_ccw_net_init(VirtioCcwDevice *ccw_dev)
557a5cf2bb4SCornelia Huck {
55889334c8bSKONRAD Frederic     VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev);
55989334c8bSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
560a5cf2bb4SCornelia Huck 
56189334c8bSKONRAD Frederic     virtio_net_set_config_size(&dev->vdev, ccw_dev->host_features[0]);
56289334c8bSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
56389334c8bSKONRAD Frederic     if (qdev_init(vdev) < 0) {
564a5cf2bb4SCornelia Huck         return -1;
565a5cf2bb4SCornelia Huck     }
566a5cf2bb4SCornelia Huck 
56789334c8bSKONRAD Frederic     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
568a5cf2bb4SCornelia Huck }
569a5cf2bb4SCornelia Huck 
57089334c8bSKONRAD Frederic static void virtio_ccw_net_instance_init(Object *obj)
571a5cf2bb4SCornelia Huck {
57289334c8bSKONRAD Frederic     VirtIONetCcw *dev = VIRTIO_NET_CCW(obj);
57389334c8bSKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_NET);
57489334c8bSKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
575a5cf2bb4SCornelia Huck }
576a5cf2bb4SCornelia Huck 
5773400c455SKONRAD Frederic static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
578a5cf2bb4SCornelia Huck {
5793400c455SKONRAD Frederic     VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
5803400c455SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
5813400c455SKONRAD Frederic     virtio_blk_set_conf(vdev, &(dev->blk));
5823400c455SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
5833400c455SKONRAD Frederic     if (qdev_init(vdev) < 0) {
584a5cf2bb4SCornelia Huck         return -1;
585a5cf2bb4SCornelia Huck     }
586a5cf2bb4SCornelia Huck 
5873400c455SKONRAD Frederic     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
588a5cf2bb4SCornelia Huck }
589a5cf2bb4SCornelia Huck 
5903400c455SKONRAD Frederic static void virtio_ccw_blk_instance_init(Object *obj)
591a5cf2bb4SCornelia Huck {
5923400c455SKONRAD Frederic     VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj);
5933400c455SKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK);
5943400c455SKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
595a5cf2bb4SCornelia Huck }
596a5cf2bb4SCornelia Huck 
5976acf69cdSKONRAD Frederic static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev)
598a5cf2bb4SCornelia Huck {
5996acf69cdSKONRAD Frederic     VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev);
6006acf69cdSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
601a5cf2bb4SCornelia Huck 
6026acf69cdSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
6036acf69cdSKONRAD Frederic     if (qdev_init(vdev) < 0) {
604a5cf2bb4SCornelia Huck         return -1;
605a5cf2bb4SCornelia Huck     }
606a5cf2bb4SCornelia Huck 
6076acf69cdSKONRAD Frederic     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
608a5cf2bb4SCornelia Huck }
609a5cf2bb4SCornelia Huck 
6106acf69cdSKONRAD Frederic 
6116acf69cdSKONRAD Frederic static void virtio_ccw_serial_instance_init(Object *obj)
612a5cf2bb4SCornelia Huck {
6136acf69cdSKONRAD Frederic     VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj);
6146acf69cdSKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SERIAL);
6156acf69cdSKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
616a5cf2bb4SCornelia Huck }
617a5cf2bb4SCornelia Huck 
61830bff6a0SKONRAD Frederic static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev)
619a5cf2bb4SCornelia Huck {
62030bff6a0SKONRAD Frederic     VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev);
62130bff6a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
622a5cf2bb4SCornelia Huck 
62330bff6a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
62430bff6a0SKONRAD Frederic     if (qdev_init(vdev) < 0) {
625a5cf2bb4SCornelia Huck         return -1;
626a5cf2bb4SCornelia Huck     }
627a5cf2bb4SCornelia Huck 
62830bff6a0SKONRAD Frederic     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
629a5cf2bb4SCornelia Huck }
630a5cf2bb4SCornelia Huck 
63124a6e7f4SKONRAD Frederic static void balloon_ccw_stats_get_all(Object *obj, struct Visitor *v,
63224a6e7f4SKONRAD Frederic                                       void *opaque, const char *name,
63324a6e7f4SKONRAD Frederic                                       Error **errp)
63424a6e7f4SKONRAD Frederic {
63524a6e7f4SKONRAD Frederic     VirtIOBalloonCcw *dev = opaque;
63624a6e7f4SKONRAD Frederic     object_property_get(OBJECT(&dev->vdev), v, "guest-stats", errp);
63724a6e7f4SKONRAD Frederic }
63824a6e7f4SKONRAD Frederic 
63924a6e7f4SKONRAD Frederic static void balloon_ccw_stats_get_poll_interval(Object *obj, struct Visitor *v,
64024a6e7f4SKONRAD Frederic                                                 void *opaque, const char *name,
64124a6e7f4SKONRAD Frederic                                                 Error **errp)
64224a6e7f4SKONRAD Frederic {
64324a6e7f4SKONRAD Frederic     VirtIOBalloonCcw *dev = opaque;
64424a6e7f4SKONRAD Frederic     object_property_get(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
64524a6e7f4SKONRAD Frederic                         errp);
64624a6e7f4SKONRAD Frederic }
64724a6e7f4SKONRAD Frederic 
64824a6e7f4SKONRAD Frederic static void balloon_ccw_stats_set_poll_interval(Object *obj, struct Visitor *v,
64924a6e7f4SKONRAD Frederic                                                 void *opaque, const char *name,
65024a6e7f4SKONRAD Frederic                                                 Error **errp)
65124a6e7f4SKONRAD Frederic {
65224a6e7f4SKONRAD Frederic     VirtIOBalloonCcw *dev = opaque;
65324a6e7f4SKONRAD Frederic     object_property_set(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
65424a6e7f4SKONRAD Frederic                         errp);
65524a6e7f4SKONRAD Frederic }
65624a6e7f4SKONRAD Frederic 
65730bff6a0SKONRAD Frederic static void virtio_ccw_balloon_instance_init(Object *obj)
658a5cf2bb4SCornelia Huck {
65930bff6a0SKONRAD Frederic     VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj);
66030bff6a0SKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BALLOON);
66130bff6a0SKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
66224a6e7f4SKONRAD Frederic 
66324a6e7f4SKONRAD Frederic     object_property_add(obj, "guest-stats", "guest statistics",
66424a6e7f4SKONRAD Frederic                         balloon_ccw_stats_get_all, NULL, NULL, dev, NULL);
66524a6e7f4SKONRAD Frederic 
66624a6e7f4SKONRAD Frederic     object_property_add(obj, "guest-stats-polling-interval", "int",
66724a6e7f4SKONRAD Frederic                         balloon_ccw_stats_get_poll_interval,
66824a6e7f4SKONRAD Frederic                         balloon_ccw_stats_set_poll_interval,
66924a6e7f4SKONRAD Frederic                         NULL, dev, NULL);
670a5cf2bb4SCornelia Huck }
671a5cf2bb4SCornelia Huck 
672c908ea10SKONRAD Frederic static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
673a5cf2bb4SCornelia Huck {
674c908ea10SKONRAD Frederic     VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev);
675c908ea10SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
676a5cf2bb4SCornelia Huck 
677c908ea10SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
678c908ea10SKONRAD Frederic     if (qdev_init(vdev) < 0) {
679a5cf2bb4SCornelia Huck         return -1;
680a5cf2bb4SCornelia Huck     }
681a5cf2bb4SCornelia Huck 
682c908ea10SKONRAD Frederic     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
683a5cf2bb4SCornelia Huck }
684a5cf2bb4SCornelia Huck 
685c908ea10SKONRAD Frederic static void virtio_ccw_scsi_instance_init(Object *obj)
686a5cf2bb4SCornelia Huck {
687c908ea10SKONRAD Frederic     VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj);
688c908ea10SKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SCSI);
689c908ea10SKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
690a5cf2bb4SCornelia Huck }
691a5cf2bb4SCornelia Huck 
692ccf6916cSPaolo Bonzini #ifdef CONFIG_VHOST_SCSI
693ccf6916cSPaolo Bonzini static int vhost_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
694ccf6916cSPaolo Bonzini {
695ccf6916cSPaolo Bonzini     VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev);
696ccf6916cSPaolo Bonzini     DeviceState *vdev = DEVICE(&dev->vdev);
697ccf6916cSPaolo Bonzini 
698ccf6916cSPaolo Bonzini     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
699ccf6916cSPaolo Bonzini     if (qdev_init(vdev) < 0) {
700ccf6916cSPaolo Bonzini         return -1;
701ccf6916cSPaolo Bonzini     }
702ccf6916cSPaolo Bonzini 
703ccf6916cSPaolo Bonzini     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
704ccf6916cSPaolo Bonzini }
705ccf6916cSPaolo Bonzini 
706ccf6916cSPaolo Bonzini static void vhost_ccw_scsi_instance_init(Object *obj)
707ccf6916cSPaolo Bonzini {
708ccf6916cSPaolo Bonzini     VHostSCSICcw *dev = VHOST_SCSI_CCW(obj);
709ccf6916cSPaolo Bonzini     object_initialize(OBJECT(&dev->vdev), TYPE_VHOST_SCSI);
710ccf6916cSPaolo Bonzini     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
711ccf6916cSPaolo Bonzini }
712ccf6916cSPaolo Bonzini #endif
713ccf6916cSPaolo Bonzini 
7142db26d4cSKONRAD Frederic static int virtio_ccw_rng_init(VirtioCcwDevice *ccw_dev)
7152362ecc5SCornelia Huck {
7162db26d4cSKONRAD Frederic     VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev);
7172db26d4cSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
7182362ecc5SCornelia Huck 
7192db26d4cSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
7202db26d4cSKONRAD Frederic     if (qdev_init(vdev) < 0) {
7212362ecc5SCornelia Huck         return -1;
7222362ecc5SCornelia Huck     }
7232362ecc5SCornelia Huck 
7242db26d4cSKONRAD Frederic     object_property_set_link(OBJECT(dev),
7252db26d4cSKONRAD Frederic                              OBJECT(dev->vdev.conf.default_backend), "rng",
7262db26d4cSKONRAD Frederic                              NULL);
7272db26d4cSKONRAD Frederic 
7282db26d4cSKONRAD Frederic     return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
7292362ecc5SCornelia Huck }
7302362ecc5SCornelia Huck 
731a5cf2bb4SCornelia Huck /* DeviceState to VirtioCcwDevice. Note: used on datapath,
732a5cf2bb4SCornelia Huck  * be careful and test performance if you change this.
733a5cf2bb4SCornelia Huck  */
734a5cf2bb4SCornelia Huck static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
735a5cf2bb4SCornelia Huck {
736a5cf2bb4SCornelia Huck     return container_of(d, VirtioCcwDevice, parent_obj);
737a5cf2bb4SCornelia Huck }
738a5cf2bb4SCornelia Huck 
739a5cf2bb4SCornelia Huck static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
740a5cf2bb4SCornelia Huck {
741a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d);
742a5cf2bb4SCornelia Huck     SubchDev *sch = dev->sch;
743a5cf2bb4SCornelia Huck     uint64_t indicators;
744a5cf2bb4SCornelia Huck 
745a5cf2bb4SCornelia Huck     if (vector >= 128) {
746a5cf2bb4SCornelia Huck         return;
747a5cf2bb4SCornelia Huck     }
748a5cf2bb4SCornelia Huck 
749a5cf2bb4SCornelia Huck     if (vector < VIRTIO_PCI_QUEUE_MAX) {
750a5cf2bb4SCornelia Huck         indicators = ldq_phys(dev->indicators);
75119380b1bSCornelia Huck         indicators |= 1ULL << vector;
752a5cf2bb4SCornelia Huck         stq_phys(dev->indicators, indicators);
753a5cf2bb4SCornelia Huck     } else {
754a5cf2bb4SCornelia Huck         vector = 0;
755a5cf2bb4SCornelia Huck         indicators = ldq_phys(dev->indicators2);
75619380b1bSCornelia Huck         indicators |= 1ULL << vector;
757a5cf2bb4SCornelia Huck         stq_phys(dev->indicators2, indicators);
758a5cf2bb4SCornelia Huck     }
759a5cf2bb4SCornelia Huck 
760a5cf2bb4SCornelia Huck     css_conditional_io_interrupt(sch);
761a5cf2bb4SCornelia Huck 
762a5cf2bb4SCornelia Huck }
763a5cf2bb4SCornelia Huck 
764a5cf2bb4SCornelia Huck static unsigned virtio_ccw_get_features(DeviceState *d)
765a5cf2bb4SCornelia Huck {
766a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
767a5cf2bb4SCornelia Huck 
768a5cf2bb4SCornelia Huck     /* Only the first 32 feature bits are used. */
769a5cf2bb4SCornelia Huck     return dev->host_features[0];
770a5cf2bb4SCornelia Huck }
771a5cf2bb4SCornelia Huck 
772a5cf2bb4SCornelia Huck static void virtio_ccw_reset(DeviceState *d)
773a5cf2bb4SCornelia Huck {
774a5cf2bb4SCornelia Huck     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
775a5cf2bb4SCornelia Huck 
776a5cf2bb4SCornelia Huck     virtio_reset(dev->vdev);
777a5cf2bb4SCornelia Huck     css_reset_sch(dev->sch);
778a5cf2bb4SCornelia Huck }
779a5cf2bb4SCornelia Huck 
780a5cf2bb4SCornelia Huck /**************** Virtio-ccw Bus Device Descriptions *******************/
781a5cf2bb4SCornelia Huck 
782a5cf2bb4SCornelia Huck static const VirtIOBindings virtio_ccw_bindings = {
783a5cf2bb4SCornelia Huck     .notify = virtio_ccw_notify,
784a5cf2bb4SCornelia Huck     .get_features = virtio_ccw_get_features,
785a5cf2bb4SCornelia Huck };
786a5cf2bb4SCornelia Huck 
787a5cf2bb4SCornelia Huck static Property virtio_ccw_net_properties[] = {
788a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
789a5cf2bb4SCornelia Huck     DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
79089334c8bSKONRAD Frederic     DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetCcw, vdev.net_conf),
79189334c8bSKONRAD Frederic     DEFINE_NIC_PROPERTIES(VirtIONetCcw, vdev.nic_conf),
792a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
793a5cf2bb4SCornelia Huck };
794a5cf2bb4SCornelia Huck 
795a5cf2bb4SCornelia Huck static void virtio_ccw_net_class_init(ObjectClass *klass, void *data)
796a5cf2bb4SCornelia Huck {
797a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
798a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
799a5cf2bb4SCornelia Huck 
800a5cf2bb4SCornelia Huck     k->init = virtio_ccw_net_init;
80189334c8bSKONRAD Frederic     k->exit = virtio_ccw_exit;
802a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
803a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_net_properties;
804a5cf2bb4SCornelia Huck }
805a5cf2bb4SCornelia Huck 
806a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_net = {
80789334c8bSKONRAD Frederic     .name          = TYPE_VIRTIO_NET_CCW,
808a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
80989334c8bSKONRAD Frederic     .instance_size = sizeof(VirtIONetCcw),
81089334c8bSKONRAD Frederic     .instance_init = virtio_ccw_net_instance_init,
811a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_net_class_init,
812a5cf2bb4SCornelia Huck };
813a5cf2bb4SCornelia Huck 
814a5cf2bb4SCornelia Huck static Property virtio_ccw_blk_properties[] = {
815a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
816a5cf2bb4SCornelia Huck     DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]),
817fe42d7fbSCornelia Huck     DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk),
818a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
819a5cf2bb4SCornelia Huck };
820a5cf2bb4SCornelia Huck 
821a5cf2bb4SCornelia Huck static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data)
822a5cf2bb4SCornelia Huck {
823a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
824a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
825a5cf2bb4SCornelia Huck 
826a5cf2bb4SCornelia Huck     k->init = virtio_ccw_blk_init;
8273400c455SKONRAD Frederic     k->exit = virtio_ccw_exit;
828a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
829a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_blk_properties;
830a5cf2bb4SCornelia Huck }
831a5cf2bb4SCornelia Huck 
832a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_blk = {
8333400c455SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_CCW,
834a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
8353400c455SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkCcw),
8363400c455SKONRAD Frederic     .instance_init = virtio_ccw_blk_instance_init,
837a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_blk_class_init,
838a5cf2bb4SCornelia Huck };
839a5cf2bb4SCornelia Huck 
840a5cf2bb4SCornelia Huck static Property virtio_ccw_serial_properties[] = {
841a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
8426acf69cdSKONRAD Frederic     DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtioSerialCcw, vdev.serial),
843a5cf2bb4SCornelia Huck     DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
844a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
845a5cf2bb4SCornelia Huck };
846a5cf2bb4SCornelia Huck 
847a5cf2bb4SCornelia Huck static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data)
848a5cf2bb4SCornelia Huck {
849a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
850a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
851a5cf2bb4SCornelia Huck 
852a5cf2bb4SCornelia Huck     k->init = virtio_ccw_serial_init;
8536acf69cdSKONRAD Frederic     k->exit = virtio_ccw_exit;
854a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
855a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_serial_properties;
856a5cf2bb4SCornelia Huck }
857a5cf2bb4SCornelia Huck 
858a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_serial = {
8596acf69cdSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_CCW,
860a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
8616acf69cdSKONRAD Frederic     .instance_size = sizeof(VirtioSerialCcw),
8626acf69cdSKONRAD Frederic     .instance_init = virtio_ccw_serial_instance_init,
863a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_serial_class_init,
864a5cf2bb4SCornelia Huck };
865a5cf2bb4SCornelia Huck 
866a5cf2bb4SCornelia Huck static Property virtio_ccw_balloon_properties[] = {
867a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
868a5cf2bb4SCornelia Huck     DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
869a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
870a5cf2bb4SCornelia Huck };
871a5cf2bb4SCornelia Huck 
872a5cf2bb4SCornelia Huck static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data)
873a5cf2bb4SCornelia Huck {
874a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
875a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
876a5cf2bb4SCornelia Huck 
877a5cf2bb4SCornelia Huck     k->init = virtio_ccw_balloon_init;
87830bff6a0SKONRAD Frederic     k->exit = virtio_ccw_exit;
879a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
880a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_balloon_properties;
881a5cf2bb4SCornelia Huck }
882a5cf2bb4SCornelia Huck 
883a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_balloon = {
88430bff6a0SKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_CCW,
885a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
88630bff6a0SKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonCcw),
88730bff6a0SKONRAD Frederic     .instance_init = virtio_ccw_balloon_instance_init,
888a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_balloon_class_init,
889a5cf2bb4SCornelia Huck };
890a5cf2bb4SCornelia Huck 
891a5cf2bb4SCornelia Huck static Property virtio_ccw_scsi_properties[] = {
892a5cf2bb4SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
893292c8e50SPaolo Bonzini     DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
8944bfeb18aSKONRAD Frederic     DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
895a5cf2bb4SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
896a5cf2bb4SCornelia Huck };
897a5cf2bb4SCornelia Huck 
898a5cf2bb4SCornelia Huck static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data)
899a5cf2bb4SCornelia Huck {
900a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
901a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
902a5cf2bb4SCornelia Huck 
903a5cf2bb4SCornelia Huck     k->init = virtio_ccw_scsi_init;
904c908ea10SKONRAD Frederic     k->exit = virtio_ccw_exit;
905a5cf2bb4SCornelia Huck     dc->reset = virtio_ccw_reset;
906a5cf2bb4SCornelia Huck     dc->props = virtio_ccw_scsi_properties;
907a5cf2bb4SCornelia Huck }
908a5cf2bb4SCornelia Huck 
909a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_scsi = {
910c908ea10SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_CCW,
911a5cf2bb4SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
912c908ea10SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSICcw),
913c908ea10SKONRAD Frederic     .instance_init = virtio_ccw_scsi_instance_init,
914a5cf2bb4SCornelia Huck     .class_init    = virtio_ccw_scsi_class_init,
915a5cf2bb4SCornelia Huck };
916a5cf2bb4SCornelia Huck 
917ccf6916cSPaolo Bonzini #ifdef CONFIG_VHOST_SCSI
918ccf6916cSPaolo Bonzini static Property vhost_ccw_scsi_properties[] = {
919ccf6916cSPaolo Bonzini     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
920ccf6916cSPaolo Bonzini     DEFINE_VHOST_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
921ccf6916cSPaolo Bonzini     DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
922ccf6916cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
923ccf6916cSPaolo Bonzini };
924ccf6916cSPaolo Bonzini 
925ccf6916cSPaolo Bonzini static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
926ccf6916cSPaolo Bonzini {
927ccf6916cSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
928ccf6916cSPaolo Bonzini     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
929ccf6916cSPaolo Bonzini 
930ccf6916cSPaolo Bonzini     k->init = vhost_ccw_scsi_init;
931ccf6916cSPaolo Bonzini     k->exit = virtio_ccw_exit;
932ccf6916cSPaolo Bonzini     dc->reset = virtio_ccw_reset;
933ccf6916cSPaolo Bonzini     dc->props = vhost_ccw_scsi_properties;
934ccf6916cSPaolo Bonzini }
935ccf6916cSPaolo Bonzini 
936ccf6916cSPaolo Bonzini static const TypeInfo vhost_ccw_scsi = {
937ccf6916cSPaolo Bonzini     .name          = TYPE_VHOST_SCSI_CCW,
938ccf6916cSPaolo Bonzini     .parent        = TYPE_VIRTIO_CCW_DEVICE,
939ccf6916cSPaolo Bonzini     .instance_size = sizeof(VirtIOSCSICcw),
940ccf6916cSPaolo Bonzini     .instance_init = vhost_ccw_scsi_instance_init,
941ccf6916cSPaolo Bonzini     .class_init    = vhost_ccw_scsi_class_init,
942ccf6916cSPaolo Bonzini };
943ccf6916cSPaolo Bonzini #endif
944ccf6916cSPaolo Bonzini 
9452db26d4cSKONRAD Frederic static void virtio_ccw_rng_instance_init(Object *obj)
9462362ecc5SCornelia Huck {
9472db26d4cSKONRAD Frederic     VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj);
9482db26d4cSKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_RNG);
9492db26d4cSKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
9502362ecc5SCornelia Huck     object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
9512db26d4cSKONRAD Frederic                              (Object **)&dev->vdev.conf.rng, NULL);
9522362ecc5SCornelia Huck }
9532362ecc5SCornelia Huck 
9542362ecc5SCornelia Huck static Property virtio_ccw_rng_properties[] = {
9552362ecc5SCornelia Huck     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
9562362ecc5SCornelia Huck     DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
9572db26d4cSKONRAD Frederic     DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf),
9582362ecc5SCornelia Huck     DEFINE_PROP_END_OF_LIST(),
9592362ecc5SCornelia Huck };
9602362ecc5SCornelia Huck 
9612362ecc5SCornelia Huck static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data)
9622362ecc5SCornelia Huck {
9632362ecc5SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
9642362ecc5SCornelia Huck     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
9652362ecc5SCornelia Huck 
9662362ecc5SCornelia Huck     k->init = virtio_ccw_rng_init;
9672db26d4cSKONRAD Frederic     k->exit = virtio_ccw_exit;
9682362ecc5SCornelia Huck     dc->reset = virtio_ccw_reset;
9692362ecc5SCornelia Huck     dc->props = virtio_ccw_rng_properties;
9702362ecc5SCornelia Huck }
9712362ecc5SCornelia Huck 
9722362ecc5SCornelia Huck static const TypeInfo virtio_ccw_rng = {
9732db26d4cSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_CCW,
9742362ecc5SCornelia Huck     .parent        = TYPE_VIRTIO_CCW_DEVICE,
9752db26d4cSKONRAD Frederic     .instance_size = sizeof(VirtIORNGCcw),
9762db26d4cSKONRAD Frederic     .instance_init = virtio_ccw_rng_instance_init,
9772362ecc5SCornelia Huck     .class_init    = virtio_ccw_rng_class_init,
9782362ecc5SCornelia Huck };
9792362ecc5SCornelia Huck 
980a5cf2bb4SCornelia Huck static int virtio_ccw_busdev_init(DeviceState *dev)
981a5cf2bb4SCornelia Huck {
982a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
983a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
984a5cf2bb4SCornelia Huck 
985a5cf2bb4SCornelia Huck     virtio_ccw_bus_new(&_dev->bus, _dev);
986a5cf2bb4SCornelia Huck 
987a5cf2bb4SCornelia Huck     return _info->init(_dev);
988a5cf2bb4SCornelia Huck }
989a5cf2bb4SCornelia Huck 
990a5cf2bb4SCornelia Huck static int virtio_ccw_busdev_exit(DeviceState *dev)
991a5cf2bb4SCornelia Huck {
992a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
993a5cf2bb4SCornelia Huck     VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
994a5cf2bb4SCornelia Huck 
995a5cf2bb4SCornelia Huck     return _info->exit(_dev);
996a5cf2bb4SCornelia Huck }
997a5cf2bb4SCornelia Huck 
998a5cf2bb4SCornelia Huck static int virtio_ccw_busdev_unplug(DeviceState *dev)
999a5cf2bb4SCornelia Huck {
1000a5cf2bb4SCornelia Huck     VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
1001a5cf2bb4SCornelia Huck     SubchDev *sch = _dev->sch;
1002a5cf2bb4SCornelia Huck 
1003a5cf2bb4SCornelia Huck     /*
1004a5cf2bb4SCornelia Huck      * We should arrive here only for device_del, since we don't support
1005a5cf2bb4SCornelia Huck      * direct hot(un)plug of channels, but only through virtio.
1006a5cf2bb4SCornelia Huck      */
1007a5cf2bb4SCornelia Huck     assert(sch != NULL);
1008a5cf2bb4SCornelia Huck     /* Subchannel is now disabled and no longer valid. */
1009a5cf2bb4SCornelia Huck     sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA |
1010a5cf2bb4SCornelia Huck                                      PMCW_FLAGS_MASK_DNV);
1011a5cf2bb4SCornelia Huck 
1012a5cf2bb4SCornelia Huck     css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
1013a5cf2bb4SCornelia Huck 
1014a5cf2bb4SCornelia Huck     qdev_free(dev);
1015a5cf2bb4SCornelia Huck     return 0;
1016a5cf2bb4SCornelia Huck }
1017a5cf2bb4SCornelia Huck 
1018a5cf2bb4SCornelia Huck static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
1019a5cf2bb4SCornelia Huck {
1020a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1021a5cf2bb4SCornelia Huck 
1022a5cf2bb4SCornelia Huck     dc->init = virtio_ccw_busdev_init;
1023a5cf2bb4SCornelia Huck     dc->exit = virtio_ccw_busdev_exit;
1024a5cf2bb4SCornelia Huck     dc->unplug = virtio_ccw_busdev_unplug;
1025a5cf2bb4SCornelia Huck     dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
1026a5cf2bb4SCornelia Huck 
1027a5cf2bb4SCornelia Huck }
1028a5cf2bb4SCornelia Huck 
1029a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_device_info = {
1030a5cf2bb4SCornelia Huck     .name = TYPE_VIRTIO_CCW_DEVICE,
1031a5cf2bb4SCornelia Huck     .parent = TYPE_DEVICE,
1032a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwDevice),
1033a5cf2bb4SCornelia Huck     .class_init = virtio_ccw_device_class_init,
1034a5cf2bb4SCornelia Huck     .class_size = sizeof(VirtIOCCWDeviceClass),
1035a5cf2bb4SCornelia Huck     .abstract = true,
1036a5cf2bb4SCornelia Huck };
1037a5cf2bb4SCornelia Huck 
1038a5cf2bb4SCornelia Huck /***************** Virtual-css Bus Bridge Device ********************/
1039a5cf2bb4SCornelia Huck /* Only required to have the virtio bus as child in the system bus */
1040a5cf2bb4SCornelia Huck 
1041a5cf2bb4SCornelia Huck static int virtual_css_bridge_init(SysBusDevice *dev)
1042a5cf2bb4SCornelia Huck {
1043a5cf2bb4SCornelia Huck     /* nothing */
1044a5cf2bb4SCornelia Huck     return 0;
1045a5cf2bb4SCornelia Huck }
1046a5cf2bb4SCornelia Huck 
1047a5cf2bb4SCornelia Huck static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
1048a5cf2bb4SCornelia Huck {
1049a5cf2bb4SCornelia Huck     DeviceClass *dc = DEVICE_CLASS(klass);
1050a5cf2bb4SCornelia Huck     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
1051a5cf2bb4SCornelia Huck 
1052a5cf2bb4SCornelia Huck     k->init = virtual_css_bridge_init;
1053a5cf2bb4SCornelia Huck     dc->no_user = 1;
1054a5cf2bb4SCornelia Huck }
1055a5cf2bb4SCornelia Huck 
1056a5cf2bb4SCornelia Huck static const TypeInfo virtual_css_bridge_info = {
1057a5cf2bb4SCornelia Huck     .name          = "virtual-css-bridge",
1058a5cf2bb4SCornelia Huck     .parent        = TYPE_SYS_BUS_DEVICE,
1059a5cf2bb4SCornelia Huck     .instance_size = sizeof(SysBusDevice),
1060a5cf2bb4SCornelia Huck     .class_init    = virtual_css_bridge_class_init,
1061a5cf2bb4SCornelia Huck };
1062a5cf2bb4SCornelia Huck 
1063a5cf2bb4SCornelia Huck /* virtio-ccw-bus */
1064a5cf2bb4SCornelia Huck 
1065*d51fcfacSKONRAD Frederic static void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev)
1066a5cf2bb4SCornelia Huck {
1067a5cf2bb4SCornelia Huck     DeviceState *qdev = DEVICE(dev);
1068a5cf2bb4SCornelia Huck     BusState *qbus;
1069a5cf2bb4SCornelia Huck 
1070a5cf2bb4SCornelia Huck     qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_CCW_BUS, qdev, NULL);
1071a5cf2bb4SCornelia Huck     qbus = BUS(bus);
1072cbd19063SKONRAD Frederic     qbus->allow_hotplug = 1;
1073a5cf2bb4SCornelia Huck }
1074a5cf2bb4SCornelia Huck 
1075a5cf2bb4SCornelia Huck static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
1076a5cf2bb4SCornelia Huck {
1077a5cf2bb4SCornelia Huck     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
1078a5cf2bb4SCornelia Huck     BusClass *bus_class = BUS_CLASS(klass);
1079a5cf2bb4SCornelia Huck 
1080a5cf2bb4SCornelia Huck     bus_class->max_dev = 1;
1081a5cf2bb4SCornelia Huck     k->notify = virtio_ccw_notify;
1082a5cf2bb4SCornelia Huck     k->get_features = virtio_ccw_get_features;
1083a5cf2bb4SCornelia Huck }
1084a5cf2bb4SCornelia Huck 
1085a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_bus_info = {
1086a5cf2bb4SCornelia Huck     .name = TYPE_VIRTIO_CCW_BUS,
1087a5cf2bb4SCornelia Huck     .parent = TYPE_VIRTIO_BUS,
1088a5cf2bb4SCornelia Huck     .instance_size = sizeof(VirtioCcwBusState),
1089a5cf2bb4SCornelia Huck     .class_init = virtio_ccw_bus_class_init,
1090a5cf2bb4SCornelia Huck };
1091a5cf2bb4SCornelia Huck 
1092a5cf2bb4SCornelia Huck static void virtio_ccw_register(void)
1093a5cf2bb4SCornelia Huck {
1094a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_bus_info);
1095a5cf2bb4SCornelia Huck     type_register_static(&virtual_css_bus_info);
1096a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_device_info);
1097a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_serial);
1098a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_blk);
1099a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_net);
1100a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_balloon);
1101a5cf2bb4SCornelia Huck     type_register_static(&virtio_ccw_scsi);
1102ccf6916cSPaolo Bonzini     type_register_static(&vhost_ccw_scsi);
11032362ecc5SCornelia Huck     type_register_static(&virtio_ccw_rng);
1104a5cf2bb4SCornelia Huck     type_register_static(&virtual_css_bridge_info);
1105a5cf2bb4SCornelia Huck }
1106a5cf2bb4SCornelia Huck 
1107a5cf2bb4SCornelia Huck type_init(virtio_ccw_register)
1108