
On 2013年03月04日 14:01, Han Cheng wrote:
Adding scsi hostdev, it should like:
<hostdev mode='subsystem' type='scsi'> <source> <adapter name='scsi_host0'/> <address bus='0' target='0' unit='0'/> </source> <address type='drive' controller='0' bus='0' target='4' unit='8'/> </hostdev> --- docs/schemas/domaincommon.rng | 33 +++++++++ src/conf/domain_audit.c | 10 +++ src/conf/domain_conf.c | 149 +++++++++++++++++++++++++++++++++++++++-- src/conf/domain_conf.h | 7 ++ 4 files changed, 194 insertions(+), 5 deletions(-)
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index fbb4001..ebd0e42 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2931,6 +2931,7 @@ <choice> <ref name="hostdevsubsyspci"/> <ref name="hostdevsubsysusb"/> +<ref name="hostdevsubsysscsi"/> </choice> </define>
@@ -2983,6 +2984,22 @@ </element> </define>
+<define name="hostdevsubsysscsi"> +<attribute name="type"> +<value>scsi</value> +</attribute> +<element name="source"> +<element name="adapter"> +<attribute name="name"> +<ref name="scsiAdapter"/> +</attribute> +</element> +<element name="address"> +<ref name="scsiaddress"/> +</element> +</element> +</define> + <define name="hostdevcapsstorage"> <attribute name="type"> <value>storage</value> @@ -3027,6 +3044,17 @@ </attribute> </element> </define> +<define name="scsiaddress"> +<attribute name="bus"> +<ref name="driveBus"/> +</attribute> +<attribute name="target"> +<ref name="driveTarget"/> +</attribute> +<attribute name="unit"> +<ref name="driveUnit"/> +</attribute> +</define> <define name="usbportaddress"> <attribute name="bus"> <ref name="usbAddr"/> @@ -3893,4 +3921,9 @@ </element> <empty/> </define> +<define name="scsiAdapter"> +<data type="string"> +<param name="pattern">scsi_host[0-9]{1,2}</param>
No need to have a duplicate definition. It can reuse what storage pool uses.
+</data> +</define> </grammar> diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index c00bd11..e6d44b1 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -281,6 +281,16 @@ virDomainAuditHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr hostdev, goto cleanup; } break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + if (virAsprintf(&address, "%.3d:%.3d:%.3d:%.3d", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit)< 0) { + VIR_WARN("OOM while encoding audit message"); + goto cleanup; + } + break; default: VIR_WARN("Unexpected hostdev type while encoding audit message: %d", hostdev->source.subsys.type); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 5e385e4..2be9129 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -557,7 +557,8 @@ VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
VIR_ENUM_IMPL(virDomainHostdevSubsys, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST, "usb", - "pci") + "pci", + "scsi")
VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST, "storage", @@ -2928,6 +2929,96 @@ virDomainParseLegacyDeviceAddress(char *devaddr, }
static int +virDomainHostdevSubsysScsiDefParseXML(const xmlNodePtr node, + virDomainHostdevDefPtr def) +{ + int ret = -1; + xmlNodePtr cur;
If you define those variables here: char *bus, *target, *unit;
+ + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if (xmlStrEqual(cur->name, BAD_CAST "address")) { + char *bus, *target, *unit; + + bus=virXMLPropString(cur, "bus"); + if (bus) {
These codes can be simplified as: if ((bus = virXMLPropString(cur, "bus")) < 0) { virReportError(...); goto out; } if (virStrToLong_ui(bus, NULL, 0, &def->source.subsys.u.scsi.bus) < 0) { virReportError(...); goto out; } With freeing the strings in "out". [1]
+ ret = virStrToLong_ui(bus, NULL, 0, +&def->source.subsys.u.scsi.bus); + VIR_FREE(bus); + if (ret< 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse bus %s"), bus); + goto out; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("scsi address needs bus id"));
Generally we uses strings like in this case: "bus must be specified for scsi hostdev address"
+ goto out; + } + target=virXMLPropString(cur, "target"); + if (target) { + ret = virStrToLong_ui(target, NULL, 0, +&def->source.subsys.u.scsi.target); + VIR_FREE(target); + if (ret< 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse target %s"), target); + goto out; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("scsi address needs target id")); + goto out; + } + unit=virXMLPropString(cur, "unit"); + if (unit) { + ret = virStrToLong_ui(unit, NULL, 0, +&def->source.subsys.u.scsi.unit); + VIR_FREE(unit); + if (ret< 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse unit %s"), unit); + goto out; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("scsi address needs unit id")); + goto out; + } + } else if (xmlStrEqual(cur->name, BAD_CAST "adapter")) { + char *adapter; + adapter = virXMLPropString(cur, "name"); + if (adapter&& STRSKIP(adapter, "scsi_host")) { + ret = virStrToLong_ui(adapter + strlen("scsi_host"), NULL, 0, +&def->source.subsys.u.scsi.adapter);
Why not storing the adapter name as a string instead?
+ VIR_FREE(adapter); + if (ret< 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse adapter %s"), adapter); + goto out; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("scsi needs adapter")); + goto out; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown scsi source type '%s'"), + cur->name); + goto out; + } + } + cur = cur->next; + } +
How about "adapter" is specified, but "source address" is not specified. Or the vice versa.
+ ret = 0; +out:
[1] VIR_FREE(bus); VIR_FREE(target); VIR_FREE(unit);
+ return ret; +} + +static int virDomainHostdevSubsysUsbDefParseXML(const xmlNodePtr node, virDomainHostdevDefPtr def) { @@ -3222,6 +3313,10 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, if (virDomainHostdevSubsysUsbDefParseXML(sourcenode, def)< 0) goto error; break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + if (virDomainHostdevSubsysScsiDefParseXML(sourcenode, def)< 0) + goto error; + break; default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("address type='%s' not supported in hostdev interfaces"), @@ -12146,6 +12241,30 @@ virDomainDefMaybeAddSmartcardController(virDomainDefPtr def) return 0; }
+static int +virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def) +{ + /* Look for any hostdev scsi dev */ + int i; + int maxController = -1; + virDomainHostdevDefPtr hostdev; + + for (i = 0; i< def->nhostdevs; i++) { + hostdev = *(def->hostdevs + i); + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS&& + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI&& + (int)hostdev->info->addr.drive.controller> maxController) { + maxController = hostdev->info->addr.drive.controller; + } + } + + for (i = 0; i<= maxController; i++) { + if (virDomainDefMaybeAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI, i)< 0) + return -1; + } + + return 0; +}
/* * Based on the declared<address/> info for any devices, @@ -12182,6 +12301,9 @@ virDomainDefAddImplicitControllers(virDomainDefPtr def) if (virDomainDefMaybeAddSmartcardController(def)< 0) return -1;
+ if (virDomainDefMaybeAddHostdevSCSIcontroller(def)< 0) + return -1; + return 0; }
@@ -12997,6 +13119,15 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf, virBufferAdjustIndent(buf, 2); switch (def->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + virBufferAsprintf(buf, "<adapter name='scsi_host%d'/>\n",
This is hard code. Assuming that a scsi host device can have different name with "scsi_host" on platform other than Linux. So again, IMHO we should just storing the adapter name as string.
+ def->source.subsys.u.scsi.adapter); + virBufferAsprintf(buf, "<address %sbus='%d' target='%d' unit='%d'/>\n", + includeTypeInAddr ? "type='scsi' " : "", + def->source.subsys.u.scsi.bus, + def->source.subsys.u.scsi.target, + def->source.subsys.u.scsi.unit); + break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: if (def->source.subsys.u.usb.vendor) { virBufferAsprintf(buf, "<vendor id='0x%.4x'/>\n", @@ -14250,10 +14381,18 @@ virDomainHostdevDefFormat(virBufferPtr buf, } virBufferAdjustIndent(buf, -6);
- if (virDomainDeviceInfoFormat(buf, def->info, - flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT - | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM)< 0) - return -1; + if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS&& + def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) { + if (virDomainDeviceInfoFormat(buf, def->info, + flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT + | VIR_DOMAIN_XML_INTERNAL_ALLOW_READONLY)< 0)
As commented in 1/5. This is no need as long as you add the "readonly" as an external XML tag.
+ return -1; + } else { + if (virDomainDeviceInfoFormat(buf, def->info, + flags | VIR_DOMAIN_XML_INTERNAL_ALLOW_BOOT + | VIR_DOMAIN_XML_INTERNAL_ALLOW_ROM)< 0) + return -1; + }
virBufferAddLit(buf, "</hostdev>\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 39c5849..c04cb23 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -366,6 +366,7 @@ enum virDomainHostdevMode { enum virDomainHostdevSubsysType { VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB, VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI, + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI,
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST }; @@ -385,6 +386,12 @@ struct _virDomainHostdevSubsys { unsigned vendor; unsigned product; } usb; + struct { + unsigned adapter;
char *adapter;
+ unsigned bus; + unsigned target; + unsigned unit; + } scsi; virDevicePCIAddress pci; /* host address */ } u; };