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 133 ck->init(dev, &err); 134 if (err) { 135 goto out_err; 136 } 137 138 cdk->realize(cdev, &err); 139 if (err) { 140 goto out_err; 141 } 142 143 return; 144 145 out_err: 146 error_propagate(errp, err); 147 css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); 148 cdev->sch = NULL; 149 g_free(sch); 150 } 151 152 static Property emulated_ccw_3270_properties[] = { 153 DEFINE_PROP_END_OF_LIST(), 154 }; 155 156 static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data) 157 { 158 DeviceClass *dc = DEVICE_CLASS(klass); 159 160 device_class_set_props(dc, emulated_ccw_3270_properties); 161 dc->realize = emulated_ccw_3270_realize; 162 dc->hotpluggable = false; 163 set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); 164 } 165 166 static const TypeInfo emulated_ccw_3270_info = { 167 .name = TYPE_EMULATED_CCW_3270, 168 .parent = TYPE_CCW_DEVICE, 169 .instance_size = sizeof(EmulatedCcw3270Device), 170 .class_init = emulated_ccw_3270_class_init, 171 .class_size = sizeof(EmulatedCcw3270Class), 172 .abstract = true, 173 }; 174 175 static void emulated_ccw_register(void) 176 { 177 type_register_static(&emulated_ccw_3270_info); 178 } 179 180 type_init(emulated_ccw_register) 181