qemu/hw/s390x/3270-ccw.c
Halil Pasic 99577c492f s390x/css: unrestrict cssids
The default css 0xfe is currently restricted to virtual subchannel
devices. The hope when the decision was made was, that non-virtual
subchannel devices will come around when guest can exploit multiple
channel subsystems. Since the guests generally don't do, the pain
of the partitioned (cssid) namespace outweighs the gain.

Let us remove the corresponding restrictions (virtual devices
can be put only in 0xfe and non-virtual devices in any css except
the 0xfe -- while s390-squash-mcss then remaps everything to cssid 0).

At the same time, change our schema for generating css bus ids to put
both virtual and non-virtual devices into the default css (spilling over
into other css images, if needed). The intention is to deprecate
s390-squash-mcss. With this change devices without a specified devno
won't end up hidden to guests not supporting multiple channel subsystems,
unless this can not be avoided (default css full).

Let us also advertise the changes to the management software (so it can
tell are cssids unrestricted or restricted).

The adverse effect of getting rid of the restriction on migration should
not be too severe.  Vfio-ccw devices are not live-migratable yet, and for
virtual devices using the extra freedom would only make sense with the
aforementioned guest support in place.

The auto-generated bus ids are affected by both changes. We hope to not
encounter any auto-generated bus ids in production as Libvirt is always
explicit about the bus id.  Since 8ed179c937 ("s390x/css: catch section
mismatch on load", 2017-05-18) the worst that can happen because the same
device ended up having a different bus id is a cleanly failed migration.
I find it hard to reason about the impact of changed auto-generated bus
ids on migration for command line users as I don't know which rules is
such an user supposed to follow.

Another pain-point is down- or upgrade of QEMU for command line users.
The old way and the new way of doing vfio-ccw are mutually incompatible.
Libvirt is only going to support the new way, so for libvirt users, the
possible problems at QEMU downgrade are the following. If a domain
contains virtual devices placed into a css different than 0xfe the domain
will refuse to start with a QEMU not having this patch. Putting devices
into a css different that 0xfe however won't make much sense in the near
future (guest support). Libvirt will refuse to do vfio-ccw with a QEMU
not having this patch. This is business as usual.

Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
Message-Id: <20171206144438.28908-2-pasic@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
2017-12-14 17:56:54 +01:00

181 lines
4.6 KiB
C

/*
* Emulated ccw-attached 3270 implementation
*
* Copyright 2017 IBM Corp.
* Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
* Jing Liu <liujbjl@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.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "cpu.h"
#include "hw/s390x/css.h"
#include "hw/s390x/css-bridge.h"
#include "hw/s390x/3270-ccw.h"
/* Handle READ ccw commands from guest */
static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw)
{
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
CcwDevice *ccw_dev = CCW_DEVICE(dev);
int len;
if (!ccw->cda) {
return -EFAULT;
}
len = ck->read_payload_3270(dev);
ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
return 0;
}
/* Handle WRITE ccw commands to write data to client */
static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw)
{
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
CcwDevice *ccw_dev = CCW_DEVICE(dev);
int len;
if (!ccw->cda) {
return -EFAULT;
}
len = ck->write_payload_3270(dev, ccw->cmd_code);
if (len <= 0) {
return -EIO;
}
ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
return 0;
}
static int emulated_ccw_3270_cb(SubchDev *sch, CCW1 ccw)
{
int rc = 0;
EmulatedCcw3270Device *dev = sch->driver_data;
switch (ccw.cmd_code) {
case TC_WRITESF:
case TC_WRITE:
case TC_EWRITE:
case TC_EWRITEA:
rc = handle_payload_3270_write(dev, &ccw);
break;
case TC_RDBUF:
case TC_READMOD:
rc = handle_payload_3270_read(dev, &ccw);
break;
default:
rc = -ENOSYS;
break;
}
if (rc == -EIO) {
/* I/O error, specific devices generate specific conditions */
SCSW *s = &sch->curr_status.scsw;
sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_CHECK;
sch->sense_data[0] = 0x40; /* intervention-req */
s->ctrl &= ~SCSW_ACTL_START_PEND;
s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
}
return rc;
}
static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
{
uint16_t chpid;
EmulatedCcw3270Device *dev = EMULATED_CCW_3270(ds);
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
CcwDevice *cdev = CCW_DEVICE(ds);
CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev);
DeviceState *parent = DEVICE(cdev);
BusState *qbus = qdev_get_parent_bus(parent);
VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus);
SubchDev *sch;
Error *err = NULL;
sch = css_create_sch(cdev->devno, cbus->squash_mcss, errp);
if (!sch) {
return;
}
if (!ck->init) {
goto out_err;
}
sch->driver_data = dev;
cdev->sch = sch;
chpid = css_find_free_chpid(sch->cssid);
if (chpid > MAX_CHPID) {
error_setg(&err, "No available chpid to use.");
goto out_err;
}
sch->id.reserved = 0xff;
sch->id.cu_type = EMULATED_CCW_3270_CU_TYPE;
css_sch_build_virtual_schib(sch, (uint8_t)chpid,
EMULATED_CCW_3270_CHPID_TYPE);
sch->do_subchannel_work = do_subchannel_work_virtual;
sch->ccw_cb = emulated_ccw_3270_cb;
ck->init(dev, &err);
if (err) {
goto out_err;
}
cdk->realize(cdev, &err);
if (err) {
goto out_err;
}
return;
out_err:
error_propagate(errp, err);
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
cdev->sch = NULL;
g_free(sch);
}
static Property emulated_ccw_3270_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = emulated_ccw_3270_properties;
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
dc->realize = emulated_ccw_3270_realize;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
}
static const TypeInfo emulated_ccw_3270_info = {
.name = TYPE_EMULATED_CCW_3270,
.parent = TYPE_CCW_DEVICE,
.instance_size = sizeof(EmulatedCcw3270Device),
.class_init = emulated_ccw_3270_class_init,
.class_size = sizeof(EmulatedCcw3270Class),
.abstract = true,
};
static void emulated_ccw_register(void)
{
type_register_static(&emulated_ccw_3270_info);
}
type_init(emulated_ccw_register)