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

Daniel Henrique Barboza danielhb413 at gmail.com
Thu Mar 26 21:45:46 UTC 2020


Just noticed that the commit title here is mentioning the new name of the function
instead of the original name, qemuDomainDeviceDefValidateController().

I'll fix it in the next spin after getting some reviews.


DHB

On 3/26/20 6:31 PM, Daniel Henrique Barboza wrote:
> 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);
> 




More information about the libvir-list mailing list