[PATCH RFC v2 11/12] s390x/css: ccws translation infrastructure

Dong Jia Shi
2017-01-12T07:25:12Z

From: Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>

Implement a basic infrastructure of handling channel I/O instruction
interception for passed through subchannels:
1. Branch the code path of instruction interception handling by
SubChannel type.
2. For a passed-through subchannel, issue the ORB to kernel to do ccw
translation and perform an I/O operation.
3. Assign different condition code based on the I/O result, or
trigger a program check.

Signed-off-by: Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
---
hw/s390x/css.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++----
hw/s390x/s390-ccw.c | 12 +++++++
hw/s390x/virtio-ccw.c | 1 +
include/hw/s390x/css.h | 4 +++
target-s390x/ioinst.c | 9 ++++++
5 files changed, 108 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index c3a323e..0e3b0ae 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -500,7 +500,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
return ret;
}

-static void sch_handle_start_func(SubchDev *sch, ORB *orb)
+static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
{

PMCW *p = &sch->curr_status.pmcw;
@@ -599,13 +599,57 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)

}

+static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb)
+{
+
+ PMCW *p = &sch->curr_status.pmcw;
+ SCSW *s = &sch->curr_status.scsw;
+ int ret;
+
+ if (!(s->ctrl & SCSW_ACTL_SUSP)) {
+ assert(orb != NULL);
+ p->intparm = orb->intparm;
+ }
+
+ /*
+ * Only support prefetch enable mode.
+ * Only support 64bit addressing idal.
+ */
+ if (!(orb->ctrl0 & ORB_CTRL0_MASK_PFCH) ||
+ !(orb->ctrl0 & ORB_CTRL0_MASK_C64)) {
+ return -EINVAL;
+ }
+
+ ret = s390_ccw_cmd_request(orb, s, sch->driver_data);
+ switch (ret) {
+ /* Currently we don't update control block and just return the cc code. */
+ case 0:
+ break;
+ case -EBUSY:
+ break;
+ case -ENODEV:
+ break;
+ case -EACCES:
+ /* Let's reflect an inaccessible host device by cc 3. */
+ ret = -ENODEV;
+ break;
+ default:
+ /* All other return codes will trigger a program check,
+ * or set cc to 1.
+ */
+ break;
+ };
+
+ return ret;
+}
+
/*
* On real machines, this would run asynchronously to the main vcpus.
* We might want to make some parts of the ssch handling (interpreting
* read/writes) asynchronous later on if we start supporting more than
* our current very simple devices.
*/
-static void do_subchannel_work(SubchDev *sch, ORB *orb)
+int do_subchannel_work_virtual(SubchDev *sch, ORB *orb)
{

SCSW *s = &sch->curr_status.scsw;
@@ -616,12 +660,45 @@ static void do_subchannel_work(SubchDev *sch, ORB *orb)
sch_handle_halt_func(sch);
} else if (s->ctrl & SCSW_FCTL_START_FUNC) {
/* Triggered by both ssch and rsch. */
- sch_handle_start_func(sch, orb);
+ sch_handle_start_func_virtual(sch, orb);
} else {
/* Cannot happen. */
- return;
+ return 0;
}
css_inject_io_interrupt(sch);
+ return 0;
+}
+
+int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb)
+{
+ int ret;
+ SCSW *s = &sch->curr_status.scsw;
+
+ if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) {
+ /* TODO: Clear handling */
+ sch_handle_clear_func(sch);
+ ret = 0;
+ } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) {
+ /* TODO: Halt handling */
+ sch_handle_halt_func(sch);
+ ret = 0;
+ } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
+ ret = sch_handle_start_func_passthrough(sch, orb);
+ } else {
+ /* Cannot happen. */
+ return -ENODEV;
+ }
+
+ return ret;
+}
+
+static int do_subchannel_work(SubchDev *sch, ORB *orb)
+{
+ if (sch->do_subchannel_work) {
+ return sch->do_subchannel_work(sch, orb);
+ } else {
+ return -EINVAL;
+ }
}

static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src)
@@ -940,8 +1017,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
s->flags &= ~SCSW_FLAGS_MASK_PNO;

- do_subchannel_work(sch, orb);
- ret = 0;
+ ret = do_subchannel_work(sch, orb);

out:
return ret;
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index 6881fc6..58fb916 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -18,6 +18,17 @@
#include "hw/s390x/css-bridge.h"
#include "s390-ccw.h"

+int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data)
+{
+ S390CCWDevice *cdev = data;
+
+ if (cdev->handle_request) {
+ return cdev->handle_request(orb, scsw, data);
+ } else {
+ return -ENOSYS;
+ }
+}
+
static void s390_ccw_realize(S390CCWDevice *cdev, Error **errp)
{
CcwDevice *ccw_dev = CCW_DEVICE(cdev);
@@ -65,6 +76,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, Error **errp)
}

sch->driver_data = cdev;
+ sch->do_subchannel_work = do_subchannel_work_passthrough;

ret = css_sch_build_schib(sch, &cdev->hostid);
if (ret) {
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index f5c1d98..c4946f4 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -675,6 +675,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
sch->disable_cb = virtio_sch_disable_cb;
sch->id.reserved = 0xff;
sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
+ sch->do_subchannel_work = do_subchannel_work_virtual;
ccw_dev->sch = sch;
dev->indicators = NULL;
dev->revision = -1;
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h
index 2884439..6e0cd86 100644
--- a/include/hw/s390x/css.h
+++ b/include/hw/s390x/css.h
@@ -88,6 +88,7 @@ struct SubchDev {
/* transport-provided data: */
int (*ccw_cb) (SubchDev *, CCW1);
void (*disable_cb)(SubchDev *);
+ int (*do_subchannel_work) (SubchDev *, ORB *);
SenseId id;
void *driver_data;
};
@@ -145,6 +146,9 @@ void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
void css_generate_css_crws(uint8_t cssid);
void css_clear_sei_pending(void);
void css_adapter_interrupt(uint8_t isc);
+int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data);
+int do_subchannel_work_virtual(SubchDev *sub, ORB *orb);
+int do_subchannel_work_passthrough(SubchDev *sub, ORB *orb);

#define CSS_IO_ADAPTER_VIRTIO 1
int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c
index 590bfa4..62a7771 100644
--- a/target-s390x/ioinst.c
+++ b/target-s390x/ioinst.c
@@ -244,6 +244,15 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
case -EBUSY:
cc = 2;
break;
+ case -EFAULT:
+ /*
+ * TODO:
+ * I'm wondering whether there is something better
+ * to do for us here (like setting some device or
+ * subchannel status).
+ */
+ program_interrupt(env, PGM_ADDRESSING, 4);
+ return;
case 0:
cc = 0;
break;
--
2.8.4