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