From nobody Fri May 3 17:16:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510160228024740.6687359054579; Wed, 8 Nov 2017 08:57:08 -0800 (PST) Received: from localhost ([::1]:60824 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eCTew-0004mB-81 for importer@patchew.org; Wed, 08 Nov 2017 11:57:02 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55189) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eCTcv-0003UJ-Os for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:55:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eCTcq-0000RT-Qb for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:54:57 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:52222 helo=mx0a-001b2d01.pphosted.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eCTcq-0000QT-Jd for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:54:52 -0500 Received: from pps.filterd (m0098419.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vA8Gr1mT050132 for ; Wed, 8 Nov 2017 11:54:50 -0500 Received: from e06smtp10.uk.ibm.com (e06smtp10.uk.ibm.com [195.75.94.106]) by mx0b-001b2d01.pphosted.com with ESMTP id 2e45u5r2s3-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Wed, 08 Nov 2017 11:54:49 -0500 Received: from localhost by e06smtp10.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 8 Nov 2017 16:54:47 -0000 Received: from b06cxnps4074.portsmouth.uk.ibm.com (9.149.109.196) by e06smtp10.uk.ibm.com (192.168.101.140) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 8 Nov 2017 16:54:46 -0000 Received: from d06av21.portsmouth.uk.ibm.com (d06av21.portsmouth.uk.ibm.com [9.149.105.232]) by b06cxnps4074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id vA8GsjYL41746678; Wed, 8 Nov 2017 16:54:45 GMT Received: from d06av21.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2F7255203F; Wed, 8 Nov 2017 15:48:36 +0000 (GMT) Received: from tuxmaker.boeblingen.de.ibm.com (unknown [9.152.85.9]) by d06av21.portsmouth.uk.ibm.com (Postfix) with ESMTPS id DF02D52045; Wed, 8 Nov 2017 15:48:35 +0000 (GMT) From: Halil Pasic To: Cornelia Huck , "Dong Jia Shi" Date: Wed, 8 Nov 2017 17:54:20 +0100 X-Mailer: git-send-email 2.13.5 In-Reply-To: <20171108165422.46267-1-pasic@linux.vnet.ibm.com> References: <20171108165422.46267-1-pasic@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 17110816-0040-0000-0000-000003EC0D80 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17110816-0041-0000-0000-000025EEAD34 Message-Id: <20171108165422.46267-2-pasic@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-08_03:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=2 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000 definitions=main-1711080223 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.158.5 Subject: [Qemu-devel] [RFC PATCH v2 1/3] s390x/ccs: add ccw-testdev emulated device X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-s390x@nongnu.org, Thomas Huth , Halil Pasic , Pierre Morel , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add a fake device meant for testing the correctness of our css emulation. What we currently have is writing a Fibonacci sequence of uint32_t to the device via ccw write. The write is going to fail if it ain't a Fibonacci and indicate a device exception in scsw together with the proper residual count. With this we can do basic verification of data integrity. Of course lot's of invalid inputs (besides basic data processing) can be tested with that as well. We also have a no-op mode where the device just tells all-good! This could be useful for fuzzing. Usage: 1) fire up a qemu with something like -device ccw-testdev,devno=3Dfe.0.0001 on the command line 2) exercise the device from the guest Signed-off-by: Halil Pasic --- Introduction ------------ While discussing v1 we (more or less) decided a test device for ccw is a good idea. This is an RFC because there are some unresolved technical questions I would like to discuss. Usage ----- Build like this: make CONFIG_CCW_TESTDEV=3Dy Changelog --------- v1 -> v2: - Renamed and moved to hw/misc/ - Changed cu_type to 0xfffe. - Changed chpid_type to 0x25 (questionable). - Extensibility: addedd both in-band (ccw) and out-of-band set mode mechanism. Currently we have two modes: fib and no-op. The purpose of the mode mechanism is to facilitate different behaviors. One can both specify and lock a mode on the command line. - Added read for fib mode. Things I've figured out and things to figure out ----------------------------------------------- The zVM folks say they don't have a reserved cu_type reserved for test (or hypervisor use in general). So I've gone with cu_type 0xfffe because according to Christian only numeric digit hex values are used, and Linux uses x0ffff as extremal value. The zVM folks say the don't have a chpid_type reserved for test (or hypervisor use in general. So I took 0x25 for now, which belongs to FC and should be safe in my opinion. AFAIR there was some discussion on using a dedicated diag function code. There are multiple such that could be re-purposed for out-of-band signaling reserved by zVM. For now I've decided to go with a new subcode for diag 0x500 as it appears to me that it requires less changes. I've implemented both in-band and out-of-band signaling for influencing what the testdev does from the guest. We should probably get rid of one. I've just implemented both so we can discuss pros and cons with some code. I've taken subcode 254, the last one supported at the moment. I'm not really happy with the way I 'took' it. Maybe all taken subcodes could go into hw/s390x/s390-virtio-hcall.h either via include or directly. I'm not really happy with the side effects of moving it to hw/misc, which ain't s390x specific. I've pretty much bounced off the build system, so I would really appreciate some help here. Currently you have to say you want it when you do make or it won't get compiled into your qemu. IMHO this device only makes sense for testing and should not be rutinely shipped in production builds. That is why I did not touch default-configs/s390x-softmmu.mak. I think, I have the most problematic places marked with a TODO comment in the code. Happy reviewing and looking forward to your comments. --- hw/misc/Makefile.objs | 1 + hw/misc/ccw-testdev.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++= ++++ hw/misc/ccw-testdev.h | 18 ++++ 3 files changed, 303 insertions(+) create mode 100644 hw/misc/ccw-testdev.c create mode 100644 hw/misc/ccw-testdev.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 19202d90cf..b41314d096 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -61,3 +61,4 @@ obj-$(CONFIG_AUX) +=3D auxbus.o obj-$(CONFIG_ASPEED_SOC) +=3D aspeed_scu.o aspeed_sdmc.o obj-y +=3D mmio_interface.o obj-$(CONFIG_MSF2) +=3D msf2-sysreg.o +obj-$(CONFIG_CCW_TESTDEV) +=3D ccw-testdev.o diff --git a/hw/misc/ccw-testdev.c b/hw/misc/ccw-testdev.c new file mode 100644 index 0000000000..39cf46e90d --- /dev/null +++ b/hw/misc/ccw-testdev.c @@ -0,0 +1,284 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "ccw-testdev.h" +#include "hw/s390x/css.h" +#include "hw/s390x/css-bridge.h" +#include "hw/s390x/3270-ccw.h" +#include "exec/address-spaces.h" +#include "hw/s390x/s390-virtio-hcall.h" +#include + +typedef struct CcwTestDevDevice { + CcwDevice parent_obj; + uint16_t cu_type; + uint8_t chpid_type; + uint32_t op_mode; + bool op_mode_locked; + struct { + uint32_t ring[4]; + unsigned int next; + } fib; +} CcwTestDevDevice; + +typedef struct CcwTestDevClass { + CCWDeviceClass parent_class; + DeviceRealize parent_realize; +} CcwTestDevClass; + +#define TYPE_CCW_TESTDEV "ccw-testdev" + +#define CCW_TESTDEV(obj) \ + OBJECT_CHECK(CcwTestDevDevice, (obj), TYPE_CCW_TESTDEV) +#define CCW_TESTDEV_CLASS(klass) \ + OBJECT_CLASS_CHECK(CcwTestDevClass, (klass), TYPE_CCW_TESTDEV) +#define CCW_TESTDEV_GET_CLASS(obj) \ + OBJECT_GET_CLASS(CcwTestDevClass, (obj), TYPE_CCW_TESTDEV) + +typedef int (*ccw_cb_t)(SubchDev *, CCW1); +static ccw_cb_t get_ccw_cb(CcwTestDevOpMode op_mode); + +/* TODO This is the in-band set mode. We may want to get rid of it. */ +static int set_mode_ccw(SubchDev *sch) +{ + CcwTestDevDevice *d =3D sch->driver_data; + const char pattern[] =3D CCW_TST_SET_MODE_INCANTATION; + char buf[sizeof(pattern)]; + int ret; + uint32_t tmp; + + if (d->op_mode_locked) { + return -EINVAL; + } + + ret =3D ccw_dstream_read(&sch->cds, buf); + if (ret) { + return ret; + } + ret =3D strncmp(buf, pattern, sizeof(pattern)); + if (ret) { + return 0; /* ignore malformed request -- maybe fuzzing */ + } + ret =3D ccw_dstream_read(&sch->cds, tmp); + if (ret) { + return ret; + } + be32_to_cpus(&tmp); + if (tmp >=3D OP_MODE_MAX) { + return -EINVAL; + } + d->op_mode =3D tmp; + sch->ccw_cb =3D get_ccw_cb(d->op_mode); + return ret; +} + + +static unsigned int abs_to_ring(unsigned int i) +{ + return i & 0x3; +} + +static int ccw_testdev_write_fib(SubchDev *sch) +{ + CcwTestDevDevice *d =3D sch->driver_data; + bool is_fib =3D true; + uint32_t tmp; + int ret =3D 0; + + d->fib.next =3D 0; + while (ccw_dstream_avail(&sch->cds) > 0) { + ret =3D ccw_dstream_read(&sch->cds, tmp); + if (ret) { + error(0, -ret, "fib"); + break; + } + d->fib.ring[abs_to_ring(d->fib.next)] =3D cpu_to_be32(tmp); + if (d->fib.next > 2) { + tmp =3D (d->fib.ring[abs_to_ring(d->fib.next - 1)] + + d->fib.ring[abs_to_ring(d->fib.next - 2)]); + is_fib =3D tmp =3D=3D d->fib.ring[abs_to_ring(d->fib.next)]; + if (!is_fib) { + break; + } + } + ++(d->fib.next); + } + if (!is_fib) { + sch->curr_status.scsw.ctrl &=3D ~SCSW_ACTL_START_PEND; + sch->curr_status.scsw.ctrl |=3D SCSW_STCTL_PRIMARY | + SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT | + SCSW_STCTL_STATUS_PEND; + sch->curr_status.scsw.count =3D ccw_dstream_residual_count(&sch->c= ds); + sch->curr_status.scsw.cpa =3D sch->channel_prog + 8; + sch->curr_status.scsw.dstat =3D SCSW_DSTAT_UNIT_EXCEP; + return -EIO; + } + return ret; +} + +static int ccw_testdev_read_fib(SubchDev *sch) +{ + uint32_t l =3D 0, m =3D 1, n =3D 0; + int ret =3D 0; + + while (ccw_dstream_avail(&sch->cds) > 0) { + n =3D m + l; + l =3D m; + m =3D n; + ret =3D ccw_dstream_read(&sch->cds, n); + } + return ret; +} + +static int ccw_testdev_ccw_cb_mode_fib(SubchDev *sch, CCW1 ccw) +{ + switch (ccw.cmd_code) { + case CCW_CMD_READ: + ccw_testdev_read_fib(sch); + break; + case CCW_CMD_WRITE: + return ccw_testdev_write_fib(sch); + case CCW_CMD_CTL_MODE: + return set_mode_ccw(sch); + default: + return -EINVAL; + } + return 0; +} + +static int ccw_testdev_ccw_cb_mode_nop(SubchDev *sch, CCW1 ccw) +{ + CcwTestDevDevice *d =3D sch->driver_data; + + if (!d->op_mode_locked && ccw.cmd_code =3D=3D CCW_CMD_CTL_MODE) { + return set_mode_ccw(sch); + } + return 0; +} + +static ccw_cb_t get_ccw_cb(CcwTestDevOpMode op_mode) +{ + switch (op_mode) { + case OP_MODE_FIB: + return ccw_testdev_ccw_cb_mode_fib; + case OP_MODE_NOP: + default: + return ccw_testdev_ccw_cb_mode_nop; + } +} + +static void ccw_testdev_realize(DeviceState *ds, Error **errp) +{ + uint16_t chpid; + CcwTestDevDevice *dev =3D CCW_TESTDEV(ds); + CcwTestDevClass *ctc =3D CCW_TESTDEV_GET_CLASS(dev); + CcwDevice *cdev =3D CCW_DEVICE(ds); + BusState *qbus =3D qdev_get_parent_bus(ds); + VirtualCssBus *cbus =3D VIRTUAL_CSS_BUS(qbus); + SubchDev *sch; + Error *err =3D NULL; + + sch =3D css_create_sch(cdev->devno, true, cbus->squash_mcss, errp); + if (!sch) { + return; + } + + sch->driver_data =3D dev; + cdev->sch =3D sch; + chpid =3D css_find_free_chpid(sch->cssid); + + if (chpid > MAX_CHPID) { + error_setg(&err, "No available chpid to use."); + goto out_err; + } + + sch->id.reserved =3D 0xff; + sch->id.cu_type =3D dev->cu_type; + css_sch_build_virtual_schib(sch, (uint8_t)chpid, + dev->chpid_type); + sch->ccw_cb =3D get_ccw_cb(dev->op_mode); + sch->do_subchannel_work =3D do_subchannel_work_virtual; + + + ctc->parent_realize(ds, &err); + if (err) { + goto out_err; + } + + css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, + ds->hotplugged, 1); + return; + +out_err: + error_propagate(errp, err); + css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); + cdev->sch =3D NULL; + g_free(sch); +} + +static Property ccw_testdev_properties[] =3D { + DEFINE_PROP_UINT16("cu_type", CcwTestDevDevice, cu_type, + 0xfffe), /* only numbers used for real HW */ + DEFINE_PROP_UINT8("chpid_type", CcwTestDevDevice, chpid_type, + 0x25), /* took FC, TODO discuss */ + DEFINE_PROP_UINT32("op_mode", CcwTestDevDevice, op_mode, + 0), /* TODO discuss */ + DEFINE_PROP_BOOL("op_mode_locked", CcwTestDevDevice, op_mode_locked, + false), /* TODO discuss */ + DEFINE_PROP_END_OF_LIST(), +}; + +/* TODO This is the out-of-band variant. We may want to get rid of it */ +static int set_mode_diag(const uint64_t *args) +{ + uint64_t subch_id =3D args[0]; + uint64_t op_mode =3D args[1]; + SubchDev *sch; + CcwTestDevDevice *dev; + int cssid, ssid, schid, m; + + if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid))= { + return -EINVAL; + } + sch =3D css_find_subch(m, cssid, ssid, schid); + if (!sch || !css_subch_visible(sch)) { + return -EINVAL; + } + dev =3D CCW_TESTDEV(sch->driver_data); + if (dev->op_mode_locked) { + return op_mode =3D=3D dev->op_mode ? 0 : -EINVAL; + } + dev->op_mode =3D op_mode; + sch->ccw_cb =3D get_ccw_cb(dev->op_mode); + return 0; +} + +static void ccw_testdev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + CcwTestDevClass *ctc =3D CCW_TESTDEV_CLASS(klass); + + dc->props =3D ccw_testdev_properties; + dc->bus_type =3D TYPE_VIRTUAL_CSS_BUS; + ctc->parent_realize =3D dc->realize; + dc->realize =3D ccw_testdev_realize; + dc->hotpluggable =3D false; + + s390_register_virtio_hypercall(CCW_TST_DIAG_500_SUB, set_mode_diag); +} + +static const TypeInfo ccw_testdev_info =3D { + .name =3D TYPE_CCW_TESTDEV, + .parent =3D TYPE_CCW_DEVICE, + .instance_size =3D sizeof(CcwTestDevDevice), + .class_init =3D ccw_testdev_class_init, + .class_size =3D sizeof(CcwTestDevClass), +}; + +static void ccw_testdev_register(void) +{ + type_register_static(&ccw_testdev_info); +} + +type_init(ccw_testdev_register) diff --git a/hw/misc/ccw-testdev.h b/hw/misc/ccw-testdev.h new file mode 100644 index 0000000000..f4d4570f5e --- /dev/null +++ b/hw/misc/ccw-testdev.h @@ -0,0 +1,18 @@ +#ifndef HW_s390X_CCW_TESTDEV_H +#define HW_s390X_CCW_TESTDEV_H + +typedef enum CcwTestDevOpMode { + OP_MODE_NOP =3D 0, + OP_MODE_FIB =3D 1, + OP_MODE_MAX /* extremal element */ +} CcwTestDevOpMode; + +#define CCW_CMD_READ 0x01U +#define CCW_CMD_WRITE 0x02U + +#define CCW_CMD_CTL_MODE 0x07U +#define CCW_TST_SET_MODE_INCANTATION "SET MODE=3D" +/* Subcode for diagnose 500 (virtio hypercall). */ +#define CCW_TST_DIAG_500_SUB 254 + +#endif --=20 2.13.5 From nobody Fri May 3 17:16:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510160324449257.9748210516525; Wed, 8 Nov 2017 08:58:44 -0800 (PST) Received: from localhost ([::1]:60833 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eCTgW-00066H-CX for importer@patchew.org; Wed, 08 Nov 2017 11:58:40 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55253) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eCTcz-0003XX-C8 for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:55:03 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eCTcu-0000Ti-8W for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:55:01 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:33540) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eCTcu-0000Sv-0g for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:54:56 -0500 Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vA8GqJrP122282 for ; Wed, 8 Nov 2017 11:54:53 -0500 Received: from e06smtp11.uk.ibm.com (e06smtp11.uk.ibm.com [195.75.94.107]) by mx0a-001b2d01.pphosted.com with ESMTP id 2e44jcwe3c-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Wed, 08 Nov 2017 11:54:53 -0500 Received: from localhost by e06smtp11.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 8 Nov 2017 16:54:50 -0000 Received: from b06cxnps4075.portsmouth.uk.ibm.com (9.149.109.197) by e06smtp11.uk.ibm.com (192.168.101.141) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 8 Nov 2017 16:54:47 -0000 Received: from d06av21.portsmouth.uk.ibm.com (d06av21.portsmouth.uk.ibm.com [9.149.105.232]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id vA8GslWj36634658; Wed, 8 Nov 2017 16:54:47 GMT Received: from d06av21.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8409352043; Wed, 8 Nov 2017 15:48:37 +0000 (GMT) Received: from tuxmaker.boeblingen.de.ibm.com (unknown [9.152.85.9]) by d06av21.portsmouth.uk.ibm.com (Postfix) with ESMTPS id 3BAA05203F; Wed, 8 Nov 2017 15:48:37 +0000 (GMT) From: Halil Pasic To: Cornelia Huck , "Dong Jia Shi" Date: Wed, 8 Nov 2017 17:54:21 +0100 X-Mailer: git-send-email 2.13.5 In-Reply-To: <20171108165422.46267-1-pasic@linux.vnet.ibm.com> References: <20171108165422.46267-1-pasic@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 17110816-0040-0000-0000-0000040C0F9D X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17110816-0041-0000-0000-000020AEB0EC Message-Id: <20171108165422.46267-3-pasic@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-08_03:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=2 phishscore=0 bulkscore=0 spamscore=0 clxscore=1011 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000 definitions=main-1711080223 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.156.1 Subject: [Qemu-devel] [RFC PATCH NOT QEMU v2 2/3] ccw-tester: a tester device for ccw I/O X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-s390x@nongnu.org, Thomas Huth , Halil Pasic , Pierre Morel , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Let's introduce a device driver for doing ccw I/O tests. The initial focus is on indirect data access. The driver is impemented as an out-of-tree Linux kernel module. A module parameter cu_type is used for matching ccw devices. The parameter defaults to 0x3831 which is the default cu_type for the qemu counterpart of this (a fully emulated ccw device just for test). The current status of the module is means to an end where the end is testing my IDA implementation. Usage: You load the module. The driver is supposed to auto detect and auto online the device and provide sysfs atributes for the tests available. Tests are triggered by writing to the attributes. Reoprting is done via printk in almost TAP format (could use improvement if more ambitious). We run one test at a time and do that async to the write. If you try to start more in parallel you will get -EBUSY. Currently all you can do something like: * echo 1 > /sys/bus/ccw/devices//w_fib To test good old ccw. * echo 1 > /sys/bus/ccw/devices//w_fib_idal To test IDA ccw. These tests are designed to wrok together with the qemu device mentioned before. The basic idea is that a device is expecting a stream of words such that the sequence words interpreted as uint32_t is a Fibonacci sequence (that is for n > 2 a_{n} =3D a_{n-1} + a{n-2}). Using his simple scheme one can check that the right bytes are transferred (with reasonable confidence). If the device detects an element violating the Fibonacci property the driver expects the device posts a device exception indicating that element. Signed-off-by: Halil Pasic --- Do not try to apply this to a QEMU tree. Use an empty repo. --- .gitignore | 8 + Makefile | 10 ++ ccw-testdev.h | 18 +++ ccw_tester.c | 467 ++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 503 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 ccw-testdev.h create mode 100644 ccw_tester.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b9eac9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +#ignore these +*.o +*.cmd +*.ko +*.mod.c +Module.symvers +modules.order +.tmp_versions/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0583456 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +ifneq ($(KERNELRELEASE),) +obj-m :=3D ccw_tester.o +else +# normal makefile +KDIR ?=3D /lib/modules/`uname -r`/build + +default: + $(MAKE) -C $(KDIR) M=3D$$PWD + +endif diff --git a/ccw-testdev.h b/ccw-testdev.h new file mode 100644 index 0000000..f4d4570 --- /dev/null +++ b/ccw-testdev.h @@ -0,0 +1,18 @@ +#ifndef HW_s390X_CCW_TESTDEV_H +#define HW_s390X_CCW_TESTDEV_H + +typedef enum CcwTestDevOpMode { + OP_MODE_NOP =3D 0, + OP_MODE_FIB =3D 1, + OP_MODE_MAX /* extremal element */ +} CcwTestDevOpMode; + +#define CCW_CMD_READ 0x01U +#define CCW_CMD_WRITE 0x02U + +#define CCW_CMD_CTL_MODE 0x07U +#define CCW_TST_SET_MODE_INCANTATION "SET MODE=3D" +/* Subcode for diagnose 500 (virtio hypercall). */ +#define CCW_TST_DIAG_500_SUB 254 + +#endif diff --git a/ccw_tester.c b/ccw_tester.c new file mode 100644 index 0000000..b8e632b --- /dev/null +++ b/ccw_tester.c @@ -0,0 +1,467 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +inline bool _ccw_test_assert(bool expr, const char *loc, int ln, + const char *expl) +{ + if (expr) + printk(KERN_NOTICE "ok -- %s:%d\n", loc, ln); + else + printk(KERN_WARNING "not ok -- %s:%d (%s)\n", loc, ln, expl); + return expr; +} + + +#define ccw_test_assert(_expr, _expl) ({_ccw_test_assert((_expr), \ + __func__, __LINE__, (_expl)); }) + +struct workqueue_struct *work_q; + +static __u16 cu_type =3D 0xfffe; +module_param(cu_type, ushort, 0444); +MODULE_PARM_DESC(cu_type, "Use this cu type for matching (default 0x3831)"= ); + + +static struct ccw_device_id ccw_tester_ids[] =3D { + { CCW_DEVICE(0, 0) }, /* placeholder */ + {}, +}; + +struct ccw_test_work { + struct work_struct work; + struct ccw1 *ccw; + __u32 intparm; + void *private; + void (*setup)(struct ccw_test_work *w); + void (*do_test)(struct ccw_test_work *w); + void (*teardown)(struct ccw_test_work *w); + struct irb irb; + int ret; + bool doing_io; +}; + +struct ccw_tester_device { + spinlock_t lock; + wait_queue_head_t wait_q; + struct ccw_device *cdev; + struct ccw_test_work work; + bool work_pending; +}; + +static struct ccw_tester_device *to_mydev(struct ccw_device *cdev) +{ + return dev_get_drvdata(&(cdev->dev)); +} + + +static void ccw_tester_auto_online(void *data, async_cookie_t cookie) +{ + struct ccw_device *cdev =3D data; + int ret; + + ret =3D ccw_device_set_online(cdev); + if (ret) + dev_warn(&cdev->dev, "Failed to set online: %d\n", ret); +} + +static void do_io_work(struct ccw_tester_device *tdev) +{ + struct ccw_test_work *w =3D &tdev->work; + unsigned long flags; + int retry =3D 124; + + do { + spin_lock_irqsave(get_ccwdev_lock(tdev->cdev), flags); + tdev->work.doing_io =3D true; + w->ret =3D ccw_device_start(tdev->cdev, w->ccw, w->intparm, 0, 0); + spin_unlock_irqrestore(get_ccwdev_lock(tdev->cdev), flags); + cpu_relax(); + } while (w->ret =3D=3D -EBUSY && --retry > 0); + wait_event(tdev->wait_q, w->doing_io =3D=3D false); +} + +static void do_test_do_io(struct ccw_test_work *w) +{ + struct ccw_tester_device *tdev; + + tdev =3D container_of(w, struct ccw_tester_device, work); + do_io_work(tdev); +} + +static int irb_is_error(struct irb *irb) +{ + if (scsw_cstat(&irb->scsw) !=3D 0) + return 1; + if (scsw_dstat(&irb->scsw) & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) + return 1; + if (scsw_cc(&irb->scsw) !=3D 0) + return 1; + return 0; +} + +static void set_mode_ccw(struct ccw_test_work *w, u32 mode) +{ + const char incant[] =3D CCW_TST_SET_MODE_INCANTATION; + char *buf; + + buf =3D kzalloc(sizeof(incant) + sizeof(mode), GFP_DMA | GFP_KERNEL); + + memcpy(buf, incant, sizeof(incant)); + memcpy(buf + sizeof(incant), &mode, sizeof(mode)); + w->ccw->cmd_code =3D CCW_CMD_CTL_MODE; + w->ccw->count =3D sizeof(incant) + sizeof(mode) ; + w->ccw->cda =3D (__u32)(unsigned long) buf; + do_test_do_io(w); + w->ret =3D irb_is_error(&w->irb) ? -EINVAL : 0; + kfree(buf); +} + +static long set_mode_diag(struct subchannel_id schid, u32 mode) +{ + register unsigned long __nr asm("1") =3D CCW_TST_DIAG_500_SUB; + register struct subchannel_id __schid asm("2") =3D schid; + register unsigned long __mode asm("3") =3D mode; + register long __rc asm("2"); + + asm volatile ("diag 2,3,0x500\n" + : "=3Dd" (__rc) : "d" (__nr), "d" (__schid), "d" (__mode) + : "memory", "cc"); + return __rc; +} + +static void w_fib_setup(struct ccw_test_work *w) +{ + const int test_fib_length =3D 32; + u32 *test_fib; + int i; + + set_mode_ccw(w, OP_MODE_FIB); + if (w->ret) { + printk(KERN_WARNING "w_fib_setup ret =3D %d\n", w->ret); + w->ret =3D 0; + return; + } + + test_fib =3D kcalloc(test_fib_length, sizeof(u32), + GFP_DMA | GFP_KERNEL); + if (!test_fib) + w->ret =3D -ENOMEM; + w->private =3D test_fib; + + test_fib[0] =3D 1; + test_fib[1] =3D 2; + for (i =3D 2; i < test_fib_length; ++i) + test_fib[i] =3D test_fib[i - 1] + test_fib[i - 2]; + + w->ccw->cmd_code =3D CCW_CMD_WRITE; + w->ccw->count =3D sizeof(*test_fib) * test_fib_length; + w->ccw->cda =3D (__u32)(unsigned long) test_fib; +} + +static void basic_teardown(struct ccw_test_work *w) +{ + kfree(w->private); + w->private =3D NULL; + if (w->ret) + printk(KERN_WARNING "w_fib_teardown ret =3D %d\n", w->ret); +} + +static void ccw_tester_int_handler(struct ccw_device *cdev, + unsigned long intparm, + struct irb *irb) +{ + struct ccw_tester_device *tdev =3D to_mydev(cdev); + + memcpy(&tdev->work.irb, irb, sizeof(*irb)); + tdev->work.doing_io =3D false; + wake_up(&tdev->wait_q); +} + +static bool expect_is_not_fib(struct irb *irb, int count_expected) +{ + if (!(irb_is_error(irb) + && (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_EXCEP) + && scsw_stctl(&irb->scsw) & SCSW_STCTL_ALERT_STATUS)) + return false; + if (irb->scsw.cmd.count =3D=3D count_expected) + return true; + printk(KERN_NOTICE + "expected residual count of %d got %d (fib at wrong place)\n", + count_expected, irb->scsw.cmd.count); + return false; +} + + +static void w_fib_do_test(struct ccw_test_work *w) +{ + u32 *test_fib =3D w->private; + + do_test_do_io(w); + ccw_test_assert(!irb_is_error(&w->irb), "completion expected"); + test_fib[25] =3D 0; + do_test_do_io(w); + ccw_test_assert(expect_is_not_fib(&w->irb, + (31-25)*sizeof(u32)), "expected non fib"); +} + + +static int queue_ccw_test_work(struct ccw_tester_device *tdev, + void (*setup)(struct ccw_test_work *), + void (*do_test)(struct ccw_test_work *), + void (*teardown)(struct ccw_test_work *)) +{ + if (!spin_trylock(&tdev->lock)) + return -EBUSY; + if (tdev->work_pending) { + spin_unlock(&tdev->lock); + return -EBUSY; + } + tdev->work_pending =3D true; + tdev->work.setup =3D setup; + tdev->work.do_test =3D do_test; + tdev->work.teardown =3D teardown; + queue_work(work_q, &tdev->work.work); + spin_unlock(&tdev->lock); + return 0; +} + + +static ssize_t w_fib_store(struct device *dev, struct device_attribute *at= tr, + const char *buf, size_t count) +{ + struct ccw_tester_device *tdev =3D to_mydev(to_ccwdev(dev)); + int ret; + + ret =3D queue_ccw_test_work(tdev, + w_fib_setup, w_fib_do_test, basic_teardown); + return ret ? ret : count; +} + +static u32 *u32_arr_in_idal_buf_at(struct idal_buffer const *ib, int i) +{ + u64 b =3D IDA_BLOCK_SIZE/sizeof(u32); + + return (u32 *)(ib->data[i/b]) + i % b; +} + +#define IDAL_TEST_BYTES (IDA_BLOCK_SIZE * 3 + IDA_BLOCK_SIZE/2) +#define IDAL_TEST_ELEMENTS (IDAL_TEST_BYTES/sizeof(u32)) + +static void fib_idal_setup(struct ccw_test_work *w) +{ + struct ccw_tester_device *tdev; + struct idal_buffer *ib =3D NULL; + u32 n, n_1 =3D 2, n_2 =3D 1; + int i =3D 0; + struct subchannel_id schid; + + tdev =3D container_of(w, struct ccw_tester_device, work); + ccw_device_get_schid(tdev->cdev, &schid); + w->ret =3D set_mode_diag(schid, OP_MODE_FIB); + if (w->ret) { + printk(KERN_WARNING "w_fib_idal_setup ret =3D %d\n", w->ret); + w->ret =3D 0; + return; + } + ib =3D idal_buffer_alloc(IDAL_TEST_BYTES, 0); + if (IS_ERR(ib)) { + w->ret =3D PTR_ERR(ib); + return; + } + w->private =3D ib; + *u32_arr_in_idal_buf_at(ib, 0) =3D n_2; + *u32_arr_in_idal_buf_at(ib, 1) =3D n_1; + for (i =3D 2; i < IDAL_TEST_ELEMENTS; ++i) { + n =3D n_1 + n_2; + n_2 =3D n_1; + n_1 =3D n; + *u32_arr_in_idal_buf_at(ib, i) =3D n; + } + idal_buffer_set_cda(ib, w->ccw); + w->ccw->count =3D IDAL_TEST_BYTES; + w->ccw->cmd_code =3D CCW_CMD_WRITE; +} + +static void fib_idal_teardown(struct ccw_test_work *w) +{ + if (w->private) { + idal_buffer_free(w->private); + w->private =3D NULL; + } + if (w->ret) + printk(KERN_WARNING "fib_idal_teardown ret =3D %d\n", w->ret); +} + +static void do_fib_idal_test(struct ccw_test_work *w) +{ + struct idal_buffer *ib =3D w->private; + + /* we have one already set up, fire it */ + do_test_do_io(w); + ccw_test_assert(!irb_is_error(&w->irb), "completion expected"); + + /* let's break fib and check if the device detects it */ + ++(*u32_arr_in_idal_buf_at(ib, IDAL_TEST_ELEMENTS - 5)); + do_test_do_io(w); + ccw_test_assert(expect_is_not_fib(&w->irb, + 4 * sizeof(u32)), "expected non fib"); + /* shorten the seq so the broken element is not included */ + w->ccw->count =3D IDAL_TEST_BYTES - 5 * sizeof(u32); + do_test_do_io(w); + ccw_test_assert(!irb_is_error(&w->irb), "completion expected"); +} + +static ssize_t w_fib_idal_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct ccw_tester_device *tdev =3D to_mydev(to_ccwdev(dev)); + + ret =3D queue_ccw_test_work(tdev, + fib_idal_setup, do_fib_idal_test, fib_idal_teardown); + return ret ? ret : count; +} + +static DEVICE_ATTR_WO(w_fib); +static DEVICE_ATTR_WO(w_fib_idal); + +static void do_ccw_test_work(struct work_struct *work) +{ + + struct ccw_test_work *w; + struct ccw_tester_device *tdev; + + w =3D container_of(work, struct ccw_test_work, work); + tdev =3D container_of(w, struct ccw_tester_device, work); + + w->ret =3D 0; + w->setup(w); + w->do_test(w); + w->teardown(w); + spin_lock(&tdev->lock); + tdev->work_pending =3D false; + spin_unlock(&tdev->lock); + memset(w->ccw, 0, sizeof(*(w->ccw))); + memset(&w->irb, 0, sizeof(w->irb)); +} + +static int ccw_tester_offline(struct ccw_device *cdev) +{ + struct ccw_tester_device *tdev =3D to_mydev(cdev); + + if (!tdev) + return 0; + device_remove_file(&(cdev->dev), &dev_attr_w_fib); + device_remove_file(&(cdev->dev), &dev_attr_w_fib_idal); + spin_lock(&tdev->lock); + tdev->work_pending =3D true; + spin_unlock(&tdev->lock); + kfree(tdev->work.ccw); + tdev->work.ccw =3D NULL; + kfree(tdev); + dev_set_drvdata(&cdev->dev, NULL); + return 0; +} + +static int ccw_tester_online(struct ccw_device *cdev) +{ + int ret; + struct ccw_tester_device *tdev; + + tdev =3D kzalloc(sizeof(*tdev), GFP_KERNEL); + if (!tdev) { + dev_warn(&cdev->dev, "Could not get memory\n"); + return -ENOMEM; + } + init_waitqueue_head(&tdev->wait_q); + INIT_WORK(&(tdev->work.work), do_ccw_test_work); + spin_lock_init(&tdev->lock); + tdev->work.ccw =3D kzalloc(sizeof(*tdev->work.ccw), GFP_DMA | GFP_KERNEL); + if (!tdev) { + dev_warn(&cdev->dev, "Could not get memory\n"); + ret =3D -ENOMEM; + goto out_free; + } + dev_set_drvdata(&cdev->dev, tdev); + tdev->cdev =3D cdev; + + ret =3D device_create_file(&(cdev->dev), &dev_attr_w_fib); + if (ret) + goto out_free; + ret =3D device_create_file(&(cdev->dev), &dev_attr_w_fib_idal); + if (ret) + goto out_free; + return ret; +out_free: + ccw_tester_offline(cdev); + return ret; +} + +static void ccw_tester_remove(struct ccw_device *cdev) +{ + ccw_device_set_offline(cdev); +} + +static int ccw_tester_probe(struct ccw_device *cdev) +{ + cdev->handler =3D ccw_tester_int_handler; + async_schedule(ccw_tester_auto_online, cdev); + return 0; +} + +static struct ccw_driver ccw_tester_driver =3D { + .driver =3D { + .owner =3D THIS_MODULE, + .name =3D "ccw_tester", + }, + .ids =3D ccw_tester_ids, + .probe =3D ccw_tester_probe, + .set_online =3D ccw_tester_online, + .set_offline =3D ccw_tester_offline, + .remove =3D ccw_tester_remove, + .int_class =3D IRQIO_VIR, +}; + + +static int __init ccw_tester_init(void) +{ + work_q =3D create_singlethread_workqueue("ccw-tester"); + ccw_tester_ids[0].cu_type =3D cu_type; + return ccw_driver_register(&ccw_tester_driver); +} +module_init(ccw_tester_init); + +static void __exit ccw_tester_exit(void) +{ + ccw_driver_unregister(&ccw_tester_driver); +} +module_exit(ccw_tester_exit); + +MODULE_DESCRIPTION("ccw test driver -- throw ccws at devices"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Halil Pasic "); --=20 2.13.5 From nobody Fri May 3 17:16:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 151016029772163.28145749250075; Wed, 8 Nov 2017 08:58:17 -0800 (PST) Received: from localhost ([::1]:60827 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eCTg4-0005jJ-UY for importer@patchew.org; Wed, 08 Nov 2017 11:58:13 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55294) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eCTd2-0003aY-C3 for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:55:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eCTcx-0000VO-RJ for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:55:04 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:55984 helo=mx0a-001b2d01.pphosted.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eCTcx-0000V7-LH for qemu-devel@nongnu.org; Wed, 08 Nov 2017 11:54:59 -0500 Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vA8GqEth128504 for ; Wed, 8 Nov 2017 11:54:52 -0500 Received: from e06smtp10.uk.ibm.com (e06smtp10.uk.ibm.com [195.75.94.106]) by mx0b-001b2d01.pphosted.com with ESMTP id 2e448sxem7-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Wed, 08 Nov 2017 11:54:51 -0500 Received: from localhost by e06smtp10.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 8 Nov 2017 16:54:50 -0000 Received: from b06cxnps4076.portsmouth.uk.ibm.com (9.149.109.198) by e06smtp10.uk.ibm.com (192.168.101.140) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 8 Nov 2017 16:54:48 -0000 Received: from d06av21.portsmouth.uk.ibm.com (d06av21.portsmouth.uk.ibm.com [9.149.105.232]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id vA8GsmNo32178316; Wed, 8 Nov 2017 16:54:48 GMT Received: from d06av21.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CB03052043; Wed, 8 Nov 2017 15:48:38 +0000 (GMT) Received: from tuxmaker.boeblingen.de.ibm.com (unknown [9.152.85.9]) by d06av21.portsmouth.uk.ibm.com (Postfix) with ESMTPS id 86A5252045; Wed, 8 Nov 2017 15:48:38 +0000 (GMT) From: Halil Pasic To: Cornelia Huck , "Dong Jia Shi" Date: Wed, 8 Nov 2017 17:54:22 +0100 X-Mailer: git-send-email 2.13.5 In-Reply-To: <20171108165422.46267-1-pasic@linux.vnet.ibm.com> References: <20171108165422.46267-1-pasic@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 17110816-0040-0000-0000-000003EC0D83 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17110816-0041-0000-0000-000025EEAD35 Message-Id: <20171108165422.46267-4-pasic@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-08_03:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=2 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000 definitions=main-1711080223 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 148.163.158.5 Subject: [Qemu-devel] [RFC PATCH NOT QEMU v2 3/3] ccw-tester: add tic test X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-s390x@nongnu.org, Thomas Huth , Halil Pasic , Pierre Morel , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Let's add a test verifying that the channel subsystlem responds to a format 1 transfer in channel ccw with non-zero count properly -- with a channel program check. Signed-off-by: Halil Pasic --- ccw_tester.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 69 insertions(+) diff --git a/ccw_tester.c b/ccw_tester.c index b8e632b..6253ae7 100644 --- a/ccw_tester.c +++ b/ccw_tester.c @@ -347,8 +347,73 @@ static ssize_t w_fib_idal_store(struct device *dev, return ret ? ret : count; } =20 +static void tic_setup(struct ccw_test_work *w) +{ + struct ccw_tester_device *tdev; + struct subchannel_id schid; + + tdev =3D container_of(w, struct ccw_tester_device, work); + ccw_device_get_schid(tdev->cdev, &schid); + w->ret =3D set_mode_diag(schid, OP_MODE_NOP); + if (w->ret) { + printk(KERN_WARNING "tic_setup ret =3D %d\n", w->ret); + w->ret =3D 0; + return; + } + w->private =3D kzalloc(sizeof(*w->ccw), GFP_DMA | GFP_KERNEL); + + w->ccw->count =3D 0x0666; /* we are evil */ + w->ccw->cmd_code =3D CCW_CMD_TIC; + /* hope this won't get used */ + w->ccw->cda =3D (__u32)(unsigned long) w->private; +} + +static void tic_teardown(struct ccw_test_work *w) +{ + if (w->private) { + idal_buffer_free(w->private); + w->private =3D NULL; + } + if (w->ret) + printk(KERN_WARNING "tic_teardown ret =3D %d\n", w->ret); +} + +static bool expect_pgm_chk(struct irb *irb) +{ + if (irb_is_error(irb) + && (scsw_cstat(&irb->scsw) & SCHN_STAT_PROG_CHECK) + && scsw_stctl(&irb->scsw) & SCSW_STCTL_ALERT_STATUS) + return true; + printk(KERN_NOTICE + "expected program check but got none (is_error =3D=3D %d)\n", + irb_is_error(irb)); + return false; +} + +static void do_tic_test(struct ccw_test_work *w) +{ + /* we have one already set up, fire it */ + do_test_do_io(w); + /* TODO: check for pgm-check */ + ccw_test_assert(expect_pgm_chk(&w->irb), + "expected pgm check for tic with count !=3D 0 fib"); +} + +static ssize_t w_tic_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct ccw_tester_device *tdev =3D to_mydev(to_ccwdev(dev)); + + ret =3D queue_ccw_test_work(tdev, + tic_setup, do_tic_test, tic_teardown); + return ret ? ret : count; +} + static DEVICE_ATTR_WO(w_fib); static DEVICE_ATTR_WO(w_fib_idal); +static DEVICE_ATTR_WO(w_tic); =20 static void do_ccw_test_work(struct work_struct *work) { @@ -378,6 +443,7 @@ static int ccw_tester_offline(struct ccw_device *cdev) return 0; device_remove_file(&(cdev->dev), &dev_attr_w_fib); device_remove_file(&(cdev->dev), &dev_attr_w_fib_idal); + device_remove_file(&(cdev->dev), &dev_attr_w_tic); spin_lock(&tdev->lock); tdev->work_pending =3D true; spin_unlock(&tdev->lock); @@ -416,6 +482,9 @@ static int ccw_tester_online(struct ccw_device *cdev) ret =3D device_create_file(&(cdev->dev), &dev_attr_w_fib_idal); if (ret) goto out_free; + ret =3D device_create_file(&(cdev->dev), &dev_attr_w_tic); + if (ret) + goto out_free; return ret; out_free: ccw_tester_offline(cdev); --=20 2.13.5