static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) { SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base); SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); int rc = -1; if (dev->id == -1) { for (dev->id = 0; dev->id < bus->ndev; dev->id++) { if (bus->devs[dev->id] == NULL) break; } } if (dev->id >= bus->ndev) { qemu_error("bad scsi device id: %d\n", dev->id); goto err; } if (bus->devs[dev->id]) { qdev_free(&bus->devs[dev->id]->qdev); } bus->devs[dev->id] = dev; dev->info = info; rc = dev->info->init(dev); if (rc != 0) { bus->devs[dev->id] = NULL; } err: return rc; }
static void unplug_nic(PCIBus *b, PCIDevice *d, void *o) { /* We have to ignore passthrough devices */ if (pci_get_word(d->config + PCI_CLASS_DEVICE) == PCI_CLASS_NETWORK_ETHERNET && strcmp(d->name, "xen-pci-passthrough") != 0) { qdev_free(&d->qdev); } }
static void unplug_nic(PCIBus *b, PCIDevice *d) { if (pci_get_word(d->config + PCI_CLASS_DEVICE) == PCI_CLASS_NETWORK_ETHERNET) { /* Until qdev_free includes a call to object_unparent, we call it here */ object_unparent(&d->qdev.parent_obj); qdev_free(&d->qdev); } }
/* Destroy the VirtIODevice */ void virtio_bus_destroy_device(VirtioBusState *bus) { DeviceState *qdev; BusState *qbus = BUS(bus); VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); DPRINTF("%s: remove device.\n", qbus->name); if (bus->vdev != NULL) { if (klass->device_unplug != NULL) { klass->device_unplug(qbus->parent); } qdev = DEVICE(bus->vdev); qdev_free(qdev); bus->vdev = NULL; } }
static int virtio_ccw_busdev_unplug(DeviceState *dev) { VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; SubchDev *sch = _dev->sch; /* * We should arrive here only for device_del, since we don't support * direct hot(un)plug of channels, but only through virtio. */ assert(sch != NULL); /* Subchannel is now disabled and no longer valid. */ sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | PMCW_FLAGS_MASK_DNV); css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); qdev_free(dev); return 0; }
static int pcie_cap_slot_hotplug(DeviceState *qdev, PCIDevice *pci_dev, PCIHotplugState state) { PCIDevice *d = PCI_DEVICE(qdev); uint8_t *exp_cap = d->config + d->exp.exp_cap; uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); /* Don't send event when device is enabled during qemu machine creation: * it is present on boot, no hotplug event is necessary. We do send an * event when the device is disabled later. */ if (state == PCI_COLDPLUG_ENABLED) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); return 0; } PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); if (sltsta & PCI_EXP_SLTSTA_EIS) { /* the slot is electromechanically locked. * This error is propagated up to qdev and then to HMP/QMP. */ return -EBUSY; } /* TODO: multifunction hot-plug. * Right now, only a device of function = 0 is allowed to be * hot plugged/unplugged. */ assert(PCI_FUNC(pci_dev->devfn) == 0); if (state == PCI_HOTPLUG_ENABLED) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); } else { qdev_free(&pci_dev->qdev); pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); } return 0; }
/* handle legacy '-drive if=scsi,...' cmd line args */ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit, bool removable) { const char *driver; DeviceState *dev; driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk"; dev = qdev_create(&bus->qbus, driver); qdev_prop_set_uint32(dev, "scsi-id", unit); if (qdev_prop_exists(dev, "removable")) { qdev_prop_set_bit(dev, "removable", removable); } if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) { qdev_free(dev); return NULL; } if (qdev_init(dev) < 0) return NULL; return DO_UPCAST(SCSIDevice, qdev, dev); }
static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, const char *devaddr, const char *opts) { PCIDevice *dev; DriveInfo *dinfo = NULL; int type = -1; char buf[128]; PCIBus *bus; int devfn; if (get_param_value(buf, sizeof(buf), "if", opts)) { if (!strcmp(buf, "scsi")) type = IF_SCSI; else if (!strcmp(buf, "virtio")) { type = IF_VIRTIO; } else { monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); return NULL; } } else { monitor_printf(mon, "no if= specified\n"); return NULL; } if (get_param_value(buf, sizeof(buf), "file", opts)) { dinfo = add_init_drive(opts); if (!dinfo) return NULL; if (dinfo->devaddr) { monitor_printf(mon, "Parameter addr not supported\n"); return NULL; } } else { dinfo = NULL; } bus = pci_get_bus_devfn(&devfn, devaddr); if (!bus) { monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); return NULL; } if (!((BusState*)bus)->allow_hotplug) { monitor_printf(mon, "PCI bus doesn't support hotplug\n"); return NULL; } switch (type) { case IF_SCSI: dev = pci_create(bus, devfn, "lsi53c895a"); if (qdev_init(&dev->qdev) < 0) dev = NULL; if (dev && dinfo) { if (scsi_hot_add(mon, &dev->qdev, dinfo, 0) != 0) { qdev_unplug(&dev->qdev, NULL); dev = NULL; } } break; case IF_VIRTIO: if (!dinfo) { monitor_printf(mon, "virtio requires a backing file/device.\n"); return NULL; } dev = pci_create(bus, devfn, "virtio-blk-pci"); if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) { qdev_free(&dev->qdev); dev = NULL; break; } if (qdev_init(&dev->qdev) < 0) dev = NULL; break; default: dev = NULL; } return dev; }