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 if (len < 0) { 35 return len; 36 } 37 ccw_dev->sch->curr_status.scsw.count = ccw->count - len; 38 39 return 0; 40 } 41 42 /* Handle WRITE ccw commands to write data to client */ 43 static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw) 44 { 45 EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev); 46 CcwDevice *ccw_dev = CCW_DEVICE(dev); 47 int len; 48 49 if (!ccw->cda) { 50 return -EFAULT; 51 } 52 53 len = ck->write_payload_3270(dev, ccw->cmd_code); 54 55 if (len <= 0) { 56 return len ? len : -EIO; 57 } 58 59 ccw_dev->sch->curr_status.scsw.count = ccw->count - len; 60 return 0; 61 } 62 63 static int emulated_ccw_3270_cb(SubchDev *sch, CCW1 ccw) 64 { 65 int rc = 0; 66 EmulatedCcw3270Device *dev = sch->driver_data; 67 68 switch (ccw.cmd_code) { 69 case TC_WRITESF: 70 case TC_WRITE: 71 case TC_EWRITE: 72 case TC_EWRITEA: 73 rc = handle_payload_3270_write(dev, &ccw); 74 break; 75 case TC_RDBUF: 76 case TC_READMOD: 77 rc = handle_payload_3270_read(dev, &ccw); 78 break; 79 default: 80 rc = -ENOSYS; 81 break; 82 } 83 84 if (rc == -EIO) { 85 /* I/O error, specific devices generate specific conditions */ 86 SCHIB *schib = &sch->curr_status; 87 88 sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_CHECK; 89 sch->sense_data[0] = 0x40; /* intervention-req */ 90 schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND; 91 schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; 92 schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | 93 SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 94 } 95 96 return rc; 97 } 98 99 static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp) 100 { 101 uint16_t chpid; 102 EmulatedCcw3270Device *dev = EMULATED_CCW_3270(ds); 103 EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev); 104 CcwDevice *cdev = CCW_DEVICE(ds); 105 CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev); 106 SubchDev *sch; 107 Error *err = NULL; 108 109 sch = css_create_sch(cdev->devno, errp); 110 if (!sch) { 111 return; 112 } 113 114 if (!ck->init) { 115 goto out_err; 116 } 117 118 sch->driver_data = dev; 119 cdev->sch = sch; 120 chpid = css_find_free_chpid(sch->cssid); 121 122 if (chpid > MAX_CHPID) { 123 error_setg(&err, "No available chpid to use."); 124 goto out_err; 125 } 126 127 sch->id.reserved = 0xff; 128 sch->id.cu_type = EMULATED_CCW_3270_CU_TYPE; 129 css_sch_build_virtual_schib(sch, (uint8_t)chpid, 130 EMULATED_CCW_3270_CHPID_TYPE); 131 sch->do_subchannel_work = do_subchannel_work_virtual; 132 sch->ccw_cb = emulated_ccw_3270_cb; 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->bus_type = TYPE_VIRTUAL_CSS_BUS; 163 dc->realize = emulated_ccw_3270_realize; 164 dc->hotpluggable = false; 165 set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); 166 } 167 168 static const TypeInfo emulated_ccw_3270_info = { 169 .name = TYPE_EMULATED_CCW_3270, 170 .parent = TYPE_CCW_DEVICE, 171 .instance_size = sizeof(EmulatedCcw3270Device), 172 .class_init = emulated_ccw_3270_class_init, 173 .class_size = sizeof(EmulatedCcw3270Class), 174 .abstract = true, 175 }; 176 177 static void emulated_ccw_register(void) 178 { 179 type_register_static(&emulated_ccw_3270_info); 180 } 181 182 type_init(emulated_ccw_register) 183