The current code for using -drive simply sets the -drive 'index' parameter. QEMU internally converts this to bus/unit depending on the type of drive. This does not give us precise control over the bus/unit assignment though. This change switches over to make libvirt explicitly calculate the bus/unit number. In addition bus/unit/index are actually irrelevant for VirtIO disks, since each virtio disk is a separate PCI device. No disk controller is involved. Doing the conversion to bus/unit in libvirt allows us to correctly attach SCSI controllers when required. * src/qemu/qemu_conf.c: Specify bus/unit instead of index for disks --- src/qemu/qemu_conf.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 79 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 27faa3f..f4fbe96 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1342,6 +1342,7 @@ qemuBuildDriveStr(virConnectPtr conn, const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus); int idx = virDiskNameToIndex(disk->dst); char *optstr = NULL; + int controllerid = -1, busid = -1, unitid = -1; if (idx < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, @@ -1349,6 +1350,80 @@ qemuBuildDriveStr(virConnectPtr conn, goto error; } + switch (disk->bus) { + case VIR_DOMAIN_DISK_BUS_SCSI: + case VIR_DOMAIN_DISK_BUS_IDE: + case VIR_DOMAIN_DISK_BUS_FDC: + if (disk->addr.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE && + disk->addr.mode == VIR_DOMAIN_DEVICE_ADDRESS_MODE_STATIC) { + /* The user specified an explicit address, so ignore dev name */ + controllerid = disk->addr.data.drive.controller; + busid = disk->addr.data.drive.bus; + unitid = disk->addr.data.drive.unit; + } else if (disk->addr.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE || + disk->addr.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) { + /* + * We auto-assign contoller/bus/unit based on the drive + * index, which was in turn based on dev name eg "sda" + */ + if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) { + /* Many SCSI controllers, only 1 bus, each with 7 units */ + controllerid = idx / 7; + busid = 0; + unitid = idx % 7; + } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) { + /* One IDE controller, with 2 buses, each 2 units */ + controllerid = 0; + busid = idx / 2; + unitid = idx % 2; + } else { + controllerid = 0; + busid = 0; + unitid = idx; + } + + disk->addr.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; + disk->addr.mode = VIR_DOMAIN_DEVICE_ADDRESS_MODE_DYNAMIC; + disk->addr.data.drive.controller = controllerid; + disk->addr.data.drive.bus = busid; + disk->addr.data.drive.unit = unitid; + } else { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected address type for ide/scsi/fdc disk")); + goto error; + } + break; + + case VIR_DOMAIN_DISK_BUS_VIRTIO: + /* Each virtio drive is a separate PCI device, no unit/busid */ + break; + + case VIR_DOMAIN_DISK_BUS_XEN: + /* Xen has no address type currently, so assign based on index */ + unitid = idx; + break; + } + + if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) { + if (busid != 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("SCSI controller only supports 1 bus")); + goto error; + } + /* Setting bus= attr for SCSI drives, causes a controller + * to be created. Yes this is slightly odd. It is not possible + * to have > 1 bus on a SCSI controller (yet). */ + busid = controllerid; + } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE || + disk->bus == VIR_DOMAIN_DISK_BUS_FDC) { + /* We can only have 1 IDE / Floppy controller (currently) */ + if (controllerid != 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("Only 1 %s controller is supported"), bus); + goto error; + } + } + if (disk->src) { if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) { /* QEMU only supports magic FAT format for now */ @@ -1375,7 +1450,10 @@ qemuBuildDriveStr(virConnectPtr conn, virBufferVSprintf(&opt, "if=%s", bus); if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) virBufferAddLit(&opt, ",media=cdrom"); - virBufferVSprintf(&opt, ",index=%d", idx); + if (busid != -1) + virBufferVSprintf(&opt, ",bus=%d", busid); + if (unitid != -1) + virBufferVSprintf(&opt, ",unit=%d", unitid); if (bootable && disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) virBufferAddLit(&opt, ",boot=on"); -- 1.6.5.2 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list