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"
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"
21 /* Handle READ ccw commands from guest */
22 static int handle_payload_3270_read(EmulatedCcw3270Device
*dev
, CCW1
*ccw
)
24 EmulatedCcw3270Class
*ck
= EMULATED_CCW_3270_GET_CLASS(dev
);
25 CcwDevice
*ccw_dev
= CCW_DEVICE(dev
);
32 len
= ck
->read_payload_3270(dev
);
36 ccw_dev
->sch
->curr_status
.scsw
.count
= ccw
->count
- len
;
41 /* Handle WRITE ccw commands to write data to client */
42 static int handle_payload_3270_write(EmulatedCcw3270Device
*dev
, CCW1
*ccw
)
44 EmulatedCcw3270Class
*ck
= EMULATED_CCW_3270_GET_CLASS(dev
);
45 CcwDevice
*ccw_dev
= CCW_DEVICE(dev
);
52 len
= ck
->write_payload_3270(dev
, ccw
->cmd_code
);
55 return len
? len
: -EIO
;
58 ccw_dev
->sch
->curr_status
.scsw
.count
= ccw
->count
- len
;
62 static int emulated_ccw_3270_cb(SubchDev
*sch
, CCW1 ccw
)
65 EmulatedCcw3270Device
*dev
= sch
->driver_data
;
67 switch (ccw
.cmd_code
) {
72 rc
= handle_payload_3270_write(dev
, &ccw
);
76 rc
= handle_payload_3270_read(dev
, &ccw
);
84 /* I/O error, specific devices generate specific conditions */
85 SCHIB
*schib
= &sch
->curr_status
;
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
;
98 static void emulated_ccw_3270_realize(DeviceState
*ds
, Error
**errp
)
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
);
108 sch
= css_create_sch(cdev
->devno
, errp
);
117 sch
->driver_data
= dev
;
119 chpid
= css_find_free_chpid(sch
->cssid
);
121 if (chpid
> MAX_CHPID
) {
122 error_setg(&err
, "No available chpid to use.");
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
;
138 cdk
->realize(cdev
, &err
);
146 error_propagate(errp
, err
);
147 css_subch_assign(sch
->cssid
, sch
->ssid
, sch
->schid
, sch
->devno
, NULL
);
152 static Property emulated_ccw_3270_properties
[] = {
153 DEFINE_PROP_END_OF_LIST(),
156 static void emulated_ccw_3270_class_init(ObjectClass
*klass
, void *data
)
158 DeviceClass
*dc
= DEVICE_CLASS(klass
);
160 device_class_set_props(dc
, emulated_ccw_3270_properties
);
161 dc
->bus_type
= TYPE_VIRTUAL_CSS_BUS
;
162 dc
->realize
= emulated_ccw_3270_realize
;
163 dc
->hotpluggable
= false;
164 set_bit(DEVICE_CATEGORY_DISPLAY
, dc
->categories
);
167 static const TypeInfo emulated_ccw_3270_info
= {
168 .name
= TYPE_EMULATED_CCW_3270
,
169 .parent
= TYPE_CCW_DEVICE
,
170 .instance_size
= sizeof(EmulatedCcw3270Device
),
171 .class_init
= emulated_ccw_3270_class_init
,
172 .class_size
= sizeof(EmulatedCcw3270Class
),
176 static void emulated_ccw_register(void)
178 type_register_static(&emulated_ccw_3270_info
);
181 type_init(emulated_ccw_register
)