return -1;
}
+/* S390 ccw bus support */
+
+struct _qemuDomainCCWAddressSet {
+ virHashTablePtr defined;
+ virDomainDeviceCCWAddress next;
+};
+
+static char*
+qemuCCWAddressAsString(virDomainDeviceCCWAddressPtr addr)
+{
+ char *addrstr = NULL;
+
+ if (virAsprintf(&addrstr, "%x.%x.%04x",
+ addr->cssid,
+ addr->ssid,
+ addr->devno) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ return addrstr;
+}
+
+static int
+qemuCCWAdressIncrement(virDomainDeviceCCWAddressPtr addr)
+{
+ virDomainDeviceCCWAddress ccwaddr = *addr;
+
+ /* We are not touching subchannel sets and channel subsystems */
+ if (++ccwaddr.devno > VIR_DOMAIN_DEVICE_CCW_MAX_DEVNO)
+ return -1;
+
+ *addr = ccwaddr;
+ return 0;
+}
+
+static void
+qemuDomainCCWAddressSetFreeEntry(void *payload,
+ const void *name ATTRIBUTE_UNUSED)
+{
+ VIR_FREE(payload);
+}
+
+int qemuDomainCCWAddressAssign(virDomainDeviceInfoPtr dev,
+ qemuDomainCCWAddressSetPtr addrs,
+ bool autoassign)
+{
+ int ret = -1;
+ char *addr = NULL;
+
+ if (dev->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
+ return 0;
+
+ if (!autoassign && dev->addr.ccw.assigned) {
+ if (!(addr = qemuCCWAddressAsString(&dev->addr.ccw)))
+ goto cleanup;
+
+ if (virHashLookup(addrs->defined, addr)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("The CCW devno '%s' is in use already "),
+ addr);
+ goto cleanup;
+ }
+ } else if (autoassign && !dev->addr.ccw.assigned) {
+ if (!(addr = qemuCCWAddressAsString(&addrs->next)) < 0)
+ goto cleanup;
+
+ while (virHashLookup(addrs->defined, addr)) {
+ if (qemuCCWAdressIncrement(&addrs->next) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("There are no more free CCW devnos."));
+ goto cleanup;
+ }
+ VIR_FREE(addr);
+ addr = qemuCCWAddressAsString(&addrs->next);
+ }
+ dev->addr.ccw = addrs->next;
+ dev->addr.ccw.assigned = true;
+ } else {
+ return 0;
+ }
+
+ if (virHashAddEntry(addrs->defined,addr,addr) < 0)
+ goto cleanup;
+ else
+ addr = NULL; /* memory will be freed by hash table */
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(addr);
+ return ret;
+}
+
static void
qemuDomainPrimeS390VirtioDevices(virDomainDefPtr def,
enum virDomainDeviceAddressType type)
def->memballoon->info.type = type;
}
-static void
-qemuDomainAssignS390Addresses(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
+static int
+qemuDomainCCWAddressAllocate(virDomainDefPtr def ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
+ virDomainDeviceInfoPtr info,
+ void *data)
+{
+ return qemuDomainCCWAddressAssign(info, data, true);
+}
+
+static int
+qemuDomainCCWAddressValidate(virDomainDefPtr def ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
+ virDomainDeviceInfoPtr info,
+ void *data)
+{
+ return qemuDomainCCWAddressAssign(info, data, false);
+}
+
+int qemuDomainCCWAddressReleaseAddr(qemuDomainCCWAddressSetPtr addrs,
+ virDomainDeviceInfoPtr dev)
+{
+ char *addr;
+ int ret;
+
+ addr = qemuCCWAddressAsString(&(dev->addr.ccw));
+ if (!addr)
+ return -1;
+
+ if ((ret = virHashRemoveEntry(addrs->defined, addr)) == 0 &&
+ dev->addr.ccw.cssid == addrs->next.cssid &&
+ dev->addr.ccw.ssid == addrs->next.ssid &&
+ dev->addr.ccw.devno < addrs->next.devno) {
+ addrs->next.devno = dev->addr.ccw.devno;
+ addrs->next.assigned = false;
+ }
+
+ VIR_FREE(addr);
+
+ return ret;
+}
+
+void qemuDomainCCWAddressSetFree(qemuDomainCCWAddressSetPtr addrs)
+{
+ if (!addrs)
+ return;
+
+ virHashFree(addrs->defined);
+ VIR_FREE(addrs);
+}
+
+static qemuDomainCCWAddressSetPtr
+qemuDomainCCWAddressSetCreate(void)
+{
+ qemuDomainCCWAddressSetPtr addrs = NULL;
+
+ if (VIR_ALLOC(addrs) < 0)
+ goto no_memory;
+
+ if (!(addrs->defined = virHashCreate(10, qemuDomainCCWAddressSetFreeEntry)))
+ goto cleanup;
+
+ /* must use cssid = 0xfe (254) for virtio-ccw devices */
+ addrs->next.cssid = 254;
+ addrs->next.ssid = 0;
+ addrs->next.devno = 0;
+ addrs->next.assigned = 0;
+ return addrs;
+
+no_memory:
+ virReportOOMError();
+cleanup:
+ qemuDomainCCWAddressSetFree(addrs);
+ return addrs;
+}
+
+/*
+ * Three steps populating CCW devnos
+ * 1. Allocate empty address set
+ * 2. Gather addresses with explicit devno
+ * 3. Assign defaults to the rest
+ */
+static int
+qemuDomainAssignS390Addresses(virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
+ virDomainObjPtr obj)
{
- /* deal with legacy virtio-s390 */
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390))
+ int ret = -1;
+ qemuDomainCCWAddressSetPtr addrs = NULL;
+ qemuDomainObjPrivatePtr priv = NULL;
+
+ if (STREQLEN(def->os.machine, "s390-ccw", 8) &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
+ qemuDomainPrimeS390VirtioDevices(
+ def, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW);
+
+ if (!(addrs = qemuDomainCCWAddressSetCreate()))
+ goto cleanup;
+
+ if (virDomainDeviceInfoIterate(def, qemuDomainCCWAddressValidate,
+ addrs) < 0)
+ goto cleanup;
+
+ if (virDomainDeviceInfoIterate(def, qemuDomainCCWAddressAllocate,
+ addrs) < 0)
+ goto cleanup;
+ } else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
+ /* deal with legacy virtio-s390 */
qemuDomainPrimeS390VirtioDevices(
def, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390);
+ }
+
+ if (obj && obj->privateData) {
+ priv = obj->privateData;
+ if (addrs) {
+ /* if this is the live domain object, we persist the CCW addresses*/
+ qemuDomainCCWAddressSetFree(priv->ccwaddrs);
+ priv->persistentAddrs = 1;
+ priv->ccwaddrs = addrs;
+ addrs = NULL;
+ } else {
+ priv->persistentAddrs = 0;
+ }
+ }
+ ret = 0;
+
+cleanup:
+ qemuDomainCCWAddressSetFree(addrs);
+
+ return ret;
}
static int
if (rc)
return rc;
- qemuDomainAssignS390Addresses(def, qemuCaps);
+ rc = qemuDomainAssignS390Addresses(def, qemuCaps, obj);
+ if (rc)
+ return rc;
return qemuDomainAssignPCIAddresses(def, qemuCaps, obj);
}
/* don't touch s390 devices */
if (def->disks[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
def->disks[i]->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390 ||
+ def->disks[i]->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)
continue;
if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
} else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO) {
if (info->addr.spaprvio.has_reg)
virBufferAsprintf(buf, ",reg=0x%llx", info->addr.spaprvio.reg);
+ } else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ if (info->addr.ccw.assigned)
+ virBufferAsprintf(buf, ",devno=%x.%x.%04x",
+ info->addr.ccw.cssid,
+ info->addr.ccw.ssid,
+ info->addr.ccw.devno);
}
return 0;
break;
case VIR_DOMAIN_DISK_BUS_VIRTIO:
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390) &&
- (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390)) {
- /* Paranoia - leave in here for now */
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("unexpected address type for s390-virtio disk"));
- goto error;
- }
idx = -1;
break;
disk->info.addr.drive.unit);
break;
case VIR_DOMAIN_DISK_BUS_VIRTIO:
- if (disk->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
+ if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ virBufferAddLit(&opt, "virtio-blk-ccw");
+ } else if (disk->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
virBufferAddLit(&opt, "virtio-blk-s390");
} else {
virBufferAddLit(&opt, "virtio-blk-pci");
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
virBufferAddLit(&buf, "virtio-serial-pci");
+ } else if (def->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ virBufferAddLit(&buf, "virtio-serial-ccw");
} else if (def->info.type ==
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
virBufferAddLit(&buf, "virtio-serial-s390");
if (!net->model) {
nic = "rtl8139";
} else if (STREQ(net->model, "virtio")) {
- if (net->info.type ==
- VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
+ if (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+ nic = "virtio-net-ccw";
+ } else if (net->info.type ==
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
nic = "virtio-net-s390";
} else {
nic = "virtio-net-pci";
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
- virBufferAddLit(&buf, "virtio-balloon-pci");
+ switch (dev->info.type) {
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
+ virBufferAddLit(&buf, "virtio-balloon-pci");
+ break;
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
+ virBufferAddLit(&buf, "virtio-balloon-ccw");
+ break;
+ default:
+ goto error;
+ }
+
virBufferAsprintf(&buf, ",id=%s", dev->info.alias);
if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0)
goto error;
}
if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+ dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
/* Check it's a virtio-serial address */
if (dev->info.type !=
* NB: Earlier we declared that VirtIO balloon will always be in
* slot 0x3 on bus 0x0
*/
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390) && def->memballoon)
+ if (STREQLEN(def->os.machine, "s390-virtio", 10) &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_S390) && def->memballoon)
def->memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_NONE;
if (def->memballoon &&