[PATCH 10/15] qemu: move qemuValidateDomainDeviceDefController() to qemu_validate.c

Daniel Henrique Barboza danielhb413 at gmail.com
Thu Mar 26 21:31:20 UTC 2020


Move the function and all its static helper functions.

Signed-off-by: Daniel Henrique Barboza <danielhb413 at gmail.com>
---
 src/qemu/qemu_domain.c   | 804 +--------------------------------------
 src/qemu/qemu_validate.c | 804 +++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_validate.h |   3 +
 3 files changed, 808 insertions(+), 803 deletions(-)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 2b3dea9d3f..522edb8274 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -5421,808 +5421,6 @@ qemuDomainValidateStorageSource(virStorageSourcePtr src,
 }
 
 
-static int
-qemuDomainDeviceDefValidateControllerAttributes(const virDomainControllerDef *controller)
-{
-    if (!(controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
-          (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI ||
-           controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL ||
-           controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL))) {
-        if (controller->queues) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("'queues' is only supported by virtio-scsi controller"));
-            return -1;
-        }
-        if (controller->cmd_per_lun) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("'cmd_per_lun' is only supported by virtio-scsi controller"));
-            return -1;
-        }
-        if (controller->max_sectors) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("'max_sectors' is only supported by virtio-scsi controller"));
-            return -1;
-        }
-        if (controller->ioeventfd) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("'ioeventfd' is only supported by virtio-scsi controller"));
-            return -1;
-        }
-        if (controller->iothread) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("'iothread' is only supported for virtio-scsi controller"));
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
-
-/**
- * @qemuCaps: QEMU capabilities
- * @model: SCSI model to check
- *
- * Using the @qemuCaps, let's ensure the provided @model can be supported
- *
- * Returns true if acceptable, false otherwise with error message set.
- */
-static bool
-qemuDomainCheckSCSIControllerModel(virQEMUCapsPtr qemuCaps,
-                                   int model)
-{
-    switch ((virDomainControllerModelSCSI) model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
-        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_LSI)) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("This QEMU doesn't support "
-                             "the LSI 53C895A SCSI controller"));
-            return false;
-        }
-        break;
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL:
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL:
-        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_SCSI)) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("This QEMU doesn't support "
-                             "virtio scsi controller"));
-            return false;
-        }
-        break;
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
-        /*TODO: need checking work here if necessary */
-        break;
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
-        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_MPTSAS1068)) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("This QEMU doesn't support "
-                             "the LSI SAS1068 (MPT Fusion) controller"));
-            return false;
-        }
-        break;
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
-        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_MEGASAS)) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("This QEMU doesn't support "
-                             "the LSI SAS1078 (MegaRAID) controller"));
-            return false;
-        }
-        break;
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO:
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI:
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("Unsupported controller model: %s"),
-                       virDomainControllerModelSCSITypeToString(model));
-        return false;
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST:
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Unexpected SCSI controller model %d"),
-                       model);
-        return false;
-    }
-
-    return true;
-}
-
-
-static int
-qemuDomainDeviceDefValidateControllerIDE(const virDomainControllerDef *controller,
-                                         const virDomainDef *def)
-{
-    /* first IDE controller is implicit on various machines */
-    if (controller->idx == 0 && qemuDomainHasBuiltinIDE(def))
-        return 0;
-
-    /* Since we currently only support the integrated IDE
-     * controller on various boards, if we ever get to here, it's
-     * because some other machinetype had an IDE controller
-     * specified, or one with a single IDE controller had multiple
-     * IDE controllers specified.
-     */
-    if (qemuDomainHasBuiltinIDE(def))
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Only a single IDE controller is supported "
-                         "for this machine type"));
-    else
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("IDE controllers are unsupported for "
-                         "this QEMU binary or machine type"));
-    return -1;
-}
-
-
-/* qemuDomainCheckSCSIControllerIOThreads:
- * @controller: Pointer to controller def
- * @def: Pointer to domain def
- *
- * If this controller definition has iothreads set, let's make sure the
- * configuration is right before adding to the command line
- *
- * Returns true if either supported or there are no iothreads for controller;
- * otherwise, returns false if configuration is not quite right.
- */
-static bool
-qemuDomainCheckSCSIControllerIOThreads(const virDomainControllerDef *controller,
-                                       const virDomainDef *def)
-{
-    if (!controller->iothread)
-        return true;
-
-    if (controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
-        controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
-        controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
-       virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("virtio-scsi IOThreads only available for virtio "
-                         "pci and virtio ccw controllers"));
-       return false;
-    }
-
-    /* Can we find the controller iothread in the iothreadid list? */
-    if (!virDomainIOThreadIDFind(def, controller->iothread)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("controller iothread '%u' not defined in iothreadid"),
-                       controller->iothread);
-        return false;
-    }
-
-    return true;
-}
-
-
-static int
-qemuDomainDeviceDefValidateControllerSCSI(const virDomainControllerDef *controller,
-                                          const virDomainDef *def)
-{
-    switch ((virDomainControllerModelSCSI) controller->model) {
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL:
-            if (!qemuDomainCheckSCSIControllerIOThreads(controller, def))
-                return -1;
-            break;
-
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT:
-        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST:
-            break;
-    }
-
-    return 0;
-}
-
-
-/**
- * virDomainControllerPCIModelNameToQEMUCaps:
- * @modelName: model name
- *
- * Maps model names for PCI controllers (virDomainControllerPCIModelName)
- * to the QEMU capabilities required to use them (virQEMUCapsFlags).
- *
- * Returns: the QEMU capability itself (>0) on success; 0 if no QEMU
- *          capability is needed; <0 on error.
- */
-static int
-virDomainControllerPCIModelNameToQEMUCaps(int modelName)
-{
-    switch ((virDomainControllerPCIModelName) modelName) {
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE:
-        return QEMU_CAPS_DEVICE_PCI_BRIDGE;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE:
-        return QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420:
-        return QEMU_CAPS_DEVICE_IOH3420;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM:
-        return QEMU_CAPS_DEVICE_X3130_UPSTREAM;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM:
-        return QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB:
-        return QEMU_CAPS_DEVICE_PXB;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE:
-        return QEMU_CAPS_DEVICE_PXB_PCIE;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT:
-        return QEMU_CAPS_DEVICE_PCIE_ROOT_PORT;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE:
-        return QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_PCI_BRIDGE:
-        return QEMU_CAPS_DEVICE_PCIE_PCI_BRIDGE;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE:
-        return 0;
-    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST:
-    default:
-        return -1;
-    }
-
-    return -1;
-}
-
-
-#define virReportControllerMissingOption(cont, model, modelName, option) \
-    virReportError(VIR_ERR_INTERNAL_ERROR, \
-                   _("Required option '%s' is not set for PCI controller " \
-                     "with index '%d', model '%s' and modelName '%s'"), \
-                   (option), (cont->idx), (model), (modelName));
-#define virReportControllerInvalidOption(cont, model, modelName, option) \
-    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
-                   _("Option '%s' is not valid for PCI controller " \
-                     "with index '%d', model '%s' and modelName '%s'"), \
-                   (option), (cont->idx), (model), (modelName));
-#define virReportControllerInvalidValue(cont, model, modelName, option) \
-    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
-                   _("Option '%s' has invalid value for PCI controller " \
-                     "with index '%d', model '%s' and modelName '%s'"), \
-                   (option), (cont->idx), (model), (modelName));
-
-
-static int
-qemuDomainDeviceDefValidateControllerPCI(const virDomainControllerDef *cont,
-                                         const virDomainDef *def,
-                                         virQEMUCapsPtr qemuCaps)
-
-{
-    const virDomainPCIControllerOpts *pciopts = &cont->opts.pciopts;
-    const char *model = virDomainControllerModelPCITypeToString(cont->model);
-    const char *modelName = virDomainControllerPCIModelNameTypeToString(pciopts->modelName);
-    int cap = virDomainControllerPCIModelNameToQEMUCaps(pciopts->modelName);
-
-    if (!model) {
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-    if (!modelName) {
-        virReportEnumRangeError(virDomainControllerPCIModelName, pciopts->modelName);
-        return -1;
-    }
-
-    /* modelName */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        /* modelName should have been set automatically */
-        if (pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
-            virReportControllerMissingOption(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-        /* modelName must be set for pSeries guests, but it's an error
-         * for it to be set for any other guest */
-        if (qemuDomainIsPSeries(def)) {
-            if (pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
-                virReportControllerMissingOption(cont, model, modelName, "modelName");
-                return -1;
-            }
-        } else {
-            if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
-                virReportControllerInvalidOption(cont, model, modelName, "modelName");
-                return -1;
-            }
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
-            virReportControllerInvalidOption(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-
-    /* modelName (cont'd) */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE &&
-            pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420 &&
-            pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_PCI_BRIDGE) {
-            virReportControllerInvalidValue(cont, model, modelName, "modelName");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-
-    /* index */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        if (cont->idx == 0) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                           _("Index for '%s' controllers must be > 0"),
-                           model);
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-        /* pSeries guests can have multiple PHBs, so it's expected that
-         * the index will not be zero for some of them */
-        if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT &&
-            pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
-            break;
-        }
-
-        /* For all other pci-root and pcie-root controllers, though,
-         * the index must be zero */
-        if (cont->idx != 0) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                           _("Index for '%s' controllers must be 0"),
-                           model);
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-
-    /* targetIndex */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-        /* PHBs for pSeries guests must have been assigned a targetIndex */
-        if (pciopts->targetIndex == -1 &&
-            pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
-            virReportControllerMissingOption(cont, model, modelName, "targetIndex");
-            return -1;
-        }
-
-        /* targetIndex only applies to PHBs, so for any other pci-root
-         * controller it being present is an error */
-        if (pciopts->targetIndex != -1 &&
-            pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
-            virReportControllerInvalidOption(cont, model, modelName, "targetIndex");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        if (pciopts->targetIndex != -1) {
-            virReportControllerInvalidOption(cont, model, modelName, "targetIndex");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-
-    /* pcihole64 */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-        if (pciopts->pcihole64 ||  pciopts->pcihole64size != 0) {
-            if (!qemuDomainIsI440FX(def)) {
-                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                               _("Setting the 64-bit PCI hole size is not "
-                                 "supported for machine '%s'"), def->os.machine);
-                return -1;
-            }
-
-            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_I440FX_PCI_HOLE64_SIZE)) {
-                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                               _("64-bit PCI hole size setting is not supported "
-                                 "with this QEMU binary"));
-                return -1;
-            }
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-        if (pciopts->pcihole64 || pciopts->pcihole64size != 0) {
-            if (!qemuDomainIsQ35(def)) {
-                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                               _("Setting the 64-bit PCI hole size is not "
-                                 "supported for machine '%s'"), def->os.machine);
-                return -1;
-            }
-
-            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_Q35_PCI_HOLE64_SIZE)) {
-                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                               _("64-bit PCI hole size setting is not supported "
-                                 "with this QEMU binary"));
-                return -1;
-            }
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        if (pciopts->pcihole64 ||
-            pciopts->pcihole64size != 0) {
-            virReportControllerInvalidOption(cont, model, modelName, "pcihole64");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-
-    /* busNr */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-        if (pciopts->busNr == -1) {
-            virReportControllerMissingOption(cont, model, modelName, "busNr");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        if (pciopts->busNr != -1) {
-            virReportControllerInvalidOption(cont, model, modelName, "busNr");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-
-    /* numaNode */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-        /* numaNode can be used for these controllers, but it's not set
-         * automatically so it can be missing */
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-        /* Only PHBs support numaNode */
-        if (pciopts->numaNode != -1 &&
-            pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
-            virReportControllerInvalidOption(cont, model, modelName, "numaNode");
-            return -1;
-        }
-
-        /* However, the default PHB doesn't support numaNode */
-        if (pciopts->numaNode != -1 &&
-            pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE &&
-            pciopts->targetIndex == 0) {
-            virReportControllerInvalidOption(cont, model, modelName, "numaNode");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        if (pciopts->numaNode != -1) {
-            virReportControllerInvalidOption(cont, model, modelName, "numaNode");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-
-    /* chassisNr */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-        if (pciopts->chassisNr == -1) {
-            virReportControllerMissingOption(cont, model, modelName, "chassisNr");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        if (pciopts->chassisNr != -1) {
-            virReportControllerInvalidOption(cont, model, modelName, "chassisNr");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-        return -1;
-    }
-
-    /* chassis and port */
-    switch ((virDomainControllerModelPCI) cont->model) {
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
-        if (pciopts->chassis == -1) {
-            virReportControllerMissingOption(cont, model, modelName, "chassis");
-            return -1;
-        }
-        if (pciopts->port == -1) {
-            virReportControllerMissingOption(cont, model, modelName, "port");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
-        if (pciopts->chassis != -1) {
-            virReportControllerInvalidOption(cont, model, modelName, "chassis");
-            return -1;
-        }
-        if (pciopts->port != -1) {
-            virReportControllerInvalidOption(cont, model, modelName, "port");
-            return -1;
-        }
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
-    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
-    default:
-        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
-    }
-
-    /* QEMU device availability */
-    if (cap < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Unknown QEMU device for '%s' controller"),
-                       modelName);
-        return -1;
-    }
-    if (cap > 0 && !virQEMUCapsGet(qemuCaps, cap)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("The '%s' device is not supported by this QEMU binary"),
-                       modelName);
-        return -1;
-    }
-
-    /* PHBs didn't support numaNode from the very beginning, so an extra
-     * capability check is required */
-    if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT &&
-        pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE &&
-        pciopts->numaNode != -1 &&
-        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPAPR_PCI_HOST_BRIDGE_NUMA_NODE)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("Option '%s' is not supported by '%s' device with this QEMU binary"),
-                       "numaNode", modelName);
-        return -1;
-    }
-
-    return 0;
-}
-
-
-#undef virReportControllerInvalidValue
-#undef virReportControllerInvalidOption
-#undef virReportControllerMissingOption
-
-
-static int
-qemuDomainDeviceDefValidateControllerSATA(const virDomainControllerDef *controller,
-                                          const virDomainDef *def,
-                                          virQEMUCapsPtr qemuCaps)
-{
-    /* first SATA controller on Q35 machines is implicit */
-    if (controller->idx == 0 && qemuDomainIsQ35(def))
-        return 0;
-
-    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_AHCI)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("SATA is not supported with this QEMU binary"));
-        return -1;
-    }
-    return 0;
-}
-
-
-static int
-qemuDomainDeviceDefValidateController(const virDomainControllerDef *controller,
-                                      const virDomainDef *def,
-                                      virQEMUCapsPtr qemuCaps)
-{
-    int ret = 0;
-
-    if (!qemuDomainCheckCCWS390AddressSupport(def, &controller->info, qemuCaps,
-                                              "controller"))
-        return -1;
-
-    if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
-        !qemuDomainCheckSCSIControllerModel(qemuCaps, controller->model))
-        return -1;
-
-    if (qemuDomainDeviceDefValidateControllerAttributes(controller) < 0)
-        return -1;
-
-    switch ((virDomainControllerType)controller->type) {
-    case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
-        ret = qemuDomainDeviceDefValidateControllerIDE(controller, def);
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
-        ret = qemuDomainDeviceDefValidateControllerSCSI(controller, def);
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
-        ret = qemuDomainDeviceDefValidateControllerPCI(controller, def,
-                                                       qemuCaps);
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
-        ret = qemuDomainDeviceDefValidateControllerSATA(controller, def,
-                                                        qemuCaps);
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
-    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
-    case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
-    case VIR_DOMAIN_CONTROLLER_TYPE_USB:
-    case VIR_DOMAIN_CONTROLLER_TYPE_XENBUS:
-    case VIR_DOMAIN_CONTROLLER_TYPE_LAST:
-        break;
-    }
-
-    return ret;
-}
-
-
 static int
 qemuDomainDeviceDefValidateVsock(const virDomainVsockDef *vsock,
                                  const virDomainDef *def,
@@ -6887,7 +6085,7 @@ qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev,
         break;
 
     case VIR_DOMAIN_DEVICE_CONTROLLER:
-        ret = qemuDomainDeviceDefValidateController(dev->data.controller, def,
+        ret = qemuValidateDomainDeviceDefController(dev->data.controller, def,
                                                     qemuCaps);
         break;
 
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 0f267b4abe..f8228f3491 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -23,6 +23,7 @@
 #include "qemu_validate.h"
 #include "qemu_block.h"
 #include "qemu_domain.h"
+#include "domain_conf.h"
 #include "virlog.h"
 #include "virutil.h"
 
@@ -1914,3 +1915,806 @@ qemuValidateDomainDeviceDefDisk(const virDomainDiskDef *disk,
 
     return 0;
 }
+
+
+/**
+ * @qemuCaps: QEMU capabilities
+ * @model: SCSI model to check
+ *
+ * Using the @qemuCaps, let's ensure the provided @model can be supported
+ *
+ * Returns true if acceptable, false otherwise with error message set.
+ */
+static bool
+qemuValidateCheckSCSIControllerModel(virQEMUCapsPtr qemuCaps,
+                                   int model)
+{
+    switch ((virDomainControllerModelSCSI) model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_LSI)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("This QEMU doesn't support "
+                             "the LSI 53C895A SCSI controller"));
+            return false;
+        }
+        break;
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL:
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL:
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_SCSI)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("This QEMU doesn't support "
+                             "virtio scsi controller"));
+            return false;
+        }
+        break;
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
+        /*TODO: need checking work here if necessary */
+        break;
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_MPTSAS1068)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("This QEMU doesn't support "
+                             "the LSI SAS1068 (MPT Fusion) controller"));
+            return false;
+        }
+        break;
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SCSI_MEGASAS)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("This QEMU doesn't support "
+                             "the LSI SAS1078 (MegaRAID) controller"));
+            return false;
+        }
+        break;
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO:
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Unsupported controller model: %s"),
+                       virDomainControllerModelSCSITypeToString(model));
+        return false;
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST:
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unexpected SCSI controller model %d"),
+                       model);
+        return false;
+    }
+
+    return true;
+}
+
+
+
+static int
+qemuValidateDomainDeviceDefControllerSATA(const virDomainControllerDef *controller,
+                                          const virDomainDef *def,
+                                          virQEMUCapsPtr qemuCaps)
+{
+    /* first SATA controller on Q35 machines is implicit */
+    if (controller->idx == 0 && qemuDomainIsQ35(def))
+        return 0;
+
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_ICH9_AHCI)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("SATA is not supported with this QEMU binary"));
+        return -1;
+    }
+    return 0;
+}
+
+
+static int
+qemuValidateDomainDeviceDefControllerIDE(const virDomainControllerDef *controller,
+                                         const virDomainDef *def)
+{
+    /* first IDE controller is implicit on various machines */
+    if (controller->idx == 0 && qemuDomainHasBuiltinIDE(def))
+        return 0;
+
+    /* Since we currently only support the integrated IDE
+     * controller on various boards, if we ever get to here, it's
+     * because some other machinetype had an IDE controller
+     * specified, or one with a single IDE controller had multiple
+     * IDE controllers specified.
+     */
+    if (qemuDomainHasBuiltinIDE(def))
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Only a single IDE controller is supported "
+                         "for this machine type"));
+    else
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("IDE controllers are unsupported for "
+                         "this QEMU binary or machine type"));
+    return -1;
+}
+
+
+/* qemuValidateCheckSCSIControllerIOThreads:
+ * @controller: Pointer to controller def
+ * @def: Pointer to domain def
+ *
+ * If this controller definition has iothreads set, let's make sure the
+ * configuration is right before adding to the command line
+ *
+ * Returns true if either supported or there are no iothreads for controller;
+ * otherwise, returns false if configuration is not quite right.
+ */
+static bool
+qemuValidateCheckSCSIControllerIOThreads(const virDomainControllerDef *controller,
+                                         const virDomainDef *def)
+{
+    if (!controller->iothread)
+        return true;
+
+    if (controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+        controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
+        controller->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
+       virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("virtio-scsi IOThreads only available for virtio "
+                         "pci and virtio ccw controllers"));
+       return false;
+    }
+
+    /* Can we find the controller iothread in the iothreadid list? */
+    if (!virDomainIOThreadIDFind(def, controller->iothread)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("controller iothread '%u' not defined in iothreadid"),
+                       controller->iothread);
+        return false;
+    }
+
+    return true;
+}
+
+
+static int
+qemuValidateDomainDeviceDefControllerSCSI(const virDomainControllerDef *controller,
+                                          const virDomainDef *def)
+{
+    switch ((virDomainControllerModelSCSI) controller->model) {
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL:
+            if (!qemuValidateCheckSCSIControllerIOThreads(controller, def))
+                return -1;
+            break;
+
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT:
+        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST:
+            break;
+    }
+
+    return 0;
+}
+
+
+/**
+ * virValidateControllerPCIModelNameToQEMUCaps:
+ * @modelName: model name
+ *
+ * Maps model names for PCI controllers (virDomainControllerPCIModelName)
+ * to the QEMU capabilities required to use them (virQEMUCapsFlags).
+ *
+ * Returns: the QEMU capability itself (>0) on success; 0 if no QEMU
+ *          capability is needed; <0 on error.
+ */
+static int
+virValidateControllerPCIModelNameToQEMUCaps(int modelName)
+{
+    switch ((virDomainControllerPCIModelName) modelName) {
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE:
+        return QEMU_CAPS_DEVICE_PCI_BRIDGE;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE:
+        return QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420:
+        return QEMU_CAPS_DEVICE_IOH3420;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM:
+        return QEMU_CAPS_DEVICE_X3130_UPSTREAM;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM:
+        return QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB:
+        return QEMU_CAPS_DEVICE_PXB;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE:
+        return QEMU_CAPS_DEVICE_PXB_PCIE;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT:
+        return QEMU_CAPS_DEVICE_PCIE_ROOT_PORT;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE:
+        return QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_PCI_BRIDGE:
+        return QEMU_CAPS_DEVICE_PCIE_PCI_BRIDGE;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE:
+        return 0;
+    case VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST:
+    default:
+        return -1;
+    }
+
+    return -1;
+}
+
+
+static int
+qemuValidateDomainDeviceDefControllerAttributes(const virDomainControllerDef *controller)
+{
+    if (!(controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
+          (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI ||
+           controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL ||
+           controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL))) {
+        if (controller->queues) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("'queues' is only supported by virtio-scsi controller"));
+            return -1;
+        }
+        if (controller->cmd_per_lun) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("'cmd_per_lun' is only supported by virtio-scsi controller"));
+            return -1;
+        }
+        if (controller->max_sectors) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("'max_sectors' is only supported by virtio-scsi controller"));
+            return -1;
+        }
+        if (controller->ioeventfd) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("'ioeventfd' is only supported by virtio-scsi controller"));
+            return -1;
+        }
+        if (controller->iothread) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("'iothread' is only supported for virtio-scsi controller"));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+#define virReportControllerMissingOption(cont, model, modelName, option) \
+    virReportError(VIR_ERR_INTERNAL_ERROR, \
+                   _("Required option '%s' is not set for PCI controller " \
+                     "with index '%d', model '%s' and modelName '%s'"), \
+                   (option), (cont->idx), (model), (modelName));
+#define virReportControllerInvalidOption(cont, model, modelName, option) \
+    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
+                   _("Option '%s' is not valid for PCI controller " \
+                     "with index '%d', model '%s' and modelName '%s'"), \
+                   (option), (cont->idx), (model), (modelName));
+#define virReportControllerInvalidValue(cont, model, modelName, option) \
+    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
+                   _("Option '%s' has invalid value for PCI controller " \
+                     "with index '%d', model '%s' and modelName '%s'"), \
+                   (option), (cont->idx), (model), (modelName));
+
+
+static int
+qemuValidateDomainDeviceDefControllerPCI(const virDomainControllerDef *cont,
+                                         const virDomainDef *def,
+                                         virQEMUCapsPtr qemuCaps)
+
+{
+    const virDomainPCIControllerOpts *pciopts = &cont->opts.pciopts;
+    const char *model = virDomainControllerModelPCITypeToString(cont->model);
+    const char *modelName = virDomainControllerPCIModelNameTypeToString(pciopts->modelName);
+    int cap = virValidateControllerPCIModelNameToQEMUCaps(pciopts->modelName);
+
+    if (!model) {
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+    if (!modelName) {
+        virReportEnumRangeError(virDomainControllerPCIModelName, pciopts->modelName);
+        return -1;
+    }
+
+    /* modelName */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        /* modelName should have been set automatically */
+        if (pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
+            virReportControllerMissingOption(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+        /* modelName must be set for pSeries guests, but it's an error
+         * for it to be set for any other guest */
+        if (qemuDomainIsPSeries(def)) {
+            if (pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
+                virReportControllerMissingOption(cont, model, modelName, "modelName");
+                return -1;
+            }
+        } else {
+            if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
+                virReportControllerInvalidOption(cont, model, modelName, "modelName");
+                return -1;
+            }
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
+            virReportControllerInvalidOption(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+
+    /* modelName (cont'd) */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE &&
+            pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_IOH3420 &&
+            pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_X3130_UPSTREAM) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_XIO3130_DOWNSTREAM) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        if (pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_PCI_BRIDGE) {
+            virReportControllerInvalidValue(cont, model, modelName, "modelName");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+
+    /* index */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        if (cont->idx == 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Index for '%s' controllers must be > 0"),
+                           model);
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+        /* pSeries guests can have multiple PHBs, so it's expected that
+         * the index will not be zero for some of them */
+        if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT &&
+            pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
+            break;
+        }
+
+        /* For all other pci-root and pcie-root controllers, though,
+         * the index must be zero */
+        if (cont->idx != 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Index for '%s' controllers must be 0"),
+                           model);
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+
+    /* targetIndex */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+        /* PHBs for pSeries guests must have been assigned a targetIndex */
+        if (pciopts->targetIndex == -1 &&
+            pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
+            virReportControllerMissingOption(cont, model, modelName, "targetIndex");
+            return -1;
+        }
+
+        /* targetIndex only applies to PHBs, so for any other pci-root
+         * controller it being present is an error */
+        if (pciopts->targetIndex != -1 &&
+            pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
+            virReportControllerInvalidOption(cont, model, modelName, "targetIndex");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        if (pciopts->targetIndex != -1) {
+            virReportControllerInvalidOption(cont, model, modelName, "targetIndex");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+
+    /* pcihole64 */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+        if (pciopts->pcihole64 ||  pciopts->pcihole64size != 0) {
+            if (!qemuDomainIsI440FX(def)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("Setting the 64-bit PCI hole size is not "
+                                 "supported for machine '%s'"), def->os.machine);
+                return -1;
+            }
+
+            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_I440FX_PCI_HOLE64_SIZE)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("64-bit PCI hole size setting is not supported "
+                                 "with this QEMU binary"));
+                return -1;
+            }
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+        if (pciopts->pcihole64 || pciopts->pcihole64size != 0) {
+            if (!qemuDomainIsQ35(def)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("Setting the 64-bit PCI hole size is not "
+                                 "supported for machine '%s'"), def->os.machine);
+                return -1;
+            }
+
+            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_Q35_PCI_HOLE64_SIZE)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("64-bit PCI hole size setting is not supported "
+                                 "with this QEMU binary"));
+                return -1;
+            }
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        if (pciopts->pcihole64 ||
+            pciopts->pcihole64size != 0) {
+            virReportControllerInvalidOption(cont, model, modelName, "pcihole64");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+
+    /* busNr */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+        if (pciopts->busNr == -1) {
+            virReportControllerMissingOption(cont, model, modelName, "busNr");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        if (pciopts->busNr != -1) {
+            virReportControllerInvalidOption(cont, model, modelName, "busNr");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+
+    /* numaNode */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+        /* numaNode can be used for these controllers, but it's not set
+         * automatically so it can be missing */
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+        /* Only PHBs support numaNode */
+        if (pciopts->numaNode != -1 &&
+            pciopts->modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) {
+            virReportControllerInvalidOption(cont, model, modelName, "numaNode");
+            return -1;
+        }
+
+        /* However, the default PHB doesn't support numaNode */
+        if (pciopts->numaNode != -1 &&
+            pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE &&
+            pciopts->targetIndex == 0) {
+            virReportControllerInvalidOption(cont, model, modelName, "numaNode");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        if (pciopts->numaNode != -1) {
+            virReportControllerInvalidOption(cont, model, modelName, "numaNode");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+
+    /* chassisNr */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+        if (pciopts->chassisNr == -1) {
+            virReportControllerMissingOption(cont, model, modelName, "chassisNr");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        if (pciopts->chassisNr != -1) {
+            virReportControllerInvalidOption(cont, model, modelName, "chassisNr");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+        return -1;
+    }
+
+    /* chassis and port */
+    switch ((virDomainControllerModelPCI) cont->model) {
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT:
+        if (pciopts->chassis == -1) {
+            virReportControllerMissingOption(cont, model, modelName, "chassis");
+            return -1;
+        }
+        if (pciopts->port == -1) {
+            virReportControllerMissingOption(cont, model, modelName, "port");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_TO_PCI_BRIDGE:
+        if (pciopts->chassis != -1) {
+            virReportControllerInvalidOption(cont, model, modelName, "chassis");
+            return -1;
+        }
+        if (pciopts->port != -1) {
+            virReportControllerInvalidOption(cont, model, modelName, "port");
+            return -1;
+        }
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_DEFAULT:
+    case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST:
+    default:
+        virReportEnumRangeError(virDomainControllerModelPCI, cont->model);
+    }
+
+    /* QEMU device availability */
+    if (cap < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unknown QEMU device for '%s' controller"),
+                       modelName);
+        return -1;
+    }
+    if (cap > 0 && !virQEMUCapsGet(qemuCaps, cap)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("The '%s' device is not supported by this QEMU binary"),
+                       modelName);
+        return -1;
+    }
+
+    /* PHBs didn't support numaNode from the very beginning, so an extra
+     * capability check is required */
+    if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT &&
+        pciopts->modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE &&
+        pciopts->numaNode != -1 &&
+        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_SPAPR_PCI_HOST_BRIDGE_NUMA_NODE)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Option '%s' is not supported by '%s' device with this QEMU binary"),
+                       "numaNode", modelName);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+#undef virReportControllerInvalidValue
+#undef virReportControllerInvalidOption
+#undef virReportControllerMissingOption
+
+
+int
+qemuValidateDomainDeviceDefController(const virDomainControllerDef *controller,
+                                      const virDomainDef *def,
+                                      virQEMUCapsPtr qemuCaps)
+{
+    int ret = 0;
+
+    if (!qemuDomainCheckCCWS390AddressSupport(def, &controller->info, qemuCaps,
+                                              "controller"))
+        return -1;
+
+    if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
+        !qemuValidateCheckSCSIControllerModel(qemuCaps, controller->model))
+        return -1;
+
+    if (qemuValidateDomainDeviceDefControllerAttributes(controller) < 0)
+        return -1;
+
+    switch ((virDomainControllerType)controller->type) {
+    case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
+        ret = qemuValidateDomainDeviceDefControllerIDE(controller, def);
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
+        ret = qemuValidateDomainDeviceDefControllerSCSI(controller, def);
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
+        ret = qemuValidateDomainDeviceDefControllerPCI(controller, def,
+                                                       qemuCaps);
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
+        ret = qemuValidateDomainDeviceDefControllerSATA(controller, def,
+                                                        qemuCaps);
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
+    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
+    case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
+    case VIR_DOMAIN_CONTROLLER_TYPE_USB:
+    case VIR_DOMAIN_CONTROLLER_TYPE_XENBUS:
+    case VIR_DOMAIN_CONTROLLER_TYPE_LAST:
+        break;
+    }
+
+    return ret;
+}
diff --git a/src/qemu/qemu_validate.h b/src/qemu/qemu_validate.h
index ba732d05d8..85efa9354f 100644
--- a/src/qemu/qemu_validate.h
+++ b/src/qemu/qemu_validate.h
@@ -48,3 +48,6 @@ int qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev,
                                        virQEMUCapsPtr qemuCaps);
 int qemuValidateDomainDeviceDefVideo(const virDomainVideoDef *video,
                                      virQEMUCapsPtr qemuCaps);
+int qemuValidateDomainDeviceDefController(const virDomainControllerDef *controller,
+                                          const virDomainDef *def,
+                                          virQEMUCapsPtr qemuCaps);
-- 
2.25.1





More information about the libvir-list mailing list