mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
conf: Generic XMLs for scsi hostdev
An example of the scsi hostdev XML: <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> Controller is implicitly added for scsi hostdev, though the scsi controller's model defaults to "lsilogic", which might be not what the user wants (same problem exists for virtio-scsi disk). It's the existing problem, will be addressed later. The device address must be specified manually. Later patch will let libvirt generate it automatically. This only introduces the generic XMLs for scsi hostdev, later patches will add other elements, e.g. <readonly>, <shareable>. Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com> Signed-off-by: Osier Yang <jyang@redhat.com>
This commit is contained in:
parent
9706d85fe9
commit
5c811dcec5
@ -2257,13 +2257,13 @@
|
||||
|
||||
<h4><a name="elementsHostDev">Host device assignment</a></h4>
|
||||
|
||||
<h5><a href="elementsHostDevSubsys">USB / PCI devices</a></h5>
|
||||
<h5><a href="elementsHostDevSubsys">USB / PCI / SCSI devices</a></h5>
|
||||
|
||||
<p>
|
||||
USB and PCI devices attached to the host can be passed through
|
||||
USB, PCI and SCSI devices attached to the host can be passed through
|
||||
to the guest using the <code>hostdev</code> element.
|
||||
<span class="since">since after 0.4.4 for USB and 0.6.0 for PCI
|
||||
(KVM only)</span>:
|
||||
<span class="since">since after 0.4.4 for USB, 0.6.0 for PCI(KVM only)
|
||||
and 1.0.6 for SCSI(KVM only)</span>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@ -2292,14 +2292,31 @@
|
||||
<rom bar='on' file='/etc/fake/boot.bin'/>
|
||||
</hostdev>
|
||||
</devices>
|
||||
...</pre>
|
||||
|
||||
<p>or:</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
<devices>
|
||||
<hostdev mode='subsystem' type='scsi'>
|
||||
<source>
|
||||
<adapter name='scsi_host0'/>
|
||||
<address type='scsi' bus='0' target='0' unit='0'/>
|
||||
</source>
|
||||
<readonly/>
|
||||
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
||||
</hostdev>
|
||||
</devices>
|
||||
...</pre>
|
||||
|
||||
<dl>
|
||||
<dt><code>hostdev</code></dt>
|
||||
<dd>The <code>hostdev</code> element is the main container for describing
|
||||
host devices. For usb device passthrough <code>mode</code> is always
|
||||
"subsystem" and <code>type</code> is "usb" for a USB device and "pci"
|
||||
for a PCI device. When <code>managed</code> is "yes" for a PCI
|
||||
"subsystem" and <code>type</code> is "usb" for a USB device, "pci"
|
||||
for a PCI device and "scsi" for a SCSI device. When
|
||||
<code>managed</code> is "yes" for a PCI
|
||||
device, it is detached from the host before being passed on to
|
||||
the guest, and reattached to the host after the guest exits.
|
||||
If <code>managed</code> is omitted or "no", and for USB
|
||||
@ -2309,13 +2326,16 @@
|
||||
hot-plugging the device,
|
||||
and <code>virNodeDeviceReAttach</code> (or <code>virsh
|
||||
nodedev-reattach</code>) after hot-unplug or stopping the
|
||||
guest.</dd>
|
||||
guest. For SCSI device, user is responsible to make sure the device
|
||||
is not used by host.</dd>
|
||||
<dt><code>source</code></dt>
|
||||
<dd>The source element describes the device as seen from the host.
|
||||
The USB device can either be addressed by vendor / product id using the
|
||||
<code>vendor</code> and <code>product</code> elements or by the device's
|
||||
address on the hosts using the <code>address</code> element. PCI devices
|
||||
on the other hand can only be described by their <code>address</code>.
|
||||
SCSI devices are described by both the <code>adapter</code> and
|
||||
<code>address</code> elements.
|
||||
|
||||
<span class="since">Since 1.0.0</span>, the <code>source</code> element
|
||||
of USB devices may contain <code>startupPolicy</code> attribute which can
|
||||
|
@ -3094,6 +3094,7 @@
|
||||
<choice>
|
||||
<ref name="hostdevsubsyspci"/>
|
||||
<ref name="hostdevsubsysusb"/>
|
||||
<ref name="hostdevsubsysscsi"/>
|
||||
</choice>
|
||||
</define>
|
||||
|
||||
@ -3162,6 +3163,20 @@
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="hostdevsubsysscsi">
|
||||
<attribute name="type">
|
||||
<value>scsi</value>
|
||||
</attribute>
|
||||
<element name="source">
|
||||
<interleave>
|
||||
<ref name="sourceinfoadapter"/>
|
||||
<element name="address">
|
||||
<ref name="scsiaddress"/>
|
||||
</element>
|
||||
</interleave>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="hostdevcapsstorage">
|
||||
<attribute name="type">
|
||||
<value>storage</value>
|
||||
@ -3217,6 +3232,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"/>
|
||||
|
@ -399,6 +399,16 @@ virDomainAuditHostdev(virDomainObjPtr vm, virDomainHostdevDefPtr hostdev,
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
|
||||
if (virAsprintf(&address, "%s:%d:%d:%d",
|
||||
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);
|
||||
|
@ -585,7 +585,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(virDomainHostdevSubsysPciBackend,
|
||||
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST,
|
||||
@ -1634,7 +1635,8 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
|
||||
if (def->parent.type == VIR_DOMAIN_DEVICE_NONE)
|
||||
virDomainDeviceInfoFree(def->info);
|
||||
|
||||
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
|
||||
switch (def->mode) {
|
||||
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
|
||||
switch (def->source.caps.type) {
|
||||
case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
|
||||
VIR_FREE(def->source.caps.u.storage.block);
|
||||
@ -1646,6 +1648,11 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
|
||||
VIR_FREE(def->source.caps.u.net.iface);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
|
||||
if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
|
||||
VIR_FREE(def->source.subsys.u.scsi.adapter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3680,6 +3687,94 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
virDomainHostdevSubsysScsiDefParseXML(const xmlNodePtr node,
|
||||
virDomainHostdevDefPtr def)
|
||||
{
|
||||
int ret = -1;
|
||||
bool got_address = false, got_adapter = false;
|
||||
xmlNodePtr cur;
|
||||
char *bus = NULL, *target = NULL, *unit = NULL;
|
||||
|
||||
cur = node->children;
|
||||
while (cur != NULL) {
|
||||
if (cur->type == XML_ELEMENT_NODE) {
|
||||
if (xmlStrEqual(cur->name, BAD_CAST "address")) {
|
||||
if (got_address) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("more than one source addresses is "
|
||||
"specified for scsi hostdev"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(bus = virXMLPropString(cur, "bus")) ||
|
||||
!(target = virXMLPropString(cur, "target")) ||
|
||||
!(unit = virXMLPropString(cur, "unit"))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("'bus', 'target', and 'unit' must be specified "
|
||||
"for scsi hostdev source address"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virStrToLong_ui(bus, NULL, 0, &def->source.subsys.u.scsi.bus) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot parse bus '%s'"), bus);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virStrToLong_ui(target, NULL, 0, &def->source.subsys.u.scsi.target) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot parse target '%s'"), target);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virStrToLong_ui(unit, NULL, 0, &def->source.subsys.u.scsi.unit) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot parse unit '%s'"), unit);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
got_address = true;
|
||||
} else if (xmlStrEqual(cur->name, BAD_CAST "adapter")) {
|
||||
if (got_adapter) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("more than one adapters is specified "
|
||||
"for scsi hostdev source"));
|
||||
goto cleanup;
|
||||
}
|
||||
if (!(def->source.subsys.u.scsi.adapter =
|
||||
virXMLPropString(cur, "name"))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("'adapter' must be specified for scsi hostdev source"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
got_adapter = true;
|
||||
} else {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("unsupported element '%s' of scsi hostdev source"),
|
||||
cur->name);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (!got_address || !got_adapter) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("'adapter' and 'address' must be specified for scsi "
|
||||
"hostdev source"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(bus);
|
||||
VIR_FREE(target);
|
||||
VIR_FREE(unit);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
|
||||
xmlXPathContextPtr ctxt,
|
||||
@ -3761,6 +3856,12 @@ 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"),
|
||||
@ -8623,6 +8724,13 @@ virDomainHostdevDefParseXML(const xmlNodePtr node,
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
|
||||
if (def->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("SCSI host devices must have address specified"));
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9150,6 +9258,17 @@ virDomainHostdevMatchSubsysPCI(virDomainHostdevDefPtr a,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virDomainHostdevMatchSubsysSCSI(virDomainHostdevDefPtr a,
|
||||
virDomainHostdevDefPtr b)
|
||||
{
|
||||
if (STREQ(a->source.subsys.u.scsi.adapter, b->source.subsys.u.scsi.adapter) &&
|
||||
a->source.subsys.u.scsi.bus == b->source.subsys.u.scsi.bus &&
|
||||
a->source.subsys.u.scsi.target == b->source.subsys.u.scsi.target &&
|
||||
a->source.subsys.u.scsi.unit == b->source.subsys.u.scsi.unit)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a,
|
||||
@ -9163,6 +9282,8 @@ virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a,
|
||||
return virDomainHostdevMatchSubsysPCI(a, b);
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
||||
return virDomainHostdevMatchSubsysUSB(a, b);
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
|
||||
return virDomainHostdevMatchSubsysSCSI(a, b);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -12987,6 +13108,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, -1) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Based on the declared <address/> info for any devices,
|
||||
@ -13023,6 +13168,9 @@ virDomainDefAddImplicitControllers(virDomainDefPtr def)
|
||||
if (virDomainDefMaybeAddSmartcardController(def) < 0)
|
||||
return -1;
|
||||
|
||||
if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -13928,6 +14076,15 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf,
|
||||
virBufferAddLit(buf, "</origstates>\n");
|
||||
}
|
||||
break;
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
|
||||
virBufferAsprintf(buf, "<adapter name='%s'/>\n",
|
||||
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;
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unexpected hostdev type %d"),
|
||||
|
@ -384,6 +384,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
|
||||
};
|
||||
@ -417,6 +418,12 @@ struct _virDomainHostdevSubsys {
|
||||
virDevicePCIAddress addr; /* host address */
|
||||
int backend; /* enum virDomainHostdevSubsysPciBackendType */
|
||||
} pci;
|
||||
struct {
|
||||
char *adapter;
|
||||
unsigned bus;
|
||||
unsigned target;
|
||||
unsigned unit;
|
||||
} scsi;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
35
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml
Normal file
35
tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi.xml
Normal file
@ -0,0 +1,35 @@
|
||||
<domain type='qemu'>
|
||||
<name>QEMUGuest2</name>
|
||||
<uuid>c7a5fdbd-edaf-9466-926a-d65c16db1809</uuid>
|
||||
<memory unit='KiB'>219100</memory>
|
||||
<currentMemory unit='KiB'>219100</currentMemory>
|
||||
<vcpu placement='static'>1</vcpu>
|
||||
<os>
|
||||
<type arch='i686' machine='pc'>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu</emulator>
|
||||
<disk type='block' device='disk'>
|
||||
<source dev='/dev/HostVG/QEMUGuest2'/>
|
||||
<target dev='hda' bus='ide'/>
|
||||
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
||||
</disk>
|
||||
<controller type='scsi' index='0' model='virtio-scsi'/>
|
||||
<controller type='usb' index='0'/>
|
||||
<controller type='ide' index='0'/>
|
||||
<controller type='pci' index='0' model='pci-root'/>
|
||||
<hostdev mode='subsystem' type='scsi' managed='yes'>
|
||||
<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>
|
||||
<memballoon model='virtio'/>
|
||||
</devices>
|
||||
</domain>
|
@ -285,6 +285,8 @@ mymain(void)
|
||||
DO_TEST_DIFFERENT("pci-autoadd-addr");
|
||||
DO_TEST_DIFFERENT("pci-autoadd-idx");
|
||||
|
||||
DO_TEST("hostdev-scsi");
|
||||
|
||||
virObjectUnref(driver.caps);
|
||||
virObjectUnref(driver.xmlopt);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user