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