All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/19] first batch of s390x patches for 4.1
@ 2019-04-25 13:21 ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Cornelia Huck

The following changes since commit 3284aa128153750f14a61e8a96fd085e6f2999b6:

  Merge remote-tracking branch 'remotes/lersek/tags/edk2-pull-2019-04-22' into staging (2019-04-24 13:19:41 +0100)

are available in the Git repository at:

  https://github.com/cohuck/qemu tags/s390x-20190425

for you to fetch changes up to 41c3d4269b1c18d12d33c5bf089dace25d08e82e:

  Merge tag 's390-ccw-bios-2019-04-12' into s390-next-staging (2019-04-25 14:09:20 +0200)

----------------------------------------------------------------
- properly detect page size of initial memory
- support for IPL (boot) from ECKD DASD passed through via vfio-ccw

----------------------------------------------------------------

Cornelia Huck (1):
      Merge tag 's390-ccw-bios-2019-04-12' into s390-next-staging

David Hildenbrand (2):
  s390x/kvm: Configure page size after memory has actually been
    initialized
  exec: Introduce qemu_maxrampagesize() and rename qemu_getrampagesize()

Jason J. Herne (16):
  s390 vfio-ccw: Add bootindex property and IPLB data
  s390-bios: decouple cio setup from virtio
  s390-bios: decouple common boot logic from virtio
  s390-bios: Clean up cio.h
  s390-bios: Decouple channel i/o logic from virtio
  s390-bios: Map low core memory
  s390-bios: ptr2u32 and u32toptr
  s390-bios: Support for running format-0/1 channel programs
  s390-bios: cio error handling
  s390-bios: Extend find_dev() for non-virtio devices
  s390-bios: Factor finding boot device out of virtio code path
  s390-bios: Refactor virtio to run channel programs via cio
  s390-bios: Use control unit type to determine boot method
  s390-bios: Add channel command codes/structs needed for dasd-ipl
  s390-bios: Support booting from real dasd device
  s390-bios: Use control unit type to find bootable devices

Thomas Huth (1):
  pc-bios/s390: Update firmware images

-- 
2.17.2

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 00/19] first batch of s390x patches for 4.1
@ 2019-04-25 13:21 ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, Cornelia Huck, qemu-devel

The following changes since commit 3284aa128153750f14a61e8a96fd085e6f2999b6:

  Merge remote-tracking branch 'remotes/lersek/tags/edk2-pull-2019-04-22' into staging (2019-04-24 13:19:41 +0100)

are available in the Git repository at:

  https://github.com/cohuck/qemu tags/s390x-20190425

for you to fetch changes up to 41c3d4269b1c18d12d33c5bf089dace25d08e82e:

  Merge tag 's390-ccw-bios-2019-04-12' into s390-next-staging (2019-04-25 14:09:20 +0200)

----------------------------------------------------------------
- properly detect page size of initial memory
- support for IPL (boot) from ECKD DASD passed through via vfio-ccw

----------------------------------------------------------------

Cornelia Huck (1):
      Merge tag 's390-ccw-bios-2019-04-12' into s390-next-staging

David Hildenbrand (2):
  s390x/kvm: Configure page size after memory has actually been
    initialized
  exec: Introduce qemu_maxrampagesize() and rename qemu_getrampagesize()

Jason J. Herne (16):
  s390 vfio-ccw: Add bootindex property and IPLB data
  s390-bios: decouple cio setup from virtio
  s390-bios: decouple common boot logic from virtio
  s390-bios: Clean up cio.h
  s390-bios: Decouple channel i/o logic from virtio
  s390-bios: Map low core memory
  s390-bios: ptr2u32 and u32toptr
  s390-bios: Support for running format-0/1 channel programs
  s390-bios: cio error handling
  s390-bios: Extend find_dev() for non-virtio devices
  s390-bios: Factor finding boot device out of virtio code path
  s390-bios: Refactor virtio to run channel programs via cio
  s390-bios: Use control unit type to determine boot method
  s390-bios: Add channel command codes/structs needed for dasd-ipl
  s390-bios: Support booting from real dasd device
  s390-bios: Use control unit type to find bootable devices

Thomas Huth (1):
  pc-bios/s390: Update firmware images

-- 
2.17.2


^ permalink raw reply	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Add bootindex property and iplb data for vfio-ccw devices. This allows us to
forward boot information into the bios for vfio-ccw devices.

Refactor s390_get_ccw_device() to return device type. This prevents us from
having to use messy casting logic in several places.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-2-git-send-email-jjherne@linux.ibm.com>
[thuth: fixed "typedef struct VFIOCCWDevice" build failure with clang]
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 MAINTAINERS                 |  1 +
 hw/s390x/ipl.c              | 61 ++++++++++++++++++++++++++++---------
 hw/s390x/s390-ccw.c         |  9 ++++++
 hw/vfio/ccw.c               |  6 ++--
 include/hw/s390x/s390-ccw.h |  1 +
 include/hw/s390x/vfio-ccw.h | 28 +++++++++++++++++
 6 files changed, 88 insertions(+), 18 deletions(-)
 create mode 100644 include/hw/s390x/vfio-ccw.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 56139ac8ab05..f7976aa43d0a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1445,6 +1445,7 @@ S: Supported
 F: hw/vfio/ccw.c
 F: hw/s390x/s390-ccw.c
 F: include/hw/s390x/s390-ccw.h
+F: include/hw/s390x/vfio-ccw.h
 T: git https://github.com/cohuck/qemu.git s390-next
 L: qemu-s390x@nongnu.org
 
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 51b272e190a9..d0cc06a05fd0 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -19,6 +19,7 @@
 #include "hw/loader.h"
 #include "hw/boards.h"
 #include "hw/s390x/virtio-ccw.h"
+#include "hw/s390x/vfio-ccw.h"
 #include "hw/s390x/css.h"
 #include "hw/s390x/ebcdic.h"
 #include "ipl.h"
@@ -303,16 +304,36 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
     ipl->qipl.boot_menu_timeout = cpu_to_be32(splash_time);
 }
 
-static CcwDevice *s390_get_ccw_device(DeviceState *dev_st)
+#define CCW_DEVTYPE_NONE        0x00
+#define CCW_DEVTYPE_VIRTIO      0x01
+#define CCW_DEVTYPE_VIRTIO_NET  0x02
+#define CCW_DEVTYPE_SCSI        0x03
+#define CCW_DEVTYPE_VFIO        0x04
+
+static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
 {
     CcwDevice *ccw_dev = NULL;
+    int tmp_dt = CCW_DEVTYPE_NONE;
 
     if (dev_st) {
+        VirtIONet *virtio_net_dev = (VirtIONet *)
+            object_dynamic_cast(OBJECT(dev_st), TYPE_VIRTIO_NET);
         VirtioCcwDevice *virtio_ccw_dev = (VirtioCcwDevice *)
             object_dynamic_cast(OBJECT(qdev_get_parent_bus(dev_st)->parent),
                                 TYPE_VIRTIO_CCW_DEVICE);
+        VFIOCCWDevice *vfio_ccw_dev = (VFIOCCWDevice *)
+            object_dynamic_cast(OBJECT(dev_st), TYPE_VFIO_CCW);
+
         if (virtio_ccw_dev) {
             ccw_dev = CCW_DEVICE(virtio_ccw_dev);
+            if (virtio_net_dev) {
+                tmp_dt = CCW_DEVTYPE_VIRTIO_NET;
+            } else {
+                tmp_dt = CCW_DEVTYPE_VIRTIO;
+            }
+        } else if (vfio_ccw_dev) {
+            ccw_dev = CCW_DEVICE(vfio_ccw_dev);
+            tmp_dt = CCW_DEVTYPE_VFIO;
         } else {
             SCSIDevice *sd = (SCSIDevice *)
                 object_dynamic_cast(OBJECT(dev_st),
@@ -325,9 +346,13 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st)
 
                 ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
                                                            TYPE_CCW_DEVICE);
+                tmp_dt = CCW_DEVTYPE_SCSI;
             }
         }
     }
+    if (devtype) {
+        *devtype = tmp_dt;
+    }
     return ccw_dev;
 }
 
@@ -335,20 +360,22 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
 {
     DeviceState *dev_st;
     CcwDevice *ccw_dev = NULL;
+    SCSIDevice *sd;
+    int devtype;
 
     dev_st = get_boot_device(0);
     if (dev_st) {
-        ccw_dev = s390_get_ccw_device(dev_st);
+        ccw_dev = s390_get_ccw_device(dev_st, &devtype);
     }
 
     /*
      * Currently allow IPL only from CCW devices.
      */
     if (ccw_dev) {
-        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
-                                                            TYPE_SCSI_DEVICE);
-
-        if (sd) {
+        switch (devtype) {
+        case CCW_DEVTYPE_SCSI:
+            sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
+                                                           TYPE_SCSI_DEVICE);
             ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
             ipl->iplb.blk0_len =
                 cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
@@ -358,20 +385,24 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
             ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
             ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
             ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
-        } else {
-            VirtIONet *vn = (VirtIONet *) object_dynamic_cast(OBJECT(dev_st),
-                                                              TYPE_VIRTIO_NET);
-
+            break;
+        case CCW_DEVTYPE_VFIO:
+            ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+            ipl->iplb.pbt = S390_IPL_TYPE_CCW;
+            ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+            ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+            break;
+        case CCW_DEVTYPE_VIRTIO_NET:
+            ipl->netboot = true;
+            /* Fall through to CCW_DEVTYPE_VIRTIO case */
+        case CCW_DEVTYPE_VIRTIO:
             ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
             ipl->iplb.blk0_len =
                 cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
             ipl->iplb.pbt = S390_IPL_TYPE_CCW;
             ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
             ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
-
-            if (vn) {
-                ipl->netboot = true;
-            }
+            break;
         }
 
         if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
@@ -530,7 +561,7 @@ void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
         !ipl->netboot &&
         ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
         is_virtio_scsi_device(&ipl->iplb)) {
-        CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0));
+        CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0), NULL);
 
         if (ccw_dev &&
             cpu_to_be16(ccw_dev->sch->devno) == ipl->iplb.ccw.devno &&
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index cad91ee62679..f5f025d1b6ca 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -124,6 +124,14 @@ static void s390_ccw_unrealize(S390CCWDevice *cdev, Error **errp)
     g_free(cdev->mdevid);
 }
 
+static void s390_ccw_instance_init(Object *obj)
+{
+    S390CCWDevice *dev = S390_CCW_DEVICE(obj);
+
+    device_add_bootindex_property(obj, &dev->bootindex, "bootindex",
+                                  "/disk@0,0", DEVICE(obj), NULL);
+}
+
 static void s390_ccw_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -137,6 +145,7 @@ static void s390_ccw_class_init(ObjectClass *klass, void *data)
 static const TypeInfo s390_ccw_info = {
     .name          = TYPE_S390_CCW,
     .parent        = TYPE_CCW_DEVICE,
+    .instance_init = s390_ccw_instance_init,
     .instance_size = sizeof(S390CCWDevice),
     .class_size    = sizeof(S390CCWDeviceClass),
     .class_init    = s390_ccw_class_init,
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index c44d13cc5081..31dd3a2a87b6 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -21,12 +21,12 @@
 #include "hw/vfio/vfio.h"
 #include "hw/vfio/vfio-common.h"
 #include "hw/s390x/s390-ccw.h"
+#include "hw/s390x/vfio-ccw.h"
 #include "hw/s390x/ccw-device.h"
 #include "exec/address-spaces.h"
 #include "qemu/error-report.h"
 
-#define TYPE_VFIO_CCW "vfio-ccw"
-typedef struct VFIOCCWDevice {
+struct VFIOCCWDevice {
     S390CCWDevice cdev;
     VFIODevice vdev;
     uint64_t io_region_size;
@@ -35,7 +35,7 @@ typedef struct VFIOCCWDevice {
     EventNotifier io_notifier;
     bool force_orb_pfch;
     bool warned_orb_pfch;
-} VFIOCCWDevice;
+};
 
 static inline void warn_once_pfch(VFIOCCWDevice *vcdev, SubchDev *sch,
                                   const char *msg)
diff --git a/include/hw/s390x/s390-ccw.h b/include/hw/s390x/s390-ccw.h
index 7d15a1a5d41d..901d805d79a3 100644
--- a/include/hw/s390x/s390-ccw.h
+++ b/include/hw/s390x/s390-ccw.h
@@ -27,6 +27,7 @@ typedef struct S390CCWDevice {
     CcwDevice parent_obj;
     CssDevId hostid;
     char *mdevid;
+    int32_t bootindex;
 } S390CCWDevice;
 
 typedef struct S390CCWDeviceClass {
diff --git a/include/hw/s390x/vfio-ccw.h b/include/hw/s390x/vfio-ccw.h
new file mode 100644
index 000000000000..ee5250d0d788
--- /dev/null
+++ b/include/hw/s390x/vfio-ccw.h
@@ -0,0 +1,28 @@
+/*
+ * vfio based subchannel assignment support
+ *
+ * Copyright 2017, 2019 IBM Corp.
+ * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
+ *            Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
+ *            Pierre Morel <pmorel@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef HW_VFIO_CCW_H
+#define HW_VFIO_CCW_H
+
+#include "hw/vfio/vfio-common.h"
+#include "hw/s390x/s390-ccw.h"
+#include "hw/s390x/ccw-device.h"
+
+#define TYPE_VFIO_CCW "vfio-ccw"
+#define VFIO_CCW(obj) \
+        OBJECT_CHECK(VFIOCCWDevice, (obj), TYPE_VFIO_CCW)
+
+#define TYPE_VFIO_CCW "vfio-ccw"
+typedef struct VFIOCCWDevice VFIOCCWDevice;
+
+#endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Add bootindex property and iplb data for vfio-ccw devices. This allows us to
forward boot information into the bios for vfio-ccw devices.

Refactor s390_get_ccw_device() to return device type. This prevents us from
having to use messy casting logic in several places.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-2-git-send-email-jjherne@linux.ibm.com>
[thuth: fixed "typedef struct VFIOCCWDevice" build failure with clang]
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 MAINTAINERS                 |  1 +
 hw/s390x/ipl.c              | 61 ++++++++++++++++++++++++++++---------
 hw/s390x/s390-ccw.c         |  9 ++++++
 hw/vfio/ccw.c               |  6 ++--
 include/hw/s390x/s390-ccw.h |  1 +
 include/hw/s390x/vfio-ccw.h | 28 +++++++++++++++++
 6 files changed, 88 insertions(+), 18 deletions(-)
 create mode 100644 include/hw/s390x/vfio-ccw.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 56139ac8ab05..f7976aa43d0a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1445,6 +1445,7 @@ S: Supported
 F: hw/vfio/ccw.c
 F: hw/s390x/s390-ccw.c
 F: include/hw/s390x/s390-ccw.h
+F: include/hw/s390x/vfio-ccw.h
 T: git https://github.com/cohuck/qemu.git s390-next
 L: qemu-s390x@nongnu.org
 
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 51b272e190a9..d0cc06a05fd0 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -19,6 +19,7 @@
 #include "hw/loader.h"
 #include "hw/boards.h"
 #include "hw/s390x/virtio-ccw.h"
+#include "hw/s390x/vfio-ccw.h"
 #include "hw/s390x/css.h"
 #include "hw/s390x/ebcdic.h"
 #include "ipl.h"
@@ -303,16 +304,36 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
     ipl->qipl.boot_menu_timeout = cpu_to_be32(splash_time);
 }
 
-static CcwDevice *s390_get_ccw_device(DeviceState *dev_st)
+#define CCW_DEVTYPE_NONE        0x00
+#define CCW_DEVTYPE_VIRTIO      0x01
+#define CCW_DEVTYPE_VIRTIO_NET  0x02
+#define CCW_DEVTYPE_SCSI        0x03
+#define CCW_DEVTYPE_VFIO        0x04
+
+static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
 {
     CcwDevice *ccw_dev = NULL;
+    int tmp_dt = CCW_DEVTYPE_NONE;
 
     if (dev_st) {
+        VirtIONet *virtio_net_dev = (VirtIONet *)
+            object_dynamic_cast(OBJECT(dev_st), TYPE_VIRTIO_NET);
         VirtioCcwDevice *virtio_ccw_dev = (VirtioCcwDevice *)
             object_dynamic_cast(OBJECT(qdev_get_parent_bus(dev_st)->parent),
                                 TYPE_VIRTIO_CCW_DEVICE);
+        VFIOCCWDevice *vfio_ccw_dev = (VFIOCCWDevice *)
+            object_dynamic_cast(OBJECT(dev_st), TYPE_VFIO_CCW);
+
         if (virtio_ccw_dev) {
             ccw_dev = CCW_DEVICE(virtio_ccw_dev);
+            if (virtio_net_dev) {
+                tmp_dt = CCW_DEVTYPE_VIRTIO_NET;
+            } else {
+                tmp_dt = CCW_DEVTYPE_VIRTIO;
+            }
+        } else if (vfio_ccw_dev) {
+            ccw_dev = CCW_DEVICE(vfio_ccw_dev);
+            tmp_dt = CCW_DEVTYPE_VFIO;
         } else {
             SCSIDevice *sd = (SCSIDevice *)
                 object_dynamic_cast(OBJECT(dev_st),
@@ -325,9 +346,13 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st)
 
                 ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
                                                            TYPE_CCW_DEVICE);
+                tmp_dt = CCW_DEVTYPE_SCSI;
             }
         }
     }
+    if (devtype) {
+        *devtype = tmp_dt;
+    }
     return ccw_dev;
 }
 
@@ -335,20 +360,22 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
 {
     DeviceState *dev_st;
     CcwDevice *ccw_dev = NULL;
+    SCSIDevice *sd;
+    int devtype;
 
     dev_st = get_boot_device(0);
     if (dev_st) {
-        ccw_dev = s390_get_ccw_device(dev_st);
+        ccw_dev = s390_get_ccw_device(dev_st, &devtype);
     }
 
     /*
      * Currently allow IPL only from CCW devices.
      */
     if (ccw_dev) {
-        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
-                                                            TYPE_SCSI_DEVICE);
-
-        if (sd) {
+        switch (devtype) {
+        case CCW_DEVTYPE_SCSI:
+            sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
+                                                           TYPE_SCSI_DEVICE);
             ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
             ipl->iplb.blk0_len =
                 cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
@@ -358,20 +385,24 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
             ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
             ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
             ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
-        } else {
-            VirtIONet *vn = (VirtIONet *) object_dynamic_cast(OBJECT(dev_st),
-                                                              TYPE_VIRTIO_NET);
-
+            break;
+        case CCW_DEVTYPE_VFIO:
+            ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+            ipl->iplb.pbt = S390_IPL_TYPE_CCW;
+            ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+            ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+            break;
+        case CCW_DEVTYPE_VIRTIO_NET:
+            ipl->netboot = true;
+            /* Fall through to CCW_DEVTYPE_VIRTIO case */
+        case CCW_DEVTYPE_VIRTIO:
             ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
             ipl->iplb.blk0_len =
                 cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
             ipl->iplb.pbt = S390_IPL_TYPE_CCW;
             ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
             ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
-
-            if (vn) {
-                ipl->netboot = true;
-            }
+            break;
         }
 
         if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
@@ -530,7 +561,7 @@ void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
         !ipl->netboot &&
         ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
         is_virtio_scsi_device(&ipl->iplb)) {
-        CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0));
+        CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0), NULL);
 
         if (ccw_dev &&
             cpu_to_be16(ccw_dev->sch->devno) == ipl->iplb.ccw.devno &&
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index cad91ee62679..f5f025d1b6ca 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -124,6 +124,14 @@ static void s390_ccw_unrealize(S390CCWDevice *cdev, Error **errp)
     g_free(cdev->mdevid);
 }
 
+static void s390_ccw_instance_init(Object *obj)
+{
+    S390CCWDevice *dev = S390_CCW_DEVICE(obj);
+
+    device_add_bootindex_property(obj, &dev->bootindex, "bootindex",
+                                  "/disk@0,0", DEVICE(obj), NULL);
+}
+
 static void s390_ccw_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -137,6 +145,7 @@ static void s390_ccw_class_init(ObjectClass *klass, void *data)
 static const TypeInfo s390_ccw_info = {
     .name          = TYPE_S390_CCW,
     .parent        = TYPE_CCW_DEVICE,
+    .instance_init = s390_ccw_instance_init,
     .instance_size = sizeof(S390CCWDevice),
     .class_size    = sizeof(S390CCWDeviceClass),
     .class_init    = s390_ccw_class_init,
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index c44d13cc5081..31dd3a2a87b6 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -21,12 +21,12 @@
 #include "hw/vfio/vfio.h"
 #include "hw/vfio/vfio-common.h"
 #include "hw/s390x/s390-ccw.h"
+#include "hw/s390x/vfio-ccw.h"
 #include "hw/s390x/ccw-device.h"
 #include "exec/address-spaces.h"
 #include "qemu/error-report.h"
 
-#define TYPE_VFIO_CCW "vfio-ccw"
-typedef struct VFIOCCWDevice {
+struct VFIOCCWDevice {
     S390CCWDevice cdev;
     VFIODevice vdev;
     uint64_t io_region_size;
@@ -35,7 +35,7 @@ typedef struct VFIOCCWDevice {
     EventNotifier io_notifier;
     bool force_orb_pfch;
     bool warned_orb_pfch;
-} VFIOCCWDevice;
+};
 
 static inline void warn_once_pfch(VFIOCCWDevice *vcdev, SubchDev *sch,
                                   const char *msg)
diff --git a/include/hw/s390x/s390-ccw.h b/include/hw/s390x/s390-ccw.h
index 7d15a1a5d41d..901d805d79a3 100644
--- a/include/hw/s390x/s390-ccw.h
+++ b/include/hw/s390x/s390-ccw.h
@@ -27,6 +27,7 @@ typedef struct S390CCWDevice {
     CcwDevice parent_obj;
     CssDevId hostid;
     char *mdevid;
+    int32_t bootindex;
 } S390CCWDevice;
 
 typedef struct S390CCWDeviceClass {
diff --git a/include/hw/s390x/vfio-ccw.h b/include/hw/s390x/vfio-ccw.h
new file mode 100644
index 000000000000..ee5250d0d788
--- /dev/null
+++ b/include/hw/s390x/vfio-ccw.h
@@ -0,0 +1,28 @@
+/*
+ * vfio based subchannel assignment support
+ *
+ * Copyright 2017, 2019 IBM Corp.
+ * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
+ *            Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
+ *            Pierre Morel <pmorel@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef HW_VFIO_CCW_H
+#define HW_VFIO_CCW_H
+
+#include "hw/vfio/vfio-common.h"
+#include "hw/s390x/s390-ccw.h"
+#include "hw/s390x/ccw-device.h"
+
+#define TYPE_VFIO_CCW "vfio-ccw"
+#define VFIO_CCW(obj) \
+        OBJECT_CHECK(VFIOCCWDevice, (obj), TYPE_VFIO_CCW)
+
+#define TYPE_VFIO_CCW "vfio-ccw"
+typedef struct VFIOCCWDevice VFIOCCWDevice;
+
+#endif
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 02/19] s390-bios: decouple cio setup from virtio
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Move channel i/o setup code out to a separate function. This decouples cio
setup from the virtio code path and allows us to make use of it for booting
dasd devices.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Collin Walling <walling@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-3-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 544851d672d8..e82fe2ce2315 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -99,6 +99,18 @@ static void menu_setup(void)
     }
 }
 
+/*
+ * Initialize the channel I/O subsystem so we can talk to our ipl/boot device.
+ */
+static void css_setup(void)
+{
+    /*
+     * Unconditionally enable mss support. In every sane configuration this
+     * will succeed; and even if it doesn't, stsch_err() can handle it.
+     */
+    enable_mss_facility();
+}
+
 static void virtio_setup(void)
 {
     Schib schib;
@@ -109,13 +121,6 @@ static void virtio_setup(void)
     VDev *vdev = virtio_get_device();
     QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
 
-    /*
-     * We unconditionally enable mss support. In every sane configuration,
-     * this will succeed; and even if it doesn't, stsch_err() can deal
-     * with the consequences.
-     */
-    enable_mss_facility();
-
     sclp_get_loadparm_ascii(loadparm_str);
     memcpy(ldp + 10, loadparm_str, LOADPARM_LEN);
     sclp_print(ldp);
@@ -168,6 +173,7 @@ static void virtio_setup(void)
 int main(void)
 {
     sclp_setup();
+    css_setup();
     virtio_setup();
 
     zipl_load(); /* no return */
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 02/19] s390-bios: decouple cio setup from virtio
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Move channel i/o setup code out to a separate function. This decouples cio
setup from the virtio code path and allows us to make use of it for booting
dasd devices.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Collin Walling <walling@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-3-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 544851d672d8..e82fe2ce2315 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -99,6 +99,18 @@ static void menu_setup(void)
     }
 }
 
+/*
+ * Initialize the channel I/O subsystem so we can talk to our ipl/boot device.
+ */
+static void css_setup(void)
+{
+    /*
+     * Unconditionally enable mss support. In every sane configuration this
+     * will succeed; and even if it doesn't, stsch_err() can handle it.
+     */
+    enable_mss_facility();
+}
+
 static void virtio_setup(void)
 {
     Schib schib;
@@ -109,13 +121,6 @@ static void virtio_setup(void)
     VDev *vdev = virtio_get_device();
     QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
 
-    /*
-     * We unconditionally enable mss support. In every sane configuration,
-     * this will succeed; and even if it doesn't, stsch_err() can deal
-     * with the consequences.
-     */
-    enable_mss_facility();
-
     sclp_get_loadparm_ascii(loadparm_str);
     memcpy(ldp + 10, loadparm_str, LOADPARM_LEN);
     sclp_print(ldp);
@@ -168,6 +173,7 @@ static void virtio_setup(void)
 int main(void)
 {
     sclp_setup();
+    css_setup();
     virtio_setup();
 
     zipl_load(); /* no return */
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 03/19] s390-bios: decouple common boot logic from virtio
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Create a boot_setup function to handle getting boot information from
the machine/hypervisor. This decouples common boot logic from the
virtio code path and allows us to make use of it for the real dasd boot
scenario.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Collin Walling <walling@linux.ibm.com
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-4-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e82fe2ce2315..67df42191b94 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -14,16 +14,17 @@
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
-IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
+IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
+static bool have_iplb;
 
 #define LOADPARM_PROMPT "PROMPT  "
 #define LOADPARM_EMPTY  "        "
 #define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL)
 
 /*
- * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
+ * Principles of Operations (SA22-7832-09) chapter 17 requires that
  * a subsystem-identification is at 184-187 and bytes 188-191 are zero
  * after list-directed-IPL and ccw-IPL.
  */
@@ -111,23 +112,33 @@ static void css_setup(void)
     enable_mss_facility();
 }
 
+/*
+ * Collect various pieces of information from the hypervisor/hardware that
+ * we'll use to determine exactly how we'll boot.
+ */
+static void boot_setup(void)
+{
+    char lpmsg[] = "LOADPARM=[________]\n";
+
+    sclp_get_loadparm_ascii(loadparm_str);
+    memcpy(lpmsg + 10, loadparm_str, 8);
+    sclp_print(lpmsg);
+
+    have_iplb = store_iplb(&iplb);
+}
+
 static void virtio_setup(void)
 {
     Schib schib;
     int ssid;
     bool found = false;
     uint16_t dev_no;
-    char ldp[] = "LOADPARM=[________]\n";
     VDev *vdev = virtio_get_device();
     QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
 
-    sclp_get_loadparm_ascii(loadparm_str);
-    memcpy(ldp + 10, loadparm_str, LOADPARM_LEN);
-    sclp_print(ldp);
-
     memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
 
-    if (store_iplb(&iplb)) {
+    if (have_iplb) {
         switch (iplb.pbt) {
         case S390_IPL_TYPE_CCW:
             dev_no = iplb.ccw.devno;
@@ -174,6 +185,7 @@ int main(void)
 {
     sclp_setup();
     css_setup();
+    boot_setup();
     virtio_setup();
 
     zipl_load(); /* no return */
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 03/19] s390-bios: decouple common boot logic from virtio
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Create a boot_setup function to handle getting boot information from
the machine/hypervisor. This decouples common boot logic from the
virtio code path and allows us to make use of it for the real dasd boot
scenario.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Collin Walling <walling@linux.ibm.com
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-4-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e82fe2ce2315..67df42191b94 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -14,16 +14,17 @@
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
-IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
+IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
+static bool have_iplb;
 
 #define LOADPARM_PROMPT "PROMPT  "
 #define LOADPARM_EMPTY  "        "
 #define BOOT_MENU_FLAG_MASK (QIPL_FLAG_BM_OPTS_CMD | QIPL_FLAG_BM_OPTS_ZIPL)
 
 /*
- * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
+ * Principles of Operations (SA22-7832-09) chapter 17 requires that
  * a subsystem-identification is at 184-187 and bytes 188-191 are zero
  * after list-directed-IPL and ccw-IPL.
  */
@@ -111,23 +112,33 @@ static void css_setup(void)
     enable_mss_facility();
 }
 
+/*
+ * Collect various pieces of information from the hypervisor/hardware that
+ * we'll use to determine exactly how we'll boot.
+ */
+static void boot_setup(void)
+{
+    char lpmsg[] = "LOADPARM=[________]\n";
+
+    sclp_get_loadparm_ascii(loadparm_str);
+    memcpy(lpmsg + 10, loadparm_str, 8);
+    sclp_print(lpmsg);
+
+    have_iplb = store_iplb(&iplb);
+}
+
 static void virtio_setup(void)
 {
     Schib schib;
     int ssid;
     bool found = false;
     uint16_t dev_no;
-    char ldp[] = "LOADPARM=[________]\n";
     VDev *vdev = virtio_get_device();
     QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
 
-    sclp_get_loadparm_ascii(loadparm_str);
-    memcpy(ldp + 10, loadparm_str, LOADPARM_LEN);
-    sclp_print(ldp);
-
     memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
 
-    if (store_iplb(&iplb)) {
+    if (have_iplb) {
         switch (iplb.pbt) {
         case S390_IPL_TYPE_CCW:
             dev_no = iplb.ccw.devno;
@@ -174,6 +185,7 @@ int main(void)
 {
     sclp_setup();
     css_setup();
+    boot_setup();
     virtio_setup();
 
     zipl_load(); /* no return */
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 04/19] s390-bios: Clean up cio.h
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Add proper typedefs to all structs and modify all bit fields to use consistent
formatting.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Collin Walling <walling@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-5-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/cio.h      | 114 ++++++++++++++++++------------------
 pc-bios/s390-ccw/s390-ccw.h |   8 ---
 2 files changed, 57 insertions(+), 65 deletions(-)

diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 1a0795f6455f..ed5b2cbf72db 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -17,35 +17,35 @@
  * path management control word
  */
 struct pmcw {
-    __u32 intparm;        /* interruption parameter */
-    __u32 qf      : 1;    /* qdio facility */
-    __u32 w       : 1;
-    __u32 isc     : 3;    /* interruption sublass */
-    __u32 res5    : 3;    /* reserved zeros */
-    __u32 ena     : 1;    /* enabled */
-    __u32 lm      : 2;    /* limit mode */
-    __u32 mme     : 2;    /* measurement-mode enable */
-    __u32 mp      : 1;    /* multipath mode */
-    __u32 tf      : 1;    /* timing facility */
-    __u32 dnv     : 1;    /* device number valid */
-    __u32 dev     : 16;   /* device number */
-    __u8  lpm;            /* logical path mask */
-    __u8  pnom;           /* path not operational mask */
-    __u8  lpum;           /* last path used mask */
-    __u8  pim;            /* path installed mask */
-    __u16 mbi;            /* measurement-block index */
-    __u8  pom;            /* path operational mask */
-    __u8  pam;            /* path available mask */
-    __u8  chpid[8];       /* CHPID 0-7 (if available) */
-    __u32 unused1 : 8;    /* reserved zeros */
-    __u32 st      : 3;    /* subchannel type */
-    __u32 unused2 : 18;   /* reserved zeros */
-    __u32 mbfc    : 1;    /* measurement block format control */
-    __u32 xmwme   : 1;    /* extended measurement word mode enable */
-    __u32 csense  : 1;    /* concurrent sense; can be enabled ...*/
-                /*  ... per MSCH, however, if facility */
-                /*  ... is not installed, this results */
-                /*  ... in an operand exception.       */
+    __u32 intparm;      /* interruption parameter */
+    __u32 qf:1;         /* qdio facility */
+    __u32 w:1;
+    __u32 isc:3;        /* interruption sublass */
+    __u32 res5:3;       /* reserved zeros */
+    __u32 ena:1;        /* enabled */
+    __u32 lm:2;         /* limit mode */
+    __u32 mme:2;        /* measurement-mode enable */
+    __u32 mp:1;         /* multipath mode */
+    __u32 tf:1;         /* timing facility */
+    __u32 dnv:1;        /* device number valid */
+    __u32 dev:16;       /* device number */
+    __u8  lpm;          /* logical path mask */
+    __u8  pnom;         /* path not operational mask */
+    __u8  lpum;         /* last path used mask */
+    __u8  pim;          /* path installed mask */
+    __u16 mbi;          /* measurement-block index */
+    __u8  pom;          /* path operational mask */
+    __u8  pam;          /* path available mask */
+    __u8  chpid[8];     /* CHPID 0-7 (if available) */
+    __u32 unused1:8;    /* reserved zeros */
+    __u32 st:3;         /* subchannel type */
+    __u32 unused2:18;   /* reserved zeros */
+    __u32 mbfc:1;       /* measurement block format control */
+    __u32 xmwme:1;      /* extended measurement word mode enable */
+    __u32 csense:1;     /* concurrent sense; can be enabled ...*/
+                        /*  ... per MSCH, however, if facility */
+                        /*  ... is not installed, this results */
+                        /*  ... in an operand exception.       */
 } __attribute__ ((packed));
 
 /* Target SCHIB configuration. */
@@ -77,28 +77,28 @@ struct scsw {
 /*
  * subchannel information block
  */
-struct schib {
+typedef struct schib {
     struct pmcw pmcw;     /* path management control word */
     struct scsw scsw;     /* subchannel status word */
     __u64 mba;            /* measurement block address */
     __u8 mda[4];          /* model dependent area */
-} __attribute__ ((packed,aligned(4)));
-
-struct subchannel_id {
-        __u32 cssid  : 8;
-        __u32        : 4;
-        __u32 m      : 1;
-        __u32 ssid   : 2;
-        __u32 one    : 1;
-        __u32 sch_no : 16;
-} __attribute__ ((packed, aligned(4)));
+} __attribute__ ((packed, aligned(4))) Schib;
+
+typedef struct subchannel_id {
+        __u32 cssid:8;
+        __u32:4;
+        __u32 m:1;
+        __u32 ssid:2;
+        __u32 one:1;
+        __u32 sch_no:16;
+} __attribute__ ((packed, aligned(4))) SubChannelId;
 
 struct chsc_header {
     __u16 length;
     __u16 code;
 } __attribute__((packed));
 
-struct chsc_area_sda {
+typedef struct chsc_area_sda {
     struct chsc_header request;
     __u8 reserved1:4;
     __u8 format:4;
@@ -111,29 +111,29 @@ struct chsc_area_sda {
     __u32 reserved5:4;
     __u32 format2:4;
     __u32 reserved6:24;
-} __attribute__((packed));
+} __attribute__((packed)) ChscAreaSda;
 
 /*
  * TPI info structure
  */
 struct tpi_info {
     struct subchannel_id schid;
-    __u32 intparm;         /* interruption parameter */
-    __u32 adapter_IO : 1;
-    __u32 reserved2  : 1;
-    __u32 isc        : 3;
-    __u32 reserved3  : 12;
-    __u32 int_type   : 3;
-    __u32 reserved4  : 12;
+    __u32 intparm;      /* interruption parameter */
+    __u32 adapter_IO:1;
+    __u32 reserved2:1;
+    __u32 isc:3;
+    __u32 reserved3:12;
+    __u32 int_type:3;
+    __u32 reserved4:12;
 } __attribute__ ((packed, aligned(4)));
 
 /* channel command word (type 1) */
-struct ccw1 {
+typedef struct ccw1 {
     __u8 cmd_code;
     __u8 flags;
     __u16 count;
     __u32 cda;
-} __attribute__ ((packed, aligned(8)));
+} __attribute__ ((packed, aligned(8))) Ccw1;
 
 #define CCW_FLAG_DC              0x80
 #define CCW_FLAG_CC              0x40
@@ -162,7 +162,7 @@ struct ccw1 {
 /*
  * Command-mode operation request block
  */
-struct cmd_orb {
+typedef struct cmd_orb {
     __u32 intparm;    /* interruption parameter */
     __u32 key:4;      /* flags, like key, suspend control, etc. */
     __u32 spnd:1;     /* suspend control */
@@ -182,7 +182,7 @@ struct cmd_orb {
     __u32 zero:6;     /* reserved zeros */
     __u32 orbx:1;     /* ORB extension control */
     __u32 cpa;    /* channel program address */
-}  __attribute__ ((packed, aligned(4)));
+}  __attribute__ ((packed, aligned(4))) CmdOrb;
 
 struct ciw {
     __u8 type;
@@ -193,7 +193,7 @@ struct ciw {
 /*
  * sense-id response buffer layout
  */
-struct senseid {
+typedef struct senseid {
     /* common part */
     __u8  reserved;   /* always 0x'FF' */
     __u16 cu_type;    /* control unit type */
@@ -203,15 +203,15 @@ struct senseid {
     __u8  unused;     /* padding byte */
     /* extended part */
     struct ciw ciw[62];
-}  __attribute__ ((packed, aligned(4)));
+}  __attribute__ ((packed, aligned(4))) SenseId;
 
 /* interruption response block */
-struct irb {
+typedef struct irb {
     struct scsw scsw;
     __u32 esw[5];
     __u32 ecw[8];
     __u32 emw[8];
-}  __attribute__ ((packed, aligned(4)));
+}  __attribute__ ((packed, aligned(4))) Irb;
 
 /*
  * Some S390 specific IO instructions as inline
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 9828aa233d2e..241c6d0b69be 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -49,14 +49,6 @@ typedef unsigned long long __u64;
 #include "cio.h"
 #include "iplb.h"
 
-typedef struct irb Irb;
-typedef struct ccw1 Ccw1;
-typedef struct cmd_orb CmdOrb;
-typedef struct schib Schib;
-typedef struct chsc_area_sda ChscAreaSda;
-typedef struct senseid SenseId;
-typedef struct subchannel_id SubChannelId;
-
 /* start.s */
 void disabled_wait(void);
 void consume_sclp_int(void);
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 04/19] s390-bios: Clean up cio.h
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Add proper typedefs to all structs and modify all bit fields to use consistent
formatting.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Collin Walling <walling@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-5-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/cio.h      | 114 ++++++++++++++++++------------------
 pc-bios/s390-ccw/s390-ccw.h |   8 ---
 2 files changed, 57 insertions(+), 65 deletions(-)

diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 1a0795f6455f..ed5b2cbf72db 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -17,35 +17,35 @@
  * path management control word
  */
 struct pmcw {
-    __u32 intparm;        /* interruption parameter */
-    __u32 qf      : 1;    /* qdio facility */
-    __u32 w       : 1;
-    __u32 isc     : 3;    /* interruption sublass */
-    __u32 res5    : 3;    /* reserved zeros */
-    __u32 ena     : 1;    /* enabled */
-    __u32 lm      : 2;    /* limit mode */
-    __u32 mme     : 2;    /* measurement-mode enable */
-    __u32 mp      : 1;    /* multipath mode */
-    __u32 tf      : 1;    /* timing facility */
-    __u32 dnv     : 1;    /* device number valid */
-    __u32 dev     : 16;   /* device number */
-    __u8  lpm;            /* logical path mask */
-    __u8  pnom;           /* path not operational mask */
-    __u8  lpum;           /* last path used mask */
-    __u8  pim;            /* path installed mask */
-    __u16 mbi;            /* measurement-block index */
-    __u8  pom;            /* path operational mask */
-    __u8  pam;            /* path available mask */
-    __u8  chpid[8];       /* CHPID 0-7 (if available) */
-    __u32 unused1 : 8;    /* reserved zeros */
-    __u32 st      : 3;    /* subchannel type */
-    __u32 unused2 : 18;   /* reserved zeros */
-    __u32 mbfc    : 1;    /* measurement block format control */
-    __u32 xmwme   : 1;    /* extended measurement word mode enable */
-    __u32 csense  : 1;    /* concurrent sense; can be enabled ...*/
-                /*  ... per MSCH, however, if facility */
-                /*  ... is not installed, this results */
-                /*  ... in an operand exception.       */
+    __u32 intparm;      /* interruption parameter */
+    __u32 qf:1;         /* qdio facility */
+    __u32 w:1;
+    __u32 isc:3;        /* interruption sublass */
+    __u32 res5:3;       /* reserved zeros */
+    __u32 ena:1;        /* enabled */
+    __u32 lm:2;         /* limit mode */
+    __u32 mme:2;        /* measurement-mode enable */
+    __u32 mp:1;         /* multipath mode */
+    __u32 tf:1;         /* timing facility */
+    __u32 dnv:1;        /* device number valid */
+    __u32 dev:16;       /* device number */
+    __u8  lpm;          /* logical path mask */
+    __u8  pnom;         /* path not operational mask */
+    __u8  lpum;         /* last path used mask */
+    __u8  pim;          /* path installed mask */
+    __u16 mbi;          /* measurement-block index */
+    __u8  pom;          /* path operational mask */
+    __u8  pam;          /* path available mask */
+    __u8  chpid[8];     /* CHPID 0-7 (if available) */
+    __u32 unused1:8;    /* reserved zeros */
+    __u32 st:3;         /* subchannel type */
+    __u32 unused2:18;   /* reserved zeros */
+    __u32 mbfc:1;       /* measurement block format control */
+    __u32 xmwme:1;      /* extended measurement word mode enable */
+    __u32 csense:1;     /* concurrent sense; can be enabled ...*/
+                        /*  ... per MSCH, however, if facility */
+                        /*  ... is not installed, this results */
+                        /*  ... in an operand exception.       */
 } __attribute__ ((packed));
 
 /* Target SCHIB configuration. */
@@ -77,28 +77,28 @@ struct scsw {
 /*
  * subchannel information block
  */
-struct schib {
+typedef struct schib {
     struct pmcw pmcw;     /* path management control word */
     struct scsw scsw;     /* subchannel status word */
     __u64 mba;            /* measurement block address */
     __u8 mda[4];          /* model dependent area */
-} __attribute__ ((packed,aligned(4)));
-
-struct subchannel_id {
-        __u32 cssid  : 8;
-        __u32        : 4;
-        __u32 m      : 1;
-        __u32 ssid   : 2;
-        __u32 one    : 1;
-        __u32 sch_no : 16;
-} __attribute__ ((packed, aligned(4)));
+} __attribute__ ((packed, aligned(4))) Schib;
+
+typedef struct subchannel_id {
+        __u32 cssid:8;
+        __u32:4;
+        __u32 m:1;
+        __u32 ssid:2;
+        __u32 one:1;
+        __u32 sch_no:16;
+} __attribute__ ((packed, aligned(4))) SubChannelId;
 
 struct chsc_header {
     __u16 length;
     __u16 code;
 } __attribute__((packed));
 
-struct chsc_area_sda {
+typedef struct chsc_area_sda {
     struct chsc_header request;
     __u8 reserved1:4;
     __u8 format:4;
@@ -111,29 +111,29 @@ struct chsc_area_sda {
     __u32 reserved5:4;
     __u32 format2:4;
     __u32 reserved6:24;
-} __attribute__((packed));
+} __attribute__((packed)) ChscAreaSda;
 
 /*
  * TPI info structure
  */
 struct tpi_info {
     struct subchannel_id schid;
-    __u32 intparm;         /* interruption parameter */
-    __u32 adapter_IO : 1;
-    __u32 reserved2  : 1;
-    __u32 isc        : 3;
-    __u32 reserved3  : 12;
-    __u32 int_type   : 3;
-    __u32 reserved4  : 12;
+    __u32 intparm;      /* interruption parameter */
+    __u32 adapter_IO:1;
+    __u32 reserved2:1;
+    __u32 isc:3;
+    __u32 reserved3:12;
+    __u32 int_type:3;
+    __u32 reserved4:12;
 } __attribute__ ((packed, aligned(4)));
 
 /* channel command word (type 1) */
-struct ccw1 {
+typedef struct ccw1 {
     __u8 cmd_code;
     __u8 flags;
     __u16 count;
     __u32 cda;
-} __attribute__ ((packed, aligned(8)));
+} __attribute__ ((packed, aligned(8))) Ccw1;
 
 #define CCW_FLAG_DC              0x80
 #define CCW_FLAG_CC              0x40
@@ -162,7 +162,7 @@ struct ccw1 {
 /*
  * Command-mode operation request block
  */
-struct cmd_orb {
+typedef struct cmd_orb {
     __u32 intparm;    /* interruption parameter */
     __u32 key:4;      /* flags, like key, suspend control, etc. */
     __u32 spnd:1;     /* suspend control */
@@ -182,7 +182,7 @@ struct cmd_orb {
     __u32 zero:6;     /* reserved zeros */
     __u32 orbx:1;     /* ORB extension control */
     __u32 cpa;    /* channel program address */
-}  __attribute__ ((packed, aligned(4)));
+}  __attribute__ ((packed, aligned(4))) CmdOrb;
 
 struct ciw {
     __u8 type;
@@ -193,7 +193,7 @@ struct ciw {
 /*
  * sense-id response buffer layout
  */
-struct senseid {
+typedef struct senseid {
     /* common part */
     __u8  reserved;   /* always 0x'FF' */
     __u16 cu_type;    /* control unit type */
@@ -203,15 +203,15 @@ struct senseid {
     __u8  unused;     /* padding byte */
     /* extended part */
     struct ciw ciw[62];
-}  __attribute__ ((packed, aligned(4)));
+}  __attribute__ ((packed, aligned(4))) SenseId;
 
 /* interruption response block */
-struct irb {
+typedef struct irb {
     struct scsw scsw;
     __u32 esw[5];
     __u32 ecw[8];
     __u32 emw[8];
-}  __attribute__ ((packed, aligned(4)));
+}  __attribute__ ((packed, aligned(4))) Irb;
 
 /*
  * Some S390 specific IO instructions as inline
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 9828aa233d2e..241c6d0b69be 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -49,14 +49,6 @@ typedef unsigned long long __u64;
 #include "cio.h"
 #include "iplb.h"
 
-typedef struct irb Irb;
-typedef struct ccw1 Ccw1;
-typedef struct cmd_orb CmdOrb;
-typedef struct schib Schib;
-typedef struct chsc_area_sda ChscAreaSda;
-typedef struct senseid SenseId;
-typedef struct subchannel_id SubChannelId;
-
 /* start.s */
 void disabled_wait(void);
 void consume_sclp_int(void);
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 05/19] s390-bios: Decouple channel i/o logic from virtio
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Create a separate library for channel i/o related code. This decouples
channel i/o operations from virtio and allows us to make use of them for
the real dasd boot path.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-6-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/Makefile    |  2 +-
 pc-bios/s390-ccw/cio.c       | 44 ++++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/cio.h       |  3 +++
 pc-bios/s390-ccw/main.c      |  1 +
 pc-bios/s390-ccw/netboot.mak |  2 +-
 pc-bios/s390-ccw/netmain.c   |  1 +
 pc-bios/s390-ccw/s390-ccw.h  |  1 -
 pc-bios/s390-ccw/virtio.c    | 27 ++--------------------
 8 files changed, 53 insertions(+), 28 deletions(-)
 create mode 100644 pc-bios/s390-ccw/cio.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 1eb316b02f1f..12ad9c1d5813 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -10,7 +10,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 .PHONY : all clean build-all
 
 OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
-	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o
+	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o
 
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
new file mode 100644
index 000000000000..87c6b34e88af
--- /dev/null
+++ b/pc-bios/s390-ccw/cio.c
@@ -0,0 +1,44 @@
+/*
+ * S390 Channel I/O
+ *
+ * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
+ * Copyright (c) 2019 IBM Corp.
+ *
+ * Author(s): Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+#include "cio.h"
+
+static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+
+int enable_mss_facility(void)
+{
+    int ret;
+    ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
+
+    memset(sda_area, 0, PAGE_SIZE);
+    sda_area->request.length = 0x0400;
+    sda_area->request.code = 0x0031;
+    sda_area->operation_code = 0x2;
+
+    ret = chsc(sda_area);
+    if ((ret == 0) && (sda_area->response.code == 0x0001)) {
+        return 0;
+    }
+    return -EIO;
+}
+
+void enable_subchannel(SubChannelId schid)
+{
+    Schib schib;
+
+    stsch_err(schid, &schib);
+    schib.pmcw.ena = 1;
+    msch(schid, &schib);
+}
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index ed5b2cbf72db..218fd96ea3a6 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -213,6 +213,9 @@ typedef struct irb {
     __u32 emw[8];
 }  __attribute__ ((packed, aligned(4))) Irb;
 
+int enable_mss_facility(void);
+void enable_subchannel(SubChannelId schid);
+
 /*
  * Some S390 specific IO instructions as inline
  */
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 67df42191b94..10f04c69068f 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -10,6 +10,7 @@
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "cio.h"
 #include "virtio.h"
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
index 14e96b2aa611..5eefb7c28939 100644
--- a/pc-bios/s390-ccw/netboot.mak
+++ b/pc-bios/s390-ccw/netboot.mak
@@ -1,7 +1,7 @@
 
 SLOF_DIR := $(SRC_PATH)/roms/SLOF
 
-NETOBJS := start.o sclp.o virtio.o virtio-net.o jump2ipl.o netmain.o \
+NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o \
 	   libnet.a libc.a
 
 LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index 0392131c27b3..5189c0fc39e5 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -33,6 +33,7 @@
 #include <pxelinux.h>
 
 #include "s390-ccw.h"
+#include "cio.h"
 #include "virtio.h"
 
 #define DEFAULT_BOOT_RETRIES 10
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 241c6d0b69be..b39ee5d32314 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -72,7 +72,6 @@ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
 bool virtio_is_supported(SubChannelId schid);
 void virtio_blk_setup_device(SubChannelId schid);
 int virtio_read(ulong sector, void *load_addr);
-int enable_mss_facility(void);
 u64 get_clock(void);
 ulong get_second(void);
 
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index cdb66f459e15..aa9da7253fb2 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -10,6 +10,7 @@
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "cio.h"
 #include "virtio.h"
 #include "virtio-scsi.h"
 #include "bswap.h"
@@ -20,8 +21,6 @@ static VRing block[VIRTIO_MAX_VQS];
 static char ring_area[VIRTIO_RING_SIZE * VIRTIO_MAX_VQS]
                      __attribute__((__aligned__(PAGE_SIZE)));
 
-static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
-
 static VDev vdev = {
     .nr_vqs = 1,
     .vrings = block,
@@ -94,14 +93,9 @@ static int run_ccw(VDev *vdev, int cmd, void *ptr, int len)
 {
     Ccw1 ccw = {};
     CmdOrb orb = {};
-    Schib schib;
     int r;
 
-    /* start command processing */
-    stsch_err(vdev->schid, &schib);
-    /* enable the subchannel for IPL device */
-    schib.pmcw.ena = 1;
-    msch(vdev->schid, &schib);
+    enable_subchannel(vdev->schid);
 
     /* start subchannel command */
     orb.fmt = 1;
@@ -343,20 +337,3 @@ bool virtio_is_supported(SubChannelId schid)
     }
     return false;
 }
-
-int enable_mss_facility(void)
-{
-    int ret;
-    ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
-
-    memset(sda_area, 0, PAGE_SIZE);
-    sda_area->request.length = 0x0400;
-    sda_area->request.code = 0x0031;
-    sda_area->operation_code = 0x2;
-
-    ret = chsc(sda_area);
-    if ((ret == 0) && (sda_area->response.code == 0x0001)) {
-        return 0;
-    }
-    return -EIO;
-}
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 05/19] s390-bios: Decouple channel i/o logic from virtio
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Create a separate library for channel i/o related code. This decouples
channel i/o operations from virtio and allows us to make use of them for
the real dasd boot path.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-6-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/Makefile    |  2 +-
 pc-bios/s390-ccw/cio.c       | 44 ++++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/cio.h       |  3 +++
 pc-bios/s390-ccw/main.c      |  1 +
 pc-bios/s390-ccw/netboot.mak |  2 +-
 pc-bios/s390-ccw/netmain.c   |  1 +
 pc-bios/s390-ccw/s390-ccw.h  |  1 -
 pc-bios/s390-ccw/virtio.c    | 27 ++--------------------
 8 files changed, 53 insertions(+), 28 deletions(-)
 create mode 100644 pc-bios/s390-ccw/cio.c

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 1eb316b02f1f..12ad9c1d5813 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -10,7 +10,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 .PHONY : all clean build-all
 
 OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
-	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o
+	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o
 
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
new file mode 100644
index 000000000000..87c6b34e88af
--- /dev/null
+++ b/pc-bios/s390-ccw/cio.c
@@ -0,0 +1,44 @@
+/*
+ * S390 Channel I/O
+ *
+ * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
+ * Copyright (c) 2019 IBM Corp.
+ *
+ * Author(s): Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+#include "cio.h"
+
+static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+
+int enable_mss_facility(void)
+{
+    int ret;
+    ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
+
+    memset(sda_area, 0, PAGE_SIZE);
+    sda_area->request.length = 0x0400;
+    sda_area->request.code = 0x0031;
+    sda_area->operation_code = 0x2;
+
+    ret = chsc(sda_area);
+    if ((ret == 0) && (sda_area->response.code == 0x0001)) {
+        return 0;
+    }
+    return -EIO;
+}
+
+void enable_subchannel(SubChannelId schid)
+{
+    Schib schib;
+
+    stsch_err(schid, &schib);
+    schib.pmcw.ena = 1;
+    msch(schid, &schib);
+}
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index ed5b2cbf72db..218fd96ea3a6 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -213,6 +213,9 @@ typedef struct irb {
     __u32 emw[8];
 }  __attribute__ ((packed, aligned(4))) Irb;
 
+int enable_mss_facility(void);
+void enable_subchannel(SubChannelId schid);
+
 /*
  * Some S390 specific IO instructions as inline
  */
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 67df42191b94..10f04c69068f 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -10,6 +10,7 @@
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "cio.h"
 #include "virtio.h"
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
index 14e96b2aa611..5eefb7c28939 100644
--- a/pc-bios/s390-ccw/netboot.mak
+++ b/pc-bios/s390-ccw/netboot.mak
@@ -1,7 +1,7 @@
 
 SLOF_DIR := $(SRC_PATH)/roms/SLOF
 
-NETOBJS := start.o sclp.o virtio.o virtio-net.o jump2ipl.o netmain.o \
+NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o \
 	   libnet.a libc.a
 
 LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index 0392131c27b3..5189c0fc39e5 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -33,6 +33,7 @@
 #include <pxelinux.h>
 
 #include "s390-ccw.h"
+#include "cio.h"
 #include "virtio.h"
 
 #define DEFAULT_BOOT_RETRIES 10
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 241c6d0b69be..b39ee5d32314 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -72,7 +72,6 @@ unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
 bool virtio_is_supported(SubChannelId schid);
 void virtio_blk_setup_device(SubChannelId schid);
 int virtio_read(ulong sector, void *load_addr);
-int enable_mss_facility(void);
 u64 get_clock(void);
 ulong get_second(void);
 
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index cdb66f459e15..aa9da7253fb2 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -10,6 +10,7 @@
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "cio.h"
 #include "virtio.h"
 #include "virtio-scsi.h"
 #include "bswap.h"
@@ -20,8 +21,6 @@ static VRing block[VIRTIO_MAX_VQS];
 static char ring_area[VIRTIO_RING_SIZE * VIRTIO_MAX_VQS]
                      __attribute__((__aligned__(PAGE_SIZE)));
 
-static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
-
 static VDev vdev = {
     .nr_vqs = 1,
     .vrings = block,
@@ -94,14 +93,9 @@ static int run_ccw(VDev *vdev, int cmd, void *ptr, int len)
 {
     Ccw1 ccw = {};
     CmdOrb orb = {};
-    Schib schib;
     int r;
 
-    /* start command processing */
-    stsch_err(vdev->schid, &schib);
-    /* enable the subchannel for IPL device */
-    schib.pmcw.ena = 1;
-    msch(vdev->schid, &schib);
+    enable_subchannel(vdev->schid);
 
     /* start subchannel command */
     orb.fmt = 1;
@@ -343,20 +337,3 @@ bool virtio_is_supported(SubChannelId schid)
     }
     return false;
 }
-
-int enable_mss_facility(void)
-{
-    int ret;
-    ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
-
-    memset(sda_area, 0, PAGE_SIZE);
-    sda_area->request.length = 0x0400;
-    sda_area->request.code = 0x0031;
-    sda_area->operation_code = 0x2;
-
-    ret = chsc(sda_area);
-    if ((ret == 0) && (sda_area->response.code == 0x0001)) {
-        return 0;
-    }
-    return -EIO;
-}
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 06/19] s390-bios: Map low core memory
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Create a new header for basic architecture specific definitions and add a
mapping of low core memory. This mapping will be used by the real dasd boot
process.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-7-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c      |  2 +
 pc-bios/s390-ccw/s390-arch.h | 90 ++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+)
 create mode 100644 pc-bios/s390-ccw/s390-arch.h

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 10f04c69068f..e403b5f733e4 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -9,6 +9,7 @@
  */
 
 #include "libc.h"
+#include "s390-arch.h"
 #include "s390-ccw.h"
 #include "cio.h"
 #include "virtio.h"
@@ -19,6 +20,7 @@ static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static bool have_iplb;
+LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
 
 #define LOADPARM_PROMPT "PROMPT  "
 #define LOADPARM_EMPTY  "        "
diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
new file mode 100644
index 000000000000..5e92c7a27d53
--- /dev/null
+++ b/pc-bios/s390-ccw/s390-arch.h
@@ -0,0 +1,90 @@
+/*
+ * S390 Basic Architecture
+ *
+ * Copyright (c) 2019 Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef S390_ARCH_H
+#define S390_ARCH_H
+
+typedef struct PSW {
+    uint64_t mask;
+    uint64_t addr;
+} __attribute__ ((aligned(8))) PSW;
+_Static_assert(sizeof(struct PSW) == 16, "PSW size incorrect");
+
+/* Older PSW format used by LPSW instruction */
+typedef struct PSWLegacy {
+    uint32_t mask;
+    uint32_t addr;
+} __attribute__ ((aligned(8))) PSWLegacy;
+_Static_assert(sizeof(struct PSWLegacy) == 8, "PSWLegacy size incorrect");
+
+/* s390 psw bit masks */
+#define PSW_MASK_IOINT      0x0200000000000000ULL
+#define PSW_MASK_WAIT       0x0002000000000000ULL
+#define PSW_MASK_EAMODE     0x0000000100000000ULL
+#define PSW_MASK_BAMODE     0x0000000080000000ULL
+#define PSW_MASK_ZMODE      (PSW_MASK_EAMODE | PSW_MASK_BAMODE)
+
+/* Low core mapping */
+typedef struct LowCore {
+    /* prefix area: defined by architecture */
+    PSWLegacy       ipl_psw;                  /* 0x000 */
+    uint32_t        ccw1[2];                  /* 0x008 */
+    uint32_t        ccw2[2];                  /* 0x010 */
+    uint8_t         pad1[0x80 - 0x18];        /* 0x018 */
+    uint32_t        ext_params;               /* 0x080 */
+    uint16_t        cpu_addr;                 /* 0x084 */
+    uint16_t        ext_int_code;             /* 0x086 */
+    uint16_t        svc_ilen;                 /* 0x088 */
+    uint16_t        svc_code;                 /* 0x08a */
+    uint16_t        pgm_ilen;                 /* 0x08c */
+    uint16_t        pgm_code;                 /* 0x08e */
+    uint32_t        data_exc_code;            /* 0x090 */
+    uint16_t        mon_class_num;            /* 0x094 */
+    uint16_t        per_perc_atmid;           /* 0x096 */
+    uint64_t        per_address;              /* 0x098 */
+    uint8_t         exc_access_id;            /* 0x0a0 */
+    uint8_t         per_access_id;            /* 0x0a1 */
+    uint8_t         op_access_id;             /* 0x0a2 */
+    uint8_t         ar_access_id;             /* 0x0a3 */
+    uint8_t         pad2[0xA8 - 0xA4];        /* 0x0a4 */
+    uint64_t        trans_exc_code;           /* 0x0a8 */
+    uint64_t        monitor_code;             /* 0x0b0 */
+    uint16_t        subchannel_id;            /* 0x0b8 */
+    uint16_t        subchannel_nr;            /* 0x0ba */
+    uint32_t        io_int_parm;              /* 0x0bc */
+    uint32_t        io_int_word;              /* 0x0c0 */
+    uint8_t         pad3[0xc8 - 0xc4];        /* 0x0c4 */
+    uint32_t        stfl_fac_list;            /* 0x0c8 */
+    uint8_t         pad4[0xe8 - 0xcc];        /* 0x0cc */
+    uint64_t        mcic;                     /* 0x0e8 */
+    uint8_t         pad5[0xf4 - 0xf0];        /* 0x0f0 */
+    uint32_t        external_damage_code;     /* 0x0f4 */
+    uint64_t        failing_storage_address;  /* 0x0f8 */
+    uint8_t         pad6[0x110 - 0x100];      /* 0x100 */
+    uint64_t        per_breaking_event_addr;  /* 0x110 */
+    uint8_t         pad7[0x120 - 0x118];      /* 0x118 */
+    PSW             restart_old_psw;          /* 0x120 */
+    PSW             external_old_psw;         /* 0x130 */
+    PSW             svc_old_psw;              /* 0x140 */
+    PSW             program_old_psw;          /* 0x150 */
+    PSW             mcck_old_psw;             /* 0x160 */
+    PSW             io_old_psw;               /* 0x170 */
+    uint8_t         pad8[0x1a0 - 0x180];      /* 0x180 */
+    PSW             restart_new_psw;          /* 0x1a0 */
+    PSW             external_new_psw;         /* 0x1b0 */
+    PSW             svc_new_psw;              /* 0x1c0 */
+    PSW             program_new_psw;          /* 0x1d0 */
+    PSW             mcck_new_psw;             /* 0x1e0 */
+    PSW             io_new_psw;               /* 0x1f0 */
+} __attribute__((packed, aligned(8192))) LowCore;
+
+extern LowCore const *lowcore;
+
+#endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 06/19] s390-bios: Map low core memory
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Create a new header for basic architecture specific definitions and add a
mapping of low core memory. This mapping will be used by the real dasd boot
process.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-7-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c      |  2 +
 pc-bios/s390-ccw/s390-arch.h | 90 ++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+)
 create mode 100644 pc-bios/s390-ccw/s390-arch.h

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 10f04c69068f..e403b5f733e4 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -9,6 +9,7 @@
  */
 
 #include "libc.h"
+#include "s390-arch.h"
 #include "s390-ccw.h"
 #include "cio.h"
 #include "virtio.h"
@@ -19,6 +20,7 @@ static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static bool have_iplb;
+LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
 
 #define LOADPARM_PROMPT "PROMPT  "
 #define LOADPARM_EMPTY  "        "
diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
new file mode 100644
index 000000000000..5e92c7a27d53
--- /dev/null
+++ b/pc-bios/s390-ccw/s390-arch.h
@@ -0,0 +1,90 @@
+/*
+ * S390 Basic Architecture
+ *
+ * Copyright (c) 2019 Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef S390_ARCH_H
+#define S390_ARCH_H
+
+typedef struct PSW {
+    uint64_t mask;
+    uint64_t addr;
+} __attribute__ ((aligned(8))) PSW;
+_Static_assert(sizeof(struct PSW) == 16, "PSW size incorrect");
+
+/* Older PSW format used by LPSW instruction */
+typedef struct PSWLegacy {
+    uint32_t mask;
+    uint32_t addr;
+} __attribute__ ((aligned(8))) PSWLegacy;
+_Static_assert(sizeof(struct PSWLegacy) == 8, "PSWLegacy size incorrect");
+
+/* s390 psw bit masks */
+#define PSW_MASK_IOINT      0x0200000000000000ULL
+#define PSW_MASK_WAIT       0x0002000000000000ULL
+#define PSW_MASK_EAMODE     0x0000000100000000ULL
+#define PSW_MASK_BAMODE     0x0000000080000000ULL
+#define PSW_MASK_ZMODE      (PSW_MASK_EAMODE | PSW_MASK_BAMODE)
+
+/* Low core mapping */
+typedef struct LowCore {
+    /* prefix area: defined by architecture */
+    PSWLegacy       ipl_psw;                  /* 0x000 */
+    uint32_t        ccw1[2];                  /* 0x008 */
+    uint32_t        ccw2[2];                  /* 0x010 */
+    uint8_t         pad1[0x80 - 0x18];        /* 0x018 */
+    uint32_t        ext_params;               /* 0x080 */
+    uint16_t        cpu_addr;                 /* 0x084 */
+    uint16_t        ext_int_code;             /* 0x086 */
+    uint16_t        svc_ilen;                 /* 0x088 */
+    uint16_t        svc_code;                 /* 0x08a */
+    uint16_t        pgm_ilen;                 /* 0x08c */
+    uint16_t        pgm_code;                 /* 0x08e */
+    uint32_t        data_exc_code;            /* 0x090 */
+    uint16_t        mon_class_num;            /* 0x094 */
+    uint16_t        per_perc_atmid;           /* 0x096 */
+    uint64_t        per_address;              /* 0x098 */
+    uint8_t         exc_access_id;            /* 0x0a0 */
+    uint8_t         per_access_id;            /* 0x0a1 */
+    uint8_t         op_access_id;             /* 0x0a2 */
+    uint8_t         ar_access_id;             /* 0x0a3 */
+    uint8_t         pad2[0xA8 - 0xA4];        /* 0x0a4 */
+    uint64_t        trans_exc_code;           /* 0x0a8 */
+    uint64_t        monitor_code;             /* 0x0b0 */
+    uint16_t        subchannel_id;            /* 0x0b8 */
+    uint16_t        subchannel_nr;            /* 0x0ba */
+    uint32_t        io_int_parm;              /* 0x0bc */
+    uint32_t        io_int_word;              /* 0x0c0 */
+    uint8_t         pad3[0xc8 - 0xc4];        /* 0x0c4 */
+    uint32_t        stfl_fac_list;            /* 0x0c8 */
+    uint8_t         pad4[0xe8 - 0xcc];        /* 0x0cc */
+    uint64_t        mcic;                     /* 0x0e8 */
+    uint8_t         pad5[0xf4 - 0xf0];        /* 0x0f0 */
+    uint32_t        external_damage_code;     /* 0x0f4 */
+    uint64_t        failing_storage_address;  /* 0x0f8 */
+    uint8_t         pad6[0x110 - 0x100];      /* 0x100 */
+    uint64_t        per_breaking_event_addr;  /* 0x110 */
+    uint8_t         pad7[0x120 - 0x118];      /* 0x118 */
+    PSW             restart_old_psw;          /* 0x120 */
+    PSW             external_old_psw;         /* 0x130 */
+    PSW             svc_old_psw;              /* 0x140 */
+    PSW             program_old_psw;          /* 0x150 */
+    PSW             mcck_old_psw;             /* 0x160 */
+    PSW             io_old_psw;               /* 0x170 */
+    uint8_t         pad8[0x1a0 - 0x180];      /* 0x180 */
+    PSW             restart_new_psw;          /* 0x1a0 */
+    PSW             external_new_psw;         /* 0x1b0 */
+    PSW             svc_new_psw;              /* 0x1c0 */
+    PSW             program_new_psw;          /* 0x1d0 */
+    PSW             mcck_new_psw;             /* 0x1e0 */
+    PSW             io_new_psw;               /* 0x1f0 */
+} __attribute__((packed, aligned(8192))) LowCore;
+
+extern LowCore const *lowcore;
+
+#endif
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 07/19] s390-bios: ptr2u32 and u32toptr
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Introduce inline functions to convert between pointers and unsigned 32-bit
ints. These are used to hide the ugliness required to  avoid compiler
warnings.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-8-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/helper.h | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 pc-bios/s390-ccw/helper.h

diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h
new file mode 100644
index 000000000000..78d5bc74421b
--- /dev/null
+++ b/pc-bios/s390-ccw/helper.h
@@ -0,0 +1,31 @@
+/*
+ * Helper Functions
+ *
+ * Copyright (c) 2019 IBM Corp.
+ *
+ * Author(s): Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef S390_CCW_HELPER_H
+#define S390_CCW_HELPER_H
+
+#include "s390-ccw.h"
+
+/* Avoids compiler warnings when casting a pointer to a u32 */
+static inline uint32_t ptr2u32(void *ptr)
+{
+    IPL_assert((uint64_t)ptr <= 0xffffffff, "ptr2u32: ptr too large");
+    return (uint32_t)(uint64_t)ptr;
+}
+
+/* Avoids compiler warnings when casting a u32 to a pointer */
+static inline void *u32toptr(uint32_t n)
+{
+    return (void *)(uint64_t)n;
+}
+
+#endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 07/19] s390-bios: ptr2u32 and u32toptr
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Introduce inline functions to convert between pointers and unsigned 32-bit
ints. These are used to hide the ugliness required to  avoid compiler
warnings.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-8-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/helper.h | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 pc-bios/s390-ccw/helper.h

diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h
new file mode 100644
index 000000000000..78d5bc74421b
--- /dev/null
+++ b/pc-bios/s390-ccw/helper.h
@@ -0,0 +1,31 @@
+/*
+ * Helper Functions
+ *
+ * Copyright (c) 2019 IBM Corp.
+ *
+ * Author(s): Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef S390_CCW_HELPER_H
+#define S390_CCW_HELPER_H
+
+#include "s390-ccw.h"
+
+/* Avoids compiler warnings when casting a pointer to a u32 */
+static inline uint32_t ptr2u32(void *ptr)
+{
+    IPL_assert((uint64_t)ptr <= 0xffffffff, "ptr2u32: ptr too large");
+    return (uint32_t)(uint64_t)ptr;
+}
+
+/* Avoids compiler warnings when casting a u32 to a pointer */
+static inline void *u32toptr(uint32_t n)
+{
+    return (void *)(uint64_t)n;
+}
+
+#endif
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 08/19] s390-bios: Support for running format-0/1 channel programs
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Introduce a library function for executing format-0 and format-1
channel programs and waiting for their completion before continuing
execution.

Add cu_type() to channel io library. This will be used to query control
unit type which is used to determine if we are booting a virtio device or a
real dasd device.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Message-Id: <1554388475-18329-9-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/cio.c      | 144 ++++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/cio.h      | 130 +++++++++++++++++++++++++++++++-
 pc-bios/s390-ccw/s390-ccw.h |   1 +
 pc-bios/s390-ccw/start.S    |  29 ++++++++
 4 files changed, 301 insertions(+), 3 deletions(-)

diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index 87c6b34e88af..c43e50b00b8e 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -13,10 +13,14 @@
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "s390-arch.h"
+#include "helper.h"
 #include "cio.h"
 
 static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
+static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb);
+
 int enable_mss_facility(void)
 {
     int ret;
@@ -42,3 +46,143 @@ void enable_subchannel(SubChannelId schid)
     schib.pmcw.ena = 1;
     msch(schid, &schib);
 }
+
+uint16_t cu_type(SubChannelId schid)
+{
+    Ccw1 sense_id_ccw;
+    SenseId sense_data;
+
+    sense_id_ccw.cmd_code = CCW_CMD_SENSE_ID;
+    sense_id_ccw.cda = ptr2u32(&sense_data);
+    sense_id_ccw.count = sizeof(sense_data);
+    sense_id_ccw.flags |= CCW_FLAG_SLI;
+
+    if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
+        panic("Failed to run SenseID CCw\n");
+    }
+
+    return sense_data.cu_type;
+}
+
+int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data,
+                 uint16_t data_size)
+{
+    Ccw1 senseCcw;
+    Irb irb;
+
+    senseCcw.cmd_code = CCW_CMD_BASIC_SENSE;
+    senseCcw.cda = ptr2u32(sense_data);
+    senseCcw.count = data_size;
+
+    return __do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1, &irb);
+}
+
+static bool irb_error(Irb *irb)
+{
+    if (irb->scsw.cstat) {
+        return true;
+    }
+    return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND);
+}
+
+/*
+ * Handles executing ssch, tsch and returns the irb obtained from tsch.
+ * Returns 0 on success, -1 if unexpected status pending and we need to retry,
+ * otherwise returns condition code from ssch/tsch for error cases.
+ */
+static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
+{
+    CmdOrb orb = {};
+    int rc;
+
+    IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format");
+
+    /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */
+    if (fmt == 0) {
+        IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address");
+    }
+
+    orb.fmt = fmt;
+    orb.pfch = 1;  /* QEMU's cio implementation requires prefetch */
+    orb.c64 = 1;   /* QEMU's cio implementation requires 64-bit idaws */
+    orb.lpm = 0xFF; /* All paths allowed */
+    orb.cpa = ccw_addr;
+
+    rc = ssch(schid, &orb);
+    if (rc == 1 || rc == 2) {
+        /* Subchannel status pending or busy. Eat status and ask for retry. */
+        tsch(schid, irb);
+        return -1;
+    }
+    if (rc) {
+        print_int("ssch failed with cc=", rc);
+        return rc;
+    }
+
+    consume_io_int();
+
+    /* collect status */
+    rc = tsch(schid, irb);
+    if (rc) {
+        print_int("tsch failed with cc=", rc);
+    }
+
+    return rc;
+}
+
+/*
+ * Executes a channel program at a given subchannel. The request to run the
+ * channel program is sent to the subchannel, we then wait for the interrupt
+ * signaling completion of the I/O operation(s) performed by the channel
+ * program. Lastly we verify that the i/o operation completed without error and
+ * that the interrupt we received was for the subchannel used to run the
+ * channel program.
+ *
+ * Note: This function assumes it is running in an environment where no other
+ * cpus are generating or receiving I/O interrupts. So either run it in a
+ * single-cpu environment or make sure all other cpus are not doing I/O and
+ * have I/O interrupts masked off. We also assume that only one device is
+ * active (generating i/o interrupts).
+ *
+ * Returns non-zero on error.
+ */
+int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
+{
+    Irb irb = {};
+    SenseDataEckdDasd sd;
+    int rc, retries = 0;
+
+    while (true) {
+        rc = __do_cio(schid, ccw_addr, fmt, &irb);
+
+        if (rc == -1) {
+            retries++;
+            continue;
+        }
+        if (rc) {
+            /* ssch/tsch error. Message already reported by __do_cio */
+            break;
+        }
+
+        if (!irb_error(&irb)) {
+            break;
+        }
+
+        /*
+         * Unexpected unit check, or interface-control-check. Use sense to
+         * clear (unit check only) then retry.
+         */
+        if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) {
+            if (unit_check(&irb)) {
+                basic_sense(schid, cutype, &sd, sizeof(sd));
+            }
+            retries++;
+            continue;
+        }
+
+        rc = -1;
+        break;
+    }
+
+    return rc;
+}
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 218fd96ea3a6..1637e32070f3 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -70,9 +70,46 @@ struct scsw {
     __u16 count;
 } __attribute__ ((packed));
 
-#define SCSW_FCTL_CLEAR_FUNC 0x1000
-#define SCSW_FCTL_HALT_FUNC 0x2000
+/* Function Control */
 #define SCSW_FCTL_START_FUNC 0x4000
+#define SCSW_FCTL_HALT_FUNC 0x2000
+#define SCSW_FCTL_CLEAR_FUNC 0x1000
+
+/* Activity Control */
+#define SCSW_ACTL_RESUME_PEND   0x0800
+#define SCSW_ACTL_START_PEND    0x0400
+#define SCSW_ACTL_HALT_PEND     0x0200
+#define SCSW_ACTL_CLEAR_PEND    0x0100
+#define SCSW_ACTL_CH_ACTIVE     0x0080
+#define SCSW_ACTL_DEV_ACTIVE    0x0040
+#define SCSW_ACTL_SUSPENDED     0x0020
+
+/* Status Control */
+#define SCSW_SCTL_ALERT         0x0010
+#define SCSW_SCTL_INTERMED      0x0008
+#define SCSW_SCTL_PRIMARY       0x0004
+#define SCSW_SCTL_SECONDARY     0x0002
+#define SCSW_SCTL_STATUS_PEND   0x0001
+
+/* SCSW Device Status Flags */
+#define SCSW_DSTAT_ATTN     0x80
+#define SCSW_DSTAT_STATMOD  0x40
+#define SCSW_DSTAT_CUEND    0x20
+#define SCSW_DSTAT_BUSY     0x10
+#define SCSW_DSTAT_CHEND    0x08
+#define SCSW_DSTAT_DEVEND   0x04
+#define SCSW_DSTAT_UCHK     0x02
+#define SCSW_DSTAT_UEXCP    0x01
+
+/* SCSW Subchannel Status Flags */
+#define SCSW_CSTAT_PCINT    0x80
+#define SCSW_CSTAT_BADLEN   0x40
+#define SCSW_CSTAT_PROGCHK  0x20
+#define SCSW_CSTAT_PROTCHK  0x10
+#define SCSW_CSTAT_CHDCHK   0x08
+#define SCSW_CSTAT_CHCCHK   0x04
+#define SCSW_CSTAT_ICCHK    0x02
+#define SCSW_CSTAT_CHAINCHK 0x01
 
 /*
  * subchannel information block
@@ -127,7 +164,23 @@ struct tpi_info {
     __u32 reserved4:12;
 } __attribute__ ((packed, aligned(4)));
 
-/* channel command word (type 1) */
+/* channel command word (format 0) */
+typedef struct ccw0 {
+    __u8 cmd_code;
+    __u32 cda:24;
+    __u32 chainData:1;
+    __u32 chain:1;
+    __u32 sli:1;
+    __u32 skip:1;
+    __u32 pci:1;
+    __u32 ida:1;
+    __u32 suspend:1;
+    __u32 mida:1;
+    __u8 reserved;
+    __u16 count;
+} __attribute__ ((packed, aligned(8))) Ccw0;
+
+/* channel command word (format 1) */
 typedef struct ccw1 {
     __u8 cmd_code;
     __u8 flags;
@@ -135,6 +188,10 @@ typedef struct ccw1 {
     __u32 cda;
 } __attribute__ ((packed, aligned(8))) Ccw1;
 
+/* do_cio() CCW formats */
+#define CCW_FMT0                 0x00
+#define CCW_FMT1                 0x01
+
 #define CCW_FLAG_DC              0x80
 #define CCW_FLAG_CC              0x40
 #define CCW_FLAG_SLI             0x20
@@ -190,6 +247,11 @@ struct ciw {
     __u16 count;
 };
 
+#define CU_TYPE_UNKNOWN         0x0000
+#define CU_TYPE_DASD_2107       0x2107
+#define CU_TYPE_VIRTIO          0x3832
+#define CU_TYPE_DASD_3990       0x3990
+
 /*
  * sense-id response buffer layout
  */
@@ -205,6 +267,64 @@ typedef struct senseid {
     struct ciw ciw[62];
 }  __attribute__ ((packed, aligned(4))) SenseId;
 
+/*
+ * architected values for first sense byte - common_status. Bits 0-5 of this
+ * field are common to all device types.
+ */
+#define SNS_STAT0_CMD_REJECT         0x80
+#define SNS_STAT0_INTERVENTION_REQ   0x40
+#define SNS_STAT0_BUS_OUT_CHECK      0x20
+#define SNS_STAT0_EQUIPMENT_CHECK    0x10
+#define SNS_STAT0_DATA_CHECK         0x08
+#define SNS_STAT0_OVERRUN            0x04
+#define SNS_STAT0_INCOMPL_DOMAIN     0x01
+
+/* ECKD DASD status[0] byte */
+#define SNS_STAT1_PERM_ERR           0x80
+#define SNS_STAT1_INV_TRACK_FORMAT   0x40
+#define SNS_STAT1_EOC                0x20
+#define SNS_STAT1_MESSAGE_TO_OPER    0x10
+#define SNS_STAT1_NO_REC_FOUND       0x08
+#define SNS_STAT1_FILE_PROTECTED     0x04
+#define SNS_STAT1_WRITE_INHIBITED    0x02
+#define SNS_STAT1_IMPRECISE_END      0x01
+
+/* ECKD DASD status[1] byte */
+#define SNS_STAT2_REQ_INH_WRITE      0x80
+#define SNS_STAT2_CORRECTABLE        0x40
+#define SNS_STAT2_FIRST_LOG_ERR      0x20
+#define SNS_STAT2_ENV_DATA_PRESENT   0x10
+#define SNS_STAT2_IMPRECISE_END      0x04
+
+/* ECKD DASD 24-byte Sense fmt_msg codes */
+#define SENSE24_FMT_PROG_SYS    0x0
+#define SENSE24_FMT_EQUIPMENT   0x2
+#define SENSE24_FMT_CONTROLLER  0x3
+#define SENSE24_FMT_MISC        0xF
+
+/* basic sense response buffer layout */
+typedef struct SenseDataEckdDasd {
+    uint8_t common_status;
+    uint8_t status[2];
+    uint8_t res_count;
+    uint8_t phys_drive_id;
+    uint8_t low_cyl_addr;
+    uint8_t head_high_cyl_addr;
+    uint8_t fmt_msg;
+    uint64_t fmt_dependent_info[2];
+    uint8_t reserved;
+    uint8_t program_action_code;
+    uint16_t config_info;
+    uint8_t mcode_hicyl;
+    uint8_t cyl_head_addr[3];
+}  __attribute__ ((packed, aligned(4))) SenseDataEckdDasd;
+
+#define ECKD_SENSE24_GET_FMT(sd)     (sd->fmt_msg & 0xF0 >> 4)
+#define ECKD_SENSE24_GET_MSG(sd)     (sd->fmt_msg & 0x0F)
+
+#define unit_check(irb)         ((irb)->scsw.dstat & SCSW_DSTAT_UCHK)
+#define iface_ctrl_check(irb)   ((irb)->scsw.cstat & SCSW_CSTAT_ICCHK)
+
 /* interruption response block */
 typedef struct irb {
     struct scsw scsw;
@@ -215,6 +335,10 @@ typedef struct irb {
 
 int enable_mss_facility(void);
 void enable_subchannel(SubChannelId schid);
+uint16_t cu_type(SubChannelId schid);
+int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data,
+                 uint16_t data_size);
+int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt);
 
 /*
  * Some S390 specific IO instructions as inline
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index b39ee5d32314..11bce7d73c85 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -52,6 +52,7 @@ typedef unsigned long long __u64;
 /* start.s */
 void disabled_wait(void);
 void consume_sclp_int(void);
+void consume_io_int(void);
 
 /* main.c */
 void panic(const char *string);
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index 5c22cb0849d3..aa8fceb19da2 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -71,6 +71,26 @@ consume_sclp_int:
         larl %r1, enabled_wait_psw
         lpswe 0(%r1)
 
+/*
+ * void consume_io_int(void)
+ *
+ * eats one I/O interrupt
+ */
+        .globl consume_io_int
+consume_io_int:
+        /* enable I/O interrupts in cr6 */
+        stctg %c6,%c6,0(%r15)
+        oi    4(%r15), 0xff
+        lctlg %c6,%c6,0(%r15)
+        /* prepare i/o call handler */
+        larl  %r1, io_new_code
+        stg   %r1, 0x1f8
+        larl  %r1, io_new_mask
+        mvc   0x1f0(8),0(%r1)
+        /* load enabled wait PSW */
+        larl  %r1, enabled_wait_psw
+        lpswe 0(%r1)
+
 external_new_code:
         /* disable service interrupts in cr0 */
         stctg   %c0,%c0,0(%r15)
@@ -78,6 +98,13 @@ external_new_code:
         lctlg   %c0,%c0,0(%r15)
         br      %r14
 
+io_new_code:
+        /* disable I/O interrupts in cr6 */
+        stctg %c6,%c6,0(%r15)
+        ni    4(%r15), 0x00
+        lctlg %c6,%c6,0(%r15)
+        br    %r14
+
         .align  8
 disabled_wait_psw:
         .quad   0x0002000180000000,0x0000000000000000
@@ -85,3 +112,5 @@ enabled_wait_psw:
         .quad   0x0302000180000000,0x0000000000000000
 external_new_mask:
         .quad   0x0000000180000000
+io_new_mask:
+        .quad   0x0000000180000000
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 08/19] s390-bios: Support for running format-0/1 channel programs
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Introduce a library function for executing format-0 and format-1
channel programs and waiting for their completion before continuing
execution.

Add cu_type() to channel io library. This will be used to query control
unit type which is used to determine if we are booting a virtio device or a
real dasd device.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Message-Id: <1554388475-18329-9-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/cio.c      | 144 ++++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/cio.h      | 130 +++++++++++++++++++++++++++++++-
 pc-bios/s390-ccw/s390-ccw.h |   1 +
 pc-bios/s390-ccw/start.S    |  29 ++++++++
 4 files changed, 301 insertions(+), 3 deletions(-)

diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index 87c6b34e88af..c43e50b00b8e 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -13,10 +13,14 @@
 
 #include "libc.h"
 #include "s390-ccw.h"
+#include "s390-arch.h"
+#include "helper.h"
 #include "cio.h"
 
 static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
+static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb);
+
 int enable_mss_facility(void)
 {
     int ret;
@@ -42,3 +46,143 @@ void enable_subchannel(SubChannelId schid)
     schib.pmcw.ena = 1;
     msch(schid, &schib);
 }
+
+uint16_t cu_type(SubChannelId schid)
+{
+    Ccw1 sense_id_ccw;
+    SenseId sense_data;
+
+    sense_id_ccw.cmd_code = CCW_CMD_SENSE_ID;
+    sense_id_ccw.cda = ptr2u32(&sense_data);
+    sense_id_ccw.count = sizeof(sense_data);
+    sense_id_ccw.flags |= CCW_FLAG_SLI;
+
+    if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
+        panic("Failed to run SenseID CCw\n");
+    }
+
+    return sense_data.cu_type;
+}
+
+int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data,
+                 uint16_t data_size)
+{
+    Ccw1 senseCcw;
+    Irb irb;
+
+    senseCcw.cmd_code = CCW_CMD_BASIC_SENSE;
+    senseCcw.cda = ptr2u32(sense_data);
+    senseCcw.count = data_size;
+
+    return __do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1, &irb);
+}
+
+static bool irb_error(Irb *irb)
+{
+    if (irb->scsw.cstat) {
+        return true;
+    }
+    return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND);
+}
+
+/*
+ * Handles executing ssch, tsch and returns the irb obtained from tsch.
+ * Returns 0 on success, -1 if unexpected status pending and we need to retry,
+ * otherwise returns condition code from ssch/tsch for error cases.
+ */
+static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
+{
+    CmdOrb orb = {};
+    int rc;
+
+    IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format");
+
+    /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */
+    if (fmt == 0) {
+        IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address");
+    }
+
+    orb.fmt = fmt;
+    orb.pfch = 1;  /* QEMU's cio implementation requires prefetch */
+    orb.c64 = 1;   /* QEMU's cio implementation requires 64-bit idaws */
+    orb.lpm = 0xFF; /* All paths allowed */
+    orb.cpa = ccw_addr;
+
+    rc = ssch(schid, &orb);
+    if (rc == 1 || rc == 2) {
+        /* Subchannel status pending or busy. Eat status and ask for retry. */
+        tsch(schid, irb);
+        return -1;
+    }
+    if (rc) {
+        print_int("ssch failed with cc=", rc);
+        return rc;
+    }
+
+    consume_io_int();
+
+    /* collect status */
+    rc = tsch(schid, irb);
+    if (rc) {
+        print_int("tsch failed with cc=", rc);
+    }
+
+    return rc;
+}
+
+/*
+ * Executes a channel program at a given subchannel. The request to run the
+ * channel program is sent to the subchannel, we then wait for the interrupt
+ * signaling completion of the I/O operation(s) performed by the channel
+ * program. Lastly we verify that the i/o operation completed without error and
+ * that the interrupt we received was for the subchannel used to run the
+ * channel program.
+ *
+ * Note: This function assumes it is running in an environment where no other
+ * cpus are generating or receiving I/O interrupts. So either run it in a
+ * single-cpu environment or make sure all other cpus are not doing I/O and
+ * have I/O interrupts masked off. We also assume that only one device is
+ * active (generating i/o interrupts).
+ *
+ * Returns non-zero on error.
+ */
+int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
+{
+    Irb irb = {};
+    SenseDataEckdDasd sd;
+    int rc, retries = 0;
+
+    while (true) {
+        rc = __do_cio(schid, ccw_addr, fmt, &irb);
+
+        if (rc == -1) {
+            retries++;
+            continue;
+        }
+        if (rc) {
+            /* ssch/tsch error. Message already reported by __do_cio */
+            break;
+        }
+
+        if (!irb_error(&irb)) {
+            break;
+        }
+
+        /*
+         * Unexpected unit check, or interface-control-check. Use sense to
+         * clear (unit check only) then retry.
+         */
+        if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) {
+            if (unit_check(&irb)) {
+                basic_sense(schid, cutype, &sd, sizeof(sd));
+            }
+            retries++;
+            continue;
+        }
+
+        rc = -1;
+        break;
+    }
+
+    return rc;
+}
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 218fd96ea3a6..1637e32070f3 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -70,9 +70,46 @@ struct scsw {
     __u16 count;
 } __attribute__ ((packed));
 
-#define SCSW_FCTL_CLEAR_FUNC 0x1000
-#define SCSW_FCTL_HALT_FUNC 0x2000
+/* Function Control */
 #define SCSW_FCTL_START_FUNC 0x4000
+#define SCSW_FCTL_HALT_FUNC 0x2000
+#define SCSW_FCTL_CLEAR_FUNC 0x1000
+
+/* Activity Control */
+#define SCSW_ACTL_RESUME_PEND   0x0800
+#define SCSW_ACTL_START_PEND    0x0400
+#define SCSW_ACTL_HALT_PEND     0x0200
+#define SCSW_ACTL_CLEAR_PEND    0x0100
+#define SCSW_ACTL_CH_ACTIVE     0x0080
+#define SCSW_ACTL_DEV_ACTIVE    0x0040
+#define SCSW_ACTL_SUSPENDED     0x0020
+
+/* Status Control */
+#define SCSW_SCTL_ALERT         0x0010
+#define SCSW_SCTL_INTERMED      0x0008
+#define SCSW_SCTL_PRIMARY       0x0004
+#define SCSW_SCTL_SECONDARY     0x0002
+#define SCSW_SCTL_STATUS_PEND   0x0001
+
+/* SCSW Device Status Flags */
+#define SCSW_DSTAT_ATTN     0x80
+#define SCSW_DSTAT_STATMOD  0x40
+#define SCSW_DSTAT_CUEND    0x20
+#define SCSW_DSTAT_BUSY     0x10
+#define SCSW_DSTAT_CHEND    0x08
+#define SCSW_DSTAT_DEVEND   0x04
+#define SCSW_DSTAT_UCHK     0x02
+#define SCSW_DSTAT_UEXCP    0x01
+
+/* SCSW Subchannel Status Flags */
+#define SCSW_CSTAT_PCINT    0x80
+#define SCSW_CSTAT_BADLEN   0x40
+#define SCSW_CSTAT_PROGCHK  0x20
+#define SCSW_CSTAT_PROTCHK  0x10
+#define SCSW_CSTAT_CHDCHK   0x08
+#define SCSW_CSTAT_CHCCHK   0x04
+#define SCSW_CSTAT_ICCHK    0x02
+#define SCSW_CSTAT_CHAINCHK 0x01
 
 /*
  * subchannel information block
@@ -127,7 +164,23 @@ struct tpi_info {
     __u32 reserved4:12;
 } __attribute__ ((packed, aligned(4)));
 
-/* channel command word (type 1) */
+/* channel command word (format 0) */
+typedef struct ccw0 {
+    __u8 cmd_code;
+    __u32 cda:24;
+    __u32 chainData:1;
+    __u32 chain:1;
+    __u32 sli:1;
+    __u32 skip:1;
+    __u32 pci:1;
+    __u32 ida:1;
+    __u32 suspend:1;
+    __u32 mida:1;
+    __u8 reserved;
+    __u16 count;
+} __attribute__ ((packed, aligned(8))) Ccw0;
+
+/* channel command word (format 1) */
 typedef struct ccw1 {
     __u8 cmd_code;
     __u8 flags;
@@ -135,6 +188,10 @@ typedef struct ccw1 {
     __u32 cda;
 } __attribute__ ((packed, aligned(8))) Ccw1;
 
+/* do_cio() CCW formats */
+#define CCW_FMT0                 0x00
+#define CCW_FMT1                 0x01
+
 #define CCW_FLAG_DC              0x80
 #define CCW_FLAG_CC              0x40
 #define CCW_FLAG_SLI             0x20
@@ -190,6 +247,11 @@ struct ciw {
     __u16 count;
 };
 
+#define CU_TYPE_UNKNOWN         0x0000
+#define CU_TYPE_DASD_2107       0x2107
+#define CU_TYPE_VIRTIO          0x3832
+#define CU_TYPE_DASD_3990       0x3990
+
 /*
  * sense-id response buffer layout
  */
@@ -205,6 +267,64 @@ typedef struct senseid {
     struct ciw ciw[62];
 }  __attribute__ ((packed, aligned(4))) SenseId;
 
+/*
+ * architected values for first sense byte - common_status. Bits 0-5 of this
+ * field are common to all device types.
+ */
+#define SNS_STAT0_CMD_REJECT         0x80
+#define SNS_STAT0_INTERVENTION_REQ   0x40
+#define SNS_STAT0_BUS_OUT_CHECK      0x20
+#define SNS_STAT0_EQUIPMENT_CHECK    0x10
+#define SNS_STAT0_DATA_CHECK         0x08
+#define SNS_STAT0_OVERRUN            0x04
+#define SNS_STAT0_INCOMPL_DOMAIN     0x01
+
+/* ECKD DASD status[0] byte */
+#define SNS_STAT1_PERM_ERR           0x80
+#define SNS_STAT1_INV_TRACK_FORMAT   0x40
+#define SNS_STAT1_EOC                0x20
+#define SNS_STAT1_MESSAGE_TO_OPER    0x10
+#define SNS_STAT1_NO_REC_FOUND       0x08
+#define SNS_STAT1_FILE_PROTECTED     0x04
+#define SNS_STAT1_WRITE_INHIBITED    0x02
+#define SNS_STAT1_IMPRECISE_END      0x01
+
+/* ECKD DASD status[1] byte */
+#define SNS_STAT2_REQ_INH_WRITE      0x80
+#define SNS_STAT2_CORRECTABLE        0x40
+#define SNS_STAT2_FIRST_LOG_ERR      0x20
+#define SNS_STAT2_ENV_DATA_PRESENT   0x10
+#define SNS_STAT2_IMPRECISE_END      0x04
+
+/* ECKD DASD 24-byte Sense fmt_msg codes */
+#define SENSE24_FMT_PROG_SYS    0x0
+#define SENSE24_FMT_EQUIPMENT   0x2
+#define SENSE24_FMT_CONTROLLER  0x3
+#define SENSE24_FMT_MISC        0xF
+
+/* basic sense response buffer layout */
+typedef struct SenseDataEckdDasd {
+    uint8_t common_status;
+    uint8_t status[2];
+    uint8_t res_count;
+    uint8_t phys_drive_id;
+    uint8_t low_cyl_addr;
+    uint8_t head_high_cyl_addr;
+    uint8_t fmt_msg;
+    uint64_t fmt_dependent_info[2];
+    uint8_t reserved;
+    uint8_t program_action_code;
+    uint16_t config_info;
+    uint8_t mcode_hicyl;
+    uint8_t cyl_head_addr[3];
+}  __attribute__ ((packed, aligned(4))) SenseDataEckdDasd;
+
+#define ECKD_SENSE24_GET_FMT(sd)     (sd->fmt_msg & 0xF0 >> 4)
+#define ECKD_SENSE24_GET_MSG(sd)     (sd->fmt_msg & 0x0F)
+
+#define unit_check(irb)         ((irb)->scsw.dstat & SCSW_DSTAT_UCHK)
+#define iface_ctrl_check(irb)   ((irb)->scsw.cstat & SCSW_CSTAT_ICCHK)
+
 /* interruption response block */
 typedef struct irb {
     struct scsw scsw;
@@ -215,6 +335,10 @@ typedef struct irb {
 
 int enable_mss_facility(void);
 void enable_subchannel(SubChannelId schid);
+uint16_t cu_type(SubChannelId schid);
+int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data,
+                 uint16_t data_size);
+int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt);
 
 /*
  * Some S390 specific IO instructions as inline
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index b39ee5d32314..11bce7d73c85 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -52,6 +52,7 @@ typedef unsigned long long __u64;
 /* start.s */
 void disabled_wait(void);
 void consume_sclp_int(void);
+void consume_io_int(void);
 
 /* main.c */
 void panic(const char *string);
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index 5c22cb0849d3..aa8fceb19da2 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -71,6 +71,26 @@ consume_sclp_int:
         larl %r1, enabled_wait_psw
         lpswe 0(%r1)
 
+/*
+ * void consume_io_int(void)
+ *
+ * eats one I/O interrupt
+ */
+        .globl consume_io_int
+consume_io_int:
+        /* enable I/O interrupts in cr6 */
+        stctg %c6,%c6,0(%r15)
+        oi    4(%r15), 0xff
+        lctlg %c6,%c6,0(%r15)
+        /* prepare i/o call handler */
+        larl  %r1, io_new_code
+        stg   %r1, 0x1f8
+        larl  %r1, io_new_mask
+        mvc   0x1f0(8),0(%r1)
+        /* load enabled wait PSW */
+        larl  %r1, enabled_wait_psw
+        lpswe 0(%r1)
+
 external_new_code:
         /* disable service interrupts in cr0 */
         stctg   %c0,%c0,0(%r15)
@@ -78,6 +98,13 @@ external_new_code:
         lctlg   %c0,%c0,0(%r15)
         br      %r14
 
+io_new_code:
+        /* disable I/O interrupts in cr6 */
+        stctg %c6,%c6,0(%r15)
+        ni    4(%r15), 0x00
+        lctlg %c6,%c6,0(%r15)
+        br    %r14
+
         .align  8
 disabled_wait_psw:
         .quad   0x0002000180000000,0x0000000000000000
@@ -85,3 +112,5 @@ enabled_wait_psw:
         .quad   0x0302000180000000,0x0000000000000000
 external_new_mask:
         .quad   0x0000000180000000
+io_new_mask:
+        .quad   0x0000000180000000
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 09/19] s390-bios: cio error handling
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Add verbose error output for when unexpected i/o errors happen. This eases the
burden of debugging and reporting i/o errors. No error information is printed
in the success case, here is an example of what is output on error:

cio device error
  ssid  : 0x0000000000000000
  cssid : 0x0000000000000000
  sch_no: 0x0000000000000000

Interrupt Response Block Data:
    Function Ctrl : [Start]
    Activity Ctrl : [Start-Pending]
    Status Ctrl : [Alert] [Primary] [Secondary] [Status-Pending]
    Device Status : [Unit-Check]
    Channel Status :
    cpa=: 0x000000007f8d6038
    prev_ccw=: 0x0000000000000000
    this_ccw=: 0x0000000000000000
Eckd Dasd Sense Data (fmt 32-bytes):
    Sense Condition Flags :
    Residual Count     =: 0x0000000000000000
    Phys Drive ID      =: 0x000000000000009e
    low cyl address    =: 0x0000000000000000
    head addr & hi cyl =: 0x0000000000000000
    format/message     =: 0x0000000000000008
    fmt-dependent[0-7] =: 0x0000000000000004
    fmt-dependent[8-15]=: 0xe561282305082fff
    prog action code   =: 0x0000000000000016
    Configuration info =: 0x00000000000040e0
    mcode / hi-cyl     =: 0x0000000000000000
    cyl & head addr [0]=: 0x0000000000000000
    cyl & head addr [1]=: 0x0000000000000000
    cyl & head addr [2]=: 0x0000000000000000

The Sense Data section is currently only printed for ECKD DASD.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-10-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/cio.c  | 235 ++++++++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/libc.h |  11 ++
 2 files changed, 246 insertions(+)

diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index c43e50b00b8e..339ec5fbe7a4 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -85,6 +85,228 @@ static bool irb_error(Irb *irb)
     return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND);
 }
 
+static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
+{
+    char msgline[512];
+
+    if (sd->config_info & 0x8000) {
+        sclp_print("Eckd Dasd Sense Data (fmt 24-bytes):\n");
+    } else {
+        sclp_print("Eckd Dasd Sense Data (fmt 32-bytes):\n");
+    }
+
+    strcat(msgline, "    Sense Condition Flags :");
+    if (sd->common_status & SNS_STAT0_CMD_REJECT) {
+        strcat(msgline, " [Cmd-Reject]");
+    }
+    if (sd->common_status & SNS_STAT0_INTERVENTION_REQ) {
+        strcat(msgline, " [Intervention-Required]");
+    }
+    if (sd->common_status & SNS_STAT0_BUS_OUT_CHECK) {
+        strcat(msgline, " [Bus-Out-Parity-Check]");
+    }
+    if (sd->common_status & SNS_STAT0_EQUIPMENT_CHECK) {
+        strcat(msgline, " [Equipment-Check]");
+    }
+    if (sd->common_status & SNS_STAT0_DATA_CHECK) {
+        strcat(msgline, " [Data-Check]");
+    }
+    if (sd->common_status & SNS_STAT0_OVERRUN) {
+        strcat(msgline, " [Overrun]");
+    }
+    if (sd->common_status & SNS_STAT0_INCOMPL_DOMAIN) {
+        strcat(msgline, " [Incomplete-Domain]");
+    }
+
+    if (sd->status[0] & SNS_STAT1_PERM_ERR) {
+        strcat(msgline, " [Permanent-Error]");
+    }
+    if (sd->status[0] & SNS_STAT1_INV_TRACK_FORMAT) {
+        strcat(msgline, " [Invalid-Track-Fmt]");
+    }
+    if (sd->status[0] & SNS_STAT1_EOC) {
+        strcat(msgline, " [End-of-Cyl]");
+    }
+    if (sd->status[0] & SNS_STAT1_MESSAGE_TO_OPER) {
+        strcat(msgline, " [Operator-Msg]");
+    }
+    if (sd->status[0] & SNS_STAT1_NO_REC_FOUND) {
+        strcat(msgline, " [No-Record-Found]");
+    }
+    if (sd->status[0] & SNS_STAT1_FILE_PROTECTED) {
+        strcat(msgline, " [File-Protected]");
+    }
+    if (sd->status[0] & SNS_STAT1_WRITE_INHIBITED) {
+        strcat(msgline, " [Write-Inhibited]");
+    }
+    if (sd->status[0] & SNS_STAT1_IMPRECISE_END) {
+        strcat(msgline, " [Imprecise-Ending]");
+    }
+
+    if (sd->status[1] & SNS_STAT2_REQ_INH_WRITE) {
+        strcat(msgline, " [Req-Inhibit-Write]");
+    }
+    if (sd->status[1] & SNS_STAT2_CORRECTABLE) {
+        strcat(msgline, " [Correctable-Data-Check]");
+    }
+    if (sd->status[1] & SNS_STAT2_FIRST_LOG_ERR) {
+        strcat(msgline, " [First-Error-Log]");
+    }
+    if (sd->status[1] & SNS_STAT2_ENV_DATA_PRESENT) {
+        strcat(msgline, " [Env-Data-Present]");
+    }
+    if (sd->status[1] & SNS_STAT2_IMPRECISE_END) {
+        strcat(msgline, " [Imprecise-End]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    print_int("    Residual Count     =", sd->res_count);
+    print_int("    Phys Drive ID      =", sd->phys_drive_id);
+    print_int("    low cyl address    =", sd->low_cyl_addr);
+    print_int("    head addr & hi cyl =", sd->head_high_cyl_addr);
+    print_int("    format/message     =", sd->fmt_msg);
+    print_int("    fmt-dependent[0-7] =", sd->fmt_dependent_info[0]);
+    print_int("    fmt-dependent[8-15]=", sd->fmt_dependent_info[1]);
+    print_int("    prog action code   =", sd->program_action_code);
+    print_int("    Configuration info =", sd->config_info);
+    print_int("    mcode / hi-cyl     =", sd->mcode_hicyl);
+    print_int("    cyl & head addr [0]=", sd->cyl_head_addr[0]);
+    print_int("    cyl & head addr [1]=", sd->cyl_head_addr[1]);
+    print_int("    cyl & head addr [2]=", sd->cyl_head_addr[2]);
+}
+
+static void print_irb_err(Irb *irb)
+{
+    uint64_t this_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa);
+    uint64_t prev_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa - 8);
+    char msgline[256];
+
+    sclp_print("Interrupt Response Block Data:\n");
+
+    strcat(msgline, "    Function Ctrl :");
+    if (irb->scsw.ctrl & SCSW_FCTL_START_FUNC) {
+        strcat(msgline, " [Start]");
+    }
+    if (irb->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
+        strcat(msgline, " [Halt]");
+    }
+    if (irb->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
+        strcat(msgline, " [Clear]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    msgline[0] = '\0';
+    strcat(msgline, "    Activity Ctrl :");
+    if (irb->scsw.ctrl & SCSW_ACTL_RESUME_PEND) {
+        strcat(msgline, " [Resume-Pending]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_START_PEND) {
+        strcat(msgline, " [Start-Pending]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_HALT_PEND) {
+        strcat(msgline, " [Halt-Pending]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_CLEAR_PEND) {
+        strcat(msgline, " [Clear-Pending]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_CH_ACTIVE) {
+        strcat(msgline, " [Channel-Active]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_DEV_ACTIVE) {
+        strcat(msgline, " [Device-Active]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_SUSPENDED) {
+        strcat(msgline, " [Suspended]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    msgline[0] = '\0';
+    strcat(msgline, "    Status Ctrl :");
+    if (irb->scsw.ctrl & SCSW_SCTL_ALERT) {
+        strcat(msgline, " [Alert]");
+    }
+    if (irb->scsw.ctrl & SCSW_SCTL_INTERMED) {
+        strcat(msgline, " [Intermediate]");
+    }
+    if (irb->scsw.ctrl & SCSW_SCTL_PRIMARY) {
+        strcat(msgline, " [Primary]");
+    }
+    if (irb->scsw.ctrl & SCSW_SCTL_SECONDARY) {
+        strcat(msgline, " [Secondary]");
+    }
+    if (irb->scsw.ctrl & SCSW_SCTL_STATUS_PEND) {
+        strcat(msgline, " [Status-Pending]");
+    }
+
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    msgline[0] = '\0';
+    strcat(msgline, "    Device Status :");
+    if (irb->scsw.dstat & SCSW_DSTAT_ATTN) {
+        strcat(msgline, " [Attention]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_STATMOD) {
+        strcat(msgline, " [Status-Modifier]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_CUEND) {
+        strcat(msgline, " [Ctrl-Unit-End]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_BUSY) {
+        strcat(msgline, " [Busy]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_CHEND) {
+        strcat(msgline, " [Channel-End]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_DEVEND) {
+        strcat(msgline, " [Device-End]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_UCHK) {
+        strcat(msgline, " [Unit-Check]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_UEXCP) {
+        strcat(msgline, " [Unit-Exception]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    msgline[0] = '\0';
+    strcat(msgline, "    Channel Status :");
+    if (irb->scsw.cstat & SCSW_CSTAT_PCINT) {
+        strcat(msgline, " [Program-Ctrl-Interruption]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_BADLEN) {
+        strcat(msgline, " [Incorrect-Length]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_PROGCHK) {
+        strcat(msgline, " [Program-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_PROTCHK) {
+        strcat(msgline, " [Protection-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_CHDCHK) {
+        strcat(msgline, " [Channel-Data-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_CHCCHK) {
+        strcat(msgline, " [Channel-Ctrl-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_ICCHK) {
+        strcat(msgline, " [Interface-Ctrl-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_CHAINCHK) {
+        strcat(msgline, " [Chaining-Check]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    print_int("    cpa=", irb->scsw.cpa);
+    print_int("    prev_ccw=", prev_ccw);
+    print_int("    this_ccw=", this_ccw);
+}
+
 /*
  * Handles executing ssch, tsch and returns the irb obtained from tsch.
  * Returns 0 on success, -1 if unexpected status pending and we need to retry,
@@ -180,6 +402,19 @@ int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
             continue;
         }
 
+        sclp_print("cio device error\n");
+        print_int("  ssid  ", schid.ssid);
+        print_int("  cssid ", schid.cssid);
+        print_int("  sch_no", schid.sch_no);
+        print_int("  ctrl-unit type", cutype);
+        sclp_print("\n");
+        print_irb_err(&irb);
+        if (cutype == CU_TYPE_DASD_3990 || cutype == CU_TYPE_DASD_2107 ||
+            cutype == CU_TYPE_UNKNOWN) {
+            if (!basic_sense(schid, cutype, &sd, sizeof(sd))) {
+                print_eckd_dasd_sense_data(&sd);
+            }
+        }
         rc = -1;
         break;
     }
diff --git a/pc-bios/s390-ccw/libc.h b/pc-bios/s390-ccw/libc.h
index 818517ff5d44..bcdc45732dd8 100644
--- a/pc-bios/s390-ccw/libc.h
+++ b/pc-bios/s390-ccw/libc.h
@@ -67,6 +67,17 @@ static inline size_t strlen(const char *str)
     return i;
 }
 
+static inline char *strcat(char *dest, const char *src)
+{
+    int i;
+    char *dest_end = dest + strlen(dest);
+
+    for (i = 0; i <= strlen(src); i++) {
+        dest_end[i] = src[i];
+    }
+    return dest;
+}
+
 static inline int isdigit(int c)
 {
     return (c >= '0') && (c <= '9');
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 09/19] s390-bios: cio error handling
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Add verbose error output for when unexpected i/o errors happen. This eases the
burden of debugging and reporting i/o errors. No error information is printed
in the success case, here is an example of what is output on error:

cio device error
  ssid  : 0x0000000000000000
  cssid : 0x0000000000000000
  sch_no: 0x0000000000000000

Interrupt Response Block Data:
    Function Ctrl : [Start]
    Activity Ctrl : [Start-Pending]
    Status Ctrl : [Alert] [Primary] [Secondary] [Status-Pending]
    Device Status : [Unit-Check]
    Channel Status :
    cpa=: 0x000000007f8d6038
    prev_ccw=: 0x0000000000000000
    this_ccw=: 0x0000000000000000
Eckd Dasd Sense Data (fmt 32-bytes):
    Sense Condition Flags :
    Residual Count     =: 0x0000000000000000
    Phys Drive ID      =: 0x000000000000009e
    low cyl address    =: 0x0000000000000000
    head addr & hi cyl =: 0x0000000000000000
    format/message     =: 0x0000000000000008
    fmt-dependent[0-7] =: 0x0000000000000004
    fmt-dependent[8-15]=: 0xe561282305082fff
    prog action code   =: 0x0000000000000016
    Configuration info =: 0x00000000000040e0
    mcode / hi-cyl     =: 0x0000000000000000
    cyl & head addr [0]=: 0x0000000000000000
    cyl & head addr [1]=: 0x0000000000000000
    cyl & head addr [2]=: 0x0000000000000000

The Sense Data section is currently only printed for ECKD DASD.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-10-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/cio.c  | 235 ++++++++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/libc.h |  11 ++
 2 files changed, 246 insertions(+)

diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index c43e50b00b8e..339ec5fbe7a4 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -85,6 +85,228 @@ static bool irb_error(Irb *irb)
     return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND);
 }
 
+static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
+{
+    char msgline[512];
+
+    if (sd->config_info & 0x8000) {
+        sclp_print("Eckd Dasd Sense Data (fmt 24-bytes):\n");
+    } else {
+        sclp_print("Eckd Dasd Sense Data (fmt 32-bytes):\n");
+    }
+
+    strcat(msgline, "    Sense Condition Flags :");
+    if (sd->common_status & SNS_STAT0_CMD_REJECT) {
+        strcat(msgline, " [Cmd-Reject]");
+    }
+    if (sd->common_status & SNS_STAT0_INTERVENTION_REQ) {
+        strcat(msgline, " [Intervention-Required]");
+    }
+    if (sd->common_status & SNS_STAT0_BUS_OUT_CHECK) {
+        strcat(msgline, " [Bus-Out-Parity-Check]");
+    }
+    if (sd->common_status & SNS_STAT0_EQUIPMENT_CHECK) {
+        strcat(msgline, " [Equipment-Check]");
+    }
+    if (sd->common_status & SNS_STAT0_DATA_CHECK) {
+        strcat(msgline, " [Data-Check]");
+    }
+    if (sd->common_status & SNS_STAT0_OVERRUN) {
+        strcat(msgline, " [Overrun]");
+    }
+    if (sd->common_status & SNS_STAT0_INCOMPL_DOMAIN) {
+        strcat(msgline, " [Incomplete-Domain]");
+    }
+
+    if (sd->status[0] & SNS_STAT1_PERM_ERR) {
+        strcat(msgline, " [Permanent-Error]");
+    }
+    if (sd->status[0] & SNS_STAT1_INV_TRACK_FORMAT) {
+        strcat(msgline, " [Invalid-Track-Fmt]");
+    }
+    if (sd->status[0] & SNS_STAT1_EOC) {
+        strcat(msgline, " [End-of-Cyl]");
+    }
+    if (sd->status[0] & SNS_STAT1_MESSAGE_TO_OPER) {
+        strcat(msgline, " [Operator-Msg]");
+    }
+    if (sd->status[0] & SNS_STAT1_NO_REC_FOUND) {
+        strcat(msgline, " [No-Record-Found]");
+    }
+    if (sd->status[0] & SNS_STAT1_FILE_PROTECTED) {
+        strcat(msgline, " [File-Protected]");
+    }
+    if (sd->status[0] & SNS_STAT1_WRITE_INHIBITED) {
+        strcat(msgline, " [Write-Inhibited]");
+    }
+    if (sd->status[0] & SNS_STAT1_IMPRECISE_END) {
+        strcat(msgline, " [Imprecise-Ending]");
+    }
+
+    if (sd->status[1] & SNS_STAT2_REQ_INH_WRITE) {
+        strcat(msgline, " [Req-Inhibit-Write]");
+    }
+    if (sd->status[1] & SNS_STAT2_CORRECTABLE) {
+        strcat(msgline, " [Correctable-Data-Check]");
+    }
+    if (sd->status[1] & SNS_STAT2_FIRST_LOG_ERR) {
+        strcat(msgline, " [First-Error-Log]");
+    }
+    if (sd->status[1] & SNS_STAT2_ENV_DATA_PRESENT) {
+        strcat(msgline, " [Env-Data-Present]");
+    }
+    if (sd->status[1] & SNS_STAT2_IMPRECISE_END) {
+        strcat(msgline, " [Imprecise-End]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    print_int("    Residual Count     =", sd->res_count);
+    print_int("    Phys Drive ID      =", sd->phys_drive_id);
+    print_int("    low cyl address    =", sd->low_cyl_addr);
+    print_int("    head addr & hi cyl =", sd->head_high_cyl_addr);
+    print_int("    format/message     =", sd->fmt_msg);
+    print_int("    fmt-dependent[0-7] =", sd->fmt_dependent_info[0]);
+    print_int("    fmt-dependent[8-15]=", sd->fmt_dependent_info[1]);
+    print_int("    prog action code   =", sd->program_action_code);
+    print_int("    Configuration info =", sd->config_info);
+    print_int("    mcode / hi-cyl     =", sd->mcode_hicyl);
+    print_int("    cyl & head addr [0]=", sd->cyl_head_addr[0]);
+    print_int("    cyl & head addr [1]=", sd->cyl_head_addr[1]);
+    print_int("    cyl & head addr [2]=", sd->cyl_head_addr[2]);
+}
+
+static void print_irb_err(Irb *irb)
+{
+    uint64_t this_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa);
+    uint64_t prev_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa - 8);
+    char msgline[256];
+
+    sclp_print("Interrupt Response Block Data:\n");
+
+    strcat(msgline, "    Function Ctrl :");
+    if (irb->scsw.ctrl & SCSW_FCTL_START_FUNC) {
+        strcat(msgline, " [Start]");
+    }
+    if (irb->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
+        strcat(msgline, " [Halt]");
+    }
+    if (irb->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
+        strcat(msgline, " [Clear]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    msgline[0] = '\0';
+    strcat(msgline, "    Activity Ctrl :");
+    if (irb->scsw.ctrl & SCSW_ACTL_RESUME_PEND) {
+        strcat(msgline, " [Resume-Pending]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_START_PEND) {
+        strcat(msgline, " [Start-Pending]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_HALT_PEND) {
+        strcat(msgline, " [Halt-Pending]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_CLEAR_PEND) {
+        strcat(msgline, " [Clear-Pending]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_CH_ACTIVE) {
+        strcat(msgline, " [Channel-Active]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_DEV_ACTIVE) {
+        strcat(msgline, " [Device-Active]");
+    }
+    if (irb->scsw.ctrl & SCSW_ACTL_SUSPENDED) {
+        strcat(msgline, " [Suspended]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    msgline[0] = '\0';
+    strcat(msgline, "    Status Ctrl :");
+    if (irb->scsw.ctrl & SCSW_SCTL_ALERT) {
+        strcat(msgline, " [Alert]");
+    }
+    if (irb->scsw.ctrl & SCSW_SCTL_INTERMED) {
+        strcat(msgline, " [Intermediate]");
+    }
+    if (irb->scsw.ctrl & SCSW_SCTL_PRIMARY) {
+        strcat(msgline, " [Primary]");
+    }
+    if (irb->scsw.ctrl & SCSW_SCTL_SECONDARY) {
+        strcat(msgline, " [Secondary]");
+    }
+    if (irb->scsw.ctrl & SCSW_SCTL_STATUS_PEND) {
+        strcat(msgline, " [Status-Pending]");
+    }
+
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    msgline[0] = '\0';
+    strcat(msgline, "    Device Status :");
+    if (irb->scsw.dstat & SCSW_DSTAT_ATTN) {
+        strcat(msgline, " [Attention]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_STATMOD) {
+        strcat(msgline, " [Status-Modifier]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_CUEND) {
+        strcat(msgline, " [Ctrl-Unit-End]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_BUSY) {
+        strcat(msgline, " [Busy]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_CHEND) {
+        strcat(msgline, " [Channel-End]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_DEVEND) {
+        strcat(msgline, " [Device-End]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_UCHK) {
+        strcat(msgline, " [Unit-Check]");
+    }
+    if (irb->scsw.dstat & SCSW_DSTAT_UEXCP) {
+        strcat(msgline, " [Unit-Exception]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    msgline[0] = '\0';
+    strcat(msgline, "    Channel Status :");
+    if (irb->scsw.cstat & SCSW_CSTAT_PCINT) {
+        strcat(msgline, " [Program-Ctrl-Interruption]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_BADLEN) {
+        strcat(msgline, " [Incorrect-Length]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_PROGCHK) {
+        strcat(msgline, " [Program-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_PROTCHK) {
+        strcat(msgline, " [Protection-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_CHDCHK) {
+        strcat(msgline, " [Channel-Data-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_CHCCHK) {
+        strcat(msgline, " [Channel-Ctrl-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_ICCHK) {
+        strcat(msgline, " [Interface-Ctrl-Check]");
+    }
+    if (irb->scsw.cstat & SCSW_CSTAT_CHAINCHK) {
+        strcat(msgline, " [Chaining-Check]");
+    }
+    strcat(msgline, "\n");
+    sclp_print(msgline);
+
+    print_int("    cpa=", irb->scsw.cpa);
+    print_int("    prev_ccw=", prev_ccw);
+    print_int("    this_ccw=", this_ccw);
+}
+
 /*
  * Handles executing ssch, tsch and returns the irb obtained from tsch.
  * Returns 0 on success, -1 if unexpected status pending and we need to retry,
@@ -180,6 +402,19 @@ int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
             continue;
         }
 
+        sclp_print("cio device error\n");
+        print_int("  ssid  ", schid.ssid);
+        print_int("  cssid ", schid.cssid);
+        print_int("  sch_no", schid.sch_no);
+        print_int("  ctrl-unit type", cutype);
+        sclp_print("\n");
+        print_irb_err(&irb);
+        if (cutype == CU_TYPE_DASD_3990 || cutype == CU_TYPE_DASD_2107 ||
+            cutype == CU_TYPE_UNKNOWN) {
+            if (!basic_sense(schid, cutype, &sd, sizeof(sd))) {
+                print_eckd_dasd_sense_data(&sd);
+            }
+        }
         rc = -1;
         break;
     }
diff --git a/pc-bios/s390-ccw/libc.h b/pc-bios/s390-ccw/libc.h
index 818517ff5d44..bcdc45732dd8 100644
--- a/pc-bios/s390-ccw/libc.h
+++ b/pc-bios/s390-ccw/libc.h
@@ -67,6 +67,17 @@ static inline size_t strlen(const char *str)
     return i;
 }
 
+static inline char *strcat(char *dest, const char *src)
+{
+    int i;
+    char *dest_end = dest + strlen(dest);
+
+    for (i = 0; i <= strlen(src); i++) {
+        dest_end[i] = src[i];
+    }
+    return dest;
+}
+
 static inline int isdigit(int c)
 {
     return (c >= '0') && (c <= '9');
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 10/19] s390-bios: Extend find_dev() for non-virtio devices
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

We need a method for finding the subchannel of a dasd device. Let's
modify find_dev to handle this since it mostly does what we need. Up to
this point find_dev has been specific to only virtio devices.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-11-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e403b5f733e4..d04ea8972a0c 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -52,6 +52,12 @@ unsigned int get_loadparm_index(void)
     return atoui(loadparm_str);
 }
 
+/*
+ * Find the subchannel connected to the given device (dev_no) and fill in the
+ * subchannel information block (schib) with the connected subchannel's info.
+ * NOTE: The global variable blk_schid is updated to contain the subchannel
+ * information.
+ */
 static bool find_dev(Schib *schib, int dev_no)
 {
     int i, r;
@@ -65,15 +71,15 @@ static bool find_dev(Schib *schib, int dev_no)
         if (!schib->pmcw.dnv) {
             continue;
         }
-        if (!virtio_is_supported(blk_schid)) {
-            continue;
-        }
+
         /* Skip net devices since no IPLB is created and therefore no
-         * no network bootloader has been loaded
+         * network bootloader has been loaded
          */
-        if (virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
+        if (virtio_is_supported(blk_schid) &&
+            virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
             continue;
         }
+
         if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
             return true;
         }
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 10/19] s390-bios: Extend find_dev() for non-virtio devices
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

We need a method for finding the subchannel of a dasd device. Let's
modify find_dev to handle this since it mostly does what we need. Up to
this point find_dev has been specific to only virtio devices.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-11-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index e403b5f733e4..d04ea8972a0c 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -52,6 +52,12 @@ unsigned int get_loadparm_index(void)
     return atoui(loadparm_str);
 }
 
+/*
+ * Find the subchannel connected to the given device (dev_no) and fill in the
+ * subchannel information block (schib) with the connected subchannel's info.
+ * NOTE: The global variable blk_schid is updated to contain the subchannel
+ * information.
+ */
 static bool find_dev(Schib *schib, int dev_no)
 {
     int i, r;
@@ -65,15 +71,15 @@ static bool find_dev(Schib *schib, int dev_no)
         if (!schib->pmcw.dnv) {
             continue;
         }
-        if (!virtio_is_supported(blk_schid)) {
-            continue;
-        }
+
         /* Skip net devices since no IPLB is created and therefore no
-         * no network bootloader has been loaded
+         * network bootloader has been loaded
          */
-        if (virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
+        if (virtio_is_supported(blk_schid) &&
+            virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
             continue;
         }
+
         if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
             return true;
         }
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 11/19] s390-bios: Factor finding boot device out of virtio code path
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Make a new routine find_boot_device to locate the boot device for all
cases, not just virtio.

The error message for the case where no boot device has been specified
and a suitable boot device cannot be auto detected was specific to
virtio devices. We update this message to remove virtio specific wording.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-12-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c  | 85 ++++++++++++++++++++++------------------
 tests/boot-serial-test.c |  2 +-
 2 files changed, 47 insertions(+), 40 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index d04ea8972a0c..d3a161c68546 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -58,17 +58,18 @@ unsigned int get_loadparm_index(void)
  * NOTE: The global variable blk_schid is updated to contain the subchannel
  * information.
  */
-static bool find_dev(Schib *schib, int dev_no)
+static bool find_subch(int dev_no)
 {
+    Schib schib;
     int i, r;
 
     for (i = 0; i < 0x10000; i++) {
         blk_schid.sch_no = i;
-        r = stsch_err(blk_schid, schib);
+        r = stsch_err(blk_schid, &schib);
         if ((r == 3) || (r == -EIO)) {
             break;
         }
-        if (!schib->pmcw.dnv) {
+        if (!schib.pmcw.dnv) {
             continue;
         }
 
@@ -80,7 +81,7 @@ static bool find_dev(Schib *schib, int dev_no)
             continue;
         }
 
-        if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
+        if ((dev_no < 0) || (schib.pmcw.dev == dev_no)) {
             return true;
         }
     }
@@ -136,56 +137,61 @@ static void boot_setup(void)
     have_iplb = store_iplb(&iplb);
 }
 
-static void virtio_setup(void)
+static void find_boot_device(void)
 {
-    Schib schib;
-    int ssid;
-    bool found = false;
-    uint16_t dev_no;
     VDev *vdev = virtio_get_device();
-    QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
-
-    memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
+    int ssid;
+    bool found;
 
-    if (have_iplb) {
-        switch (iplb.pbt) {
-        case S390_IPL_TYPE_CCW:
-            dev_no = iplb.ccw.devno;
-            debug_print_int("device no. ", dev_no);
-            blk_schid.ssid = iplb.ccw.ssid & 0x3;
-            debug_print_int("ssid ", blk_schid.ssid);
-            found = find_dev(&schib, dev_no);
-            break;
-        case S390_IPL_TYPE_QEMU_SCSI:
-            vdev->scsi_device_selected = true;
-            vdev->selected_scsi_device.channel = iplb.scsi.channel;
-            vdev->selected_scsi_device.target = iplb.scsi.target;
-            vdev->selected_scsi_device.lun = iplb.scsi.lun;
-            blk_schid.ssid = iplb.scsi.ssid & 0x3;
-            found = find_dev(&schib, iplb.scsi.devno);
-            break;
-        default:
-            panic("List-directed IPL not supported yet!\n");
-        }
-        menu_setup();
-    } else {
+    if (!have_iplb) {
         for (ssid = 0; ssid < 0x3; ssid++) {
             blk_schid.ssid = ssid;
-            found = find_dev(&schib, -1);
+            found = find_subch(-1);
             if (found) {
-                break;
+                return;
             }
         }
+        panic("Could not find a suitable boot device (none specified)\n");
+    }
+
+    switch (iplb.pbt) {
+    case S390_IPL_TYPE_CCW:
+        debug_print_int("device no. ", iplb.ccw.devno);
+        blk_schid.ssid = iplb.ccw.ssid & 0x3;
+        debug_print_int("ssid ", blk_schid.ssid);
+        found = find_subch(iplb.ccw.devno);
+        break;
+    case S390_IPL_TYPE_QEMU_SCSI:
+        vdev->scsi_device_selected = true;
+        vdev->selected_scsi_device.channel = iplb.scsi.channel;
+        vdev->selected_scsi_device.target = iplb.scsi.target;
+        vdev->selected_scsi_device.lun = iplb.scsi.lun;
+        blk_schid.ssid = iplb.scsi.ssid & 0x3;
+        found = find_subch(iplb.scsi.devno);
+        break;
+    default:
+        panic("List-directed IPL not supported yet!\n");
     }
 
-    IPL_assert(found, "No virtio device found");
+    IPL_assert(found, "Boot device not found\n");
+}
+
+static void virtio_setup(void)
+{
+    VDev *vdev = virtio_get_device();
+    QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
+
+    memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
+
+    if (have_iplb) {
+        menu_setup();
+    }
 
     if (virtio_get_device_type() == VIRTIO_ID_NET) {
         sclp_print("Network boot device detected\n");
         vdev->netboot_start_addr = qipl.netboot_start_addr;
     } else {
         virtio_blk_setup_device(blk_schid);
-
         IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
     }
 }
@@ -195,8 +201,9 @@ int main(void)
     sclp_setup();
     css_setup();
     boot_setup();
-    virtio_setup();
+    find_boot_device();
 
+    virtio_setup();
     zipl_load(); /* no return */
 
     panic("Failed to load OS from hard disk\n");
diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c
index c591748aaf00..24852d4c7d0b 100644
--- a/tests/boot-serial-test.c
+++ b/tests/boot-serial-test.c
@@ -114,7 +114,7 @@ static testdef_t tests[] = {
     { "sparc", "SS-4", "", "MB86904" },
     { "sparc", "SS-600MP", "", "TMS390Z55" },
     { "sparc64", "sun4u", "", "UltraSPARC" },
-    { "s390x", "s390-ccw-virtio", "", "virtio device" },
+    { "s390x", "s390-ccw-virtio", "", "device" },
     { "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
     { "microblaze", "petalogix-s3adsp1800", "", "TT",
       sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 11/19] s390-bios: Factor finding boot device out of virtio code path
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Make a new routine find_boot_device to locate the boot device for all
cases, not just virtio.

The error message for the case where no boot device has been specified
and a suitable boot device cannot be auto detected was specific to
virtio devices. We update this message to remove virtio specific wording.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-12-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c  | 85 ++++++++++++++++++++++------------------
 tests/boot-serial-test.c |  2 +-
 2 files changed, 47 insertions(+), 40 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index d04ea8972a0c..d3a161c68546 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -58,17 +58,18 @@ unsigned int get_loadparm_index(void)
  * NOTE: The global variable blk_schid is updated to contain the subchannel
  * information.
  */
-static bool find_dev(Schib *schib, int dev_no)
+static bool find_subch(int dev_no)
 {
+    Schib schib;
     int i, r;
 
     for (i = 0; i < 0x10000; i++) {
         blk_schid.sch_no = i;
-        r = stsch_err(blk_schid, schib);
+        r = stsch_err(blk_schid, &schib);
         if ((r == 3) || (r == -EIO)) {
             break;
         }
-        if (!schib->pmcw.dnv) {
+        if (!schib.pmcw.dnv) {
             continue;
         }
 
@@ -80,7 +81,7 @@ static bool find_dev(Schib *schib, int dev_no)
             continue;
         }
 
-        if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) {
+        if ((dev_no < 0) || (schib.pmcw.dev == dev_no)) {
             return true;
         }
     }
@@ -136,56 +137,61 @@ static void boot_setup(void)
     have_iplb = store_iplb(&iplb);
 }
 
-static void virtio_setup(void)
+static void find_boot_device(void)
 {
-    Schib schib;
-    int ssid;
-    bool found = false;
-    uint16_t dev_no;
     VDev *vdev = virtio_get_device();
-    QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
-
-    memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
+    int ssid;
+    bool found;
 
-    if (have_iplb) {
-        switch (iplb.pbt) {
-        case S390_IPL_TYPE_CCW:
-            dev_no = iplb.ccw.devno;
-            debug_print_int("device no. ", dev_no);
-            blk_schid.ssid = iplb.ccw.ssid & 0x3;
-            debug_print_int("ssid ", blk_schid.ssid);
-            found = find_dev(&schib, dev_no);
-            break;
-        case S390_IPL_TYPE_QEMU_SCSI:
-            vdev->scsi_device_selected = true;
-            vdev->selected_scsi_device.channel = iplb.scsi.channel;
-            vdev->selected_scsi_device.target = iplb.scsi.target;
-            vdev->selected_scsi_device.lun = iplb.scsi.lun;
-            blk_schid.ssid = iplb.scsi.ssid & 0x3;
-            found = find_dev(&schib, iplb.scsi.devno);
-            break;
-        default:
-            panic("List-directed IPL not supported yet!\n");
-        }
-        menu_setup();
-    } else {
+    if (!have_iplb) {
         for (ssid = 0; ssid < 0x3; ssid++) {
             blk_schid.ssid = ssid;
-            found = find_dev(&schib, -1);
+            found = find_subch(-1);
             if (found) {
-                break;
+                return;
             }
         }
+        panic("Could not find a suitable boot device (none specified)\n");
+    }
+
+    switch (iplb.pbt) {
+    case S390_IPL_TYPE_CCW:
+        debug_print_int("device no. ", iplb.ccw.devno);
+        blk_schid.ssid = iplb.ccw.ssid & 0x3;
+        debug_print_int("ssid ", blk_schid.ssid);
+        found = find_subch(iplb.ccw.devno);
+        break;
+    case S390_IPL_TYPE_QEMU_SCSI:
+        vdev->scsi_device_selected = true;
+        vdev->selected_scsi_device.channel = iplb.scsi.channel;
+        vdev->selected_scsi_device.target = iplb.scsi.target;
+        vdev->selected_scsi_device.lun = iplb.scsi.lun;
+        blk_schid.ssid = iplb.scsi.ssid & 0x3;
+        found = find_subch(iplb.scsi.devno);
+        break;
+    default:
+        panic("List-directed IPL not supported yet!\n");
     }
 
-    IPL_assert(found, "No virtio device found");
+    IPL_assert(found, "Boot device not found\n");
+}
+
+static void virtio_setup(void)
+{
+    VDev *vdev = virtio_get_device();
+    QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
+
+    memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
+
+    if (have_iplb) {
+        menu_setup();
+    }
 
     if (virtio_get_device_type() == VIRTIO_ID_NET) {
         sclp_print("Network boot device detected\n");
         vdev->netboot_start_addr = qipl.netboot_start_addr;
     } else {
         virtio_blk_setup_device(blk_schid);
-
         IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
     }
 }
@@ -195,8 +201,9 @@ int main(void)
     sclp_setup();
     css_setup();
     boot_setup();
-    virtio_setup();
+    find_boot_device();
 
+    virtio_setup();
     zipl_load(); /* no return */
 
     panic("Failed to load OS from hard disk\n");
diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c
index c591748aaf00..24852d4c7d0b 100644
--- a/tests/boot-serial-test.c
+++ b/tests/boot-serial-test.c
@@ -114,7 +114,7 @@ static testdef_t tests[] = {
     { "sparc", "SS-4", "", "MB86904" },
     { "sparc", "SS-600MP", "", "TMS390Z55" },
     { "sparc64", "sun4u", "", "UltraSPARC" },
-    { "s390x", "s390-ccw-virtio", "", "virtio device" },
+    { "s390x", "s390-ccw-virtio", "", "device" },
     { "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
     { "microblaze", "petalogix-s3adsp1800", "", "TT",
       sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 12/19] s390-bios: Refactor virtio to run channel programs via cio
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Now that we have a Channel I/O library let's modify virtio boot code to
make use of it for running channel programs.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-13-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/virtio.c | 57 +++++++++++++++++++--------------------
 1 file changed, 27 insertions(+), 30 deletions(-)

diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index aa9da7253fb2..35278eaee13d 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -14,6 +14,7 @@
 #include "virtio.h"
 #include "virtio-scsi.h"
 #include "bswap.h"
+#include "helper.h"
 
 #define VRING_WAIT_REPLY_TIMEOUT 30
 
@@ -89,33 +90,20 @@ int drain_irqs(SubChannelId schid)
     }
 }
 
-static int run_ccw(VDev *vdev, int cmd, void *ptr, int len)
+static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
 {
     Ccw1 ccw = {};
-    CmdOrb orb = {};
-    int r;
-
-    enable_subchannel(vdev->schid);
-
-    /* start subchannel command */
-    orb.fmt = 1;
-    orb.cpa = (u32)(long)&ccw;
-    orb.lpm = 0x80;
 
     ccw.cmd_code = cmd;
     ccw.cda = (long)ptr;
     ccw.count = len;
 
-    r = ssch(vdev->schid, &orb);
-    /*
-     * XXX Wait until device is done processing the CCW. For now we can
-     *     assume that a simple tsch will have finished the CCW processing,
-     *     but the architecture allows for asynchronous operation
-     */
-    if (!r) {
-        r = drain_irqs(vdev->schid);
+    if (sli) {
+        ccw.flags |= CCW_FLAG_SLI;
     }
-    return r;
+
+    enable_subchannel(vdev->schid);
+    return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), CCW_FMT1);
 }
 
 static void vring_init(VRing *vr, VqInfo *info)
@@ -257,7 +245,7 @@ void virtio_setup_ccw(VDev *vdev)
     vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
     vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
 
-    run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0);
+    run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
 
     switch (vdev->senseid.cu_model) {
     case VIRTIO_ID_NET:
@@ -278,18 +266,19 @@ void virtio_setup_ccw(VDev *vdev)
     default:
         panic("Unsupported virtio device\n");
     }
-    IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0,
-               "Could not get block device configuration");
+    IPL_assert(
+        run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false) == 0,
+       "Could not get block device configuration");
 
     /* Feature negotiation */
     for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
         feats.features = 0;
         feats.index = i;
-        rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats));
+        rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false);
         IPL_assert(rc == 0, "Could not get features bits");
         vdev->guest_features[i] &= bswap32(feats.features);
         feats.features = bswap32(vdev->guest_features[i]);
-        rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats));
+        rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false);
         IPL_assert(rc == 0, "Could not set features bits");
     }
 
@@ -306,16 +295,17 @@ void virtio_setup_ccw(VDev *vdev)
         };
 
         IPL_assert(
-            run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config)) == 0,
+            run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false) == 0,
             "Could not get block device VQ configuration");
         info.num = config.num;
         vring_init(&vdev->vrings[i], &info);
         vdev->vrings[i].schid = vdev->schid;
-        IPL_assert(run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0,
-                   "Cannot set VQ info");
+        IPL_assert(
+            run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false) == 0,
+            "Cannot set VQ info");
     }
     IPL_assert(
-        run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status)) == 0,
+        run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false) == 0,
         "Could not write status to host");
 }
 
@@ -323,8 +313,15 @@ bool virtio_is_supported(SubChannelId schid)
 {
     vdev.schid = schid;
     memset(&vdev.senseid, 0, sizeof(vdev.senseid));
-    /* run sense id command */
-    if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid))) {
+
+    /*
+     * Run sense id command.
+     * The size of the senseid data differs between devices (notably,
+     * between virtio devices and dasds), so specify the largest possible
+     * size and suppress the incorrect length indication for smaller sizes.
+     */
+    if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid),
+                true)) {
         return false;
     }
     if (vdev.senseid.cu_type == 0x3832) {
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 12/19] s390-bios: Refactor virtio to run channel programs via cio
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Now that we have a Channel I/O library let's modify virtio boot code to
make use of it for running channel programs.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-13-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/virtio.c | 57 +++++++++++++++++++--------------------
 1 file changed, 27 insertions(+), 30 deletions(-)

diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index aa9da7253fb2..35278eaee13d 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -14,6 +14,7 @@
 #include "virtio.h"
 #include "virtio-scsi.h"
 #include "bswap.h"
+#include "helper.h"
 
 #define VRING_WAIT_REPLY_TIMEOUT 30
 
@@ -89,33 +90,20 @@ int drain_irqs(SubChannelId schid)
     }
 }
 
-static int run_ccw(VDev *vdev, int cmd, void *ptr, int len)
+static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
 {
     Ccw1 ccw = {};
-    CmdOrb orb = {};
-    int r;
-
-    enable_subchannel(vdev->schid);
-
-    /* start subchannel command */
-    orb.fmt = 1;
-    orb.cpa = (u32)(long)&ccw;
-    orb.lpm = 0x80;
 
     ccw.cmd_code = cmd;
     ccw.cda = (long)ptr;
     ccw.count = len;
 
-    r = ssch(vdev->schid, &orb);
-    /*
-     * XXX Wait until device is done processing the CCW. For now we can
-     *     assume that a simple tsch will have finished the CCW processing,
-     *     but the architecture allows for asynchronous operation
-     */
-    if (!r) {
-        r = drain_irqs(vdev->schid);
+    if (sli) {
+        ccw.flags |= CCW_FLAG_SLI;
     }
-    return r;
+
+    enable_subchannel(vdev->schid);
+    return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), CCW_FMT1);
 }
 
 static void vring_init(VRing *vr, VqInfo *info)
@@ -257,7 +245,7 @@ void virtio_setup_ccw(VDev *vdev)
     vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
     vdev->guessed_disk_nature = VIRTIO_GDN_NONE;
 
-    run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0);
+    run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
 
     switch (vdev->senseid.cu_model) {
     case VIRTIO_ID_NET:
@@ -278,18 +266,19 @@ void virtio_setup_ccw(VDev *vdev)
     default:
         panic("Unsupported virtio device\n");
     }
-    IPL_assert(run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size) == 0,
-               "Could not get block device configuration");
+    IPL_assert(
+        run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false) == 0,
+       "Could not get block device configuration");
 
     /* Feature negotiation */
     for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
         feats.features = 0;
         feats.index = i;
-        rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats));
+        rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false);
         IPL_assert(rc == 0, "Could not get features bits");
         vdev->guest_features[i] &= bswap32(feats.features);
         feats.features = bswap32(vdev->guest_features[i]);
-        rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats));
+        rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false);
         IPL_assert(rc == 0, "Could not set features bits");
     }
 
@@ -306,16 +295,17 @@ void virtio_setup_ccw(VDev *vdev)
         };
 
         IPL_assert(
-            run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config)) == 0,
+            run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false) == 0,
             "Could not get block device VQ configuration");
         info.num = config.num;
         vring_init(&vdev->vrings[i], &info);
         vdev->vrings[i].schid = vdev->schid;
-        IPL_assert(run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0,
-                   "Cannot set VQ info");
+        IPL_assert(
+            run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false) == 0,
+            "Cannot set VQ info");
     }
     IPL_assert(
-        run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status)) == 0,
+        run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false) == 0,
         "Could not write status to host");
 }
 
@@ -323,8 +313,15 @@ bool virtio_is_supported(SubChannelId schid)
 {
     vdev.schid = schid;
     memset(&vdev.senseid, 0, sizeof(vdev.senseid));
-    /* run sense id command */
-    if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid))) {
+
+    /*
+     * Run sense id command.
+     * The size of the senseid data differs between devices (notably,
+     * between virtio devices and dasds), so specify the largest possible
+     * size and suppress the incorrect length indication for smaller sizes.
+     */
+    if (run_ccw(&vdev, CCW_CMD_SENSE_ID, &vdev.senseid, sizeof(vdev.senseid),
+                true)) {
         return false;
     }
     if (vdev.senseid.cu_type == 0x3832) {
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 13/19] s390-bios: Use control unit type to determine boot method
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

The boot method is different depending on which device type we are
booting from. Let's examine the control unit type to determine if we're
a virtio device. We'll eventually add a case to check for a real dasd device
here as well.

Since we have to call enable_subchannel() in main now, might as well
remove that call from virtio.c : run_ccw(). This requires adding some
additional enable_subchannel calls to not break calls to
virtio_is_supported().

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-14-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c    | 16 ++++++++++++++--
 pc-bios/s390-ccw/netmain.c |  1 +
 pc-bios/s390-ccw/virtio.c  |  1 -
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index d3a161c68546..57a10138c65d 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -76,6 +76,7 @@ static bool find_subch(int dev_no)
         /* Skip net devices since no IPLB is created and therefore no
          * network bootloader has been loaded
          */
+        enable_subchannel(blk_schid);
         if (virtio_is_supported(blk_schid) &&
             virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
             continue;
@@ -198,13 +199,24 @@ static void virtio_setup(void)
 
 int main(void)
 {
+    uint16_t cutype;
+
     sclp_setup();
     css_setup();
     boot_setup();
     find_boot_device();
+    enable_subchannel(blk_schid);
 
-    virtio_setup();
-    zipl_load(); /* no return */
+    cutype = cu_type(blk_schid);
+    switch (cutype) {
+    case CU_TYPE_VIRTIO:
+        virtio_setup();
+        zipl_load(); /* no return */
+        break;
+    default:
+        print_int("Attempting to boot from unexpected device type", cutype);
+        panic("");
+    }
 
     panic("Failed to load OS from hard disk\n");
     return 0; /* make compiler happy */
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index 5189c0fc39e5..f3542cb2cf11 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -476,6 +476,7 @@ static bool find_net_dev(Schib *schib, int dev_no)
         if (!schib->pmcw.dnv) {
             continue;
         }
+        enable_subchannel(net_schid);
         if (!virtio_is_supported(net_schid)) {
             continue;
         }
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 35278eaee13d..fb40ca982853 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -102,7 +102,6 @@ static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
         ccw.flags |= CCW_FLAG_SLI;
     }
 
-    enable_subchannel(vdev->schid);
     return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), CCW_FMT1);
 }
 
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 13/19] s390-bios: Use control unit type to determine boot method
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

The boot method is different depending on which device type we are
booting from. Let's examine the control unit type to determine if we're
a virtio device. We'll eventually add a case to check for a real dasd device
here as well.

Since we have to call enable_subchannel() in main now, might as well
remove that call from virtio.c : run_ccw(). This requires adding some
additional enable_subchannel calls to not break calls to
virtio_is_supported().

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-14-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c    | 16 ++++++++++++++--
 pc-bios/s390-ccw/netmain.c |  1 +
 pc-bios/s390-ccw/virtio.c  |  1 -
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index d3a161c68546..57a10138c65d 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -76,6 +76,7 @@ static bool find_subch(int dev_no)
         /* Skip net devices since no IPLB is created and therefore no
          * network bootloader has been loaded
          */
+        enable_subchannel(blk_schid);
         if (virtio_is_supported(blk_schid) &&
             virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
             continue;
@@ -198,13 +199,24 @@ static void virtio_setup(void)
 
 int main(void)
 {
+    uint16_t cutype;
+
     sclp_setup();
     css_setup();
     boot_setup();
     find_boot_device();
+    enable_subchannel(blk_schid);
 
-    virtio_setup();
-    zipl_load(); /* no return */
+    cutype = cu_type(blk_schid);
+    switch (cutype) {
+    case CU_TYPE_VIRTIO:
+        virtio_setup();
+        zipl_load(); /* no return */
+        break;
+    default:
+        print_int("Attempting to boot from unexpected device type", cutype);
+        panic("");
+    }
 
     panic("Failed to load OS from hard disk\n");
     return 0; /* make compiler happy */
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index 5189c0fc39e5..f3542cb2cf11 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -476,6 +476,7 @@ static bool find_net_dev(Schib *schib, int dev_no)
         if (!schib->pmcw.dnv) {
             continue;
         }
+        enable_subchannel(net_schid);
         if (!virtio_is_supported(net_schid)) {
             continue;
         }
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 35278eaee13d..fb40ca982853 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -102,7 +102,6 @@ static int run_ccw(VDev *vdev, int cmd, void *ptr, int len, bool sli)
         ccw.flags |= CCW_FLAG_SLI;
     }
 
-    enable_subchannel(vdev->schid);
     return do_cio(vdev->schid, vdev->senseid.cu_type, ptr2u32(&ccw), CCW_FMT1);
 }
 
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 14/19] s390-bios: Add channel command codes/structs needed for dasd-ipl
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

The dasd IPL procedure needs to execute a few previously unused
channel commands. Let's define them and their associated data
structures.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-15-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/cio.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 1637e32070f3..aaa432deddb9 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -200,11 +200,14 @@ typedef struct ccw1 {
 #define CCW_FLAG_IDA             0x04
 #define CCW_FLAG_SUSPEND         0x02
 
+/* Common CCW commands */
+#define CCW_CMD_READ_IPL         0x02
 #define CCW_CMD_NOOP             0x03
 #define CCW_CMD_BASIC_SENSE      0x04
 #define CCW_CMD_TIC              0x08
 #define CCW_CMD_SENSE_ID         0xe4
 
+/* Virtio CCW commands */
 #define CCW_CMD_SET_VQ           0x13
 #define CCW_CMD_VDEV_RESET       0x33
 #define CCW_CMD_READ_FEAT        0x12
@@ -216,6 +219,12 @@ typedef struct ccw1 {
 #define CCW_CMD_SET_CONF_IND     0x53
 #define CCW_CMD_READ_VQ_CONF     0x32
 
+/* DASD CCW commands */
+#define CCW_CMD_DASD_READ             0x06
+#define CCW_CMD_DASD_SEEK             0x07
+#define CCW_CMD_DASD_SEARCH_ID_EQ     0x31
+#define CCW_CMD_DASD_READ_MT          0x86
+
 /*
  * Command-mode operation request block
  */
@@ -333,6 +342,20 @@ typedef struct irb {
     __u32 emw[8];
 }  __attribute__ ((packed, aligned(4))) Irb;
 
+/* Used for SEEK ccw commands */
+typedef struct CcwSeekData {
+    uint16_t reserved;
+    uint16_t cyl;
+    uint16_t head;
+} __attribute__((packed)) CcwSeekData;
+
+/* Used for SEARCH ID ccw commands */
+typedef struct CcwSearchIdData {
+    uint16_t cyl;
+    uint16_t head;
+    uint8_t record;
+} __attribute__((packed)) CcwSearchIdData;
+
 int enable_mss_facility(void);
 void enable_subchannel(SubChannelId schid);
 uint16_t cu_type(SubChannelId schid);
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 14/19] s390-bios: Add channel command codes/structs needed for dasd-ipl
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

The dasd IPL procedure needs to execute a few previously unused
channel commands. Let's define them and their associated data
structures.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1554388475-18329-15-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/cio.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 1637e32070f3..aaa432deddb9 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -200,11 +200,14 @@ typedef struct ccw1 {
 #define CCW_FLAG_IDA             0x04
 #define CCW_FLAG_SUSPEND         0x02
 
+/* Common CCW commands */
+#define CCW_CMD_READ_IPL         0x02
 #define CCW_CMD_NOOP             0x03
 #define CCW_CMD_BASIC_SENSE      0x04
 #define CCW_CMD_TIC              0x08
 #define CCW_CMD_SENSE_ID         0xe4
 
+/* Virtio CCW commands */
 #define CCW_CMD_SET_VQ           0x13
 #define CCW_CMD_VDEV_RESET       0x33
 #define CCW_CMD_READ_FEAT        0x12
@@ -216,6 +219,12 @@ typedef struct ccw1 {
 #define CCW_CMD_SET_CONF_IND     0x53
 #define CCW_CMD_READ_VQ_CONF     0x32
 
+/* DASD CCW commands */
+#define CCW_CMD_DASD_READ             0x06
+#define CCW_CMD_DASD_SEEK             0x07
+#define CCW_CMD_DASD_SEARCH_ID_EQ     0x31
+#define CCW_CMD_DASD_READ_MT          0x86
+
 /*
  * Command-mode operation request block
  */
@@ -333,6 +342,20 @@ typedef struct irb {
     __u32 emw[8];
 }  __attribute__ ((packed, aligned(4))) Irb;
 
+/* Used for SEEK ccw commands */
+typedef struct CcwSeekData {
+    uint16_t reserved;
+    uint16_t cyl;
+    uint16_t head;
+} __attribute__((packed)) CcwSeekData;
+
+/* Used for SEARCH ID ccw commands */
+typedef struct CcwSearchIdData {
+    uint16_t cyl;
+    uint16_t head;
+    uint8_t record;
+} __attribute__((packed)) CcwSearchIdData;
+
 int enable_mss_facility(void);
 void enable_subchannel(SubChannelId schid);
 uint16_t cu_type(SubChannelId schid);
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 15/19] s390-bios: Support booting from real dasd device
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Allows guest to boot from a vfio configured real dasd device.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-16-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 MAINTAINERS                  |   1 +
 docs/devel/s390-dasd-ipl.txt | 133 ++++++++++++++++++++
 pc-bios/s390-ccw/Makefile    |   2 +-
 pc-bios/s390-ccw/dasd-ipl.c  | 235 +++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/dasd-ipl.h  |  16 +++
 pc-bios/s390-ccw/main.c      |   5 +
 pc-bios/s390-ccw/s390-arch.h |  13 ++
 7 files changed, 404 insertions(+), 1 deletion(-)
 create mode 100644 docs/devel/s390-dasd-ipl.txt
 create mode 100644 pc-bios/s390-ccw/dasd-ipl.c
 create mode 100644 pc-bios/s390-ccw/dasd-ipl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f7976aa43d0a..be53b7d3b703 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1181,6 +1181,7 @@ S: Supported
 F: hw/s390x/ipl.*
 F: pc-bios/s390-ccw/
 F: pc-bios/s390-ccw.img
+F: docs/devel/s390-dasd-ipl.txt
 T: git https://github.com/borntraeger/qemu.git s390-next
 L: qemu-s390x@nongnu.org
 
diff --git a/docs/devel/s390-dasd-ipl.txt b/docs/devel/s390-dasd-ipl.txt
new file mode 100644
index 000000000000..9107e048e4e6
--- /dev/null
+++ b/docs/devel/s390-dasd-ipl.txt
@@ -0,0 +1,133 @@
+*****************************
+***** s390 hardware IPL *****
+*****************************
+
+The s390 hardware IPL process consists of the following steps.
+
+1. A READ IPL ccw is constructed in memory location 0x0.
+    This ccw, by definition, reads the IPL1 record which is located on the disk
+    at cylinder 0 track 0 record 1. Note that the chain flag is on in this ccw
+    so when it is complete another ccw will be fetched and executed from memory
+    location 0x08.
+
+2. Execute the Read IPL ccw at 0x00, thereby reading IPL1 data into 0x00.
+    IPL1 data is 24 bytes in length and consists of the following pieces of
+    information: [psw][read ccw][tic ccw]. When the machine executes the Read
+    IPL ccw it read the 24-bytes of IPL1 to be read into memory starting at
+    location 0x0. Then the ccw program at 0x08 which consists of a read
+    ccw and a tic ccw is automatically executed because of the chain flag from
+    the original READ IPL ccw. The read ccw will read the IPL2 data into memory
+    and the TIC (Transfer In Channel) will transfer control to the channel
+    program contained in the IPL2 data. The TIC channel command is the
+    equivalent of a branch/jump/goto instruction for channel programs.
+    NOTE: The ccws in IPL1 are defined by the architecture to be format 0.
+
+3. Execute IPL2.
+    The TIC ccw instruction at the end of the IPL1 channel program will begin
+    the execution of the IPL2 channel program. IPL2 is stage-2 of the boot
+    process and will contain a larger channel program than IPL1. The point of
+    IPL2 is to find and load either the operating system or a small program that
+    loads the operating system from disk. At the end of this step all or some of
+    the real operating system is loaded into memory and we are ready to hand
+    control over to the guest operating system. At this point the guest
+    operating system is entirely responsible for loading any more data it might
+    need to function. NOTE: The IPL2 channel program might read data into memory
+    location 0 thereby overwriting the IPL1 psw and channel program. This is ok
+    as long as the data placed in location 0 contains a psw whose instruction
+    address points to the guest operating system code to execute at the end of
+    the IPL/boot process.
+    NOTE: The ccws in IPL2 are defined by the architecture to be format 0.
+
+4. Start executing the guest operating system.
+    The psw that was loaded into memory location 0 as part of the ipl process
+    should contain the needed flags for the operating system we have loaded. The
+    psw's instruction address will point to the location in memory where we want
+    to start executing the operating system. This psw is loaded (via LPSW
+    instruction) causing control to be passed to the operating system code.
+
+In a non-virtualized environment this process, handled entirely by the hardware,
+is kicked off by the user initiating a "Load" procedure from the hardware
+management console. This "Load" procedure crafts a special "Read IPL" ccw in
+memory location 0x0 that reads IPL1. It then executes this ccw thereby kicking
+off the reading of IPL1 data. Since the channel program from IPL1 will be
+written immediately after the special "Read IPL" ccw, the IPL1 channel program
+will be executed immediately (the special read ccw has the chaining bit turned
+on). The TIC at the end of the IPL1 channel program will cause the IPL2 channel
+program to be executed automatically. After this sequence completes the "Load"
+procedure then loads the psw from 0x0.
+
+**********************************************************
+***** How this all pertains to QEMU (and the kernel) *****
+**********************************************************
+
+In theory we should merely have to do the following to IPL/boot a guest
+operating system from a DASD device:
+
+1. Place a "Read IPL" ccw into memory location 0x0 with chaining bit on.
+2. Execute channel program at 0x0.
+3. LPSW 0x0.
+
+However, our emulation of the machine's channel program logic within the kernel
+is missing one key feature that is required for this process to work:
+non-prefetch of ccw data.
+
+When we start a channel program we pass the channel subsystem parameters via an
+ORB (Operation Request Block). One of those parameters is a prefetch bit. If the
+bit is on then the vfio-ccw kernel driver is allowed to read the entire channel
+program from guest memory before it starts executing it. This means that any
+channel commands that read additional channel commands will not work as expected
+because the newly read commands will only exist in guest memory and NOT within
+the kernel's channel subsystem memory. The kernel vfio-ccw driver currently
+requires this bit to be on for all channel programs. This is a problem because
+the IPL process consists of transferring control from the "Read IPL" ccw
+immediately to the IPL1 channel program that was read by "Read IPL".
+
+Not being able to turn off prefetch will also prevent the TIC at the end of the
+IPL1 channel program from transferring control to the IPL2 channel program.
+
+Lastly, in some cases (the zipl bootloader for example) the IPL2 program also
+transfers control to another channel program segment immediately after reading
+it from the disk. So we need to be able to handle this case.
+
+**************************
+***** What QEMU does *****
+**************************
+
+Since we are forced to live with prefetch we cannot use the very simple IPL
+procedure we defined in the preceding section. So we compensate by doing the
+following.
+
+1. Place "Read IPL" ccw into memory location 0x0, but turn off chaining bit.
+2. Execute "Read IPL" at 0x0.
+
+   So now IPL1's psw is at 0x0 and IPL1's channel program is at 0x08.
+
+4. Write a custom channel program that will seek to the IPL2 record and then
+   execute the READ and TIC ccws from IPL1.  Normally the seek is not required
+   because after reading the IPL1 record the disk is automatically positioned
+   to read the very next record which will be IPL2. But since we are not reading
+   both IPL1 and IPL2 as part of the same channel program we must manually set
+   the position.
+
+5. Grab the target address of the TIC instruction from the IPL1 channel program.
+   This address is where the IPL2 channel program starts.
+
+   Now IPL2 is loaded into memory somewhere, and we know the address.
+
+6. Execute the IPL2 channel program at the address obtained in step #5.
+
+   Because this channel program can be dynamic, we must use a special algorithm
+   that detects a READ immediately followed by a TIC and breaks the ccw chain
+   by turning off the chain bit in the READ ccw. When control is returned from
+   the kernel/hardware to the QEMU bios code we immediately issue another start
+   subchannel to execute the remaining TIC instruction. This causes the entire
+   channel program (starting from the TIC) and all needed data to be refetched
+   thereby stepping around the limitation that would otherwise prevent this
+   channel program from executing properly.
+
+   Now the operating system code is loaded somewhere in guest memory and the psw
+   in memory location 0x0 will point to entry code for the guest operating
+   system.
+
+7. LPSW 0x0.
+   LPSW transfers control to the guest operating system and we're done.
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 12ad9c1d5813..a048b6b077a9 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -10,7 +10,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 .PHONY : all clean build-all
 
 OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
-	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o
+	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o dasd-ipl.o
 
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
diff --git a/pc-bios/s390-ccw/dasd-ipl.c b/pc-bios/s390-ccw/dasd-ipl.c
new file mode 100644
index 000000000000..0fc879bb8e8f
--- /dev/null
+++ b/pc-bios/s390-ccw/dasd-ipl.c
@@ -0,0 +1,235 @@
+/*
+ * S390 IPL (boot) from a real DASD device via vfio framework.
+ *
+ * Copyright (c) 2019 Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+#include "s390-arch.h"
+#include "dasd-ipl.h"
+#include "helper.h"
+
+static char prefix_page[PAGE_SIZE * 2]
+            __attribute__((__aligned__(PAGE_SIZE * 2)));
+
+static void enable_prefixing(void)
+{
+    memcpy(&prefix_page, lowcore, 4096);
+    set_prefix(ptr2u32(&prefix_page));
+}
+
+static void disable_prefixing(void)
+{
+    set_prefix(0);
+    /* Copy io interrupt info back to low core */
+    memcpy((void *)&lowcore->subchannel_id, prefix_page + 0xB8, 12);
+}
+
+static bool is_read_tic_ccw_chain(Ccw0 *ccw)
+{
+    Ccw0 *next_ccw = ccw + 1;
+
+    return ((ccw->cmd_code == CCW_CMD_DASD_READ ||
+            ccw->cmd_code == CCW_CMD_DASD_READ_MT) &&
+            ccw->chain && next_ccw->cmd_code == CCW_CMD_TIC);
+}
+
+static bool dynamic_cp_fixup(uint32_t ccw_addr, uint32_t  *next_cpa)
+{
+    Ccw0 *cur_ccw = (Ccw0 *)(uint64_t)ccw_addr;
+    Ccw0 *tic_ccw;
+
+    while (true) {
+        /* Skip over inline TIC (it might not have the chain bit on)  */
+        if (cur_ccw->cmd_code == CCW_CMD_TIC &&
+            cur_ccw->cda == ptr2u32(cur_ccw) - 8) {
+            cur_ccw += 1;
+            continue;
+        }
+
+        if (!cur_ccw->chain) {
+            break;
+        }
+        if (is_read_tic_ccw_chain(cur_ccw)) {
+            /*
+             * Breaking a chain of CCWs may alter the semantics or even the
+             * validity of a channel program. The heuristic implemented below
+             * seems to work well in practice for the channel programs
+             * generated by zipl.
+             */
+            tic_ccw = cur_ccw + 1;
+            *next_cpa = tic_ccw->cda;
+            cur_ccw->chain = 0;
+            return true;
+        }
+        cur_ccw += 1;
+    }
+    return false;
+}
+
+static int run_dynamic_ccw_program(SubChannelId schid, uint16_t cutype,
+                                   uint32_t cpa)
+{
+    bool has_next;
+    uint32_t next_cpa = 0;
+    int rc;
+
+    do {
+        has_next = dynamic_cp_fixup(cpa, &next_cpa);
+
+        print_int("executing ccw chain at ", cpa);
+        enable_prefixing();
+        rc = do_cio(schid, cutype, cpa, CCW_FMT0);
+        disable_prefixing();
+
+        if (rc) {
+            break;
+        }
+        cpa = next_cpa;
+    } while (has_next);
+
+    return rc;
+}
+
+static void make_readipl(void)
+{
+    Ccw0 *ccwIplRead = (Ccw0 *)0x00;
+
+    /* Create Read IPL ccw at address 0 */
+    ccwIplRead->cmd_code = CCW_CMD_READ_IPL;
+    ccwIplRead->cda = 0x00; /* Read into address 0x00 in main memory */
+    ccwIplRead->chain = 0; /* Chain flag */
+    ccwIplRead->count = 0x18; /* Read 0x18 bytes of data */
+}
+
+static void run_readipl(SubChannelId schid, uint16_t cutype)
+{
+    if (do_cio(schid, cutype, 0x00, CCW_FMT0)) {
+        panic("dasd-ipl: Failed to run Read IPL channel program\n");
+    }
+}
+
+/*
+ * The architecture states that IPL1 data should consist of a psw followed by
+ * format-0 READ and TIC CCWs. Let's sanity check.
+ */
+static void check_ipl1(void)
+{
+    Ccw0 *ccwread = (Ccw0 *)0x08;
+    Ccw0 *ccwtic = (Ccw0 *)0x10;
+
+    if (ccwread->cmd_code != CCW_CMD_DASD_READ ||
+        ccwtic->cmd_code != CCW_CMD_TIC) {
+        panic("dasd-ipl: IPL1 data invalid. Is this disk really bootable?\n");
+    }
+}
+
+static void check_ipl2(uint32_t ipl2_addr)
+{
+    Ccw0 *ccw = u32toptr(ipl2_addr);
+
+    if (ipl2_addr == 0x00) {
+        panic("IPL2 address invalid. Is this disk really bootable?\n");
+    }
+    if (ccw->cmd_code == 0x00) {
+        panic("IPL2 ccw data invalid. Is this disk really bootable?\n");
+    }
+}
+
+static uint32_t read_ipl2_addr(void)
+{
+    Ccw0 *ccwtic = (Ccw0 *)0x10;
+
+    return ccwtic->cda;
+}
+
+static void ipl1_fixup(void)
+{
+    Ccw0 *ccwSeek = (Ccw0 *) 0x08;
+    Ccw0 *ccwSearchID = (Ccw0 *) 0x10;
+    Ccw0 *ccwSearchTic = (Ccw0 *) 0x18;
+    Ccw0 *ccwRead = (Ccw0 *) 0x20;
+    CcwSeekData *seekData = (CcwSeekData *) 0x30;
+    CcwSearchIdData *searchData = (CcwSearchIdData *) 0x38;
+
+    /* move IPL1 CCWs to make room for CCWs needed to locate record 2 */
+    memcpy(ccwRead, (void *)0x08, 16);
+
+    /* Disable chaining so we don't TIC to IPL2 channel program */
+    ccwRead->chain = 0x00;
+
+    ccwSeek->cmd_code = CCW_CMD_DASD_SEEK;
+    ccwSeek->cda = ptr2u32(seekData);
+    ccwSeek->chain = 1;
+    ccwSeek->count = sizeof(*seekData);
+    seekData->reserved = 0x00;
+    seekData->cyl = 0x00;
+    seekData->head = 0x00;
+
+    ccwSearchID->cmd_code = CCW_CMD_DASD_SEARCH_ID_EQ;
+    ccwSearchID->cda = ptr2u32(searchData);
+    ccwSearchID->chain = 1;
+    ccwSearchID->count = sizeof(*searchData);
+    searchData->cyl = 0;
+    searchData->head = 0;
+    searchData->record = 2;
+
+    /* Go back to Search CCW if correct record not yet found */
+    ccwSearchTic->cmd_code = CCW_CMD_TIC;
+    ccwSearchTic->cda = ptr2u32(ccwSearchID);
+}
+
+static void run_ipl1(SubChannelId schid, uint16_t cutype)
+ {
+    uint32_t startAddr = 0x08;
+
+    if (do_cio(schid, cutype, startAddr, CCW_FMT0)) {
+        panic("dasd-ipl: Failed to run IPL1 channel program\n");
+    }
+}
+
+static void run_ipl2(SubChannelId schid, uint16_t cutype, uint32_t addr)
+{
+    if (run_dynamic_ccw_program(schid, cutype, addr)) {
+        panic("dasd-ipl: Failed to run IPL2 channel program\n");
+    }
+}
+
+/*
+ * Limitations in vfio-ccw support complicate the IPL process. Details can
+ * be found in docs/devel/s390-dasd-ipl.txt
+ */
+void dasd_ipl(SubChannelId schid, uint16_t cutype)
+{
+    PSWLegacy *pswl = (PSWLegacy *) 0x00;
+    uint32_t ipl2_addr;
+
+    /* Construct Read IPL CCW and run it to read IPL1 from boot disk */
+    make_readipl();
+    run_readipl(schid, cutype);
+    ipl2_addr = read_ipl2_addr();
+    check_ipl1();
+
+    /*
+     * Fixup IPL1 channel program to account for vfio-ccw limitations, then run
+     * it to read IPL2 channel program from boot disk.
+     */
+    ipl1_fixup();
+    run_ipl1(schid, cutype);
+    check_ipl2(ipl2_addr);
+
+    /*
+     * Run IPL2 channel program to read operating system code from boot disk
+     */
+    run_ipl2(schid, cutype, ipl2_addr);
+
+    /* Transfer control to the guest operating system */
+    pswl->mask |= PSW_MASK_EAMODE;   /* Force z-mode */
+    pswl->addr |= PSW_MASK_BAMODE;   /* ...          */
+    jump_to_low_kernel();
+}
diff --git a/pc-bios/s390-ccw/dasd-ipl.h b/pc-bios/s390-ccw/dasd-ipl.h
new file mode 100644
index 000000000000..c3948289062c
--- /dev/null
+++ b/pc-bios/s390-ccw/dasd-ipl.h
@@ -0,0 +1,16 @@
+/*
+ * S390 IPL (boot) from a real DASD device via vfio framework.
+ *
+ * Copyright (c) 2019 Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef DASD_IPL_H
+#define DASD_IPL_H
+
+void dasd_ipl(SubChannelId schid, uint16_t cutype);
+
+#endif /* DASD_IPL_H */
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 57a10138c65d..3c449ad49688 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -13,6 +13,7 @@
 #include "s390-ccw.h"
 #include "cio.h"
 #include "virtio.h"
+#include "dasd-ipl.h"
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
@@ -209,6 +210,10 @@ int main(void)
 
     cutype = cu_type(blk_schid);
     switch (cutype) {
+    case CU_TYPE_DASD_3990:
+    case CU_TYPE_DASD_2107:
+        dasd_ipl(blk_schid, cutype); /* no return */
+        break;
     case CU_TYPE_VIRTIO:
         virtio_setup();
         zipl_load(); /* no return */
diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
index 5e92c7a27d53..504fc7c2f098 100644
--- a/pc-bios/s390-ccw/s390-arch.h
+++ b/pc-bios/s390-ccw/s390-arch.h
@@ -87,4 +87,17 @@ typedef struct LowCore {
 
 extern LowCore const *lowcore;
 
+static inline void set_prefix(uint32_t address)
+{
+    asm volatile("spx %0" : : "m" (address) : "memory");
+}
+
+static inline uint32_t store_prefix(void)
+{
+    uint32_t address;
+
+    asm volatile("stpx %0" : "=m" (address));
+    return address;
+}
+
 #endif
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 15/19] s390-bios: Support booting from real dasd device
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

Allows guest to boot from a vfio configured real dasd device.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <1554388475-18329-16-git-send-email-jjherne@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 MAINTAINERS                  |   1 +
 docs/devel/s390-dasd-ipl.txt | 133 ++++++++++++++++++++
 pc-bios/s390-ccw/Makefile    |   2 +-
 pc-bios/s390-ccw/dasd-ipl.c  | 235 +++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/dasd-ipl.h  |  16 +++
 pc-bios/s390-ccw/main.c      |   5 +
 pc-bios/s390-ccw/s390-arch.h |  13 ++
 7 files changed, 404 insertions(+), 1 deletion(-)
 create mode 100644 docs/devel/s390-dasd-ipl.txt
 create mode 100644 pc-bios/s390-ccw/dasd-ipl.c
 create mode 100644 pc-bios/s390-ccw/dasd-ipl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f7976aa43d0a..be53b7d3b703 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1181,6 +1181,7 @@ S: Supported
 F: hw/s390x/ipl.*
 F: pc-bios/s390-ccw/
 F: pc-bios/s390-ccw.img
+F: docs/devel/s390-dasd-ipl.txt
 T: git https://github.com/borntraeger/qemu.git s390-next
 L: qemu-s390x@nongnu.org
 
diff --git a/docs/devel/s390-dasd-ipl.txt b/docs/devel/s390-dasd-ipl.txt
new file mode 100644
index 000000000000..9107e048e4e6
--- /dev/null
+++ b/docs/devel/s390-dasd-ipl.txt
@@ -0,0 +1,133 @@
+*****************************
+***** s390 hardware IPL *****
+*****************************
+
+The s390 hardware IPL process consists of the following steps.
+
+1. A READ IPL ccw is constructed in memory location 0x0.
+    This ccw, by definition, reads the IPL1 record which is located on the disk
+    at cylinder 0 track 0 record 1. Note that the chain flag is on in this ccw
+    so when it is complete another ccw will be fetched and executed from memory
+    location 0x08.
+
+2. Execute the Read IPL ccw at 0x00, thereby reading IPL1 data into 0x00.
+    IPL1 data is 24 bytes in length and consists of the following pieces of
+    information: [psw][read ccw][tic ccw]. When the machine executes the Read
+    IPL ccw it read the 24-bytes of IPL1 to be read into memory starting at
+    location 0x0. Then the ccw program at 0x08 which consists of a read
+    ccw and a tic ccw is automatically executed because of the chain flag from
+    the original READ IPL ccw. The read ccw will read the IPL2 data into memory
+    and the TIC (Transfer In Channel) will transfer control to the channel
+    program contained in the IPL2 data. The TIC channel command is the
+    equivalent of a branch/jump/goto instruction for channel programs.
+    NOTE: The ccws in IPL1 are defined by the architecture to be format 0.
+
+3. Execute IPL2.
+    The TIC ccw instruction at the end of the IPL1 channel program will begin
+    the execution of the IPL2 channel program. IPL2 is stage-2 of the boot
+    process and will contain a larger channel program than IPL1. The point of
+    IPL2 is to find and load either the operating system or a small program that
+    loads the operating system from disk. At the end of this step all or some of
+    the real operating system is loaded into memory and we are ready to hand
+    control over to the guest operating system. At this point the guest
+    operating system is entirely responsible for loading any more data it might
+    need to function. NOTE: The IPL2 channel program might read data into memory
+    location 0 thereby overwriting the IPL1 psw and channel program. This is ok
+    as long as the data placed in location 0 contains a psw whose instruction
+    address points to the guest operating system code to execute at the end of
+    the IPL/boot process.
+    NOTE: The ccws in IPL2 are defined by the architecture to be format 0.
+
+4. Start executing the guest operating system.
+    The psw that was loaded into memory location 0 as part of the ipl process
+    should contain the needed flags for the operating system we have loaded. The
+    psw's instruction address will point to the location in memory where we want
+    to start executing the operating system. This psw is loaded (via LPSW
+    instruction) causing control to be passed to the operating system code.
+
+In a non-virtualized environment this process, handled entirely by the hardware,
+is kicked off by the user initiating a "Load" procedure from the hardware
+management console. This "Load" procedure crafts a special "Read IPL" ccw in
+memory location 0x0 that reads IPL1. It then executes this ccw thereby kicking
+off the reading of IPL1 data. Since the channel program from IPL1 will be
+written immediately after the special "Read IPL" ccw, the IPL1 channel program
+will be executed immediately (the special read ccw has the chaining bit turned
+on). The TIC at the end of the IPL1 channel program will cause the IPL2 channel
+program to be executed automatically. After this sequence completes the "Load"
+procedure then loads the psw from 0x0.
+
+**********************************************************
+***** How this all pertains to QEMU (and the kernel) *****
+**********************************************************
+
+In theory we should merely have to do the following to IPL/boot a guest
+operating system from a DASD device:
+
+1. Place a "Read IPL" ccw into memory location 0x0 with chaining bit on.
+2. Execute channel program at 0x0.
+3. LPSW 0x0.
+
+However, our emulation of the machine's channel program logic within the kernel
+is missing one key feature that is required for this process to work:
+non-prefetch of ccw data.
+
+When we start a channel program we pass the channel subsystem parameters via an
+ORB (Operation Request Block). One of those parameters is a prefetch bit. If the
+bit is on then the vfio-ccw kernel driver is allowed to read the entire channel
+program from guest memory before it starts executing it. This means that any
+channel commands that read additional channel commands will not work as expected
+because the newly read commands will only exist in guest memory and NOT within
+the kernel's channel subsystem memory. The kernel vfio-ccw driver currently
+requires this bit to be on for all channel programs. This is a problem because
+the IPL process consists of transferring control from the "Read IPL" ccw
+immediately to the IPL1 channel program that was read by "Read IPL".
+
+Not being able to turn off prefetch will also prevent the TIC at the end of the
+IPL1 channel program from transferring control to the IPL2 channel program.
+
+Lastly, in some cases (the zipl bootloader for example) the IPL2 program also
+transfers control to another channel program segment immediately after reading
+it from the disk. So we need to be able to handle this case.
+
+**************************
+***** What QEMU does *****
+**************************
+
+Since we are forced to live with prefetch we cannot use the very simple IPL
+procedure we defined in the preceding section. So we compensate by doing the
+following.
+
+1. Place "Read IPL" ccw into memory location 0x0, but turn off chaining bit.
+2. Execute "Read IPL" at 0x0.
+
+   So now IPL1's psw is at 0x0 and IPL1's channel program is at 0x08.
+
+4. Write a custom channel program that will seek to the IPL2 record and then
+   execute the READ and TIC ccws from IPL1.  Normally the seek is not required
+   because after reading the IPL1 record the disk is automatically positioned
+   to read the very next record which will be IPL2. But since we are not reading
+   both IPL1 and IPL2 as part of the same channel program we must manually set
+   the position.
+
+5. Grab the target address of the TIC instruction from the IPL1 channel program.
+   This address is where the IPL2 channel program starts.
+
+   Now IPL2 is loaded into memory somewhere, and we know the address.
+
+6. Execute the IPL2 channel program at the address obtained in step #5.
+
+   Because this channel program can be dynamic, we must use a special algorithm
+   that detects a READ immediately followed by a TIC and breaks the ccw chain
+   by turning off the chain bit in the READ ccw. When control is returned from
+   the kernel/hardware to the QEMU bios code we immediately issue another start
+   subchannel to execute the remaining TIC instruction. This causes the entire
+   channel program (starting from the TIC) and all needed data to be refetched
+   thereby stepping around the limitation that would otherwise prevent this
+   channel program from executing properly.
+
+   Now the operating system code is loaded somewhere in guest memory and the psw
+   in memory location 0x0 will point to entry code for the guest operating
+   system.
+
+7. LPSW 0x0.
+   LPSW transfers control to the guest operating system and we're done.
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 12ad9c1d5813..a048b6b077a9 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -10,7 +10,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 .PHONY : all clean build-all
 
 OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
-	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o
+	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o dasd-ipl.o
 
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
diff --git a/pc-bios/s390-ccw/dasd-ipl.c b/pc-bios/s390-ccw/dasd-ipl.c
new file mode 100644
index 000000000000..0fc879bb8e8f
--- /dev/null
+++ b/pc-bios/s390-ccw/dasd-ipl.c
@@ -0,0 +1,235 @@
+/*
+ * S390 IPL (boot) from a real DASD device via vfio framework.
+ *
+ * Copyright (c) 2019 Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "libc.h"
+#include "s390-ccw.h"
+#include "s390-arch.h"
+#include "dasd-ipl.h"
+#include "helper.h"
+
+static char prefix_page[PAGE_SIZE * 2]
+            __attribute__((__aligned__(PAGE_SIZE * 2)));
+
+static void enable_prefixing(void)
+{
+    memcpy(&prefix_page, lowcore, 4096);
+    set_prefix(ptr2u32(&prefix_page));
+}
+
+static void disable_prefixing(void)
+{
+    set_prefix(0);
+    /* Copy io interrupt info back to low core */
+    memcpy((void *)&lowcore->subchannel_id, prefix_page + 0xB8, 12);
+}
+
+static bool is_read_tic_ccw_chain(Ccw0 *ccw)
+{
+    Ccw0 *next_ccw = ccw + 1;
+
+    return ((ccw->cmd_code == CCW_CMD_DASD_READ ||
+            ccw->cmd_code == CCW_CMD_DASD_READ_MT) &&
+            ccw->chain && next_ccw->cmd_code == CCW_CMD_TIC);
+}
+
+static bool dynamic_cp_fixup(uint32_t ccw_addr, uint32_t  *next_cpa)
+{
+    Ccw0 *cur_ccw = (Ccw0 *)(uint64_t)ccw_addr;
+    Ccw0 *tic_ccw;
+
+    while (true) {
+        /* Skip over inline TIC (it might not have the chain bit on)  */
+        if (cur_ccw->cmd_code == CCW_CMD_TIC &&
+            cur_ccw->cda == ptr2u32(cur_ccw) - 8) {
+            cur_ccw += 1;
+            continue;
+        }
+
+        if (!cur_ccw->chain) {
+            break;
+        }
+        if (is_read_tic_ccw_chain(cur_ccw)) {
+            /*
+             * Breaking a chain of CCWs may alter the semantics or even the
+             * validity of a channel program. The heuristic implemented below
+             * seems to work well in practice for the channel programs
+             * generated by zipl.
+             */
+            tic_ccw = cur_ccw + 1;
+            *next_cpa = tic_ccw->cda;
+            cur_ccw->chain = 0;
+            return true;
+        }
+        cur_ccw += 1;
+    }
+    return false;
+}
+
+static int run_dynamic_ccw_program(SubChannelId schid, uint16_t cutype,
+                                   uint32_t cpa)
+{
+    bool has_next;
+    uint32_t next_cpa = 0;
+    int rc;
+
+    do {
+        has_next = dynamic_cp_fixup(cpa, &next_cpa);
+
+        print_int("executing ccw chain at ", cpa);
+        enable_prefixing();
+        rc = do_cio(schid, cutype, cpa, CCW_FMT0);
+        disable_prefixing();
+
+        if (rc) {
+            break;
+        }
+        cpa = next_cpa;
+    } while (has_next);
+
+    return rc;
+}
+
+static void make_readipl(void)
+{
+    Ccw0 *ccwIplRead = (Ccw0 *)0x00;
+
+    /* Create Read IPL ccw at address 0 */
+    ccwIplRead->cmd_code = CCW_CMD_READ_IPL;
+    ccwIplRead->cda = 0x00; /* Read into address 0x00 in main memory */
+    ccwIplRead->chain = 0; /* Chain flag */
+    ccwIplRead->count = 0x18; /* Read 0x18 bytes of data */
+}
+
+static void run_readipl(SubChannelId schid, uint16_t cutype)
+{
+    if (do_cio(schid, cutype, 0x00, CCW_FMT0)) {
+        panic("dasd-ipl: Failed to run Read IPL channel program\n");
+    }
+}
+
+/*
+ * The architecture states that IPL1 data should consist of a psw followed by
+ * format-0 READ and TIC CCWs. Let's sanity check.
+ */
+static void check_ipl1(void)
+{
+    Ccw0 *ccwread = (Ccw0 *)0x08;
+    Ccw0 *ccwtic = (Ccw0 *)0x10;
+
+    if (ccwread->cmd_code != CCW_CMD_DASD_READ ||
+        ccwtic->cmd_code != CCW_CMD_TIC) {
+        panic("dasd-ipl: IPL1 data invalid. Is this disk really bootable?\n");
+    }
+}
+
+static void check_ipl2(uint32_t ipl2_addr)
+{
+    Ccw0 *ccw = u32toptr(ipl2_addr);
+
+    if (ipl2_addr == 0x00) {
+        panic("IPL2 address invalid. Is this disk really bootable?\n");
+    }
+    if (ccw->cmd_code == 0x00) {
+        panic("IPL2 ccw data invalid. Is this disk really bootable?\n");
+    }
+}
+
+static uint32_t read_ipl2_addr(void)
+{
+    Ccw0 *ccwtic = (Ccw0 *)0x10;
+
+    return ccwtic->cda;
+}
+
+static void ipl1_fixup(void)
+{
+    Ccw0 *ccwSeek = (Ccw0 *) 0x08;
+    Ccw0 *ccwSearchID = (Ccw0 *) 0x10;
+    Ccw0 *ccwSearchTic = (Ccw0 *) 0x18;
+    Ccw0 *ccwRead = (Ccw0 *) 0x20;
+    CcwSeekData *seekData = (CcwSeekData *) 0x30;
+    CcwSearchIdData *searchData = (CcwSearchIdData *) 0x38;
+
+    /* move IPL1 CCWs to make room for CCWs needed to locate record 2 */
+    memcpy(ccwRead, (void *)0x08, 16);
+
+    /* Disable chaining so we don't TIC to IPL2 channel program */
+    ccwRead->chain = 0x00;
+
+    ccwSeek->cmd_code = CCW_CMD_DASD_SEEK;
+    ccwSeek->cda = ptr2u32(seekData);
+    ccwSeek->chain = 1;
+    ccwSeek->count = sizeof(*seekData);
+    seekData->reserved = 0x00;
+    seekData->cyl = 0x00;
+    seekData->head = 0x00;
+
+    ccwSearchID->cmd_code = CCW_CMD_DASD_SEARCH_ID_EQ;
+    ccwSearchID->cda = ptr2u32(searchData);
+    ccwSearchID->chain = 1;
+    ccwSearchID->count = sizeof(*searchData);
+    searchData->cyl = 0;
+    searchData->head = 0;
+    searchData->record = 2;
+
+    /* Go back to Search CCW if correct record not yet found */
+    ccwSearchTic->cmd_code = CCW_CMD_TIC;
+    ccwSearchTic->cda = ptr2u32(ccwSearchID);
+}
+
+static void run_ipl1(SubChannelId schid, uint16_t cutype)
+ {
+    uint32_t startAddr = 0x08;
+
+    if (do_cio(schid, cutype, startAddr, CCW_FMT0)) {
+        panic("dasd-ipl: Failed to run IPL1 channel program\n");
+    }
+}
+
+static void run_ipl2(SubChannelId schid, uint16_t cutype, uint32_t addr)
+{
+    if (run_dynamic_ccw_program(schid, cutype, addr)) {
+        panic("dasd-ipl: Failed to run IPL2 channel program\n");
+    }
+}
+
+/*
+ * Limitations in vfio-ccw support complicate the IPL process. Details can
+ * be found in docs/devel/s390-dasd-ipl.txt
+ */
+void dasd_ipl(SubChannelId schid, uint16_t cutype)
+{
+    PSWLegacy *pswl = (PSWLegacy *) 0x00;
+    uint32_t ipl2_addr;
+
+    /* Construct Read IPL CCW and run it to read IPL1 from boot disk */
+    make_readipl();
+    run_readipl(schid, cutype);
+    ipl2_addr = read_ipl2_addr();
+    check_ipl1();
+
+    /*
+     * Fixup IPL1 channel program to account for vfio-ccw limitations, then run
+     * it to read IPL2 channel program from boot disk.
+     */
+    ipl1_fixup();
+    run_ipl1(schid, cutype);
+    check_ipl2(ipl2_addr);
+
+    /*
+     * Run IPL2 channel program to read operating system code from boot disk
+     */
+    run_ipl2(schid, cutype, ipl2_addr);
+
+    /* Transfer control to the guest operating system */
+    pswl->mask |= PSW_MASK_EAMODE;   /* Force z-mode */
+    pswl->addr |= PSW_MASK_BAMODE;   /* ...          */
+    jump_to_low_kernel();
+}
diff --git a/pc-bios/s390-ccw/dasd-ipl.h b/pc-bios/s390-ccw/dasd-ipl.h
new file mode 100644
index 000000000000..c3948289062c
--- /dev/null
+++ b/pc-bios/s390-ccw/dasd-ipl.h
@@ -0,0 +1,16 @@
+/*
+ * S390 IPL (boot) from a real DASD device via vfio framework.
+ *
+ * Copyright (c) 2019 Jason J. Herne <jjherne@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef DASD_IPL_H
+#define DASD_IPL_H
+
+void dasd_ipl(SubChannelId schid, uint16_t cutype);
+
+#endif /* DASD_IPL_H */
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 57a10138c65d..3c449ad49688 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -13,6 +13,7 @@
 #include "s390-ccw.h"
 #include "cio.h"
 #include "virtio.h"
+#include "dasd-ipl.h"
 
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
@@ -209,6 +210,10 @@ int main(void)
 
     cutype = cu_type(blk_schid);
     switch (cutype) {
+    case CU_TYPE_DASD_3990:
+    case CU_TYPE_DASD_2107:
+        dasd_ipl(blk_schid, cutype); /* no return */
+        break;
     case CU_TYPE_VIRTIO:
         virtio_setup();
         zipl_load(); /* no return */
diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
index 5e92c7a27d53..504fc7c2f098 100644
--- a/pc-bios/s390-ccw/s390-arch.h
+++ b/pc-bios/s390-ccw/s390-arch.h
@@ -87,4 +87,17 @@ typedef struct LowCore {
 
 extern LowCore const *lowcore;
 
+static inline void set_prefix(uint32_t address)
+{
+    asm volatile("spx %0" : : "m" (address) : "memory");
+}
+
+static inline uint32_t store_prefix(void)
+{
+    uint32_t address;
+
+    asm volatile("stpx %0" : "=m" (address));
+    return address;
+}
+
 #endif
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 16/19] s390-bios: Use control unit type to find bootable devices
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Jason J. Herne, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

When the user does not specify which device to boot from then we end
up guessing. Instead of simply grabbing the first available device let's
be a little bit smarter and only choose devices that might be bootable
like disk, and not console devices.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Message-Id: <1554388475-18329-17-git-send-email-jjherne@linux.ibm.com>
[thuth: Added fix for virtio_is_supported() not being called anymore]
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c | 45 ++++++++++++++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 3c449ad49688..a69c73349e8f 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -21,6 +21,7 @@ static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static bool have_iplb;
+static uint16_t cutype;
 LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
 
 #define LOADPARM_PROMPT "PROMPT  "
@@ -58,11 +59,15 @@ unsigned int get_loadparm_index(void)
  * subchannel information block (schib) with the connected subchannel's info.
  * NOTE: The global variable blk_schid is updated to contain the subchannel
  * information.
+ *
+ * If the caller gives dev_no=-1 then the user did not specify a boot device.
+ * In this case we'll just use the first potentially bootable device we find.
  */
 static bool find_subch(int dev_no)
 {
     Schib schib;
     int i, r;
+    bool is_virtio;
 
     for (i = 0; i < 0x10000; i++) {
         blk_schid.sch_no = i;
@@ -74,16 +79,39 @@ static bool find_subch(int dev_no)
             continue;
         }
 
-        /* Skip net devices since no IPLB is created and therefore no
-         * network bootloader has been loaded
-         */
         enable_subchannel(blk_schid);
-        if (virtio_is_supported(blk_schid) &&
-            virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
-            continue;
+        cutype = cu_type(blk_schid);
+
+        /*
+         * Note: we always have to run virtio_is_supported() here to make
+         * sure that the vdev.senseid data gets pre-initialized correctly
+         */
+        is_virtio = virtio_is_supported(blk_schid);
+
+        /* No specific devno given, just return 1st possibly bootable device */
+        if (dev_no < 0) {
+            switch (cutype) {
+            case CU_TYPE_VIRTIO:
+                if (is_virtio) {
+                    /*
+                     * Skip net devices since no IPLB is created and therefore
+                     * no network bootloader has been loaded
+                     */
+                    if (virtio_get_device_type() != VIRTIO_ID_NET) {
+                        return true;
+                    }
+                }
+                continue;
+            case CU_TYPE_DASD_3990:
+            case CU_TYPE_DASD_2107:
+                return true;
+            default:
+                continue;
+            }
         }
 
-        if ((dev_no < 0) || (schib.pmcw.dev == dev_no)) {
+        /* Caller asked for a specific devno */
+        if (schib.pmcw.dev == dev_no) {
             return true;
         }
     }
@@ -200,15 +228,12 @@ static void virtio_setup(void)
 
 int main(void)
 {
-    uint16_t cutype;
-
     sclp_setup();
     css_setup();
     boot_setup();
     find_boot_device();
     enable_subchannel(blk_schid);
 
-    cutype = cu_type(blk_schid);
     switch (cutype) {
     case CU_TYPE_DASD_3990:
     case CU_TYPE_DASD_2107:
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 16/19] s390-bios: Use control unit type to find bootable devices
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Jason J. Herne, qemu-s390x, qemu-devel, Thomas Huth

From: "Jason J. Herne" <jjherne@linux.ibm.com>

When the user does not specify which device to boot from then we end
up guessing. Instead of simply grabbing the first available device let's
be a little bit smarter and only choose devices that might be bootable
like disk, and not console devices.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Message-Id: <1554388475-18329-17-git-send-email-jjherne@linux.ibm.com>
[thuth: Added fix for virtio_is_supported() not being called anymore]
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/main.c | 45 ++++++++++++++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 3c449ad49688..a69c73349e8f 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -21,6 +21,7 @@ static char loadparm_str[LOADPARM_LEN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 QemuIplParameters qipl;
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static bool have_iplb;
+static uint16_t cutype;
 LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
 
 #define LOADPARM_PROMPT "PROMPT  "
@@ -58,11 +59,15 @@ unsigned int get_loadparm_index(void)
  * subchannel information block (schib) with the connected subchannel's info.
  * NOTE: The global variable blk_schid is updated to contain the subchannel
  * information.
+ *
+ * If the caller gives dev_no=-1 then the user did not specify a boot device.
+ * In this case we'll just use the first potentially bootable device we find.
  */
 static bool find_subch(int dev_no)
 {
     Schib schib;
     int i, r;
+    bool is_virtio;
 
     for (i = 0; i < 0x10000; i++) {
         blk_schid.sch_no = i;
@@ -74,16 +79,39 @@ static bool find_subch(int dev_no)
             continue;
         }
 
-        /* Skip net devices since no IPLB is created and therefore no
-         * network bootloader has been loaded
-         */
         enable_subchannel(blk_schid);
-        if (virtio_is_supported(blk_schid) &&
-            virtio_get_device_type() == VIRTIO_ID_NET && dev_no < 0) {
-            continue;
+        cutype = cu_type(blk_schid);
+
+        /*
+         * Note: we always have to run virtio_is_supported() here to make
+         * sure that the vdev.senseid data gets pre-initialized correctly
+         */
+        is_virtio = virtio_is_supported(blk_schid);
+
+        /* No specific devno given, just return 1st possibly bootable device */
+        if (dev_no < 0) {
+            switch (cutype) {
+            case CU_TYPE_VIRTIO:
+                if (is_virtio) {
+                    /*
+                     * Skip net devices since no IPLB is created and therefore
+                     * no network bootloader has been loaded
+                     */
+                    if (virtio_get_device_type() != VIRTIO_ID_NET) {
+                        return true;
+                    }
+                }
+                continue;
+            case CU_TYPE_DASD_3990:
+            case CU_TYPE_DASD_2107:
+                return true;
+            default:
+                continue;
+            }
         }
 
-        if ((dev_no < 0) || (schib.pmcw.dev == dev_no)) {
+        /* Caller asked for a specific devno */
+        if (schib.pmcw.dev == dev_no) {
             return true;
         }
     }
@@ -200,15 +228,12 @@ static void virtio_setup(void)
 
 int main(void)
 {
-    uint16_t cutype;
-
     sclp_setup();
     css_setup();
     boot_setup();
     find_boot_device();
     enable_subchannel(blk_schid);
 
-    cutype = cu_type(blk_schid);
     switch (cutype) {
     case CU_TYPE_DASD_3990:
     case CU_TYPE_DASD_2107:
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 17/19] pc-bios/s390: Update firmware images
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, Thomas Huth

From: Thomas Huth <thuth@redhat.com>

s390-ccw.img contains support for booting from vfio-ccw dasd passthrough
devices now, and s390-netboot.img is updated since there were changes
to the code that is shared between s390-ccw.img and s390-netboot.img.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw.img     | Bin 34568 -> 42608 bytes
 pc-bios/s390-netboot.img | Bin 54944 -> 67232 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 450a076dc0ad9f2babc7f2e3005ea05a1082a808..ba054828d35d72fd1ed5521a48f43f593a1c291f 100644
GIT binary patch
literal 42608
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

delta 16147
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
R&FRaA2C%C;_qK6~{|{5#FdqN_

diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
index 2c6886efb8320ff711589119ffbf077e68ec8784..aa90fbccb142470924ad5f0de5a4c6337916c63a 100644
GIT binary patch
delta 23541
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

delta 11243
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

-- 
2.17.2

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 17/19] pc-bios/s390: Update firmware images
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Thomas Huth, qemu-s390x, qemu-devel

From: Thomas Huth <thuth@redhat.com>

s390-ccw.img contains support for booting from vfio-ccw dasd passthrough
devices now, and s390-netboot.img is updated since there were changes
to the code that is shared between s390-ccw.img and s390-netboot.img.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw.img     | Bin 34568 -> 42608 bytes
 pc-bios/s390-netboot.img | Bin 54944 -> 67232 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 450a076dc0ad9f2babc7f2e3005ea05a1082a808..ba054828d35d72fd1ed5521a48f43f593a1c291f 100644
GIT binary patch
literal 42608
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

delta 16147
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
R&FRaA2C%C;_qK6~{|{5#FdqN_

diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
index 2c6886efb8320ff711589119ffbf077e68ec8784..aa90fbccb142470924ad5f0de5a4c6337916c63a 100644
GIT binary patch
delta 23541
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

delta 11243
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

-- 
2.17.2



^ permalink raw reply	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 18/19] s390x/kvm: Configure page size after memory has actually been initialized
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, David Hildenbrand, Cornelia Huck

From: David Hildenbrand <david@redhat.com>

Right now we configure the pagesize quite early, when initializing KVM.
This is long before system memory is actually allocated via
memory_region_allocate_system_memory(), and therefore memory backends
marked as mapped.

Instead, let's configure the maximum page size after initializing
memory in s390_memory_init(). cap_hpage_1m is still properly
configured before creating any CPUs, and therefore before configuring
the CPU model and eventually enabling CMMA.

This is not a fix but rather a preparation for the future, when initial
memory might reside on memory backends (not the case for s390x right now)
We will replace qemu_getrampagesize() soon by a function that will always
return the maximum page size (not the minimum page size, which only
works by pure luck so far, as there are no memory backends).

Acked-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190417113143.5551-2-david@redhat.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
---
 hw/s390x/s390-virtio-ccw.c | 12 ++++++++++++
 target/s390x/cpu.c         |  7 +++++++
 target/s390x/cpu.h         |  1 +
 target/s390x/kvm-stub.c    |  4 ++++
 target/s390x/kvm.c         | 35 ++++++++++++++---------------------
 target/s390x/kvm_s390x.h   |  1 +
 6 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index d11069b860b4..3be567965736 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -15,6 +15,7 @@
 #include "cpu.h"
 #include "hw/boards.h"
 #include "exec/address-spaces.h"
+#include "exec/ram_addr.h"
 #include "hw/s390x/s390-virtio-hcall.h"
 #include "hw/s390x/sclp.h"
 #include "hw/s390x/s390_flic.h"
@@ -163,6 +164,7 @@ static void s390_memory_init(ram_addr_t mem_size)
     MemoryRegion *sysmem = get_system_memory();
     ram_addr_t chunk, offset = 0;
     unsigned int number = 0;
+    Error *local_err = NULL;
     gchar *name;
 
     /* allocate RAM for core */
@@ -182,6 +184,15 @@ static void s390_memory_init(ram_addr_t mem_size)
     }
     g_free(name);
 
+    /*
+     * Configure the maximum page size. As no memory devices were created
+     * yet, this is the page size of initial memory only.
+     */
+    s390_set_max_pagesize(qemu_getrampagesize(), &local_err);
+    if (local_err) {
+        error_report_err(local_err);
+        exit(EXIT_FAILURE);
+    }
     /* Initialize storage key device */
     s390_skeys_init();
     /* Initialize storage attributes device */
@@ -253,6 +264,7 @@ static void ccw_init(MachineState *machine)
     DeviceState *dev;
 
     s390_sclp_init();
+    /* init memory + setup max page size. Required for the CPU model */
     s390_memory_init(machine->ram_size);
 
     /* init CPUs (incl. CPU model) early so s390_has_feature() works */
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 698dd9cb82ab..b58ef0a8ef62 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -399,6 +399,13 @@ int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
     return 0;
 }
 
+void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
+{
+    if (kvm_enabled()) {
+        kvm_s390_set_max_pagesize(pagesize, errp);
+    }
+}
+
 void s390_cmma_reset(void)
 {
     if (kvm_enabled()) {
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index d8990c405a5d..7305cacc7b77 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -734,6 +734,7 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg)
 /* cpu.c */
 void s390_crypto_reset(void);
 int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit);
+void s390_set_max_pagesize(uint64_t pagesize, Error **errp);
 void s390_cmma_reset(void);
 void s390_enable_css_support(S390CPU *cpu);
 int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c
index bf7795e47a1c..22b4514ca68c 100644
--- a/target/s390x/kvm-stub.c
+++ b/target/s390x/kvm-stub.c
@@ -93,6 +93,10 @@ int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit)
     return 0;
 }
 
+void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
+{
+}
+
 void kvm_s390_crypto_reset(void)
 {
 }
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 2c6e35b5aafe..7df7be4a1bdc 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -283,44 +283,37 @@ void kvm_s390_crypto_reset(void)
     }
 }
 
-static int kvm_s390_configure_mempath_backing(KVMState *s)
+void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
 {
-    size_t path_psize = qemu_getrampagesize();
-
-    if (path_psize == 4 * KiB) {
-        return 0;
+    if (pagesize == 4 * KiB) {
+        return;
     }
 
     if (!hpage_1m_allowed()) {
-        error_report("This QEMU machine does not support huge page "
-                     "mappings");
-        return -EINVAL;
+        error_setg(errp, "This QEMU machine does not support huge page "
+                   "mappings");
+        return;
     }
 
-    if (path_psize != 1 * MiB) {
-        error_report("Memory backing with 2G pages was specified, "
-                     "but KVM does not support this memory backing");
-        return -EINVAL;
+    if (pagesize != 1 * MiB) {
+        error_setg(errp, "Memory backing with 2G pages was specified, "
+                   "but KVM does not support this memory backing");
+        return;
     }
 
-    if (kvm_vm_enable_cap(s, KVM_CAP_S390_HPAGE_1M, 0)) {
-        error_report("Memory backing with 1M pages was specified, "
-                     "but KVM does not support this memory backing");
-        return -EINVAL;
+    if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_HPAGE_1M, 0)) {
+        error_setg(errp, "Memory backing with 1M pages was specified, "
+                   "but KVM does not support this memory backing");
+        return;
     }
 
     cap_hpage_1m = 1;
-    return 0;
 }
 
 int kvm_arch_init(MachineState *ms, KVMState *s)
 {
     MachineClass *mc = MACHINE_GET_CLASS(ms);
 
-    if (kvm_s390_configure_mempath_backing(s)) {
-        return -EINVAL;
-    }
-
     mc->default_cpu_type = S390_CPU_TYPE_NAME("host");
     cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
     cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h
index 6e52287da3f0..caf985955ba5 100644
--- a/target/s390x/kvm_s390x.h
+++ b/target/s390x/kvm_s390x.h
@@ -36,6 +36,7 @@ int kvm_s390_cmma_active(void);
 void kvm_s390_cmma_reset(void);
 void kvm_s390_reset_vcpu(S390CPU *cpu);
 int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit);
+void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp);
 void kvm_s390_crypto_reset(void);
 void kvm_s390_restart_interrupt(S390CPU *cpu);
 void kvm_s390_stop_interrupt(S390CPU *cpu);
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 18/19] s390x/kvm: Configure page size after memory has actually been initialized
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, Cornelia Huck, qemu-devel, David Hildenbrand

From: David Hildenbrand <david@redhat.com>

Right now we configure the pagesize quite early, when initializing KVM.
This is long before system memory is actually allocated via
memory_region_allocate_system_memory(), and therefore memory backends
marked as mapped.

Instead, let's configure the maximum page size after initializing
memory in s390_memory_init(). cap_hpage_1m is still properly
configured before creating any CPUs, and therefore before configuring
the CPU model and eventually enabling CMMA.

This is not a fix but rather a preparation for the future, when initial
memory might reside on memory backends (not the case for s390x right now)
We will replace qemu_getrampagesize() soon by a function that will always
return the maximum page size (not the minimum page size, which only
works by pure luck so far, as there are no memory backends).

Acked-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190417113143.5551-2-david@redhat.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
---
 hw/s390x/s390-virtio-ccw.c | 12 ++++++++++++
 target/s390x/cpu.c         |  7 +++++++
 target/s390x/cpu.h         |  1 +
 target/s390x/kvm-stub.c    |  4 ++++
 target/s390x/kvm.c         | 35 ++++++++++++++---------------------
 target/s390x/kvm_s390x.h   |  1 +
 6 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index d11069b860b4..3be567965736 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -15,6 +15,7 @@
 #include "cpu.h"
 #include "hw/boards.h"
 #include "exec/address-spaces.h"
+#include "exec/ram_addr.h"
 #include "hw/s390x/s390-virtio-hcall.h"
 #include "hw/s390x/sclp.h"
 #include "hw/s390x/s390_flic.h"
@@ -163,6 +164,7 @@ static void s390_memory_init(ram_addr_t mem_size)
     MemoryRegion *sysmem = get_system_memory();
     ram_addr_t chunk, offset = 0;
     unsigned int number = 0;
+    Error *local_err = NULL;
     gchar *name;
 
     /* allocate RAM for core */
@@ -182,6 +184,15 @@ static void s390_memory_init(ram_addr_t mem_size)
     }
     g_free(name);
 
+    /*
+     * Configure the maximum page size. As no memory devices were created
+     * yet, this is the page size of initial memory only.
+     */
+    s390_set_max_pagesize(qemu_getrampagesize(), &local_err);
+    if (local_err) {
+        error_report_err(local_err);
+        exit(EXIT_FAILURE);
+    }
     /* Initialize storage key device */
     s390_skeys_init();
     /* Initialize storage attributes device */
@@ -253,6 +264,7 @@ static void ccw_init(MachineState *machine)
     DeviceState *dev;
 
     s390_sclp_init();
+    /* init memory + setup max page size. Required for the CPU model */
     s390_memory_init(machine->ram_size);
 
     /* init CPUs (incl. CPU model) early so s390_has_feature() works */
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 698dd9cb82ab..b58ef0a8ef62 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -399,6 +399,13 @@ int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
     return 0;
 }
 
+void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
+{
+    if (kvm_enabled()) {
+        kvm_s390_set_max_pagesize(pagesize, errp);
+    }
+}
+
 void s390_cmma_reset(void)
 {
     if (kvm_enabled()) {
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index d8990c405a5d..7305cacc7b77 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -734,6 +734,7 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg)
 /* cpu.c */
 void s390_crypto_reset(void);
 int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit);
+void s390_set_max_pagesize(uint64_t pagesize, Error **errp);
 void s390_cmma_reset(void);
 void s390_enable_css_support(S390CPU *cpu);
 int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c
index bf7795e47a1c..22b4514ca68c 100644
--- a/target/s390x/kvm-stub.c
+++ b/target/s390x/kvm-stub.c
@@ -93,6 +93,10 @@ int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit)
     return 0;
 }
 
+void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
+{
+}
+
 void kvm_s390_crypto_reset(void)
 {
 }
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 2c6e35b5aafe..7df7be4a1bdc 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -283,44 +283,37 @@ void kvm_s390_crypto_reset(void)
     }
 }
 
-static int kvm_s390_configure_mempath_backing(KVMState *s)
+void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
 {
-    size_t path_psize = qemu_getrampagesize();
-
-    if (path_psize == 4 * KiB) {
-        return 0;
+    if (pagesize == 4 * KiB) {
+        return;
     }
 
     if (!hpage_1m_allowed()) {
-        error_report("This QEMU machine does not support huge page "
-                     "mappings");
-        return -EINVAL;
+        error_setg(errp, "This QEMU machine does not support huge page "
+                   "mappings");
+        return;
     }
 
-    if (path_psize != 1 * MiB) {
-        error_report("Memory backing with 2G pages was specified, "
-                     "but KVM does not support this memory backing");
-        return -EINVAL;
+    if (pagesize != 1 * MiB) {
+        error_setg(errp, "Memory backing with 2G pages was specified, "
+                   "but KVM does not support this memory backing");
+        return;
     }
 
-    if (kvm_vm_enable_cap(s, KVM_CAP_S390_HPAGE_1M, 0)) {
-        error_report("Memory backing with 1M pages was specified, "
-                     "but KVM does not support this memory backing");
-        return -EINVAL;
+    if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_HPAGE_1M, 0)) {
+        error_setg(errp, "Memory backing with 1M pages was specified, "
+                   "but KVM does not support this memory backing");
+        return;
     }
 
     cap_hpage_1m = 1;
-    return 0;
 }
 
 int kvm_arch_init(MachineState *ms, KVMState *s)
 {
     MachineClass *mc = MACHINE_GET_CLASS(ms);
 
-    if (kvm_s390_configure_mempath_backing(s)) {
-        return -EINVAL;
-    }
-
     mc->default_cpu_type = S390_CPU_TYPE_NAME("host");
     cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
     cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h
index 6e52287da3f0..caf985955ba5 100644
--- a/target/s390x/kvm_s390x.h
+++ b/target/s390x/kvm_s390x.h
@@ -36,6 +36,7 @@ int kvm_s390_cmma_active(void);
 void kvm_s390_cmma_reset(void);
 void kvm_s390_reset_vcpu(S390CPU *cpu);
 int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit);
+void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp);
 void kvm_s390_crypto_reset(void);
 void kvm_s390_restart_interrupt(S390CPU *cpu);
 void kvm_s390_stop_interrupt(S390CPU *cpu);
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 19/19] exec: Introduce qemu_maxrampagesize() and rename qemu_getrampagesize()
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, qemu-devel, David Hildenbrand, Cornelia Huck

From: David Hildenbrand <david@redhat.com>

Rename qemu_getrampagesize() to qemu_minrampagesize(). While at it,
properly rename find_max_supported_pagesize() to
find_min_backend_pagesize().

s390x is actually interested into the maximum ram pagesize, so
introduce and use qemu_maxrampagesize().

Add a TODO, indicating that looking at any mapped memory backends is not
100% correct in some cases.

Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190417113143.5551-3-david@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
---
 exec.c                     | 44 ++++++++++++++++++++++++++++++++++----
 hw/ppc/spapr_caps.c        |  4 ++--
 hw/s390x/s390-virtio-ccw.c |  2 +-
 hw/vfio/spapr.c            |  2 +-
 include/exec/ram_addr.h    |  3 ++-
 target/ppc/kvm.c           |  2 +-
 6 files changed, 47 insertions(+), 10 deletions(-)

diff --git a/exec.c b/exec.c
index 2646207661d4..bb1dff423aaf 100644
--- a/exec.c
+++ b/exec.c
@@ -1688,7 +1688,7 @@ void ram_block_dump(Monitor *mon)
  * when we actually open and map them.  Iterate over the file
  * descriptors instead, and use qemu_fd_getpagesize().
  */
-static int find_max_supported_pagesize(Object *obj, void *opaque)
+static int find_min_backend_pagesize(Object *obj, void *opaque)
 {
     long *hpsize_min = opaque;
 
@@ -1704,7 +1704,27 @@ static int find_max_supported_pagesize(Object *obj, void *opaque)
     return 0;
 }
 
-long qemu_getrampagesize(void)
+static int find_max_backend_pagesize(Object *obj, void *opaque)
+{
+    long *hpsize_max = opaque;
+
+    if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
+        HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+        long hpsize = host_memory_backend_pagesize(backend);
+
+        if (host_memory_backend_is_mapped(backend) && (hpsize > *hpsize_max)) {
+            *hpsize_max = hpsize;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * TODO: We assume right now that all mapped host memory backends are
+ * used as RAM, however some might be used for different purposes.
+ */
+long qemu_minrampagesize(void)
 {
     long hpsize = LONG_MAX;
     long mainrampagesize;
@@ -1724,7 +1744,7 @@ long qemu_getrampagesize(void)
      */
     memdev_root = object_resolve_path("/objects", NULL);
     if (memdev_root) {
-        object_child_foreach(memdev_root, find_max_supported_pagesize, &hpsize);
+        object_child_foreach(memdev_root, find_min_backend_pagesize, &hpsize);
     }
     if (hpsize == LONG_MAX) {
         /* No additional memory regions found ==> Report main RAM page size */
@@ -1747,8 +1767,24 @@ long qemu_getrampagesize(void)
 
     return hpsize;
 }
+
+long qemu_maxrampagesize(void)
+{
+    long pagesize = qemu_mempath_getpagesize(mem_path);
+    Object *memdev_root = object_resolve_path("/objects", NULL);
+
+    if (memdev_root) {
+        object_child_foreach(memdev_root, find_max_backend_pagesize,
+                             &pagesize);
+    }
+    return pagesize;
+}
 #else
-long qemu_getrampagesize(void)
+long qemu_minrampagesize(void)
+{
+    return getpagesize();
+}
+long qemu_maxrampagesize(void)
 {
     return getpagesize();
 }
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index edc5ed0e0c4e..9b1c10baa6c5 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -347,7 +347,7 @@ static void cap_hpt_maxpagesize_apply(SpaprMachineState *spapr,
         warn_report("Many guests require at least 64kiB hpt-max-page-size");
     }
 
-    spapr_check_pagesize(spapr, qemu_getrampagesize(), errp);
+    spapr_check_pagesize(spapr, qemu_minrampagesize(), errp);
 }
 
 static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift,
@@ -609,7 +609,7 @@ static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
         uint8_t mps;
 
         if (kvmppc_hpt_needs_host_contiguous_pages()) {
-            mps = ctz64(qemu_getrampagesize());
+            mps = ctz64(qemu_minrampagesize());
         } else {
             mps = 34; /* allow everything up to 16GiB, i.e. everything */
         }
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 3be567965736..7e256d3d31b8 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -188,7 +188,7 @@ static void s390_memory_init(ram_addr_t mem_size)
      * Configure the maximum page size. As no memory devices were created
      * yet, this is the page size of initial memory only.
      */
-    s390_set_max_pagesize(qemu_getrampagesize(), &local_err);
+    s390_set_max_pagesize(qemu_maxrampagesize(), &local_err);
     if (local_err) {
         error_report_err(local_err);
         exit(EXIT_FAILURE);
diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index 57fe758e5441..96c0ad9d9b7e 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -148,7 +148,7 @@ int vfio_spapr_create_window(VFIOContainer *container,
     uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
     unsigned entries, bits_total, bits_per_level, max_levels;
     struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
-    long rampagesize = qemu_getrampagesize();
+    long rampagesize = qemu_minrampagesize();
 
     /*
      * The host might not support the guest supported IOMMU page size,
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 9ecd911c3e78..139ad79390fa 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -73,7 +73,8 @@ static inline unsigned long int ramblock_recv_bitmap_offset(void *host_addr,
 
 bool ramblock_is_pmem(RAMBlock *rb);
 
-long qemu_getrampagesize(void);
+long qemu_minrampagesize(void);
+long qemu_maxrampagesize(void);
 
 /**
  * qemu_ram_alloc_from_file,
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 2427c8ee13ae..59d92c42751e 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2136,7 +2136,7 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
     /* Find the largest hardware supported page size that's less than
      * or equal to the (logical) backing page size of guest RAM */
     kvm_get_smmu_info(&info, &error_fatal);
-    rampagesize = qemu_getrampagesize();
+    rampagesize = qemu_minrampagesize();
     best_page_shift = 0;
 
     for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
-- 
2.17.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [Qemu-devel] [PULL 19/19] exec: Introduce qemu_maxrampagesize() and rename qemu_getrampagesize()
@ 2019-04-25 13:21   ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-04-25 13:21 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-s390x, Cornelia Huck, qemu-devel, David Hildenbrand

From: David Hildenbrand <david@redhat.com>

Rename qemu_getrampagesize() to qemu_minrampagesize(). While at it,
properly rename find_max_supported_pagesize() to
find_min_backend_pagesize().

s390x is actually interested into the maximum ram pagesize, so
introduce and use qemu_maxrampagesize().

Add a TODO, indicating that looking at any mapped memory backends is not
100% correct in some cases.

Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190417113143.5551-3-david@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
---
 exec.c                     | 44 ++++++++++++++++++++++++++++++++++----
 hw/ppc/spapr_caps.c        |  4 ++--
 hw/s390x/s390-virtio-ccw.c |  2 +-
 hw/vfio/spapr.c            |  2 +-
 include/exec/ram_addr.h    |  3 ++-
 target/ppc/kvm.c           |  2 +-
 6 files changed, 47 insertions(+), 10 deletions(-)

diff --git a/exec.c b/exec.c
index 2646207661d4..bb1dff423aaf 100644
--- a/exec.c
+++ b/exec.c
@@ -1688,7 +1688,7 @@ void ram_block_dump(Monitor *mon)
  * when we actually open and map them.  Iterate over the file
  * descriptors instead, and use qemu_fd_getpagesize().
  */
-static int find_max_supported_pagesize(Object *obj, void *opaque)
+static int find_min_backend_pagesize(Object *obj, void *opaque)
 {
     long *hpsize_min = opaque;
 
@@ -1704,7 +1704,27 @@ static int find_max_supported_pagesize(Object *obj, void *opaque)
     return 0;
 }
 
-long qemu_getrampagesize(void)
+static int find_max_backend_pagesize(Object *obj, void *opaque)
+{
+    long *hpsize_max = opaque;
+
+    if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
+        HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+        long hpsize = host_memory_backend_pagesize(backend);
+
+        if (host_memory_backend_is_mapped(backend) && (hpsize > *hpsize_max)) {
+            *hpsize_max = hpsize;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * TODO: We assume right now that all mapped host memory backends are
+ * used as RAM, however some might be used for different purposes.
+ */
+long qemu_minrampagesize(void)
 {
     long hpsize = LONG_MAX;
     long mainrampagesize;
@@ -1724,7 +1744,7 @@ long qemu_getrampagesize(void)
      */
     memdev_root = object_resolve_path("/objects", NULL);
     if (memdev_root) {
-        object_child_foreach(memdev_root, find_max_supported_pagesize, &hpsize);
+        object_child_foreach(memdev_root, find_min_backend_pagesize, &hpsize);
     }
     if (hpsize == LONG_MAX) {
         /* No additional memory regions found ==> Report main RAM page size */
@@ -1747,8 +1767,24 @@ long qemu_getrampagesize(void)
 
     return hpsize;
 }
+
+long qemu_maxrampagesize(void)
+{
+    long pagesize = qemu_mempath_getpagesize(mem_path);
+    Object *memdev_root = object_resolve_path("/objects", NULL);
+
+    if (memdev_root) {
+        object_child_foreach(memdev_root, find_max_backend_pagesize,
+                             &pagesize);
+    }
+    return pagesize;
+}
 #else
-long qemu_getrampagesize(void)
+long qemu_minrampagesize(void)
+{
+    return getpagesize();
+}
+long qemu_maxrampagesize(void)
 {
     return getpagesize();
 }
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index edc5ed0e0c4e..9b1c10baa6c5 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -347,7 +347,7 @@ static void cap_hpt_maxpagesize_apply(SpaprMachineState *spapr,
         warn_report("Many guests require at least 64kiB hpt-max-page-size");
     }
 
-    spapr_check_pagesize(spapr, qemu_getrampagesize(), errp);
+    spapr_check_pagesize(spapr, qemu_minrampagesize(), errp);
 }
 
 static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift,
@@ -609,7 +609,7 @@ static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
         uint8_t mps;
 
         if (kvmppc_hpt_needs_host_contiguous_pages()) {
-            mps = ctz64(qemu_getrampagesize());
+            mps = ctz64(qemu_minrampagesize());
         } else {
             mps = 34; /* allow everything up to 16GiB, i.e. everything */
         }
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 3be567965736..7e256d3d31b8 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -188,7 +188,7 @@ static void s390_memory_init(ram_addr_t mem_size)
      * Configure the maximum page size. As no memory devices were created
      * yet, this is the page size of initial memory only.
      */
-    s390_set_max_pagesize(qemu_getrampagesize(), &local_err);
+    s390_set_max_pagesize(qemu_maxrampagesize(), &local_err);
     if (local_err) {
         error_report_err(local_err);
         exit(EXIT_FAILURE);
diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index 57fe758e5441..96c0ad9d9b7e 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -148,7 +148,7 @@ int vfio_spapr_create_window(VFIOContainer *container,
     uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
     unsigned entries, bits_total, bits_per_level, max_levels;
     struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
-    long rampagesize = qemu_getrampagesize();
+    long rampagesize = qemu_minrampagesize();
 
     /*
      * The host might not support the guest supported IOMMU page size,
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 9ecd911c3e78..139ad79390fa 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -73,7 +73,8 @@ static inline unsigned long int ramblock_recv_bitmap_offset(void *host_addr,
 
 bool ramblock_is_pmem(RAMBlock *rb);
 
-long qemu_getrampagesize(void);
+long qemu_minrampagesize(void);
+long qemu_maxrampagesize(void);
 
 /**
  * qemu_ram_alloc_from_file,
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 2427c8ee13ae..59d92c42751e 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2136,7 +2136,7 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
     /* Find the largest hardware supported page size that's less than
      * or equal to the (logical) backing page size of guest RAM */
     kvm_get_smmu_info(&info, &error_fatal);
-    rampagesize = qemu_getrampagesize();
+    rampagesize = qemu_minrampagesize();
     best_page_shift = 0;
 
     for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
-- 
2.17.2



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [Qemu-devel] [PULL 00/19] first batch of s390x patches for 4.1
  2019-04-25 13:21 ` Cornelia Huck
                   ` (19 preceding siblings ...)
  (?)
@ 2019-04-26 13:29 ` Peter Maydell
  -1 siblings, 0 replies; 47+ messages in thread
From: Peter Maydell @ 2019-04-26 13:29 UTC (permalink / raw)
  To: Cornelia Huck; +Cc: qemu-s390x, QEMU Developers

On Thu, 25 Apr 2019 at 14:21, Cornelia Huck <cohuck@redhat.com> wrote:
>
> The following changes since commit 3284aa128153750f14a61e8a96fd085e6f2999b6:
>
>   Merge remote-tracking branch 'remotes/lersek/tags/edk2-pull-2019-04-22' into staging (2019-04-24 13:19:41 +0100)
>
> are available in the Git repository at:
>
>   https://github.com/cohuck/qemu tags/s390x-20190425
>
> for you to fetch changes up to 41c3d4269b1c18d12d33c5bf089dace25d08e82e:
>
>   Merge tag 's390-ccw-bios-2019-04-12' into s390-next-staging (2019-04-25 14:09:20 +0200)
>
> ----------------------------------------------------------------
> - properly detect page size of initial memory
> - support for IPL (boot) from ECKD DASD passed through via vfio-ccw
>
> ----------------------------------------------------------------
>


Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/4.1
for any user-visible changes.

-- PMM

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data
@ 2019-04-30 16:54     ` Peter Maydell
  0 siblings, 0 replies; 47+ messages in thread
From: Peter Maydell @ 2019-04-30 16:54 UTC (permalink / raw)
  To: Cornelia Huck; +Cc: qemu-s390x, QEMU Developers, Jason J. Herne, Thomas Huth

On Thu, 25 Apr 2019 at 14:21, Cornelia Huck <cohuck@redhat.com> wrote:
>
> From: "Jason J. Herne" <jjherne@linux.ibm.com>
>
> Add bootindex property and iplb data for vfio-ccw devices. This allows us to
> forward boot information into the bios for vfio-ccw devices.
>
> Refactor s390_get_ccw_device() to return device type. This prevents us from
> having to use messy casting logic in several places.
>
> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
> Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
> Reviewed-by: Cornelia Huck <cohuck@redhat.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> Message-Id: <1554388475-18329-2-git-send-email-jjherne@linux.ibm.com>
> [thuth: fixed "typedef struct VFIOCCWDevice" build failure with clang]
> Signed-off-by: Thomas Huth <thuth@redhat.com>

Hi; Coverity has a complaint (CID 1401098) about the use of
object_dynamic_cast() in this function. It looks like it's just
the result of code motion making it forget we'd dismissed the
warning before, but maybe we can avoid it entirely...

> @@ -335,20 +360,22 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
>  {
>      DeviceState *dev_st;
>      CcwDevice *ccw_dev = NULL;
> +    SCSIDevice *sd;
> +    int devtype;
>
>      dev_st = get_boot_device(0);
>      if (dev_st) {
> -        ccw_dev = s390_get_ccw_device(dev_st);
> +        ccw_dev = s390_get_ccw_device(dev_st, &devtype);
>      }
>
>      /*
>       * Currently allow IPL only from CCW devices.
>       */
>      if (ccw_dev) {
> -        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> -                                                            TYPE_SCSI_DEVICE);
> -
> -        if (sd) {
> +        switch (devtype) {
> +        case CCW_DEVTYPE_SCSI:
> +            sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> +                                                           TYPE_SCSI_DEVICE);

Coverity doesn't like the use of object_dynamic_cast() without a
check that the return value isn't NULL before we dereference
it a few lines further down.

I think that if we know this cast must always succeed, we
could instead just write
  SCSIDevice *sd = SCSI_DEVICE(dev_st);

On the other hand if the cast might not succeed because dev_st
isn't necessarily of the right type, then we should check it
for NULL and handle that appropriately.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data
@ 2019-04-30 16:54     ` Peter Maydell
  0 siblings, 0 replies; 47+ messages in thread
From: Peter Maydell @ 2019-04-30 16:54 UTC (permalink / raw)
  To: Cornelia Huck; +Cc: Jason J. Herne, qemu-s390x, QEMU Developers, Thomas Huth

On Thu, 25 Apr 2019 at 14:21, Cornelia Huck <cohuck@redhat.com> wrote:
>
> From: "Jason J. Herne" <jjherne@linux.ibm.com>
>
> Add bootindex property and iplb data for vfio-ccw devices. This allows us to
> forward boot information into the bios for vfio-ccw devices.
>
> Refactor s390_get_ccw_device() to return device type. This prevents us from
> having to use messy casting logic in several places.
>
> Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
> Acked-by: Halil Pasic <pasic@linux.vnet.ibm.com>
> Reviewed-by: Cornelia Huck <cohuck@redhat.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> Message-Id: <1554388475-18329-2-git-send-email-jjherne@linux.ibm.com>
> [thuth: fixed "typedef struct VFIOCCWDevice" build failure with clang]
> Signed-off-by: Thomas Huth <thuth@redhat.com>

Hi; Coverity has a complaint (CID 1401098) about the use of
object_dynamic_cast() in this function. It looks like it's just
the result of code motion making it forget we'd dismissed the
warning before, but maybe we can avoid it entirely...

> @@ -335,20 +360,22 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
>  {
>      DeviceState *dev_st;
>      CcwDevice *ccw_dev = NULL;
> +    SCSIDevice *sd;
> +    int devtype;
>
>      dev_st = get_boot_device(0);
>      if (dev_st) {
> -        ccw_dev = s390_get_ccw_device(dev_st);
> +        ccw_dev = s390_get_ccw_device(dev_st, &devtype);
>      }
>
>      /*
>       * Currently allow IPL only from CCW devices.
>       */
>      if (ccw_dev) {
> -        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> -                                                            TYPE_SCSI_DEVICE);
> -
> -        if (sd) {
> +        switch (devtype) {
> +        case CCW_DEVTYPE_SCSI:
> +            sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> +                                                           TYPE_SCSI_DEVICE);

Coverity doesn't like the use of object_dynamic_cast() without a
check that the return value isn't NULL before we dereference
it a few lines further down.

I think that if we know this cast must always succeed, we
could instead just write
  SCSIDevice *sd = SCSI_DEVICE(dev_st);

On the other hand if the cast might not succeed because dev_st
isn't necessarily of the right type, then we should check it
for NULL and handle that appropriately.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data
@ 2019-04-30 20:30       ` Eduardo Habkost
  0 siblings, 0 replies; 47+ messages in thread
From: Eduardo Habkost @ 2019-04-30 20:30 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Cornelia Huck, Jason J. Herne, qemu-s390x, QEMU Developers,
	Thomas Huth

On Tue, Apr 30, 2019 at 05:54:49PM +0100, Peter Maydell wrote:
> On Thu, 25 Apr 2019 at 14:21, Cornelia Huck <cohuck@redhat.com> wrote:
[...]
> > -        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> > -                                                            TYPE_SCSI_DEVICE);
> > -
> > -        if (sd) {
> > +        switch (devtype) {
> > +        case CCW_DEVTYPE_SCSI:
> > +            sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> > +                                                           TYPE_SCSI_DEVICE);
> 
> Coverity doesn't like the use of object_dynamic_cast() without a
> check that the return value isn't NULL before we dereference
> it a few lines further down.
> 
> I think that if we know this cast must always succeed, we
> could instead just write
>   SCSIDevice *sd = SCSI_DEVICE(dev_st);
> 
> On the other hand if the cast might not succeed because dev_st
> isn't necessarily of the right type, then we should check it
> for NULL and handle that appropriately.

s390_get_ccw_device() will set devtype=CCW_DEVTYPE_SCSI only if
dev_st is TYPE_SCSI_DEVICE, so the cast must always succeed and
we should use SCSI_DEVICE(dev_st) here.

-- 
Eduardo

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data
@ 2019-04-30 20:30       ` Eduardo Habkost
  0 siblings, 0 replies; 47+ messages in thread
From: Eduardo Habkost @ 2019-04-30 20:30 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Jason J. Herne, qemu-s390x, Cornelia Huck, QEMU Developers,
	Thomas Huth

On Tue, Apr 30, 2019 at 05:54:49PM +0100, Peter Maydell wrote:
> On Thu, 25 Apr 2019 at 14:21, Cornelia Huck <cohuck@redhat.com> wrote:
[...]
> > -        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> > -                                                            TYPE_SCSI_DEVICE);
> > -
> > -        if (sd) {
> > +        switch (devtype) {
> > +        case CCW_DEVTYPE_SCSI:
> > +            sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> > +                                                           TYPE_SCSI_DEVICE);
> 
> Coverity doesn't like the use of object_dynamic_cast() without a
> check that the return value isn't NULL before we dereference
> it a few lines further down.
> 
> I think that if we know this cast must always succeed, we
> could instead just write
>   SCSIDevice *sd = SCSI_DEVICE(dev_st);
> 
> On the other hand if the cast might not succeed because dev_st
> isn't necessarily of the right type, then we should check it
> for NULL and handle that appropriately.

s390_get_ccw_device() will set devtype=CCW_DEVTYPE_SCSI only if
dev_st is TYPE_SCSI_DEVICE, so the cast must always succeed and
we should use SCSI_DEVICE(dev_st) here.

-- 
Eduardo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data
@ 2019-05-02 15:48         ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-05-02 15:48 UTC (permalink / raw)
  To: Eduardo Habkost
  Cc: Peter Maydell, Jason J. Herne, qemu-s390x, QEMU Developers,
	Thomas Huth

On Tue, 30 Apr 2019 17:30:09 -0300
Eduardo Habkost <ehabkost@redhat.com> wrote:

> On Tue, Apr 30, 2019 at 05:54:49PM +0100, Peter Maydell wrote:
> > On Thu, 25 Apr 2019 at 14:21, Cornelia Huck <cohuck@redhat.com> wrote:  
> [...]
> > > -        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> > > -                                                            TYPE_SCSI_DEVICE);
> > > -
> > > -        if (sd) {
> > > +        switch (devtype) {
> > > +        case CCW_DEVTYPE_SCSI:
> > > +            sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> > > +                                                           TYPE_SCSI_DEVICE);  
> > 
> > Coverity doesn't like the use of object_dynamic_cast() without a
> > check that the return value isn't NULL before we dereference
> > it a few lines further down.
> > 
> > I think that if we know this cast must always succeed, we
> > could instead just write
> >   SCSIDevice *sd = SCSI_DEVICE(dev_st);
> > 
> > On the other hand if the cast might not succeed because dev_st
> > isn't necessarily of the right type, then we should check it
> > for NULL and handle that appropriately.  
> 
> s390_get_ccw_device() will set devtype=CCW_DEVTYPE_SCSI only if
> dev_st is TYPE_SCSI_DEVICE, so the cast must always succeed and
> we should use SCSI_DEVICE(dev_st) here.
> 

Yes; sending a patch.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data
@ 2019-05-02 15:48         ` Cornelia Huck
  0 siblings, 0 replies; 47+ messages in thread
From: Cornelia Huck @ 2019-05-02 15:48 UTC (permalink / raw)
  To: Eduardo Habkost
  Cc: Jason J. Herne, Peter Maydell, qemu-s390x, QEMU Developers,
	Thomas Huth

On Tue, 30 Apr 2019 17:30:09 -0300
Eduardo Habkost <ehabkost@redhat.com> wrote:

> On Tue, Apr 30, 2019 at 05:54:49PM +0100, Peter Maydell wrote:
> > On Thu, 25 Apr 2019 at 14:21, Cornelia Huck <cohuck@redhat.com> wrote:  
> [...]
> > > -        SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> > > -                                                            TYPE_SCSI_DEVICE);
> > > -
> > > -        if (sd) {
> > > +        switch (devtype) {
> > > +        case CCW_DEVTYPE_SCSI:
> > > +            sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st),
> > > +                                                           TYPE_SCSI_DEVICE);  
> > 
> > Coverity doesn't like the use of object_dynamic_cast() without a
> > check that the return value isn't NULL before we dereference
> > it a few lines further down.
> > 
> > I think that if we know this cast must always succeed, we
> > could instead just write
> >   SCSIDevice *sd = SCSI_DEVICE(dev_st);
> > 
> > On the other hand if the cast might not succeed because dev_st
> > isn't necessarily of the right type, then we should check it
> > for NULL and handle that appropriately.  
> 
> s390_get_ccw_device() will set devtype=CCW_DEVTYPE_SCSI only if
> dev_st is TYPE_SCSI_DEVICE, so the cast must always succeed and
> we should use SCSI_DEVICE(dev_st) here.
> 

Yes; sending a patch.


^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2019-05-02 15:51 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-04-25 13:21 [Qemu-devel] [PULL 00/19] first batch of s390x patches for 4.1 Cornelia Huck
2019-04-25 13:21 ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 01/19] s390 vfio-ccw: Add bootindex property and IPLB data Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-30 16:54   ` Peter Maydell
2019-04-30 16:54     ` Peter Maydell
2019-04-30 20:30     ` Eduardo Habkost
2019-04-30 20:30       ` Eduardo Habkost
2019-05-02 15:48       ` Cornelia Huck
2019-05-02 15:48         ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 02/19] s390-bios: decouple cio setup from virtio Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 03/19] s390-bios: decouple common boot logic " Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 04/19] s390-bios: Clean up cio.h Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 05/19] s390-bios: Decouple channel i/o logic from virtio Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 06/19] s390-bios: Map low core memory Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 07/19] s390-bios: ptr2u32 and u32toptr Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 08/19] s390-bios: Support for running format-0/1 channel programs Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 09/19] s390-bios: cio error handling Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 10/19] s390-bios: Extend find_dev() for non-virtio devices Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 11/19] s390-bios: Factor finding boot device out of virtio code path Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 12/19] s390-bios: Refactor virtio to run channel programs via cio Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 13/19] s390-bios: Use control unit type to determine boot method Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 14/19] s390-bios: Add channel command codes/structs needed for dasd-ipl Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 15/19] s390-bios: Support booting from real dasd device Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 16/19] s390-bios: Use control unit type to find bootable devices Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 17/19] pc-bios/s390: Update firmware images Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 18/19] s390x/kvm: Configure page size after memory has actually been initialized Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-25 13:21 ` [Qemu-devel] [PULL 19/19] exec: Introduce qemu_maxrampagesize() and rename qemu_getrampagesize() Cornelia Huck
2019-04-25 13:21   ` Cornelia Huck
2019-04-26 13:29 ` [Qemu-devel] [PULL 00/19] first batch of s390x patches for 4.1 Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.