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