]>
Commit | Line | Data |
---|---|---|
df1fe5bb CH |
1 | /* |
2 | * Channel subsystem structures and definitions. | |
3 | * | |
4 | * Copyright 2012 IBM Corp. | |
5 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | |
6 | * | |
7 | * This work is licensed under the terms of the GNU GPL, version 2 or (at | |
8 | * your option) any later version. See the COPYING file in the top-level | |
9 | * directory. | |
10 | */ | |
11 | ||
12 | #ifndef CSS_H | |
13 | #define CSS_H | |
14 | ||
2283f4d6 | 15 | #include "cpu.h" |
a28d8391 YMZ |
16 | #include "hw/s390x/adapter.h" |
17 | #include "hw/s390x/s390_flic.h" | |
bd3f16ac | 18 | #include "hw/s390x/ioinst.h" |
f16bbb9b | 19 | #include "sysemu/kvm.h" |
df1fe5bb CH |
20 | |
21 | /* Channel subsystem constants. */ | |
cf249935 | 22 | #define MAX_DEVNO 65535 |
df1fe5bb CH |
23 | #define MAX_SCHID 65535 |
24 | #define MAX_SSID 3 | |
882b3b97 | 25 | #define MAX_CSSID 255 |
df1fe5bb CH |
26 | #define MAX_CHPID 255 |
27 | ||
dde522bb FL |
28 | #define MAX_ISC 7 |
29 | ||
df1fe5bb CH |
30 | #define MAX_CIWS 62 |
31 | ||
cf249935 | 32 | #define VIRTUAL_CSSID 0xfe |
6c15e9bf | 33 | #define VIRTIO_CCW_CHPID 0 /* used by convention */ |
cf249935 | 34 | |
df1fe5bb CH |
35 | typedef struct CIW { |
36 | uint8_t type; | |
37 | uint8_t command; | |
38 | uint16_t count; | |
39 | } QEMU_PACKED CIW; | |
40 | ||
41 | typedef struct SenseId { | |
42 | /* common part */ | |
43 | uint8_t reserved; /* always 0x'FF' */ | |
44 | uint16_t cu_type; /* control unit type */ | |
45 | uint8_t cu_model; /* control unit model */ | |
46 | uint16_t dev_type; /* device type */ | |
47 | uint8_t dev_model; /* device model */ | |
48 | uint8_t unused; /* padding byte */ | |
49 | /* extended part */ | |
50 | CIW ciw[MAX_CIWS]; /* variable # of CIWs */ | |
729315eb | 51 | } SenseId; /* Note: No QEMU_PACKED due to unaligned members */ |
df1fe5bb CH |
52 | |
53 | /* Channel measurements, from linux/drivers/s390/cio/cmf.c. */ | |
54 | typedef struct CMB { | |
55 | uint16_t ssch_rsch_count; | |
56 | uint16_t sample_count; | |
57 | uint32_t device_connect_time; | |
58 | uint32_t function_pending_time; | |
59 | uint32_t device_disconnect_time; | |
60 | uint32_t control_unit_queuing_time; | |
61 | uint32_t device_active_only_time; | |
62 | uint32_t reserved[2]; | |
63 | } QEMU_PACKED CMB; | |
64 | ||
65 | typedef struct CMBE { | |
66 | uint32_t ssch_rsch_count; | |
67 | uint32_t sample_count; | |
68 | uint32_t device_connect_time; | |
69 | uint32_t function_pending_time; | |
70 | uint32_t device_disconnect_time; | |
71 | uint32_t control_unit_queuing_time; | |
72 | uint32_t device_active_only_time; | |
73 | uint32_t device_busy_time; | |
74 | uint32_t initial_command_response_time; | |
75 | uint32_t reserved[7]; | |
76 | } QEMU_PACKED CMBE; | |
77 | ||
57065a70 HP |
78 | typedef enum CcwDataStreamOp { |
79 | CDS_OP_R = 0, /* read, false when used as is_write */ | |
80 | CDS_OP_W = 1, /* write, true when used as is_write */ | |
81 | CDS_OP_A = 2 /* advance, should not be used as is_write */ | |
82 | } CcwDataStreamOp; | |
83 | ||
84 | /* normal usage is via SuchchDev.cds instead of instantiating */ | |
85 | typedef struct CcwDataStream { | |
86 | #define CDS_F_IDA 0x01 | |
87 | #define CDS_F_MIDA 0x02 | |
88 | #define CDS_F_I2K 0x04 | |
89 | #define CDS_F_C64 0x08 | |
62a2554e | 90 | #define CDS_F_FMT 0x10 /* CCW format-1 */ |
57065a70 HP |
91 | #define CDS_F_STREAM_BROKEN 0x80 |
92 | uint8_t flags; | |
93 | uint8_t at_idaw; | |
94 | uint16_t at_byte; | |
95 | uint16_t count; | |
96 | uint32_t cda_orig; | |
97 | int (*op_handler)(struct CcwDataStream *cds, void *buff, int len, | |
98 | CcwDataStreamOp op); | |
99 | hwaddr cda; | |
100 | } CcwDataStream; | |
101 | ||
e443ef9f HP |
102 | /* |
103 | * IO instructions conclude according to this. Currently we have only | |
104 | * cc codes. Valid values are 0, 1, 2, 3 and the generic semantic for | |
105 | * IO instructions is described briefly. For more details consult the PoP. | |
106 | */ | |
107 | typedef enum IOInstEnding { | |
108 | /* produced expected result */ | |
109 | IOINST_CC_EXPECTED = 0, | |
110 | /* status conditions were present or produced alternate result */ | |
111 | IOINST_CC_STATUS_PRESENT = 1, | |
112 | /* inst. ineffective because busy with previously initiated function */ | |
113 | IOINST_CC_BUSY = 2, | |
114 | /* inst. ineffective because not operational */ | |
115 | IOINST_CC_NOT_OPERATIONAL = 3 | |
116 | } IOInstEnding; | |
117 | ||
bd3f16ac | 118 | typedef struct SubchDev SubchDev; |
df1fe5bb CH |
119 | struct SubchDev { |
120 | /* channel-subsystem related things: */ | |
cb89b349 TH |
121 | SCHIB curr_status; /* Needs alignment and thus must come first */ |
122 | ORB orb; | |
df1fe5bb CH |
123 | uint8_t cssid; |
124 | uint8_t ssid; | |
125 | uint16_t schid; | |
126 | uint16_t devno; | |
df1fe5bb CH |
127 | uint8_t sense_data[32]; |
128 | hwaddr channel_prog; | |
129 | CCW1 last_cmd; | |
130 | bool last_cmd_valid; | |
a327c921 | 131 | bool ccw_fmt_1; |
7e749462 | 132 | bool thinint_active; |
e8601dd5 | 133 | uint8_t ccw_no_data_cnt; |
517ff12c | 134 | uint16_t migrated_schid; /* used for missmatch detection */ |
57065a70 | 135 | CcwDataStream cds; |
df1fe5bb CH |
136 | /* transport-provided data: */ |
137 | int (*ccw_cb) (SubchDev *, CCW1); | |
62ac4a52 | 138 | void (*disable_cb)(SubchDev *); |
66dc50f7 | 139 | IOInstEnding (*do_subchannel_work) (SubchDev *); |
df1fe5bb CH |
140 | SenseId id; |
141 | void *driver_data; | |
142 | }; | |
143 | ||
66dc50f7 HP |
144 | static inline void sch_gen_unit_exception(SubchDev *sch) |
145 | { | |
146 | sch->curr_status.scsw.ctrl &= ~SCSW_ACTL_START_PEND; | |
147 | sch->curr_status.scsw.ctrl |= SCSW_STCTL_PRIMARY | | |
148 | SCSW_STCTL_SECONDARY | | |
149 | SCSW_STCTL_ALERT | | |
150 | SCSW_STCTL_STATUS_PEND; | |
151 | sch->curr_status.scsw.cpa = sch->channel_prog + 8; | |
152 | sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_EXCEP; | |
153 | } | |
154 | ||
517ff12c HP |
155 | extern const VMStateDescription vmstate_subch_dev; |
156 | ||
8f3cf012 XFR |
157 | /* |
158 | * Identify a device within the channel subsystem. | |
159 | * Note that this can be used to identify either the subchannel or | |
160 | * the attached I/O device, as there's always one I/O device per | |
161 | * subchannel. | |
162 | */ | |
163 | typedef struct CssDevId { | |
164 | uint8_t cssid; | |
165 | uint8_t ssid; | |
166 | uint16_t devid; | |
167 | bool valid; | |
168 | } CssDevId; | |
169 | ||
1b6b7d10 | 170 | extern const PropertyInfo css_devid_propinfo; |
8f3cf012 XFR |
171 | |
172 | #define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \ | |
173 | DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId) | |
174 | ||
a28d8391 YMZ |
175 | typedef struct IndAddr { |
176 | hwaddr addr; | |
177 | uint64_t map; | |
178 | unsigned long refcnt; | |
517ff12c | 179 | int32_t len; |
a28d8391 YMZ |
180 | QTAILQ_ENTRY(IndAddr) sibling; |
181 | } IndAddr; | |
182 | ||
517ff12c HP |
183 | extern const VMStateDescription vmstate_ind_addr; |
184 | ||
185 | #define VMSTATE_PTR_TO_IND_ADDR(_f, _s) \ | |
186 | VMSTATE_STRUCT(_f, _s, 1, vmstate_ind_addr, IndAddr*) | |
187 | ||
a28d8391 YMZ |
188 | IndAddr *get_indicator(hwaddr ind_addr, int len); |
189 | void release_indicator(AdapterInfo *adapter, IndAddr *indicator); | |
190 | int map_indicator(AdapterInfo *adapter, IndAddr *indicator); | |
191 | ||
df1fe5bb CH |
192 | typedef SubchDev *(*css_subch_cb_func)(uint8_t m, uint8_t cssid, uint8_t ssid, |
193 | uint16_t schid); | |
194 | int css_create_css_image(uint8_t cssid, bool default_image); | |
195 | bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno); | |
196 | void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, | |
197 | uint16_t devno, SubchDev *sch); | |
198 | void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type); | |
8f3cf012 | 199 | int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id); |
6c15e9bf | 200 | unsigned int css_find_free_chpid(uint8_t cssid); |
b4436a0b | 201 | uint16_t css_build_subchannel_id(SubchDev *sch); |
8ca2b376 XFR |
202 | void copy_scsw_to_guest(SCSW *dest, const SCSW *src); |
203 | void css_inject_io_interrupt(SubchDev *sch); | |
df1fe5bb CH |
204 | void css_reset(void); |
205 | void css_reset_sch(SubchDev *sch); | |
5c8d6f00 DJS |
206 | void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited, |
207 | int chain, uint16_t rsid); | |
df1fe5bb CH |
208 | void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, |
209 | int hotplugged, int add); | |
210 | void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); | |
8cba80c3 | 211 | void css_generate_css_crws(uint8_t cssid); |
c81b4f89 | 212 | void css_clear_sei_pending(void); |
66dc50f7 HP |
213 | IOInstEnding s390_ccw_cmd_request(SubchDev *sch); |
214 | IOInstEnding do_subchannel_work_virtual(SubchDev *sub); | |
215 | IOInstEnding do_subchannel_work_passthrough(SubchDev *sub); | |
03cf077a | 216 | |
5b00bef2 FL |
217 | typedef enum { |
218 | CSS_IO_ADAPTER_VIRTIO = 0, | |
219 | CSS_IO_ADAPTER_PCI = 1, | |
220 | CSS_IO_ADAPTER_TYPE_NUMS, | |
221 | } CssIoAdapterType; | |
222 | ||
25a08b8d | 223 | void css_adapter_interrupt(CssIoAdapterType type, uint8_t isc); |
2283f4d6 | 224 | int css_do_sic(CPUS390XState *env, uint8_t isc, uint16_t mode); |
dde522bb FL |
225 | uint32_t css_get_adapter_id(CssIoAdapterType type, uint8_t isc); |
226 | void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable, | |
1497c160 FL |
227 | uint8_t flags, Error **errp); |
228 | ||
229 | #ifndef CONFIG_KVM | |
230 | #define S390_ADAPTER_SUPPRESSIBLE 0x01 | |
231 | #else | |
232 | #define S390_ADAPTER_SUPPRESSIBLE KVM_S390_ADAPTER_SUPPRESSIBLE | |
233 | #endif | |
bd3f16ac PB |
234 | |
235 | #ifndef CONFIG_USER_ONLY | |
236 | SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, | |
237 | uint16_t schid); | |
238 | bool css_subch_visible(SubchDev *sch); | |
239 | void css_conditional_io_interrupt(SubchDev *sch); | |
240 | int css_do_stsch(SubchDev *sch, SCHIB *schib); | |
241 | bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid); | |
6bb6f194 | 242 | IOInstEnding css_do_msch(SubchDev *sch, const SCHIB *schib); |
96376408 | 243 | IOInstEnding css_do_xsch(SubchDev *sch); |
77331442 | 244 | IOInstEnding css_do_csch(SubchDev *sch); |
ae9f1be3 | 245 | IOInstEnding css_do_hsch(SubchDev *sch); |
66dc50f7 | 246 | IOInstEnding css_do_ssch(SubchDev *sch, ORB *orb); |
bd3f16ac PB |
247 | int css_do_tsch_get_irb(SubchDev *sch, IRB *irb, int *irb_len); |
248 | void css_do_tsch_update_subch(SubchDev *sch); | |
249 | int css_do_stcrw(CRW *crw); | |
250 | void css_undo_stcrw(CRW *crw); | |
bd3f16ac PB |
251 | int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, |
252 | int rfmt, void *buf); | |
253 | void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo); | |
254 | int css_enable_mcsse(void); | |
255 | int css_enable_mss(void); | |
66dc50f7 | 256 | IOInstEnding css_do_rsch(SubchDev *sch); |
bd3f16ac PB |
257 | int css_do_rchp(uint8_t cssid, uint8_t chpid); |
258 | bool css_present(uint8_t cssid); | |
259 | #endif | |
260 | ||
1b6b7d10 | 261 | extern const PropertyInfo css_devid_ro_propinfo; |
c35fc6aa DJS |
262 | |
263 | #define DEFINE_PROP_CSS_DEV_ID_RO(_n, _s, _f) \ | |
264 | DEFINE_PROP(_n, _s, _f, css_devid_ro_propinfo, CssDevId) | |
265 | ||
cf249935 SS |
266 | /** |
267 | * Create a subchannel for the given bus id. | |
268 | * | |
36699ab4 CH |
269 | * If @p bus_id is valid, verify that it is not already in use, and find a |
270 | * free devno for it. | |
99577c49 HP |
271 | * If @p bus_id is not valid find a free subchannel id and device number |
272 | * across all subchannel sets and all css images starting from the default | |
273 | * css image. | |
817d4a6b DJS |
274 | * |
275 | * If either of the former actions succeed, allocate a subchannel structure, | |
276 | * initialise it with the bus id, subchannel id and device number, register | |
277 | * it with the CSS and return it. Otherwise return NULL. | |
cf249935 SS |
278 | * |
279 | * The caller becomes owner of the returned subchannel structure and | |
280 | * is responsible for unregistering and freeing it. | |
281 | */ | |
36699ab4 | 282 | SubchDev *css_create_sch(CssDevId bus_id, Error **errp); |
e996583e HP |
283 | |
284 | /** Turn on css migration */ | |
285 | void css_register_vmstate(void); | |
286 | ||
57065a70 HP |
287 | |
288 | void ccw_dstream_init(CcwDataStream *cds, CCW1 const *ccw, ORB const *orb); | |
289 | ||
290 | static inline void ccw_dstream_rewind(CcwDataStream *cds) | |
291 | { | |
292 | cds->at_byte = 0; | |
293 | cds->at_idaw = 0; | |
294 | cds->cda = cds->cda_orig; | |
295 | } | |
296 | ||
297 | static inline bool ccw_dstream_good(CcwDataStream *cds) | |
298 | { | |
299 | return !(cds->flags & CDS_F_STREAM_BROKEN); | |
300 | } | |
301 | ||
302 | static inline uint16_t ccw_dstream_residual_count(CcwDataStream *cds) | |
303 | { | |
304 | return cds->count - cds->at_byte; | |
305 | } | |
306 | ||
307 | static inline uint16_t ccw_dstream_avail(CcwDataStream *cds) | |
308 | { | |
309 | return ccw_dstream_good(cds) ? ccw_dstream_residual_count(cds) : 0; | |
310 | } | |
311 | ||
312 | static inline int ccw_dstream_advance(CcwDataStream *cds, int len) | |
313 | { | |
314 | return cds->op_handler(cds, NULL, len, CDS_OP_A); | |
315 | } | |
316 | ||
317 | static inline int ccw_dstream_write_buf(CcwDataStream *cds, void *buff, int len) | |
318 | { | |
319 | return cds->op_handler(cds, buff, len, CDS_OP_W); | |
320 | } | |
321 | ||
322 | static inline int ccw_dstream_read_buf(CcwDataStream *cds, void *buff, int len) | |
323 | { | |
324 | return cds->op_handler(cds, buff, len, CDS_OP_R); | |
325 | } | |
326 | ||
327 | #define ccw_dstream_read(cds, v) ccw_dstream_read_buf((cds), &(v), sizeof(v)) | |
328 | #define ccw_dstream_write(cds, v) ccw_dstream_write_buf((cds), &(v), sizeof(v)) | |
329 | ||
df1fe5bb | 330 | #endif |