qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

3270-ccw.c (4638B)


      1 /*
      2  * Emulated ccw-attached 3270 implementation
      3  *
      4  * Copyright 2017 IBM Corp.
      5  * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
      6  *            Jing Liu <liujbjl@linux.vnet.ibm.com>
      7  *
      8  * This work is licensed under the terms of the GNU GPL, version 2 or (at
      9  * your option) any later version. See the COPYING file in the top-level
     10  * directory.
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include "qapi/error.h"
     15 #include "qemu/module.h"
     16 #include "hw/s390x/css.h"
     17 #include "hw/s390x/css-bridge.h"
     18 #include "hw/qdev-properties.h"
     19 #include "hw/s390x/3270-ccw.h"
     20 
     21 /* Handle READ ccw commands from guest */
     22 static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw)
     23 {
     24     EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
     25     CcwDevice *ccw_dev = CCW_DEVICE(dev);
     26     int len;
     27 
     28     if (!ccw->cda) {
     29         return -EFAULT;
     30     }
     31 
     32     len = ck->read_payload_3270(dev);
     33     if (len < 0) {
     34         return len;
     35     }
     36     ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
     37 
     38     return 0;
     39 }
     40 
     41 /* Handle WRITE ccw commands to write data to client */
     42 static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw)
     43 {
     44     EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
     45     CcwDevice *ccw_dev = CCW_DEVICE(dev);
     46     int len;
     47 
     48     if (!ccw->cda) {
     49         return -EFAULT;
     50     }
     51 
     52     len = ck->write_payload_3270(dev, ccw->cmd_code);
     53 
     54     if (len <= 0) {
     55         return len ? len : -EIO;
     56     }
     57 
     58     ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
     59     return 0;
     60 }
     61 
     62 static int emulated_ccw_3270_cb(SubchDev *sch, CCW1 ccw)
     63 {
     64     int rc = 0;
     65     EmulatedCcw3270Device *dev = sch->driver_data;
     66 
     67     switch (ccw.cmd_code) {
     68     case TC_WRITESF:
     69     case TC_WRITE:
     70     case TC_EWRITE:
     71     case TC_EWRITEA:
     72         rc = handle_payload_3270_write(dev, &ccw);
     73         break;
     74     case TC_RDBUF:
     75     case TC_READMOD:
     76         rc = handle_payload_3270_read(dev, &ccw);
     77         break;
     78     default:
     79         rc = -ENOSYS;
     80         break;
     81     }
     82 
     83     if (rc == -EIO) {
     84         /* I/O error, specific devices generate specific conditions */
     85         SCHIB *schib = &sch->curr_status;
     86 
     87         sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_CHECK;
     88         sch->sense_data[0] = 0x40;    /* intervention-req */
     89         schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND;
     90         schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL;
     91         schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
     92                    SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
     93     }
     94 
     95     return rc;
     96 }
     97 
     98 static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
     99 {
    100     uint16_t chpid;
    101     EmulatedCcw3270Device *dev = EMULATED_CCW_3270(ds);
    102     EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
    103     CcwDevice *cdev = CCW_DEVICE(ds);
    104     CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev);
    105     SubchDev *sch;
    106     Error *err = NULL;
    107 
    108     sch = css_create_sch(cdev->devno, errp);
    109     if (!sch) {
    110         return;
    111     }
    112 
    113     if (!ck->init) {
    114         goto out_err;
    115     }
    116 
    117     sch->driver_data = dev;
    118     cdev->sch = sch;
    119     chpid = css_find_free_chpid(sch->cssid);
    120 
    121     if (chpid > MAX_CHPID) {
    122         error_setg(&err, "No available chpid to use.");
    123         goto out_err;
    124     }
    125 
    126     sch->id.reserved = 0xff;
    127     sch->id.cu_type = EMULATED_CCW_3270_CU_TYPE;
    128     css_sch_build_virtual_schib(sch, (uint8_t)chpid,
    129                                 EMULATED_CCW_3270_CHPID_TYPE);
    130     sch->do_subchannel_work = do_subchannel_work_virtual;
    131     sch->ccw_cb = emulated_ccw_3270_cb;
    132     sch->irb_cb = build_irb_virtual;
    133 
    134     ck->init(dev, &err);
    135     if (err) {
    136         goto out_err;
    137     }
    138 
    139     cdk->realize(cdev, &err);
    140     if (err) {
    141         goto out_err;
    142     }
    143 
    144     return;
    145 
    146 out_err:
    147     error_propagate(errp, err);
    148     css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
    149     cdev->sch = NULL;
    150     g_free(sch);
    151 }
    152 
    153 static Property emulated_ccw_3270_properties[] = {
    154     DEFINE_PROP_END_OF_LIST(),
    155 };
    156 
    157 static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data)
    158 {
    159     DeviceClass *dc = DEVICE_CLASS(klass);
    160 
    161     device_class_set_props(dc, emulated_ccw_3270_properties);
    162     dc->realize = emulated_ccw_3270_realize;
    163     dc->hotpluggable = false;
    164     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
    165 }
    166 
    167 static const TypeInfo emulated_ccw_3270_info = {
    168     .name = TYPE_EMULATED_CCW_3270,
    169     .parent = TYPE_CCW_DEVICE,
    170     .instance_size = sizeof(EmulatedCcw3270Device),
    171     .class_init = emulated_ccw_3270_class_init,
    172     .class_size = sizeof(EmulatedCcw3270Class),
    173     .abstract = true,
    174 };
    175 
    176 static void emulated_ccw_register(void)
    177 {
    178     type_register_static(&emulated_ccw_3270_info);
    179 }
    180 
    181 type_init(emulated_ccw_register)