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
);
37 ccw_dev
->sch
->curr_status
.scsw
.count
= ccw
->count
- len
;
42 /* Handle WRITE ccw commands to write data to client */
43 static int handle_payload_3270_write(EmulatedCcw3270Device
*dev
, CCW1
*ccw
)
45 EmulatedCcw3270Class
*ck
= EMULATED_CCW_3270_GET_CLASS(dev
);
46 CcwDevice
*ccw_dev
= CCW_DEVICE(dev
);
53 len
= ck
->write_payload_3270(dev
, ccw
->cmd_code
);
56 return len
? len
: -EIO
;
59 ccw_dev
->sch
->curr_status
.scsw
.count
= ccw
->count
- len
;
63 static int emulated_ccw_3270_cb(SubchDev
*sch
, CCW1 ccw
)
66 EmulatedCcw3270Device
*dev
= sch
->driver_data
;
68 switch (ccw
.cmd_code
) {
73 rc
= handle_payload_3270_write(dev
, &ccw
);
77 rc
= handle_payload_3270_read(dev
, &ccw
);
85 /* I/O error, specific devices generate specific conditions */
86 SCHIB
*schib
= &sch
->curr_status
;
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
;
99 static void emulated_ccw_3270_realize(DeviceState
*ds
, Error
**errp
)
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
);
109 sch
= css_create_sch(cdev
->devno
, errp
);
118 sch
->driver_data
= dev
;
120 chpid
= css_find_free_chpid(sch
->cssid
);
122 if (chpid
> MAX_CHPID
) {
123 error_setg(&err
, "No available chpid to use.");
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
;
139 cdk
->realize(cdev
, &err
);
147 error_propagate(errp
, err
);
148 css_subch_assign(sch
->cssid
, sch
->ssid
, sch
->schid
, sch
->devno
, NULL
);
153 static Property emulated_ccw_3270_properties
[] = {
154 DEFINE_PROP_END_OF_LIST(),
157 static void emulated_ccw_3270_class_init(ObjectClass
*klass
, void *data
)
159 DeviceClass
*dc
= DEVICE_CLASS(klass
);
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
);
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
),
177 static void emulated_ccw_register(void)
179 type_register_static(&emulated_ccw_3270_info
);
182 type_init(emulated_ccw_register
)