2 * Emulated ccw-attached 3270 implementation
4 * Copyright 2017 IBM Corp.
5 * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
6 * Jing Liu <liujbjl@linux.vnet.ibm.com>
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
13 #include "qemu/osdep.h"
14 #include "qapi/error.h"
15 #include "qemu/module.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"
22 /* Handle READ ccw commands from guest */
23 static int handle_payload_3270_read(EmulatedCcw3270Device
*dev
, CCW1
*ccw
)
25 EmulatedCcw3270Class
*ck
= EMULATED_CCW_3270_GET_CLASS(dev
);
26 CcwDevice
*ccw_dev
= CCW_DEVICE(dev
);
33 len
= ck
->read_payload_3270(dev
);
34 ccw_dev
->sch
->curr_status
.scsw
.count
= ccw
->count
- len
;
39 /* Handle WRITE ccw commands to write data to client */
40 static int handle_payload_3270_write(EmulatedCcw3270Device
*dev
, CCW1
*ccw
)
42 EmulatedCcw3270Class
*ck
= EMULATED_CCW_3270_GET_CLASS(dev
);
43 CcwDevice
*ccw_dev
= CCW_DEVICE(dev
);
50 len
= ck
->write_payload_3270(dev
, ccw
->cmd_code
);
56 ccw_dev
->sch
->curr_status
.scsw
.count
= ccw
->count
- len
;
60 static int emulated_ccw_3270_cb(SubchDev
*sch
, CCW1 ccw
)
63 EmulatedCcw3270Device
*dev
= sch
->driver_data
;
65 switch (ccw
.cmd_code
) {
70 rc
= handle_payload_3270_write(dev
, &ccw
);
74 rc
= handle_payload_3270_read(dev
, &ccw
);
82 /* I/O error, specific devices generate specific conditions */
83 SCHIB
*schib
= &sch
->curr_status
;
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
;
96 static void emulated_ccw_3270_realize(DeviceState
*ds
, Error
**errp
)
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
);
106 sch
= css_create_sch(cdev
->devno
, errp
);
115 sch
->driver_data
= dev
;
117 chpid
= css_find_free_chpid(sch
->cssid
);
119 if (chpid
> MAX_CHPID
) {
120 error_setg(&err
, "No available chpid to use.");
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
;
136 cdk
->realize(cdev
, &err
);
144 error_propagate(errp
, err
);
145 css_subch_assign(sch
->cssid
, sch
->ssid
, sch
->schid
, sch
->devno
, NULL
);
150 static Property emulated_ccw_3270_properties
[] = {
151 DEFINE_PROP_END_OF_LIST(),
154 static void emulated_ccw_3270_class_init(ObjectClass
*klass
, void *data
)
156 DeviceClass
*dc
= DEVICE_CLASS(klass
);
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
);
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
),
174 static void emulated_ccw_register(void)
176 type_register_static(&emulated_ccw_3270_info
);
179 type_init(emulated_ccw_register
)