diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index f26596645a..abf024c7b2 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -766,12 +766,12 @@ enum virDomainControllerType {
};
-enum virDomainControllerModelPCI {
+typedef enum {
VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT,
VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE,
VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST
-};
+} virDomainControllerModelPCI;
enum virDomainControllerModelSCSI {
VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5a5d1129ca..22c2f25688 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -139,6 +139,7 @@ virDomainControllerDefFree;
virDomainControllerFind;
virDomainControllerInsert;
virDomainControllerInsertPreAlloced;
+virDomainControllerModelPCITypeToString;
virDomainControllerModelSCSITypeFromString;
virDomainControllerModelSCSITypeToString;
virDomainControllerModelUSBTypeFromString;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 9bba9d04a2..aa3a2fd691 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1412,7 +1412,15 @@ cleanup:
#define QEMU_PCI_ADDRESS_FUNCTION_LAST 7
typedef struct {
- /* Each bit in a slot represents one function on that slot */
+ virDomainControllerModelPCI model;
+ /* flags an min/max can be computed from model, but
+ * having them ready makes life easier.
+ */
+ qemuDomainPCIConnectFlags flags;
+ size_t minSlot, maxSlot; /* usually 0,0 or 1,31 */
+ /* Each bit in a slot represents one function on that slot. If the
+ * bit is set, that function is in use by a device.
+ */
uint8_t slots[QEMU_PCI_ADDRESS_SLOT_LAST + 1];
} qemuDomainPCIAddressBus;
typedef qemuDomainPCIAddressBus *qemuDomainPCIAddressBusPtr;
@@ -1430,9 +1438,13 @@ struct _qemuDomainPCIAddressSet {
* Check that the PCI address is valid for use
* with the specified PCI address set.
*/
-static bool qemuPCIAddressValidate(qemuDomainPCIAddressSetPtr addrs ATTRIBUTE_UNUSED,
- virDevicePCIAddressPtr addr)
+static bool
+qemuPCIAddressValidate(qemuDomainPCIAddressSetPtr addrs ATTRIBUTE_UNUSED,
+ virDevicePCIAddressPtr addr,
+ qemuDomainPCIConnectFlags flags)
{
+ qemuDomainPCIAddressBusPtr bus;
+
if (addrs->nbuses == 0) {
virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
return false;
@@ -1448,32 +1460,81 @@ static bool qemuPCIAddressValidate(qemuDomainPCIAddressSetPtr addrs ATTRIBUTE_UN
addrs->nbuses - 1);
return false;
}
+
+ bus = &addrs->buses[addr->bus];
+
+ /* assure that at least one of the requested connection types is
+ * provided by this bus
+ */
+ if (!(flags & bus->flags & QEMU_PCI_CONNECT_TYPES_MASK)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid PCI address: The PCI controller "
+ "providing bus %04x doesn't support "
+ "connections appropriate for the device "
+ "(%x required vs. %x provided by bus)"),
+ addr->bus, flags & QEMU_PCI_CONNECT_TYPES_MASK,
+ bus->flags & QEMU_PCI_CONNECT_TYPES_MASK);
+ return false;
+ }
+ /* make sure this bus allows hot-plug if the caller demands it */
+ if ((flags & QEMU_PCI_CONNECT_HOTPLUGGABLE) &&
+ !(bus->flags & QEMU_PCI_CONNECT_HOTPLUGGABLE)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid PCI address: hot-pluggable slot requested, "
+ "but bus %04x doesn't support hot-plug"), addr->bus);
+ return false;
+ }
+ /* some "buses" are really just a single port */
+ if (bus->minSlot && addr->slot < bus->minSlot) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid PCI address: slot must be >= %zu"),
+ bus->minSlot);
+ return false;
+ }
+ if (addr->slot > bus->maxSlot) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid PCI address: slot must be <= %zu"),
+ bus->maxSlot);
+ return false;
+ }
if (addr->function > QEMU_PCI_ADDRESS_FUNCTION_LAST) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid PCI address: function must be <= %u"),
QEMU_PCI_ADDRESS_FUNCTION_LAST);
return false;
}
- if (addr->slot > QEMU_PCI_ADDRESS_SLOT_LAST) {
- virReportError(VIR_ERR_XML_ERROR,
- _("Invalid PCI address: slot must be <= %u"),
- QEMU_PCI_ADDRESS_SLOT_LAST);
- return false;
- }
- if (addr->slot == 0) {
- if (addr->bus) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Slot 0 is unusable on PCI bridges"));
- } else {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Slot 0 on bus 0 is reserved for the host bridge"));
- }
- return false;
- }
return true;
}
+
+static int
+qemuDomainPCIAddressBusSetModel(qemuDomainPCIAddressBusPtr bus,
+ virDomainControllerModelPCI model)
+{
+ switch (model) {
+ case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+ case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+ bus->flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
+ QEMU_PCI_CONNECT_TYPE_PCI);
+ bus->minSlot = 1;
+ bus->maxSlot = QEMU_PCI_ADDRESS_SLOT_LAST;
+ break;
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Invalid PCI controller model %d"), model);
+ return -1;
+ }
+
+ bus->model = model;
+ return 0;
+}
+
+
/* Ensure addr fits in the address set, by expanding it if needed.
+ * This will only grow if the flags say that we need a normal
+ * hot-pluggable PCI slot. If we need a different type of slot, it
+ * will fail.
+ *
* Return value:
* -1 = OOM
* 0 = no action performed
@@ -1481,7 +1542,8 @@ static bool qemuPCIAddressValidate(qemuDomainPCIAddressSetPtr addrs ATTRIBUTE_UN
*/
static int
qemuDomainPCIAddressSetGrow(qemuDomainPCIAddressSetPtr addrs,
- virDevicePCIAddressPtr addr)
+ virDevicePCIAddressPtr addr,
+ qemuDomainPCIConnectFlags flags)
{
int add;
size_t i;
@@ -1490,16 +1552,33 @@ qemuDomainPCIAddressSetGrow(qemuDomainPCIAddressSetPtr addrs,
i = addrs->nbuses;
if (add <= 0)
return 0;
+
+ /* auto-grow only works when we're adding plain PCI devices */
+ if (!(flags & QEMU_PCI_CONNECT_TYPE_PCI)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot automatically add a new PCI bus for a "
+ "device requiring a slot other than standard PCI."));
+ return -1;
+ }
+
if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, add) < 0)
return -1;
- /* reserve slot 0 on the new buses */
- for (; i < addrs->nbuses; i++)
- addrs->buses[i].slots[0] = 0xFF;
+
+ for (; i < addrs->nbuses; i++) {
+ /* Any time we auto-add a bus, we will want a multi-slot
+ * bus. Currently the only type of bus we will auto-add is a
+ * pci-bridge, which is hot-pluggable and provides standard
+ * PCI slots.
+ */
+ qemuDomainPCIAddressBusSetModel(&addrs->buses[i],
+ VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
+ }
return add;
}
-static char *qemuPCIAddressAsString(virDevicePCIAddressPtr addr)
+static char *
+qemuPCIAddressAsString(virDevicePCIAddressPtr addr)
{
char *str;
@@ -1512,15 +1591,19 @@ static char *qemuPCIAddressAsString(virDevicePCIAddressPtr addr)
}
-static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
- virDomainDeviceDefPtr device,
- virDomainDeviceInfoPtr info,
- void *opaque)
+static int
+qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr device,
+ virDomainDeviceInfoPtr info,
+ void *opaque)
{
int ret = -1;
char *str = NULL;
virDevicePCIAddressPtr addr = &info->addr.pci;
qemuDomainPCIAddressSetPtr addrs = opaque;
+ /* FIXME: flags should be set according to the requirements of @device */
+ qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
+ QEMU_PCI_CONNECT_TYPE_PCI);
if ((info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
|| ((device->type == VIR_DOMAIN_DEVICE_HOSTDEV) &&
@@ -1538,6 +1621,11 @@ static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
*
* If the machine does have a PCI bus, they will get reserved
* in qemuAssignDevicePCISlots().
+ *
+ * FIXME: When we have support for a pcie-root controller at bus
+ * 0, we will no longer be able to skip checking of these devices,
+ * as they are PCI, and thus can't be connected to bus 0 if it is
+ * PCIe rather than PCI.
*/
if (device->type == VIR_DOMAIN_DEVICE_CONTROLLER && addr->domain == 0 &&
addr->bus == 0 && addr->slot == 1) {
@@ -1551,15 +1639,22 @@ static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
return 0;
}
- if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr) < 0)
+ /* add an additional bus of the correct type if needed */
+ if (addrs->dryRun &&
+ qemuDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
return -1;
- if (!qemuPCIAddressValidate(addrs, addr))
+ /* verify that the address is in bounds for the chosen bus, and
+ * that the bus is of the correct type for the device (via
+ * comparing the flags).
+ */
+ if (!qemuPCIAddressValidate(addrs, addr, flags))
return -1;
if (!(str = qemuPCIAddressAsString(addr)))
goto cleanup;
+ /* check if already in use */
if (addrs->buses[addr->bus].slots[addr->slot] & (1 << addr->function)) {
if (info->addr.pci.function != 0) {
virReportError(VIR_ERR_XML_ERROR,
@@ -1573,6 +1668,7 @@ static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
goto cleanup;
}
+ /* mark as in use */
if ((info->addr.pci.function == 0) &&
(info->addr.pci.multi != VIR_DEVICE_ADDRESS_PCI_MULTI_ON)) {
/* a function 0 w/o multifunction=on must reserve the entire slot */
@@ -1611,6 +1707,8 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
int nbuses = 0;
size_t i;
int rv;
+ qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
+ QEMU_PCI_CONNECT_TYPE_PCI);
for (i = 0; i < def->ncontrollers; i++) {
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
@@ -1624,22 +1722,25 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
if (nbuses > 0 &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PCI_BRIDGE)) {
virDomainDeviceInfo info;
+
/* 1st pass to figure out how many PCI bridges we need */
if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true)))
goto cleanup;
if (qemuAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
goto cleanup;
/* Reserve 1 extra slot for a (potential) bridge */
- if (qemuDomainPCIAddressSetNextAddr(addrs, &info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &info, flags) < 0)
goto cleanup;
for (i = 1; i < addrs->nbuses; i++) {
+ qemuDomainPCIAddressBusPtr bus = &addrs->buses[i];
+
if ((rv = virDomainDefMaybeAddController(
- def, VIR_DOMAIN_CONTROLLER_TYPE_PCI,
- i, VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE)) < 0)
+ def, VIR_DOMAIN_CONTROLLER_TYPE_PCI,
+ i, bus->model)) < 0)
goto cleanup;
/* If we added a new bridge, we will need one more address */
- if (rv > 0 && qemuDomainPCIAddressSetNextAddr(addrs, &info) < 0)
+ if (rv > 0 && qemuDomainPCIAddressSetNextAddr(addrs, &info, flags) < 0)
goto cleanup;
}
nbuses = addrs->nbuses;
@@ -1698,9 +1799,11 @@ int qemuDomainAssignAddresses(virDomainDefPtr def,
return qemuDomainAssignPCIAddresses(def, qemuCaps, obj);
}
-qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
- unsigned int nbuses,
- bool dryRun)
+
+qemuDomainPCIAddressSetPtr
+qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
+ unsigned int nbuses,
+ bool dryRun)
{
qemuDomainPCIAddressSetPtr addrs;
size_t i;
@@ -1714,10 +1817,38 @@ qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
addrs->nbuses = nbuses;
addrs->dryRun = dryRun;
- /* reserve slot 0 in every bus - it's used by the host bridge on bus 0
- * and unusable on PCI bridges */
- for (i = 0; i < nbuses; i++)
- addrs->buses[i].slots[0] = 0xFF;
+ /* As a safety measure, set default model='pci-root' for first pci
+ * controller and 'pci-bridge' for all subsequent. After setting
+ * those defaults, then scan the config and set the actual model
+ * for all addrs[idx]->bus that already have a corresponding
+ * controller in the config.
+ *
+ */
+ if (nbuses > 0)
+ qemuDomainPCIAddressBusSetModel(&addrs->buses[0],
+ VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT);
+ for (i = 1; i < nbuses; i++) {
+ qemuDomainPCIAddressBusSetModel(&addrs->buses[i],
+ VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
+ }
+
+ for (i = 0; i < def->ncontrollers; i++) {
+ size_t idx = def->controllers[i]->idx;
+
+ if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI)
+ continue;
+
+ if (idx >= addrs->nbuses) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Inappropriate new pci controller index %zu "
+ "not found in addrs"), idx);
+ goto error;
+ }
+
+ if (qemuDomainPCIAddressBusSetModel(&addrs->buses[idx],
+ def->controllers[i]->model) < 0)
+ goto error;
+ }
if (virDomainDeviceInfoIterate(def, qemuCollectPCIAddress, addrs) < 0)
goto error;
@@ -1738,12 +1869,16 @@ static bool qemuDomainPCIAddressSlotInUse(qemuDomainPCIAddressSetPtr addrs,
return !!addrs->buses[addr->bus].slots[addr->slot];
}
-int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
- virDevicePCIAddressPtr addr)
+
+int
+qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
+ virDevicePCIAddressPtr addr,
+ qemuDomainPCIConnectFlags flags)
{
char *str;
+ qemuDomainPCIAddressBusPtr bus;
- if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr) < 0)
+ if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
return -1;
if (!(str = qemuPCIAddressAsString(addr)))
@@ -1751,9 +1886,19 @@ int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
VIR_DEBUG("Reserving PCI addr %s", str);
- if (addrs->buses[addr->bus].slots[addr->slot] & (1 << addr->function)) {
+ bus = &addrs->buses[addr->bus];
+ if ((bus->minSlot && addr->slot < bus->minSlot) ||
+ addr->slot > bus->maxSlot) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unable to reserve PCI address %s"), str);
+ _("Unable to reserve PCI address %s. "
+ "Slot %02x can't be used on bus %04x, "
+ "only slots %02zx - %02zx are permitted on this bus."),
+ str, addr->slot, addr->bus, bus->minSlot, bus->maxSlot);
+ }
+
+ if (bus->slots[addr->slot] & (1 << addr->function)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unable to reserve PCI address %s already in use"), str);
VIR_FREE(str);
return -1;
}
@@ -1763,16 +1908,19 @@ int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
addrs->lastaddr = *addr;
addrs->lastaddr.function = 0;
addrs->lastaddr.multi = 0;
- addrs->buses[addr->bus].slots[addr->slot] |= 1 << addr->function;
+ bus->slots[addr->slot] |= 1 << addr->function;
return 0;
}
-int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
- virDevicePCIAddressPtr addr)
+
+int
+qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
+ virDevicePCIAddressPtr addr,
+ qemuDomainPCIConnectFlags flags)
{
char *str;
- if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr) < 0)
+ if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
return -1;
if (!(str = qemuPCIAddressAsString(addr)))
@@ -1796,6 +1944,10 @@ int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev)
{
int ret = 0;
+ /* FIXME: flags should be set according to the particular device */
+ qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
+ QEMU_PCI_CONNECT_TYPE_PCI);
+
if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
/* We do not support hotplug multi-function PCI device now, so we should
* reserve the whole slot. The function of the PCI device must be 0.
@@ -1807,12 +1959,12 @@ int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
return -1;
}
- if (!qemuPCIAddressValidate(addrs, &dev->addr.pci))
+ if (!qemuPCIAddressValidate(addrs, &dev->addr.pci, flags))
return -1;
- ret = qemuDomainPCIAddressReserveSlot(addrs, &dev->addr.pci);
+ ret = qemuDomainPCIAddressReserveSlot(addrs, &dev->addr.pci, flags);
} else {
- ret = qemuDomainPCIAddressSetNextAddr(addrs, dev);
+ ret = qemuDomainPCIAddressSetNextAddr(addrs, dev, flags);
}
return ret;
}
@@ -1829,7 +1981,12 @@ static int
qemuDomainPCIAddressReleaseSlot(qemuDomainPCIAddressSetPtr addrs,
virDevicePCIAddressPtr addr)
{
- if (!qemuPCIAddressValidate(addrs, addr))
+ /* permit any kind of connection type in validation, since we
+ * already had it, and are giving it back.
+ */
+ qemuDomainPCIConnectFlags flags = QEMU_PCI_CONNECT_TYPES_MASK;
+
+ if (!qemuPCIAddressValidate(addrs, addr, flags))
return -1;
addrs->buses[addr->bus].slots[addr->slot] = 0;
@@ -1848,7 +2005,8 @@ void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
static int
qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
- virDevicePCIAddressPtr next_addr)
+ virDevicePCIAddressPtr next_addr,
+ qemuDomainPCIConnectFlags flags)
{
virDevicePCIAddress a = addrs->lastaddr;
@@ -1872,7 +2030,7 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
/* There were no free slots after the last used one */
if (addrs->dryRun) {
/* a is already set to the first new bus and slot 1 */
- if (qemuDomainPCIAddressSetGrow(addrs, &a) < 0)
+ if (qemuDomainPCIAddressSetGrow(addrs, &a, flags) < 0)
return -1;
goto success;
} else {
@@ -1900,14 +2058,16 @@ success:
return 0;
}
-int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
- virDomainDeviceInfoPtr dev)
+int
+qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
+ virDomainDeviceInfoPtr dev,
+ qemuDomainPCIConnectFlags flags)
{
virDevicePCIAddress addr;
- if (qemuDomainPCIAddressGetNextSlot(addrs, &addr) < 0)
+ if (qemuDomainPCIAddressGetNextSlot(addrs, &addr, flags) < 0)
return -1;
- if (qemuDomainPCIAddressReserveSlot(addrs, &addr) < 0)
+ if (qemuDomainPCIAddressReserveSlot(addrs, &addr, flags) < 0)
return -1;
if (!addrs->dryRun) {
@@ -1962,6 +2122,7 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
virDevicePCIAddress tmp_addr;
bool qemuDeviceVideoUsable = virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIDEO_PRIMARY);
virDevicePCIAddressPtr addrptr;
+ qemuDomainPCIConnectFlags flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI;
/* Verify that first IDE and USB controllers (if any) is on the PIIX3, fn 1 */
for (i = 0; i < def->ncontrollers; i++) {
@@ -2013,7 +2174,7 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
if (addrs->nbuses) {
memset(&tmp_addr, 0, sizeof(tmp_addr));
tmp_addr.slot = 1;
- if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr) < 0)
+ if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0)
goto error;
}
@@ -2027,21 +2188,21 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
primaryVideo->info.addr.pci.function = 0;
addrptr = &primaryVideo->info.addr.pci;
- if (!qemuPCIAddressValidate(addrs, addrptr))
+ if (!qemuPCIAddressValidate(addrs, addrptr, flags))
goto error;
if (qemuDomainPCIAddressSlotInUse(addrs, addrptr)) {
if (qemuDeviceVideoUsable) {
virResetLastError();
- if (qemuDomainPCIAddressSetNextAddr(addrs, &primaryVideo->info) < 0)
- goto error;
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &primaryVideo->info, flags) < 0)
+ goto error;;
} else {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("PCI address 0:0:2.0 is in use, "
"QEMU needs it for primary video"));
goto error;
}
- } else if (qemuDomainPCIAddressReserveSlot(addrs, addrptr) < 0) {
+ } else if (qemuDomainPCIAddressReserveSlot(addrs, addrptr, flags) < 0) {
goto error;
}
} else if (!qemuDeviceVideoUsable) {
@@ -2065,7 +2226,7 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
" device will not be possible without manual"
" intervention");
virResetLastError();
- } else if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr) < 0) {
+ } else if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) {
goto error;
}
}
@@ -2114,6 +2275,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
qemuDomainPCIAddressSetPtr addrs)
{
size_t i, j;
+ qemuDomainPCIConnectFlags flags;
virDevicePCIAddress tmp_addr;
if ((STRPREFIX(def->os.machine, "pc-0.") ||
@@ -2125,6 +2287,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
goto error;
}
+ flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI;
+
/* PCI controllers */
for (i = 0; i < def->ncontrollers; i++) {
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
@@ -2132,7 +2296,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
continue;
if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
continue;
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info, flags) < 0)
goto error;
}
}
@@ -2143,7 +2307,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
/* Only support VirtIO-9p-pci so far. If that changes,
* we might need to skip devices here */
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->fss[i]->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->fss[i]->info, flags) < 0)
goto error;
}
@@ -2157,7 +2321,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
(def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)) {
continue;
}
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->nets[i]->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->nets[i]->info, flags) < 0)
goto error;
}
@@ -2170,7 +2334,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK)
continue;
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->sounds[i]->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->sounds[i]->info, flags) < 0)
goto error;
}
@@ -2232,20 +2396,20 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
if (addr.slot == 0) {
/* This is the first part of the controller, so need
* to find a free slot & then reserve a function */
- if (qemuDomainPCIAddressGetNextSlot(addrs, &tmp_addr) < 0)
+ if (qemuDomainPCIAddressGetNextSlot(addrs, &tmp_addr, flags) < 0)
goto error;
addr.bus = tmp_addr.bus;
addr.slot = tmp_addr.slot;
}
/* Finally we can reserve the slot+function */
- if (qemuDomainPCIAddressReserveAddr(addrs, &addr) < 0)
+ if (qemuDomainPCIAddressReserveAddr(addrs, &addr, flags) < 0)
goto error;
def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
def->controllers[i]->info.addr.pci = addr;
} else {
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info, flags) < 0)
goto error;
}
}
@@ -2270,7 +2434,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
goto error;
}
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->disks[i]->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->disks[i]->info, flags) < 0)
goto error;
}
@@ -2282,7 +2446,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
continue;
- if (qemuDomainPCIAddressSetNextAddr(addrs, def->hostdevs[i]->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, def->hostdevs[i]->info, flags) < 0)
goto error;
}
@@ -2290,7 +2454,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
if (def->memballoon &&
def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->memballoon->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->memballoon->info, flags) < 0)
goto error;
}
@@ -2298,7 +2462,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
if (def->rng &&
def->rng->model == VIR_DOMAIN_RNG_MODEL_VIRTIO &&
def->rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->rng->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->rng->info, flags) < 0)
goto error;
}
@@ -2306,7 +2470,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
if (def->watchdog &&
def->watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_IB700 &&
def->watchdog->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->watchdog->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->watchdog->info, flags) < 0)
goto error;
}
@@ -2319,7 +2483,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
}
if (def->videos[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
continue;
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->videos[i]->info) < 0)
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->videos[i]->info, flags) < 0)
goto error;
}
for (i = 0; i < def->ninputs; i++) {
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index e15fe647fe..2b02d6eaf0 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -225,6 +225,23 @@ void qemuDomainReleaseDeviceAddress(virDomainObjPtr vm,
virDomainDeviceInfoPtr info,
const char *devstr);
+typedef enum {
+ QEMU_PCI_CONNECT_HOTPLUGGABLE = 1 << 0,
+ /* This bus supports hot-plug */
+ QEMU_PCI_CONNECT_SINGLESLOT = 1 << 1,
+ /* This "bus" has only a single downstream slot/port */
+
+ QEMU_PCI_CONNECT_TYPE_PCI = 1 << 2,
+ /* PCI devices can connect to this bus */
+} qemuDomainPCIConnectFlags;
+
+/* a combination of all bit that describe the type of connections
+ * allowed, e.g. PCI, PCIe, switch
+ */
+# define QEMU_PCI_CONNECT_TYPES_MASK \
+ QEMU_PCI_CONNECT_TYPE_PCI
+
+
int qemuDomainAssignPCIAddresses(virDomainDefPtr def,
virQEMUCapsPtr qemuCaps,
virDomainObjPtr obj);
@@ -232,11 +249,14 @@ qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
unsigned int nbuses,
bool dryRun);
int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
- virDevicePCIAddressPtr addr);
+ virDevicePCIAddressPtr addr,
+ qemuDomainPCIConnectFlags flags);
int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
- virDevicePCIAddressPtr addr);
+ virDevicePCIAddressPtr addr,
+ qemuDomainPCIConnectFlags flags);
int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
- virDomainDeviceInfoPtr dev);
+ virDomainDeviceInfoPtr dev,
+ qemuDomainPCIConnectFlags flags);
int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
virDomainDeviceInfoPtr dev);
int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge-many-disks.args b/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge-many-disks.args
new file mode 100644
index 0000000000..b2cf685fb4
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge-many-disks.args
@@ -0,0 +1,217 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu-kvm \
+-S -M pc-i440fx-1.4 -cpu qemu64,-kvmclock -bios /usr/share/seabios/bios.bin \
+-m 3907 -smp 1 -nographic -nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait -boot c \
+-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x3 \
+-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.0,addr=0x4 \
+-device pci-bridge,chassis_nr=3,id=pci.3,bus=pci.0,addr=0x5 \
+-usb -drive file=/var/lib/libvirt/images/test.img,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,bus=pci.0,addr=0x6,drive=drive-virtio-disk0,id=virtio-disk0 \
+-drive file=/var/lib/libvirt/images/disk-a-a.img,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,bus=pci.0,addr=0x7,drive=drive-virtio-disk0,id=virtio-disk0 \
+-drive file=/var/lib/libvirt/images/disk-a-b.img,if=none,id=drive-virtio-disk27 \
+-device virtio-blk-pci,bus=pci.0,addr=0x8,drive=drive-virtio-disk27,id=virtio-disk27 \
+-drive file=/var/lib/libvirt/images/disk-a-c.img,if=none,id=drive-virtio-disk28 \
+-device virtio-blk-pci,bus=pci.0,addr=0x9,drive=drive-virtio-disk28,id=virtio-disk28 \
+-drive file=/var/lib/libvirt/images/disk-a-d.img,if=none,id=drive-virtio-disk29 \
+-device virtio-blk-pci,bus=pci.0,addr=0xa,drive=drive-virtio-disk29,id=virtio-disk29 \
+-drive file=/var/lib/libvirt/images/disk-b-a.img,if=none,id=drive-virtio-disk52 \
+-device virtio-blk-pci,bus=pci.0,addr=0xb,drive=drive-virtio-disk52,id=virtio-disk52 \
+-drive file=/var/lib/libvirt/images/disk-b-b.img,if=none,id=drive-virtio-disk53 \
+-device virtio-blk-pci,bus=pci.0,addr=0xc,drive=drive-virtio-disk53,id=virtio-disk53 \
+-drive file=/var/lib/libvirt/images/disk-b-c.img,if=none,id=drive-virtio-disk54 \
+-device virtio-blk-pci,bus=pci.0,addr=0xd,drive=drive-virtio-disk54,id=virtio-disk54 \
+-drive file=/var/lib/libvirt/images/disk-b-d.img,if=none,id=drive-virtio-disk55 \
+-device virtio-blk-pci,bus=pci.0,addr=0xe,drive=drive-virtio-disk55,id=virtio-disk55 \
+-drive file=/var/lib/libvirt/images/disk-c-a.img,if=none,id=drive-virtio-disk78 \
+-device virtio-blk-pci,bus=pci.0,addr=0xf,drive=drive-virtio-disk78,id=virtio-disk78 \
+-drive file=/var/lib/libvirt/images/disk-c-b.img,if=none,id=drive-virtio-disk79 \
+-device virtio-blk-pci,bus=pci.0,addr=0x10,drive=drive-virtio-disk79,id=virtio-disk79 \
+-drive file=/var/lib/libvirt/images/disk-c-c.img,if=none,id=drive-virtio-disk80 \
+-device virtio-blk-pci,bus=pci.0,addr=0x11,drive=drive-virtio-disk80,id=virtio-disk80 \
+-drive file=/var/lib/libvirt/images/disk-c-d.img,if=none,id=drive-virtio-disk81 \
+-device virtio-blk-pci,bus=pci.0,addr=0x12,drive=drive-virtio-disk81,id=virtio-disk81 \
+-drive file=/var/lib/libvirt/images/disk-d-a.img,if=none,id=drive-virtio-disk104 \
+-device virtio-blk-pci,bus=pci.0,addr=0x13,drive=drive-virtio-disk104,id=virtio-disk104 \
+-drive file=/var/lib/libvirt/images/disk-d-b.img,if=none,id=drive-virtio-disk105 \
+-device virtio-blk-pci,bus=pci.0,addr=0x14,drive=drive-virtio-disk105,id=virtio-disk105 \
+-drive file=/var/lib/libvirt/images/disk-d-c.img,if=none,id=drive-virtio-disk106 \
+-device virtio-blk-pci,bus=pci.0,addr=0x15,drive=drive-virtio-disk106,id=virtio-disk106 \
+-drive file=/var/lib/libvirt/images/disk-d-d.img,if=none,id=drive-virtio-disk107 \
+-device virtio-blk-pci,bus=pci.0,addr=0x16,drive=drive-virtio-disk107,id=virtio-disk107 \
+-drive file=/var/lib/libvirt/images/disk-e-a.img,if=none,id=drive-virtio-disk130 \
+-device virtio-blk-pci,bus=pci.0,addr=0x17,drive=drive-virtio-disk130,id=virtio-disk130 \
+-drive file=/var/lib/libvirt/images/disk-e-b.img,if=none,id=drive-virtio-disk131 \
+-device virtio-blk-pci,bus=pci.0,addr=0x18,drive=drive-virtio-disk131,id=virtio-disk131 \
+-drive file=/var/lib/libvirt/images/disk-e-c.img,if=none,id=drive-virtio-disk132 \
+-device virtio-blk-pci,bus=pci.0,addr=0x19,drive=drive-virtio-disk132,id=virtio-disk132 \
+-drive file=/var/lib/libvirt/images/disk-e-d.img,if=none,id=drive-virtio-disk133 \
+-device virtio-blk-pci,bus=pci.0,addr=0x1a,drive=drive-virtio-disk133,id=virtio-disk133 \
+-drive file=/var/lib/libvirt/images/disk-f-a.img,if=none,id=drive-virtio-disk156 \
+-device virtio-blk-pci,bus=pci.0,addr=0x1b,drive=drive-virtio-disk156,id=virtio-disk156 \
+-drive file=/var/lib/libvirt/images/disk-f-b.img,if=none,id=drive-virtio-disk157 \
+-device virtio-blk-pci,bus=pci.0,addr=0x1c,drive=drive-virtio-disk157,id=virtio-disk157 \
+-drive file=/var/lib/libvirt/images/disk-f-c.img,if=none,id=drive-virtio-disk158 \
+-device virtio-blk-pci,bus=pci.0,addr=0x1d,drive=drive-virtio-disk158,id=virtio-disk158 \
+-drive file=/var/lib/libvirt/images/disk-f-d.img,if=none,id=drive-virtio-disk159 \
+-device virtio-blk-pci,bus=pci.0,addr=0x1e,drive=drive-virtio-disk159,id=virtio-disk159 \
+-drive file=/var/lib/libvirt/images/disk-g-a.img,if=none,id=drive-virtio-disk182 \
+-device virtio-blk-pci,bus=pci.0,addr=0x1f,drive=drive-virtio-disk182,id=virtio-disk182 \
+-drive file=/var/lib/libvirt/images/disk-g-b.img,if=none,id=drive-virtio-disk183 \
+-device virtio-blk-pci,bus=pci.1,addr=0x1,drive=drive-virtio-disk183,id=virtio-disk183 \
+-drive file=/var/lib/libvirt/images/disk-g-c.img,if=none,id=drive-virtio-disk184 \
+-device virtio-blk-pci,bus=pci.1,addr=0x2,drive=drive-virtio-disk184,id=virtio-disk184 \
+-drive file=/var/lib/libvirt/images/disk-g-d.img,if=none,id=drive-virtio-disk185 \
+-device virtio-blk-pci,bus=pci.1,addr=0x3,drive=drive-virtio-disk185,id=virtio-disk185 \
+-drive file=/var/lib/libvirt/images/disk-h-a.img,if=none,id=drive-virtio-disk208 \
+-device virtio-blk-pci,bus=pci.1,addr=0x4,drive=drive-virtio-disk208,id=virtio-disk208 \
+-drive file=/var/lib/libvirt/images/disk-h-b.img,if=none,id=drive-virtio-disk209 \
+-device virtio-blk-pci,bus=pci.1,addr=0x5,drive=drive-virtio-disk209,id=virtio-disk209 \
+-drive file=/var/lib/libvirt/images/disk-h-c.img,if=none,id=drive-virtio-disk210 \
+-device virtio-blk-pci,bus=pci.1,addr=0x6,drive=drive-virtio-disk210,id=virtio-disk210 \
+-drive file=/var/lib/libvirt/images/disk-h-d.img,if=none,id=drive-virtio-disk211 \
+-device virtio-blk-pci,bus=pci.1,addr=0x7,drive=drive-virtio-disk211,id=virtio-disk211 \
+-drive file=/var/lib/libvirt/images/disk-i-a.img,if=none,id=drive-virtio-disk234 \
+-device virtio-blk-pci,bus=pci.1,addr=0x8,drive=drive-virtio-disk234,id=virtio-disk234 \
+-drive file=/var/lib/libvirt/images/disk-i-b.img,if=none,id=drive-virtio-disk235 \
+-device virtio-blk-pci,bus=pci.1,addr=0x9,drive=drive-virtio-disk235,id=virtio-disk235 \
+-drive file=/var/lib/libvirt/images/disk-i-c.img,if=none,id=drive-virtio-disk236 \
+-device virtio-blk-pci,bus=pci.1,addr=0xa,drive=drive-virtio-disk236,id=virtio-disk236 \
+-drive file=/var/lib/libvirt/images/disk-i-d.img,if=none,id=drive-virtio-disk237 \
+-device virtio-blk-pci,bus=pci.1,addr=0xb,drive=drive-virtio-disk237,id=virtio-disk237 \
+-drive file=/var/lib/libvirt/images/disk-j-a.img,if=none,id=drive-virtio-disk260 \
+-device virtio-blk-pci,bus=pci.1,addr=0xc,drive=drive-virtio-disk260,id=virtio-disk260 \
+-drive file=/var/lib/libvirt/images/disk-j-b.img,if=none,id=drive-virtio-disk261 \
+-device virtio-blk-pci,bus=pci.1,addr=0xd,drive=drive-virtio-disk261,id=virtio-disk261 \
+-drive file=/var/lib/libvirt/images/disk-j-c.img,if=none,id=drive-virtio-disk262 \
+-device virtio-blk-pci,bus=pci.1,addr=0xe,drive=drive-virtio-disk262,id=virtio-disk262 \
+-drive file=/var/lib/libvirt/images/disk-j-d.img,if=none,id=drive-virtio-disk263 \
+-device virtio-blk-pci,bus=pci.1,addr=0xf,drive=drive-virtio-disk263,id=virtio-disk263 \
+-drive file=/var/lib/libvirt/images/disk-k-a.img,if=none,id=drive-virtio-disk286 \
+-device virtio-blk-pci,bus=pci.1,addr=0x10,drive=drive-virtio-disk286,id=virtio-disk286 \
+-drive file=/var/lib/libvirt/images/disk-k-b.img,if=none,id=drive-virtio-disk287 \
+-device virtio-blk-pci,bus=pci.1,addr=0x11,drive=drive-virtio-disk287,id=virtio-disk287 \
+-drive file=/var/lib/libvirt/images/disk-k-c.img,if=none,id=drive-virtio-disk288 \
+-device virtio-blk-pci,bus=pci.1,addr=0x12,drive=drive-virtio-disk288,id=virtio-disk288 \
+-drive file=/var/lib/libvirt/images/disk-k-d.img,if=none,id=drive-virtio-disk289 \
+-device virtio-blk-pci,bus=pci.1,addr=0x13,drive=drive-virtio-disk289,id=virtio-disk289 \
+-drive file=/var/lib/libvirt/images/disk-l-a.img,if=none,id=drive-virtio-disk312 \
+-device virtio-blk-pci,bus=pci.1,addr=0x14,drive=drive-virtio-disk312,id=virtio-disk312 \
+-drive file=/var/lib/libvirt/images/disk-l-b.img,if=none,id=drive-virtio-disk313 \
+-device virtio-blk-pci,bus=pci.1,addr=0x15,drive=drive-virtio-disk313,id=virtio-disk313 \
+-drive file=/var/lib/libvirt/images/disk-l-c.img,if=none,id=drive-virtio-disk314 \
+-device virtio-blk-pci,bus=pci.1,addr=0x16,drive=drive-virtio-disk314,id=virtio-disk314 \
+-drive file=/var/lib/libvirt/images/disk-l-d.img,if=none,id=drive-virtio-disk315 \
+-device virtio-blk-pci,bus=pci.1,addr=0x17,drive=drive-virtio-disk315,id=virtio-disk315 \
+-drive file=/var/lib/libvirt/images/disk-m-a.img,if=none,id=drive-virtio-disk338 \
+-device virtio-blk-pci,bus=pci.1,addr=0x18,drive=drive-virtio-disk338,id=virtio-disk338 \
+-drive file=/var/lib/libvirt/images/disk-m-b.img,if=none,id=drive-virtio-disk339 \
+-device virtio-blk-pci,bus=pci.1,addr=0x19,drive=drive-virtio-disk339,id=virtio-disk339 \
+-drive file=/var/lib/libvirt/images/disk-m-c.img,if=none,id=drive-virtio-disk340 \
+-device virtio-blk-pci,bus=pci.1,addr=0x1a,drive=drive-virtio-disk340,id=virtio-disk340 \
+-drive file=/var/lib/libvirt/images/disk-m-d.img,if=none,id=drive-virtio-disk341 \
+-device virtio-blk-pci,bus=pci.1,addr=0x1b,drive=drive-virtio-disk341,id=virtio-disk341 \
+-drive file=/var/lib/libvirt/images/disk-n-a.img,if=none,id=drive-virtio-disk364 \
+-device virtio-blk-pci,bus=pci.1,addr=0x1c,drive=drive-virtio-disk364,id=virtio-disk364 \
+-drive file=/var/lib/libvirt/images/disk-n-b.img,if=none,id=drive-virtio-disk365 \
+-device virtio-blk-pci,bus=pci.1,addr=0x1d,drive=drive-virtio-disk365,id=virtio-disk365 \
+-drive file=/var/lib/libvirt/images/disk-n-c.img,if=none,id=drive-virtio-disk366 \
+-device virtio-blk-pci,bus=pci.1,addr=0x1e,drive=drive-virtio-disk366,id=virtio-disk366 \
+-drive file=/var/lib/libvirt/images/disk-n-d.img,if=none,id=drive-virtio-disk367 \
+-device virtio-blk-pci,bus=pci.1,addr=0x1f,drive=drive-virtio-disk367,id=virtio-disk367 \
+-drive file=/var/lib/libvirt/images/disk-o-a.img,if=none,id=drive-virtio-disk390 \
+-device virtio-blk-pci,bus=pci.2,addr=0x1,drive=drive-virtio-disk390,id=virtio-disk390 \
+-drive file=/var/lib/libvirt/images/disk-o-b.img,if=none,id=drive-virtio-disk391 \
+-device virtio-blk-pci,bus=pci.2,addr=0x2,drive=drive-virtio-disk391,id=virtio-disk391 \
+-drive file=/var/lib/libvirt/images/disk-o-c.img,if=none,id=drive-virtio-disk392 \
+-device virtio-blk-pci,bus=pci.2,addr=0x3,drive=drive-virtio-disk392,id=virtio-disk392 \
+-drive file=/var/lib/libvirt/images/disk-o-d.img,if=none,id=drive-virtio-disk393 \
+-device virtio-blk-pci,bus=pci.2,addr=0x4,drive=drive-virtio-disk393,id=virtio-disk393 \
+-drive file=/var/lib/libvirt/images/disk-p-a.img,if=none,id=drive-virtio-disk416 \
+-device virtio-blk-pci,bus=pci.2,addr=0x5,drive=drive-virtio-disk416,id=virtio-disk416 \
+-drive file=/var/lib/libvirt/images/disk-p-b.img,if=none,id=drive-virtio-disk417 \
+-device virtio-blk-pci,bus=pci.2,addr=0x6,drive=drive-virtio-disk417,id=virtio-disk417 \
+-drive file=/var/lib/libvirt/images/disk-p-c.img,if=none,id=drive-virtio-disk418 \
+-device virtio-blk-pci,bus=pci.2,addr=0x7,drive=drive-virtio-disk418,id=virtio-disk418 \
+-drive file=/var/lib/libvirt/images/disk-p-d.img,if=none,id=drive-virtio-disk419 \
+-device virtio-blk-pci,bus=pci.2,addr=0x8,drive=drive-virtio-disk419,id=virtio-disk419 \
+-drive file=/var/lib/libvirt/images/disk-q-a.img,if=none,id=drive-virtio-disk442 \
+-device virtio-blk-pci,bus=pci.2,addr=0x9,drive=drive-virtio-disk442,id=virtio-disk442 \
+-drive file=/var/lib/libvirt/images/disk-q-b.img,if=none,id=drive-virtio-disk443 \
+-device virtio-blk-pci,bus=pci.2,addr=0xa,drive=drive-virtio-disk443,id=virtio-disk443 \
+-drive file=/var/lib/libvirt/images/disk-q-c.img,if=none,id=drive-virtio-disk444 \
+-device virtio-blk-pci,bus=pci.2,addr=0xb,drive=drive-virtio-disk444,id=virtio-disk444 \
+-drive file=/var/lib/libvirt/images/disk-q-d.img,if=none,id=drive-virtio-disk445 \
+-device virtio-blk-pci,bus=pci.2,addr=0xc,drive=drive-virtio-disk445,id=virtio-disk445 \
+-drive file=/var/lib/libvirt/images/disk-r-a.img,if=none,id=drive-virtio-disk468 \
+-device virtio-blk-pci,bus=pci.2,addr=0xd,drive=drive-virtio-disk468,id=virtio-disk468 \
+-drive file=/var/lib/libvirt/images/disk-r-b.img,if=none,id=drive-virtio-disk469 \
+-device virtio-blk-pci,bus=pci.2,addr=0xe,drive=drive-virtio-disk469,id=virtio-disk469 \
+-drive file=/var/lib/libvirt/images/disk-r-c.img,if=none,id=drive-virtio-disk470 \
+-device virtio-blk-pci,bus=pci.2,addr=0xf,drive=drive-virtio-disk470,id=virtio-disk470 \
+-drive file=/var/lib/libvirt/images/disk-r-d.img,if=none,id=drive-virtio-disk471 \
+-device virtio-blk-pci,bus=pci.2,addr=0x10,drive=drive-virtio-disk471,id=virtio-disk471 \
+-drive file=/var/lib/libvirt/images/disk-s-a.img,if=none,id=drive-virtio-disk494 \
+-device virtio-blk-pci,bus=pci.2,addr=0x11,drive=drive-virtio-disk494,id=virtio-disk494 \
+-drive file=/var/lib/libvirt/images/disk-s-b.img,if=none,id=drive-virtio-disk495 \
+-device virtio-blk-pci,bus=pci.2,addr=0x12,drive=drive-virtio-disk495,id=virtio-disk495 \
+-drive file=/var/lib/libvirt/images/disk-s-c.img,if=none,id=drive-virtio-disk496 \
+-device virtio-blk-pci,bus=pci.2,addr=0x13,drive=drive-virtio-disk496,id=virtio-disk496 \
+-drive file=/var/lib/libvirt/images/disk-s-d.img,if=none,id=drive-virtio-disk497 \
+-device virtio-blk-pci,bus=pci.2,addr=0x14,drive=drive-virtio-disk497,id=virtio-disk497 \
+-drive file=/var/lib/libvirt/images/disk-t-a.img,if=none,id=drive-virtio-disk520 \
+-device virtio-blk-pci,bus=pci.2,addr=0x15,drive=drive-virtio-disk520,id=virtio-disk520 \
+-drive file=/var/lib/libvirt/images/disk-t-b.img,if=none,id=drive-virtio-disk521 \
+-device virtio-blk-pci,bus=pci.2,addr=0x16,drive=drive-virtio-disk521,id=virtio-disk521 \
+-drive file=/var/lib/libvirt/images/disk-t-c.img,if=none,id=drive-virtio-disk522 \
+-device virtio-blk-pci,bus=pci.2,addr=0x17,drive=drive-virtio-disk522,id=virtio-disk522 \
+-drive file=/var/lib/libvirt/images/disk-t-d.img,if=none,id=drive-virtio-disk523 \
+-device virtio-blk-pci,bus=pci.2,addr=0x18,drive=drive-virtio-disk523,id=virtio-disk523 \
+-drive file=/var/lib/libvirt/images/disk-u-a.img,if=none,id=drive-virtio-disk546 \
+-device virtio-blk-pci,bus=pci.2,addr=0x19,drive=drive-virtio-disk546,id=virtio-disk546 \
+-drive file=/var/lib/libvirt/images/disk-u-b.img,if=none,id=drive-virtio-disk547 \
+-device virtio-blk-pci,bus=pci.2,addr=0x1a,drive=drive-virtio-disk547,id=virtio-disk547 \
+-drive file=/var/lib/libvirt/images/disk-u-c.img,if=none,id=drive-virtio-disk548 \
+-device virtio-blk-pci,bus=pci.2,addr=0x1b,drive=drive-virtio-disk548,id=virtio-disk548 \
+-drive file=/var/lib/libvirt/images/disk-u-d.img,if=none,id=drive-virtio-disk549 \
+-device virtio-blk-pci,bus=pci.2,addr=0x1c,drive=drive-virtio-disk549,id=virtio-disk549 \
+-drive file=/var/lib/libvirt/images/disk-v-a.img,if=none,id=drive-virtio-disk572 \
+-device virtio-blk-pci,bus=pci.2,addr=0x1d,drive=drive-virtio-disk572,id=virtio-disk572 \
+-drive file=/var/lib/libvirt/images/disk-v-b.img,if=none,id=drive-virtio-disk573 \
+-device virtio-blk-pci,bus=pci.2,addr=0x1e,drive=drive-virtio-disk573,id=virtio-disk573 \
+-drive file=/var/lib/libvirt/images/disk-v-c.img,if=none,id=drive-virtio-disk574 \
+-device virtio-blk-pci,bus=pci.2,addr=0x1f,drive=drive-virtio-disk574,id=virtio-disk574 \
+-drive file=/var/lib/libvirt/images/disk-v-d.img,if=none,id=drive-virtio-disk575 \
+-device virtio-blk-pci,bus=pci.3,addr=0x1,drive=drive-virtio-disk575,id=virtio-disk575 \
+-drive file=/var/lib/libvirt/images/disk-w-a.img,if=none,id=drive-virtio-disk598 \
+-device virtio-blk-pci,bus=pci.3,addr=0x2,drive=drive-virtio-disk598,id=virtio-disk598 \
+-drive file=/var/lib/libvirt/images/disk-w-b.img,if=none,id=drive-virtio-disk599 \
+-device virtio-blk-pci,bus=pci.3,addr=0x3,drive=drive-virtio-disk599,id=virtio-disk599 \
+-drive file=/var/lib/libvirt/images/disk-w-c.img,if=none,id=drive-virtio-disk600 \
+-device virtio-blk-pci,bus=pci.3,addr=0x4,drive=drive-virtio-disk600,id=virtio-disk600 \
+-drive file=/var/lib/libvirt/images/disk-w-d.img,if=none,id=drive-virtio-disk601 \
+-device virtio-blk-pci,bus=pci.3,addr=0x5,drive=drive-virtio-disk601,id=virtio-disk601 \
+-drive file=/var/lib/libvirt/images/disk-x-a.img,if=none,id=drive-virtio-disk624 \
+-device virtio-blk-pci,bus=pci.3,addr=0x6,drive=drive-virtio-disk624,id=virtio-disk624 \
+-drive file=/var/lib/libvirt/images/disk-x-b.img,if=none,id=drive-virtio-disk625 \
+-device virtio-blk-pci,bus=pci.3,addr=0x7,drive=drive-virtio-disk625,id=virtio-disk625 \
+-drive file=/var/lib/libvirt/images/disk-x-c.img,if=none,id=drive-virtio-disk626 \
+-device virtio-blk-pci,bus=pci.3,addr=0x8,drive=drive-virtio-disk626,id=virtio-disk626 \
+-drive file=/var/lib/libvirt/images/disk-x-d.img,if=none,id=drive-virtio-disk627 \
+-device virtio-blk-pci,bus=pci.3,addr=0x9,drive=drive-virtio-disk627,id=virtio-disk627 \
+-drive file=/var/lib/libvirt/images/disk-y-a.img,if=none,id=drive-virtio-disk650 \
+-device virtio-blk-pci,bus=pci.3,addr=0xa,drive=drive-virtio-disk650,id=virtio-disk650 \
+-drive file=/var/lib/libvirt/images/disk-y-b.img,if=none,id=drive-virtio-disk651 \
+-device virtio-blk-pci,bus=pci.3,addr=0xb,drive=drive-virtio-disk651,id=virtio-disk651 \
+-drive file=/var/lib/libvirt/images/disk-y-c.img,if=none,id=drive-virtio-disk652 \
+-device virtio-blk-pci,bus=pci.3,addr=0xc,drive=drive-virtio-disk652,id=virtio-disk652 \
+-drive file=/var/lib/libvirt/images/disk-y-d.img,if=none,id=drive-virtio-disk653 \
+-device virtio-blk-pci,bus=pci.3,addr=0xd,drive=drive-virtio-disk653,id=virtio-disk653 \
+-drive file=/var/lib/libvirt/images/disk-z-a.img,if=none,id=drive-virtio-disk676 \
+-device virtio-blk-pci,bus=pci.3,addr=0xe,drive=drive-virtio-disk676,id=virtio-disk676 \
+-drive file=/var/lib/libvirt/images/disk-z-b.img,if=none,id=drive-virtio-disk677 \
+-device virtio-blk-pci,bus=pci.3,addr=0xf,drive=drive-virtio-disk677,id=virtio-disk677 \
+-drive file=/var/lib/libvirt/images/disk-z-c.img,if=none,id=drive-virtio-disk678 \
+-device virtio-blk-pci,bus=pci.3,addr=0x10,drive=drive-virtio-disk678,id=virtio-disk678 \
+-drive file=/var/lib/libvirt/images/disk-z-d.img,if=none,id=drive-virtio-disk679 \
+-device virtio-blk-pci,bus=pci.3,addr=0x11,drive=drive-virtio-disk679,id=virtio-disk679
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge-many-disks.xml b/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge-many-disks.xml
new file mode 100644
index 0000000000..1f3ad6ecbc
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-pci-bridge-many-disks.xml
@@ -0,0 +1,551 @@
+
+ lots-of-disks
+ 04872dc1-e1de-434b-ab21-e3e80e416349
+ 4000768
+ 4000000
+
+ hvm
+ /usr/share/seabios/bios.bin
+
+
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ restart
+
+ /usr/bin/qemu-kvm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 0f96eef91e..8185c541b9 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -992,6 +992,8 @@ mymain(void)
DO_TEST("pci-autoadd-addr", QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE);
DO_TEST("pci-autoadd-idx", QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_PCI_BRIDGE);
+ DO_TEST("pci-bridge-many-disks",
+ QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE_PCI_BRIDGE);
DO_TEST("hostdev-scsi-lsi", QEMU_CAPS_DRIVE,
QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE,
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pci-bridge-many-disks.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pci-bridge-many-disks.xml
new file mode 100644
index 0000000000..d469b8b568
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pci-bridge-many-disks.xml
@@ -0,0 +1,554 @@
+
+ lots-of-disks
+ 04872dc1-e1de-434b-ab21-e3e80e416349
+ 4000768
+ 4000000
+ 1
+
+ hvm
+ /usr/share/seabios/bios.bin
+
+
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ restart
+
+ /usr/bin/qemu-kvm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 77cac3f687..66be40e648 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -291,6 +291,7 @@ mymain(void)
DO_TEST("tpm-passthrough");
DO_TEST("pci-bridge");
+ DO_TEST_DIFFERENT("pci-bridge-many-disks");
DO_TEST_DIFFERENT("pci-autoadd-addr");
DO_TEST_DIFFERENT("pci-autoadd-idx");