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