ddf19c
From b73e3e52f76db823d7bffe3f705f575ca413863b Mon Sep 17 00:00:00 2001
ddf19c
From: Cornelia Huck <cohuck@redhat.com>
ddf19c
Date: Tue, 23 Jun 2020 09:25:39 -0400
ddf19c
Subject: [PATCH 05/12] vfio-ccw: Add support for the schib region
ddf19c
ddf19c
RH-Author: Cornelia Huck <cohuck@redhat.com>
ddf19c
Message-id: <20200623092543.358315-6-cohuck@redhat.com>
ddf19c
Patchwork-id: 97697
ddf19c
O-Subject: [RHEL-8.3.0 qemu-kvm PATCH 5/9] vfio-ccw: Add support for the schib region
ddf19c
Bugzilla: 1660916
ddf19c
RH-Acked-by: Claudio Imbrenda <cimbrend@redhat.com>
ddf19c
RH-Acked-by: David Hildenbrand <david@redhat.com>
ddf19c
RH-Acked-by: Thomas Huth <thuth@redhat.com>
ddf19c
ddf19c
From: Farhan Ali <alifm@linux.ibm.com>
ddf19c
ddf19c
The schib region can be used to obtain the latest SCHIB from the host
ddf19c
passthrough subchannel. Since the guest SCHIB is virtualized,
ddf19c
we currently only update the path related information so that the
ddf19c
guest is aware of any path related changes when it issues the
ddf19c
'stsch' instruction.
ddf19c
ddf19c
Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
ddf19c
Signed-off-by: Eric Farman <farman@linux.ibm.com>
ddf19c
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
ddf19c
Message-Id: <20200505125757.98209-4-farman@linux.ibm.com>
ddf19c
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
ddf19c
(cherry picked from commit 46ea3841edaff2a7657b8f6c7f474e5e3850cd62)
ddf19c
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
ddf19c
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ddf19c
---
ddf19c
 hw/s390x/css.c              | 13 ++++++--
ddf19c
 hw/s390x/s390-ccw.c         | 21 +++++++++++++
ddf19c
 hw/vfio/ccw.c               | 63 +++++++++++++++++++++++++++++++++++++
ddf19c
 include/hw/s390x/css.h      |  3 +-
ddf19c
 include/hw/s390x/s390-ccw.h |  1 +
ddf19c
 target/s390x/ioinst.c       |  3 +-
ddf19c
 6 files changed, 99 insertions(+), 5 deletions(-)
ddf19c
ddf19c
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
ddf19c
index 844caab408..71fd3f9a00 100644
ddf19c
--- a/hw/s390x/css.c
ddf19c
+++ b/hw/s390x/css.c
ddf19c
@@ -1335,11 +1335,20 @@ static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src)
ddf19c
     }
ddf19c
 }
ddf19c
 
ddf19c
-int css_do_stsch(SubchDev *sch, SCHIB *schib)
ddf19c
+IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib)
ddf19c
 {
ddf19c
+    int ret;
ddf19c
+
ddf19c
+    /*
ddf19c
+     * For some subchannels, we may want to update parts of
ddf19c
+     * the schib (e.g., update path masks from the host device
ddf19c
+     * for passthrough subchannels).
ddf19c
+     */
ddf19c
+    ret = s390_ccw_store(sch);
ddf19c
+
ddf19c
     /* Use current status. */
ddf19c
     copy_schib_to_guest(schib, &sch->curr_status);
ddf19c
-    return 0;
ddf19c
+    return ret;
ddf19c
 }
ddf19c
 
ddf19c
 static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src)
ddf19c
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
ddf19c
index 0c5a5b60bd..75b788c95e 100644
ddf19c
--- a/hw/s390x/s390-ccw.c
ddf19c
+++ b/hw/s390x/s390-ccw.c
ddf19c
@@ -51,6 +51,27 @@ int s390_ccw_clear(SubchDev *sch)
ddf19c
     return cdc->handle_clear(sch);
ddf19c
 }
ddf19c
 
ddf19c
+IOInstEnding s390_ccw_store(SubchDev *sch)
ddf19c
+{
ddf19c
+    S390CCWDeviceClass *cdc = NULL;
ddf19c
+    int ret = IOINST_CC_EXPECTED;
ddf19c
+
ddf19c
+    /*
ddf19c
+     * This code is called for both virtual and passthrough devices,
ddf19c
+     * but only applies to to the latter.  This ugly check makes that
ddf19c
+     * distinction for us.
ddf19c
+     */
ddf19c
+    if (object_dynamic_cast(OBJECT(sch->driver_data), TYPE_S390_CCW)) {
ddf19c
+        cdc = S390_CCW_DEVICE_GET_CLASS(sch->driver_data);
ddf19c
+    }
ddf19c
+
ddf19c
+    if (cdc && cdc->handle_store) {
ddf19c
+        ret = cdc->handle_store(sch);
ddf19c
+    }
ddf19c
+
ddf19c
+    return ret;
ddf19c
+}
ddf19c
+
ddf19c
 static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
ddf19c
                                   char *sysfsdev,
ddf19c
                                   Error **errp)
ddf19c
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
ddf19c
index 17eb4c4048..859ad646f1 100644
ddf19c
--- a/hw/vfio/ccw.c
ddf19c
+++ b/hw/vfio/ccw.c
ddf19c
@@ -41,6 +41,9 @@ struct VFIOCCWDevice {
ddf19c
     uint64_t async_cmd_region_size;
ddf19c
     uint64_t async_cmd_region_offset;
ddf19c
     struct ccw_cmd_region *async_cmd_region;
ddf19c
+    uint64_t schib_region_size;
ddf19c
+    uint64_t schib_region_offset;
ddf19c
+    struct ccw_schib_region *schib_region;
ddf19c
     EventNotifier io_notifier;
ddf19c
     bool force_orb_pfch;
ddf19c
     bool warned_orb_pfch;
ddf19c
@@ -116,6 +119,51 @@ again:
ddf19c
     }
ddf19c
 }
ddf19c
 
ddf19c
+static IOInstEnding vfio_ccw_handle_store(SubchDev *sch)
ddf19c
+{
ddf19c
+    S390CCWDevice *cdev = sch->driver_data;
ddf19c
+    VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
ddf19c
+    SCHIB *schib = &sch->curr_status;
ddf19c
+    struct ccw_schib_region *region = vcdev->schib_region;
ddf19c
+    SCHIB *s;
ddf19c
+    int ret;
ddf19c
+
ddf19c
+    /* schib region not available so nothing else to do */
ddf19c
+    if (!region) {
ddf19c
+        return IOINST_CC_EXPECTED;
ddf19c
+    }
ddf19c
+
ddf19c
+    memset(region, 0, sizeof(*region));
ddf19c
+    ret = pread(vcdev->vdev.fd, region, vcdev->schib_region_size,
ddf19c
+                vcdev->schib_region_offset);
ddf19c
+
ddf19c
+    if (ret == -1) {
ddf19c
+        /*
ddf19c
+         * Device is probably damaged, but store subchannel does not
ddf19c
+         * have a nonzero cc defined for this scenario.  Log an error,
ddf19c
+         * and presume things are otherwise fine.
ddf19c
+         */
ddf19c
+        error_report("vfio-ccw: store region read failed with errno=%d", errno);
ddf19c
+        return IOINST_CC_EXPECTED;
ddf19c
+    }
ddf19c
+
ddf19c
+    /*
ddf19c
+     * Selectively copy path-related bits of the SCHIB,
ddf19c
+     * rather than copying the entire struct.
ddf19c
+     */
ddf19c
+    s = (SCHIB *)region->schib_area;
ddf19c
+    schib->pmcw.pnom = s->pmcw.pnom;
ddf19c
+    schib->pmcw.lpum = s->pmcw.lpum;
ddf19c
+    schib->pmcw.pam = s->pmcw.pam;
ddf19c
+    schib->pmcw.pom = s->pmcw.pom;
ddf19c
+
ddf19c
+    if (s->scsw.flags & SCSW_FLAGS_MASK_PNO) {
ddf19c
+        schib->scsw.flags |= SCSW_FLAGS_MASK_PNO;
ddf19c
+    }
ddf19c
+
ddf19c
+    return IOINST_CC_EXPECTED;
ddf19c
+}
ddf19c
+
ddf19c
 static int vfio_ccw_handle_clear(SubchDev *sch)
ddf19c
 {
ddf19c
     S390CCWDevice *cdev = sch->driver_data;
ddf19c
@@ -382,10 +430,23 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
ddf19c
         vcdev->async_cmd_region = g_malloc0(info->size);
ddf19c
     }
ddf19c
 
ddf19c
+    ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW,
ddf19c
+                                   VFIO_REGION_SUBTYPE_CCW_SCHIB, &info;;
ddf19c
+    if (!ret) {
ddf19c
+        vcdev->schib_region_size = info->size;
ddf19c
+        if (sizeof(*vcdev->schib_region) != vcdev->schib_region_size) {
ddf19c
+            error_setg(errp, "vfio: Unexpected size of the schib region");
ddf19c
+            goto out_err;
ddf19c
+        }
ddf19c
+        vcdev->schib_region_offset = info->offset;
ddf19c
+        vcdev->schib_region = g_malloc(info->size);
ddf19c
+    }
ddf19c
+
ddf19c
     g_free(info);
ddf19c
     return;
ddf19c
 
ddf19c
 out_err:
ddf19c
+    g_free(vcdev->schib_region);
ddf19c
     g_free(vcdev->async_cmd_region);
ddf19c
     g_free(vcdev->io_region);
ddf19c
     g_free(info);
ddf19c
@@ -394,6 +455,7 @@ out_err:
ddf19c
 
ddf19c
 static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
ddf19c
 {
ddf19c
+    g_free(vcdev->schib_region);
ddf19c
     g_free(vcdev->async_cmd_region);
ddf19c
     g_free(vcdev->io_region);
ddf19c
 }
ddf19c
@@ -569,6 +631,7 @@ static void vfio_ccw_class_init(ObjectClass *klass, void *data)
ddf19c
     cdc->handle_request = vfio_ccw_handle_request;
ddf19c
     cdc->handle_halt = vfio_ccw_handle_halt;
ddf19c
     cdc->handle_clear = vfio_ccw_handle_clear;
ddf19c
+    cdc->handle_store = vfio_ccw_handle_store;
ddf19c
 }
ddf19c
 
ddf19c
 static const TypeInfo vfio_ccw_info = {
ddf19c
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h
ddf19c
index f46bcafb16..7e3a5e7433 100644
ddf19c
--- a/include/hw/s390x/css.h
ddf19c
+++ b/include/hw/s390x/css.h
ddf19c
@@ -218,6 +218,7 @@ IOInstEnding do_subchannel_work_passthrough(SubchDev *sub);
ddf19c
 
ddf19c
 int s390_ccw_halt(SubchDev *sch);
ddf19c
 int s390_ccw_clear(SubchDev *sch);
ddf19c
+IOInstEnding s390_ccw_store(SubchDev *sch);
ddf19c
 
ddf19c
 typedef enum {
ddf19c
     CSS_IO_ADAPTER_VIRTIO = 0,
ddf19c
@@ -242,7 +243,7 @@ SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid,
ddf19c
                          uint16_t schid);
ddf19c
 bool css_subch_visible(SubchDev *sch);
ddf19c
 void css_conditional_io_interrupt(SubchDev *sch);
ddf19c
-int css_do_stsch(SubchDev *sch, SCHIB *schib);
ddf19c
+IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib);
ddf19c
 bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid);
ddf19c
 IOInstEnding css_do_msch(SubchDev *sch, const SCHIB *schib);
ddf19c
 IOInstEnding css_do_xsch(SubchDev *sch);
ddf19c
diff --git a/include/hw/s390x/s390-ccw.h b/include/hw/s390x/s390-ccw.h
ddf19c
index fffb54562f..4a43803ef2 100644
ddf19c
--- a/include/hw/s390x/s390-ccw.h
ddf19c
+++ b/include/hw/s390x/s390-ccw.h
ddf19c
@@ -37,6 +37,7 @@ typedef struct S390CCWDeviceClass {
ddf19c
     IOInstEnding (*handle_request) (SubchDev *sch);
ddf19c
     int (*handle_halt) (SubchDev *sch);
ddf19c
     int (*handle_clear) (SubchDev *sch);
ddf19c
+    IOInstEnding (*handle_store) (SubchDev *sch);
ddf19c
 } S390CCWDeviceClass;
ddf19c
 
ddf19c
 #endif
ddf19c
diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
ddf19c
index f40c35c6ff..b6be300cc4 100644
ddf19c
--- a/target/s390x/ioinst.c
ddf19c
+++ b/target/s390x/ioinst.c
ddf19c
@@ -292,8 +292,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
ddf19c
     sch = css_find_subch(m, cssid, ssid, schid);
ddf19c
     if (sch) {
ddf19c
         if (css_subch_visible(sch)) {
ddf19c
-            css_do_stsch(sch, &schib);
ddf19c
-            cc = 0;
ddf19c
+            cc = css_do_stsch(sch, &schib);
ddf19c
         } else {
ddf19c
             /* Indicate no more subchannels in this css/ss */
ddf19c
             cc = 3;
ddf19c
-- 
ddf19c
2.27.0
ddf19c