c480ed
From fddd43e717869d56e481c3fde2d5ee6b5513a1f5 Mon Sep 17 00:00:00 2001
c480ed
Message-Id: <fddd43e717869d56e481c3fde2d5ee6b5513a1f5@dist-git>
c480ed
From: Yi Min Zhao <zyimin@linux.ibm.com>
c480ed
Date: Mon, 8 Apr 2019 10:57:25 +0200
c480ed
Subject: [PATCH] conf: Introduce parser, formatter for uid and fid
c480ed
MIME-Version: 1.0
c480ed
Content-Type: text/plain; charset=UTF-8
c480ed
Content-Transfer-Encoding: 8bit
c480ed
c480ed
This patch introduces new XML parser/formatter functions. Uid is
c480ed
16-bit and non-zero. Fid is 32-bit. They are the two attributes of zpci
c480ed
which is introduced as PCI address element. Zpci element is parsed and
c480ed
formatted along with PCI address. And add the related test cases.
c480ed
c480ed
Signed-off-by: Yi Min Zhao <zyimin@linux.ibm.com>
c480ed
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
c480ed
Reviewed-by: Stefan Zimmermann <stzi@linux.ibm.com>
c480ed
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
c480ed
Reviewed-by: Ján Tomko <jtomko@redhat.com>
c480ed
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
c480ed
c480ed
(cherry picked from commit b4833b2c2f7be8a68eb6495ed57ed61918e3ecd8)
c480ed
c480ed
https://bugzilla.redhat.com/show_bug.cgi?id=1508149
c480ed
c480ed
Conflicts:
c480ed
c480ed
  * src/conf/device_conf.c
c480ed
    + context
c480ed
      - missing edeef779585
c480ed
c480ed
  * tests/qemuxml2argvtest.c
c480ed
    + context
c480ed
      - missing a0ff9fbe5cad, 0bdb704383f7
c480ed
c480ed
Changed:
c480ed
c480ed
  * tests/qemuxml2argvdata/disk-virtio-s390-zpci.args
c480ed
    tests/qemuxml2argvdata/hostdev-vfio-zpci.args
c480ed
    + no -boot in output
c480ed
      - missing caccbba64aa9
c480ed
c480ed
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
c480ed
Message-Id: <20190408085732.28684-9-abologna@redhat.com>
c480ed
Reviewed-by: Laine Stump <laine@redhat.com>
c480ed
Reviewed-by: Ján Tomko <jtomko@redhat.com>
c480ed
---
c480ed
 docs/schemas/basictypes.rng                   | 27 ++++++++++
c480ed
 docs/schemas/domaincommon.rng                 |  1 +
c480ed
 src/conf/device_conf.c                        | 53 +++++++++++++++++++
c480ed
 src/conf/domain_addr.c                        |  3 ++
c480ed
 src/conf/domain_conf.c                        | 12 ++++-
c480ed
 src/libvirt_private.syms                      |  2 +
c480ed
 src/util/virpci.c                             | 26 +++++++++
c480ed
 src/util/virpci.h                             |  6 +++
c480ed
 .../disk-virtio-s390-zpci.args                | 26 +++++++++
c480ed
 .../disk-virtio-s390-zpci.xml                 | 19 +++++++
c480ed
 tests/qemuxml2argvdata/hostdev-vfio-zpci.args | 24 +++++++++
c480ed
 tests/qemuxml2argvdata/hostdev-vfio-zpci.xml  | 21 ++++++++
c480ed
 tests/qemuxml2argvtest.c                      |  7 +++
c480ed
 .../disk-virtio-s390-zpci.xml                 | 31 +++++++++++
c480ed
 .../qemuxml2xmloutdata/hostdev-vfio-zpci.xml  | 32 +++++++++++
c480ed
 tests/qemuxml2xmltest.c                       |  6 +++
c480ed
 16 files changed, 295 insertions(+), 1 deletion(-)
c480ed
 create mode 100644 tests/qemuxml2argvdata/disk-virtio-s390-zpci.args
c480ed
 create mode 100644 tests/qemuxml2argvdata/disk-virtio-s390-zpci.xml
c480ed
 create mode 100644 tests/qemuxml2argvdata/hostdev-vfio-zpci.args
c480ed
 create mode 100644 tests/qemuxml2argvdata/hostdev-vfio-zpci.xml
c480ed
 create mode 100644 tests/qemuxml2xmloutdata/disk-virtio-s390-zpci.xml
c480ed
 create mode 100644 tests/qemuxml2xmloutdata/hostdev-vfio-zpci.xml
c480ed
c480ed
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
c480ed
index b45a7fcdc8..97e14d7ca8 100644
c480ed
--- a/docs/schemas/basictypes.rng
c480ed
+++ b/docs/schemas/basictypes.rng
c480ed
@@ -65,6 +65,17 @@
c480ed
       </data>
c480ed
     </choice>
c480ed
   </define>
c480ed
+  <define name="uint32">
c480ed
+    <choice>
c480ed
+      <data type="string">
c480ed
+        <param name="pattern">(0x)?[0-9a-fA-F]{1,8}</param>
c480ed
+      </data>
c480ed
+      <data type="unsignedInt">
c480ed
+        <param name="minInclusive">0</param>
c480ed
+        <param name="maxInclusive">4294967295</param>
c480ed
+      </data>
c480ed
+    </choice>
c480ed
+  </define>
c480ed
 
c480ed
   <define name="UUID">
c480ed
     <choice>
c480ed
@@ -111,6 +122,22 @@
c480ed
       </attribute>
c480ed
     </optional>
c480ed
   </define>
c480ed
+  <define name="zpciaddress">
c480ed
+    <optional>
c480ed
+      <element name="zpci">
c480ed
+        <optional>
c480ed
+          <attribute name="uid">
c480ed
+            <ref name="uint16"/>
c480ed
+          </attribute>
c480ed
+        </optional>
c480ed
+        <optional>
c480ed
+          <attribute name="fid">
c480ed
+            <ref name="uint32"/>
c480ed
+          </attribute>
c480ed
+        </optional>
c480ed
+      </element>
c480ed
+    </optional>
c480ed
+  </define>
c480ed
 
c480ed
   
c480ed
   
c480ed
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
c480ed
index 70a7767d9c..2b6d4dced6 100644
c480ed
--- a/docs/schemas/domaincommon.rng
c480ed
+++ b/docs/schemas/domaincommon.rng
c480ed
@@ -5186,6 +5186,7 @@
c480ed
             <value>pci</value>
c480ed
           </attribute>
c480ed
           <ref name="pciaddress"/>
c480ed
+          <ref name="zpciaddress"/>
c480ed
         </group>
c480ed
         <group>
c480ed
           <attribute name="type">
c480ed
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c
c480ed
index d69f94fadf..cadac32603 100644
c480ed
--- a/src/conf/device_conf.c
c480ed
+++ b/src/conf/device_conf.c
c480ed
@@ -32,6 +32,45 @@
c480ed
 
c480ed
 #define VIR_FROM_THIS VIR_FROM_DEVICE
c480ed
 
c480ed
+static int
c480ed
+virZPCIDeviceAddressParseXML(xmlNodePtr node,
c480ed
+                             virPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    virZPCIDeviceAddress def = { 0 };
c480ed
+    char *uid;
c480ed
+    char *fid;
c480ed
+    int ret = -1;
c480ed
+
c480ed
+    uid = virXMLPropString(node, "uid");
c480ed
+    fid = virXMLPropString(node, "fid");
c480ed
+
c480ed
+    if (uid &&
c480ed
+        virStrToLong_uip(uid, NULL, 0, &def.uid) < 0) {
c480ed
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
c480ed
+                       _("Cannot parse <address> 'uid' attribute"));
c480ed
+        goto cleanup;
c480ed
+    }
c480ed
+
c480ed
+    if (fid &&
c480ed
+        virStrToLong_uip(fid, NULL, 0, &def.fid) < 0) {
c480ed
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
c480ed
+                       _("Cannot parse <address> 'fid' attribute"));
c480ed
+        goto cleanup;
c480ed
+    }
c480ed
+
c480ed
+    if (!virZPCIDeviceAddressIsEmpty(&def) &&
c480ed
+        !virZPCIDeviceAddressIsValid(&def))
c480ed
+        goto cleanup;
c480ed
+
c480ed
+    addr->zpci = def;
c480ed
+    ret = 0;
c480ed
+
c480ed
+ cleanup:
c480ed
+    VIR_FREE(uid);
c480ed
+    VIR_FREE(fid);
c480ed
+    return ret;
c480ed
+}
c480ed
+
c480ed
 int
c480ed
 virDomainDeviceInfoCopy(virDomainDeviceInfoPtr dst,
c480ed
                         virDomainDeviceInfoPtr src)
c480ed
@@ -196,6 +235,8 @@ virPCIDeviceAddressParseXML(xmlNodePtr node,
c480ed
                             virPCIDeviceAddressPtr addr)
c480ed
 {
c480ed
     char *domain, *slot, *bus, *function, *multi;
c480ed
+    xmlNodePtr cur;
c480ed
+    xmlNodePtr zpci = NULL;
c480ed
     int ret = -1;
c480ed
 
c480ed
     memset(addr, 0, sizeof(*addr));
c480ed
@@ -245,6 +286,18 @@ virPCIDeviceAddressParseXML(xmlNodePtr node,
c480ed
     if (!virPCIDeviceAddressIsEmpty(addr) && !virPCIDeviceAddressIsValid(addr, true))
c480ed
         goto cleanup;
c480ed
 
c480ed
+    cur = node->children;
c480ed
+    while (cur) {
c480ed
+        if (cur->type == XML_ELEMENT_NODE &&
c480ed
+            virXMLNodeNameEqual(cur, "zpci")) {
c480ed
+            zpci = cur;
c480ed
+        }
c480ed
+        cur = cur->next;
c480ed
+    }
c480ed
+
c480ed
+    if (zpci && virZPCIDeviceAddressParseXML(zpci, addr) < 0)
c480ed
+        goto cleanup;
c480ed
+
c480ed
     ret = 0;
c480ed
 
c480ed
  cleanup:
c480ed
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
c480ed
index 3e33549c3d..9e0a0fdf95 100644
c480ed
--- a/src/conf/domain_addr.c
c480ed
+++ b/src/conf/domain_addr.c
c480ed
@@ -1054,6 +1054,9 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
c480ed
                                                dev->isolationGroup, false) < 0)
c480ed
         return -1;
c480ed
 
c480ed
+    addr.extFlags = dev->addr.pci.extFlags;
c480ed
+    addr.zpci = dev->addr.pci.zpci;
c480ed
+
c480ed
     if (!addrs->dryRun) {
c480ed
         dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
c480ed
         dev->addr.pci = addr;
c480ed
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
c480ed
index bcb0558bc3..29ebf0a930 100644
c480ed
--- a/src/conf/domain_conf.c
c480ed
+++ b/src/conf/domain_conf.c
c480ed
@@ -6448,6 +6448,7 @@ virDomainDeviceInfoFormat(virBufferPtr buf,
c480ed
                           unsigned int flags)
c480ed
 {
c480ed
     virBuffer attrBuf = VIR_BUFFER_INITIALIZER;
c480ed
+    virBuffer childBuf = VIR_BUFFER_INITIALIZER;
c480ed
 
c480ed
     if ((flags & VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT) && info->bootIndex) {
c480ed
         virBufferAsprintf(buf, "<boot order='%u'", info->bootIndex);
c480ed
@@ -6510,6 +6511,14 @@ virDomainDeviceInfoFormat(virBufferPtr buf,
c480ed
             virBufferAsprintf(&attrBuf, " multifunction='%s'",
c480ed
                               virTristateSwitchTypeToString(info->addr.pci.multi));
c480ed
         }
c480ed
+
c480ed
+        if (!virZPCIDeviceAddressIsEmpty(&info->addr.pci.zpci)) {
c480ed
+            virBufferSetChildIndent(&childBuf, buf);
c480ed
+            virBufferAsprintf(&childBuf,
c480ed
+                              "<zpci uid='0x%.4x' fid='0x%.8x'/>\n",
c480ed
+                              info->addr.pci.zpci.uid,
c480ed
+                              info->addr.pci.zpci.fid);
c480ed
+        }
c480ed
         break;
c480ed
 
c480ed
     case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
c480ed
@@ -6577,9 +6586,10 @@ virDomainDeviceInfoFormat(virBufferPtr buf,
c480ed
         break;
c480ed
     }
c480ed
 
c480ed
-    virXMLFormatElement(buf, "address", &attrBuf, NULL);
c480ed
+    virXMLFormatElement(buf, "address", &attrBuf, &childBuf);
c480ed
 
c480ed
     virBufferFreeAndReset(&attrBuf);
c480ed
+    virBufferFreeAndReset(&childBuf);
c480ed
 }
c480ed
 
c480ed
 static int
c480ed
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
c480ed
index df27ac4b3a..b2a2a1f265 100644
c480ed
--- a/src/libvirt_private.syms
c480ed
+++ b/src/libvirt_private.syms
c480ed
@@ -2569,6 +2569,8 @@ virPCIHeaderTypeToString;
c480ed
 virPCIIsVirtualFunction;
c480ed
 virPCIStubDriverTypeFromString;
c480ed
 virPCIStubDriverTypeToString;
c480ed
+virZPCIDeviceAddressIsEmpty;
c480ed
+virZPCIDeviceAddressIsValid;
c480ed
 
c480ed
 
c480ed
 # util/virperf.h
c480ed
diff --git a/src/util/virpci.c b/src/util/virpci.c
c480ed
index 8d02366664..3a1e49a7a7 100644
c480ed
--- a/src/util/virpci.c
c480ed
+++ b/src/util/virpci.c
c480ed
@@ -2597,6 +2597,32 @@ virPCIDeviceAddressParse(char *address,
c480ed
 
c480ed
 #ifdef __linux__
c480ed
 
c480ed
+bool
c480ed
+virZPCIDeviceAddressIsValid(virZPCIDeviceAddressPtr zpci)
c480ed
+{
c480ed
+    /* We don't need to check fid because fid covers
c480ed
+     * all range of uint32 type.
c480ed
+     */
c480ed
+    if (zpci->uid > VIR_DOMAIN_DEVICE_ZPCI_MAX_UID ||
c480ed
+        zpci->uid == 0) {
c480ed
+        virReportError(VIR_ERR_XML_ERROR,
c480ed
+                       _("Invalid PCI address uid='0x%.4x', "
c480ed
+                         "must be > 0x0000 and <= 0x%.4x"),
c480ed
+                       zpci->uid,
c480ed
+                       VIR_DOMAIN_DEVICE_ZPCI_MAX_UID);
c480ed
+        return false;
c480ed
+    }
c480ed
+
c480ed
+    return true;
c480ed
+}
c480ed
+
c480ed
+bool
c480ed
+virZPCIDeviceAddressIsEmpty(const virZPCIDeviceAddress *addr)
c480ed
+{
c480ed
+    return !(addr->uid || addr->fid);
c480ed
+}
c480ed
+
c480ed
+
c480ed
 /*
c480ed
  * returns true if equal
c480ed
  */
c480ed
diff --git a/src/util/virpci.h b/src/util/virpci.h
c480ed
index b366d7d9c3..1ed9e2381e 100644
c480ed
--- a/src/util/virpci.h
c480ed
+++ b/src/util/virpci.h
c480ed
@@ -36,6 +36,9 @@ typedef virPCIDeviceAddress *virPCIDeviceAddressPtr;
c480ed
 typedef struct _virPCIDeviceList virPCIDeviceList;
c480ed
 typedef virPCIDeviceList *virPCIDeviceListPtr;
c480ed
 
c480ed
+# define VIR_DOMAIN_DEVICE_ZPCI_MAX_UID UINT16_MAX
c480ed
+# define VIR_DOMAIN_DEVICE_ZPCI_MAX_FID UINT32_MAX
c480ed
+
c480ed
 typedef struct _virZPCIDeviceAddress virZPCIDeviceAddress;
c480ed
 typedef virZPCIDeviceAddress *virZPCIDeviceAddressPtr;
c480ed
 struct _virZPCIDeviceAddress {
c480ed
@@ -235,6 +238,9 @@ int virPCIGetAddrString(unsigned int domain,
c480ed
 
c480ed
 int virPCIDeviceAddressParse(char *address, virPCIDeviceAddressPtr bdf);
c480ed
 
c480ed
+bool virZPCIDeviceAddressIsValid(virZPCIDeviceAddressPtr zpci);
c480ed
+bool virZPCIDeviceAddressIsEmpty(const virZPCIDeviceAddress *addr);
c480ed
+
c480ed
 int virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path,
c480ed
                                  int pfNetDevIdx,
c480ed
                                  char **pfname,
c480ed
diff --git a/tests/qemuxml2argvdata/disk-virtio-s390-zpci.args b/tests/qemuxml2argvdata/disk-virtio-s390-zpci.args
c480ed
new file mode 100644
c480ed
index 0000000000..20e63a15b5
c480ed
--- /dev/null
c480ed
+++ b/tests/qemuxml2argvdata/disk-virtio-s390-zpci.args
c480ed
@@ -0,0 +1,26 @@
c480ed
+LC_ALL=C \
c480ed
+PATH=/bin \
c480ed
+HOME=/home/test \
c480ed
+USER=test \
c480ed
+LOGNAME=test \
c480ed
+QEMU_AUDIO_DRV=none \
c480ed
+/usr/bin/qemu-system-s390x \
c480ed
+-name QEMUGuest1 \
c480ed
+-S \
c480ed
+-machine s390-ccw-virtio,accel=tcg,usb=off,dump-guest-core=off \
c480ed
+-m 214 \
c480ed
+-smp 1,sockets=1,cores=1,threads=1 \
c480ed
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
c480ed
+-display none \
c480ed
+-no-user-config \
c480ed
+-nodefaults \
c480ed
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
c480ed
+server,nowait \
c480ed
+-mon chardev=charmonitor,id=monitor,mode=control \
c480ed
+-rtc base=utc \
c480ed
+-no-shutdown \
c480ed
+-boot c \
c480ed
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk0 \
c480ed
+-device virtio-blk-pci,bus=pci.0,addr=0x8,drive=drive-virtio-disk0,\
c480ed
+id=virtio-disk0 \
c480ed
+-device virtio-balloon-ccw,id=balloon0,devno=fe.0.0000
c480ed
diff --git a/tests/qemuxml2argvdata/disk-virtio-s390-zpci.xml b/tests/qemuxml2argvdata/disk-virtio-s390-zpci.xml
c480ed
new file mode 100644
c480ed
index 0000000000..8bf4a23670
c480ed
--- /dev/null
c480ed
+++ b/tests/qemuxml2argvdata/disk-virtio-s390-zpci.xml
c480ed
@@ -0,0 +1,19 @@
c480ed
+<domain type='qemu'>
c480ed
+  <name>QEMUGuest1</name>
c480ed
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
c480ed
+  <memory>219136</memory>
c480ed
+  <vcpu>1</vcpu>
c480ed
+  <os>
c480ed
+    <type arch='s390x' machine='s390-ccw-virtio'>hvm</type>
c480ed
+  </os>
c480ed
+  <devices>
c480ed
+    <emulator>/usr/bin/qemu-system-s390x</emulator>
c480ed
+    <disk type='block' device='disk'>
c480ed
+      <source dev='/dev/HostVG/QEMUGuest1'/>
c480ed
+      <target dev='hda' bus='virtio'/>
c480ed
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'>
c480ed
+        <zpci uid='0x0019' fid='0x0000001f'/>
c480ed
+      </address>
c480ed
+    </disk>
c480ed
+  </devices>
c480ed
+</domain>
c480ed
diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci.args b/tests/qemuxml2argvdata/hostdev-vfio-zpci.args
c480ed
new file mode 100644
c480ed
index 0000000000..622c504da0
c480ed
--- /dev/null
c480ed
+++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci.args
c480ed
@@ -0,0 +1,24 @@
c480ed
+LC_ALL=C \
c480ed
+PATH=/bin \
c480ed
+HOME=/home/test \
c480ed
+USER=test \
c480ed
+LOGNAME=test \
c480ed
+QEMU_AUDIO_DRV=none \
c480ed
+/usr/bin/qemu-system-s390x \
c480ed
+-name QEMUGuest1 \
c480ed
+-S \
c480ed
+-machine s390-ccw-virtio,accel=tcg,usb=off,dump-guest-core=off \
c480ed
+-m 214 \
c480ed
+-smp 1,sockets=1,cores=1,threads=1 \
c480ed
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
c480ed
+-display none \
c480ed
+-no-user-config \
c480ed
+-nodefaults \
c480ed
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
c480ed
+server,nowait \
c480ed
+-mon chardev=charmonitor,id=monitor,mode=control \
c480ed
+-rtc base=utc \
c480ed
+-no-shutdown \
c480ed
+-boot c \
c480ed
+-device vfio-pci,host=00:00.0,id=hostdev0,bus=pci.0,addr=0x8 \
c480ed
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x1
c480ed
diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci.xml
c480ed
new file mode 100644
c480ed
index 0000000000..002b99c52d
c480ed
--- /dev/null
c480ed
+++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci.xml
c480ed
@@ -0,0 +1,21 @@
c480ed
+<domain type='qemu'>
c480ed
+  <name>QEMUGuest1</name>
c480ed
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
c480ed
+  <memory>219100</memory>
c480ed
+  <os>
c480ed
+    <type arch='s390x' machine='s390-ccw-virtio'>hvm</type>
c480ed
+  </os>
c480ed
+  <devices>
c480ed
+    <emulator>/usr/bin/qemu-system-s390x</emulator>
c480ed
+    <controller type='pci' index='0' model='pci-root'/>
c480ed
+    <hostdev mode='subsystem' type='pci' managed='no'>
c480ed
+      <driver name='vfio'/>
c480ed
+      <source>
c480ed
+        <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/>
c480ed
+      </source>
c480ed
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'>
c480ed
+        <zpci uid='0x0019' fid='0x0000001f'/>
c480ed
+      </address>
c480ed
+    </hostdev>
c480ed
+  </devices>
c480ed
+</domain>
c480ed
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
c480ed
index 7f25cccf9d..2eb2505971 100644
c480ed
--- a/tests/qemuxml2argvtest.c
c480ed
+++ b/tests/qemuxml2argvtest.c
c480ed
@@ -1038,6 +1038,10 @@ mymain(void)
c480ed
             QEMU_CAPS_CCW, QEMU_CAPS_VIRTIO_S390);
c480ed
     DO_TEST("disk-virtio-scsi-ccw", QEMU_CAPS_VIRTIO_SCSI,
c480ed
             QEMU_CAPS_CCW, QEMU_CAPS_VIRTIO_S390);
c480ed
+    DO_TEST("disk-virtio-s390-zpci",
c480ed
+            QEMU_CAPS_DEVICE_ZPCI,
c480ed
+            QEMU_CAPS_CCW,
c480ed
+            QEMU_CAPS_VIRTIO_S390);
c480ed
     DO_TEST("disk-order",
c480ed
             QEMU_CAPS_DRIVE_BOOT, QEMU_CAPS_VIRTIO_BLK_SCSI);
c480ed
     DO_TEST("disk-virtio-drive-queues",
c480ed
@@ -1628,6 +1632,9 @@ mymain(void)
c480ed
     DO_TEST_PARSE_ERROR("hostdev-mdev-display-missing-graphics",
c480ed
             QEMU_CAPS_DEVICE_VFIO_PCI,
c480ed
             QEMU_CAPS_VFIO_PCI_DISPLAY);
c480ed
+    DO_TEST("hostdev-vfio-zpci",
c480ed
+            QEMU_CAPS_DEVICE_VFIO_PCI,
c480ed
+            QEMU_CAPS_DEVICE_ZPCI);
c480ed
     DO_TEST("pci-rom", NONE);
c480ed
     DO_TEST("pci-rom-disabled", NONE);
c480ed
     DO_TEST("pci-rom-disabled-invalid", NONE);
c480ed
diff --git a/tests/qemuxml2xmloutdata/disk-virtio-s390-zpci.xml b/tests/qemuxml2xmloutdata/disk-virtio-s390-zpci.xml
c480ed
new file mode 100644
c480ed
index 0000000000..37684c82b1
c480ed
--- /dev/null
c480ed
+++ b/tests/qemuxml2xmloutdata/disk-virtio-s390-zpci.xml
c480ed
@@ -0,0 +1,31 @@
c480ed
+<domain type='qemu'>
c480ed
+  <name>QEMUGuest1</name>
c480ed
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
c480ed
+  <memory unit='KiB'>219136</memory>
c480ed
+  <currentMemory unit='KiB'>219136</currentMemory>
c480ed
+  <vcpu placement='static'>1</vcpu>
c480ed
+  <os>
c480ed
+    <type arch='s390x' machine='s390-ccw-virtio'>hvm</type>
c480ed
+    <boot dev='hd'/>
c480ed
+  </os>
c480ed
+  <clock offset='utc'/>
c480ed
+  <on_poweroff>destroy</on_poweroff>
c480ed
+  <on_reboot>restart</on_reboot>
c480ed
+  <on_crash>destroy</on_crash>
c480ed
+  <devices>
c480ed
+    <emulator>/usr/bin/qemu-system-s390x</emulator>
c480ed
+    <disk type='block' device='disk'>
c480ed
+      <driver name='qemu' type='raw'/>
c480ed
+      <source dev='/dev/HostVG/QEMUGuest1'/>
c480ed
+      <target dev='hda' bus='virtio'/>
c480ed
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'>
c480ed
+        <zpci uid='0x0019' fid='0x0000001f'/>
c480ed
+      </address>
c480ed
+    </disk>
c480ed
+    <controller type='pci' index='0' model='pci-root'/>
c480ed
+    <memballoon model='virtio'>
c480ed
+      <address type='ccw' cssid='0xfe' ssid='0x0' devno='0x0000'/>
c480ed
+    </memballoon>
c480ed
+    <panic model='s390'/>
c480ed
+  </devices>
c480ed
+</domain>
c480ed
diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci.xml b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci.xml
c480ed
new file mode 100644
c480ed
index 0000000000..fc8c38ab66
c480ed
--- /dev/null
c480ed
+++ b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci.xml
c480ed
@@ -0,0 +1,32 @@
c480ed
+<domain type='qemu'>
c480ed
+  <name>QEMUGuest1</name>
c480ed
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
c480ed
+  <memory unit='KiB'>219100</memory>
c480ed
+  <currentMemory unit='KiB'>219100</currentMemory>
c480ed
+  <vcpu placement='static'>1</vcpu>
c480ed
+  <os>
c480ed
+    <type arch='s390x' machine='s390-ccw-virtio'>hvm</type>
c480ed
+    <boot dev='hd'/>
c480ed
+  </os>
c480ed
+  <clock offset='utc'/>
c480ed
+  <on_poweroff>destroy</on_poweroff>
c480ed
+  <on_reboot>restart</on_reboot>
c480ed
+  <on_crash>destroy</on_crash>
c480ed
+  <devices>
c480ed
+    <emulator>/usr/bin/qemu-system-s390x</emulator>
c480ed
+    <controller type='pci' index='0' model='pci-root'/>
c480ed
+    <hostdev mode='subsystem' type='pci' managed='no'>
c480ed
+      <driver name='vfio'/>
c480ed
+      <source>
c480ed
+        <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/>
c480ed
+      </source>
c480ed
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'>
c480ed
+        <zpci uid='0x0019' fid='0x0000001f'/>
c480ed
+      </address>
c480ed
+    </hostdev>
c480ed
+    <memballoon model='virtio'>
c480ed
+      <address type='ccw' cssid='0xfe' ssid='0x0' devno='0x0000'/>
c480ed
+    </memballoon>
c480ed
+    <panic model='s390'/>
c480ed
+  </devices>
c480ed
+</domain>
c480ed
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
c480ed
index 2a2bf01ffa..a787f4f4a3 100644
c480ed
--- a/tests/qemuxml2xmltest.c
c480ed
+++ b/tests/qemuxml2xmltest.c
c480ed
@@ -400,6 +400,9 @@ mymain(void)
c480ed
             QEMU_CAPS_VIRTIO_SCSI);
c480ed
     DO_TEST("disk-virtio-scsi-ioeventfd",
c480ed
             QEMU_CAPS_VIRTIO_SCSI);
c480ed
+    DO_TEST("disk-virtio-s390-zpci",
c480ed
+            QEMU_CAPS_DEVICE_ZPCI,
c480ed
+            QEMU_CAPS_CCW);
c480ed
     DO_TEST("disk-scsi-megasas",
c480ed
             QEMU_CAPS_SCSI_MEGASAS);
c480ed
     DO_TEST("disk-scsi-mptsas1068",
c480ed
@@ -482,6 +485,9 @@ mymain(void)
c480ed
     DO_TEST("hostdev-usb-address", NONE);
c480ed
     DO_TEST("hostdev-pci-address", NONE);
c480ed
     DO_TEST("hostdev-vfio", NONE);
c480ed
+    DO_TEST("hostdev-vfio-zpci",
c480ed
+            QEMU_CAPS_DEVICE_ZPCI,
c480ed
+            QEMU_CAPS_CCW);
c480ed
     DO_TEST("hostdev-mdev-precreated", NONE);
c480ed
     DO_TEST("hostdev-mdev-display", QEMU_CAPS_VFIO_PCI_DISPLAY);
c480ed
     DO_TEST("pci-rom", NONE);
c480ed
-- 
c480ed
2.22.0
c480ed