]>
Commit | Line | Data |
---|---|---|
1e17c2c1 AG |
1 | /* |
2 | * Channel IO definitions | |
3 | * | |
4 | * Copyright (c) 2013 Alexander Graf <agraf@suse.de> | |
5 | * | |
6 | * Inspired by various s390 headers in Linux 3.9. | |
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 | ||
13 | #ifndef CIO_H | |
14 | #define CIO_H | |
15 | ||
16 | /* | |
17 | * path management control word | |
18 | */ | |
19 | struct pmcw { | |
d96c5db7 JH |
20 | __u32 intparm; /* interruption parameter */ |
21 | __u32 qf:1; /* qdio facility */ | |
22 | __u32 w:1; | |
23 | __u32 isc:3; /* interruption sublass */ | |
24 | __u32 res5:3; /* reserved zeros */ | |
25 | __u32 ena:1; /* enabled */ | |
26 | __u32 lm:2; /* limit mode */ | |
27 | __u32 mme:2; /* measurement-mode enable */ | |
28 | __u32 mp:1; /* multipath mode */ | |
29 | __u32 tf:1; /* timing facility */ | |
30 | __u32 dnv:1; /* device number valid */ | |
31 | __u32 dev:16; /* device number */ | |
32 | __u8 lpm; /* logical path mask */ | |
33 | __u8 pnom; /* path not operational mask */ | |
34 | __u8 lpum; /* last path used mask */ | |
35 | __u8 pim; /* path installed mask */ | |
36 | __u16 mbi; /* measurement-block index */ | |
37 | __u8 pom; /* path operational mask */ | |
38 | __u8 pam; /* path available mask */ | |
39 | __u8 chpid[8]; /* CHPID 0-7 (if available) */ | |
40 | __u32 unused1:8; /* reserved zeros */ | |
41 | __u32 st:3; /* subchannel type */ | |
42 | __u32 unused2:18; /* reserved zeros */ | |
43 | __u32 mbfc:1; /* measurement block format control */ | |
44 | __u32 xmwme:1; /* extended measurement word mode enable */ | |
45 | __u32 csense:1; /* concurrent sense; can be enabled ...*/ | |
46 | /* ... per MSCH, however, if facility */ | |
47 | /* ... is not installed, this results */ | |
48 | /* ... in an operand exception. */ | |
1e17c2c1 AG |
49 | } __attribute__ ((packed)); |
50 | ||
51 | /* Target SCHIB configuration. */ | |
52 | struct schib_config { | |
53 | __u64 mba; | |
54 | __u32 intparm; | |
55 | __u16 mbi; | |
56 | __u32 isc:3; | |
57 | __u32 ena:1; | |
58 | __u32 mme:2; | |
59 | __u32 mp:1; | |
60 | __u32 csense:1; | |
61 | __u32 mbfc:1; | |
62 | } __attribute__ ((packed)); | |
63 | ||
64 | struct scsw { | |
65 | __u16 flags; | |
66 | __u16 ctrl; | |
67 | __u32 cpa; | |
68 | __u8 dstat; | |
69 | __u8 cstat; | |
70 | __u16 count; | |
71 | } __attribute__ ((packed)); | |
72 | ||
3083a1bb | 73 | /* Function Control */ |
1e17c2c1 | 74 | #define SCSW_FCTL_START_FUNC 0x4000 |
3083a1bb JH |
75 | #define SCSW_FCTL_HALT_FUNC 0x2000 |
76 | #define SCSW_FCTL_CLEAR_FUNC 0x1000 | |
77 | ||
78 | /* Activity Control */ | |
79 | #define SCSW_ACTL_RESUME_PEND 0x0800 | |
80 | #define SCSW_ACTL_START_PEND 0x0400 | |
81 | #define SCSW_ACTL_HALT_PEND 0x0200 | |
82 | #define SCSW_ACTL_CLEAR_PEND 0x0100 | |
83 | #define SCSW_ACTL_CH_ACTIVE 0x0080 | |
84 | #define SCSW_ACTL_DEV_ACTIVE 0x0040 | |
85 | #define SCSW_ACTL_SUSPENDED 0x0020 | |
86 | ||
87 | /* Status Control */ | |
88 | #define SCSW_SCTL_ALERT 0x0010 | |
89 | #define SCSW_SCTL_INTERMED 0x0008 | |
90 | #define SCSW_SCTL_PRIMARY 0x0004 | |
91 | #define SCSW_SCTL_SECONDARY 0x0002 | |
92 | #define SCSW_SCTL_STATUS_PEND 0x0001 | |
93 | ||
94 | /* SCSW Device Status Flags */ | |
95 | #define SCSW_DSTAT_ATTN 0x80 | |
96 | #define SCSW_DSTAT_STATMOD 0x40 | |
97 | #define SCSW_DSTAT_CUEND 0x20 | |
98 | #define SCSW_DSTAT_BUSY 0x10 | |
99 | #define SCSW_DSTAT_CHEND 0x08 | |
100 | #define SCSW_DSTAT_DEVEND 0x04 | |
101 | #define SCSW_DSTAT_UCHK 0x02 | |
102 | #define SCSW_DSTAT_UEXCP 0x01 | |
103 | ||
104 | /* SCSW Subchannel Status Flags */ | |
105 | #define SCSW_CSTAT_PCINT 0x80 | |
106 | #define SCSW_CSTAT_BADLEN 0x40 | |
107 | #define SCSW_CSTAT_PROGCHK 0x20 | |
108 | #define SCSW_CSTAT_PROTCHK 0x10 | |
109 | #define SCSW_CSTAT_CHDCHK 0x08 | |
110 | #define SCSW_CSTAT_CHCCHK 0x04 | |
111 | #define SCSW_CSTAT_ICCHK 0x02 | |
112 | #define SCSW_CSTAT_CHAINCHK 0x01 | |
1e17c2c1 AG |
113 | |
114 | /* | |
115 | * subchannel information block | |
116 | */ | |
d96c5db7 | 117 | typedef struct schib { |
1e17c2c1 AG |
118 | struct pmcw pmcw; /* path management control word */ |
119 | struct scsw scsw; /* subchannel status word */ | |
120 | __u64 mba; /* measurement block address */ | |
121 | __u8 mda[4]; /* model dependent area */ | |
d96c5db7 JH |
122 | } __attribute__ ((packed, aligned(4))) Schib; |
123 | ||
124 | typedef struct subchannel_id { | |
e6d393d0 JF |
125 | union { |
126 | struct { | |
127 | __u16 cssid:8; | |
128 | __u16 reserved:4; | |
129 | __u16 m:1; | |
130 | __u16 ssid:2; | |
131 | __u16 one:1; | |
132 | }; | |
133 | __u16 sch_id; | |
134 | }; | |
135 | __u16 sch_no; | |
d96c5db7 | 136 | } __attribute__ ((packed, aligned(4))) SubChannelId; |
1e17c2c1 | 137 | |
c8cda874 DD |
138 | struct chsc_header { |
139 | __u16 length; | |
140 | __u16 code; | |
141 | } __attribute__((packed)); | |
142 | ||
d96c5db7 | 143 | typedef struct chsc_area_sda { |
c8cda874 DD |
144 | struct chsc_header request; |
145 | __u8 reserved1:4; | |
146 | __u8 format:4; | |
147 | __u8 reserved2; | |
148 | __u16 operation_code; | |
149 | __u32 reserved3; | |
150 | __u32 reserved4; | |
151 | __u32 operation_data_area[252]; | |
152 | struct chsc_header response; | |
153 | __u32 reserved5:4; | |
154 | __u32 format2:4; | |
155 | __u32 reserved6:24; | |
d96c5db7 | 156 | } __attribute__((packed)) ChscAreaSda; |
c8cda874 | 157 | |
1e17c2c1 AG |
158 | /* |
159 | * TPI info structure | |
160 | */ | |
161 | struct tpi_info { | |
162 | struct subchannel_id schid; | |
d96c5db7 JH |
163 | __u32 intparm; /* interruption parameter */ |
164 | __u32 adapter_IO:1; | |
165 | __u32 reserved2:1; | |
166 | __u32 isc:3; | |
167 | __u32 reserved3:12; | |
168 | __u32 int_type:3; | |
169 | __u32 reserved4:12; | |
a6e4385d | 170 | } __attribute__ ((packed, aligned(4))); |
1e17c2c1 | 171 | |
3083a1bb JH |
172 | /* channel command word (format 0) */ |
173 | typedef struct ccw0 { | |
174 | __u8 cmd_code; | |
175 | __u32 cda:24; | |
176 | __u32 chainData:1; | |
177 | __u32 chain:1; | |
178 | __u32 sli:1; | |
179 | __u32 skip:1; | |
180 | __u32 pci:1; | |
181 | __u32 ida:1; | |
182 | __u32 suspend:1; | |
183 | __u32 mida:1; | |
184 | __u8 reserved; | |
185 | __u16 count; | |
186 | } __attribute__ ((packed, aligned(8))) Ccw0; | |
187 | ||
188 | /* channel command word (format 1) */ | |
d96c5db7 | 189 | typedef struct ccw1 { |
1e17c2c1 AG |
190 | __u8 cmd_code; |
191 | __u8 flags; | |
192 | __u16 count; | |
193 | __u32 cda; | |
d96c5db7 | 194 | } __attribute__ ((packed, aligned(8))) Ccw1; |
1e17c2c1 | 195 | |
3083a1bb JH |
196 | /* do_cio() CCW formats */ |
197 | #define CCW_FMT0 0x00 | |
198 | #define CCW_FMT1 0x01 | |
199 | ||
1e17c2c1 AG |
200 | #define CCW_FLAG_DC 0x80 |
201 | #define CCW_FLAG_CC 0x40 | |
202 | #define CCW_FLAG_SLI 0x20 | |
203 | #define CCW_FLAG_SKIP 0x10 | |
204 | #define CCW_FLAG_PCI 0x08 | |
205 | #define CCW_FLAG_IDA 0x04 | |
206 | #define CCW_FLAG_SUSPEND 0x02 | |
207 | ||
69333c36 JH |
208 | /* Common CCW commands */ |
209 | #define CCW_CMD_READ_IPL 0x02 | |
1e17c2c1 AG |
210 | #define CCW_CMD_NOOP 0x03 |
211 | #define CCW_CMD_BASIC_SENSE 0x04 | |
212 | #define CCW_CMD_TIC 0x08 | |
213 | #define CCW_CMD_SENSE_ID 0xe4 | |
214 | ||
69333c36 | 215 | /* Virtio CCW commands */ |
1e17c2c1 AG |
216 | #define CCW_CMD_SET_VQ 0x13 |
217 | #define CCW_CMD_VDEV_RESET 0x33 | |
218 | #define CCW_CMD_READ_FEAT 0x12 | |
219 | #define CCW_CMD_WRITE_FEAT 0x11 | |
220 | #define CCW_CMD_READ_CONF 0x22 | |
221 | #define CCW_CMD_WRITE_CONF 0x21 | |
222 | #define CCW_CMD_WRITE_STATUS 0x31 | |
223 | #define CCW_CMD_SET_IND 0x43 | |
224 | #define CCW_CMD_SET_CONF_IND 0x53 | |
225 | #define CCW_CMD_READ_VQ_CONF 0x32 | |
226 | ||
69333c36 JH |
227 | /* DASD CCW commands */ |
228 | #define CCW_CMD_DASD_READ 0x06 | |
229 | #define CCW_CMD_DASD_SEEK 0x07 | |
230 | #define CCW_CMD_DASD_SEARCH_ID_EQ 0x31 | |
231 | #define CCW_CMD_DASD_READ_MT 0x86 | |
232 | ||
1e17c2c1 AG |
233 | /* |
234 | * Command-mode operation request block | |
235 | */ | |
d96c5db7 | 236 | typedef struct cmd_orb { |
1e17c2c1 AG |
237 | __u32 intparm; /* interruption parameter */ |
238 | __u32 key:4; /* flags, like key, suspend control, etc. */ | |
239 | __u32 spnd:1; /* suspend control */ | |
240 | __u32 res1:1; /* reserved */ | |
241 | __u32 mod:1; /* modification control */ | |
242 | __u32 sync:1; /* synchronize control */ | |
243 | __u32 fmt:1; /* format control */ | |
244 | __u32 pfch:1; /* prefetch control */ | |
245 | __u32 isic:1; /* initial-status-interruption control */ | |
246 | __u32 alcc:1; /* address-limit-checking control */ | |
247 | __u32 ssic:1; /* suppress-suspended-interr. control */ | |
248 | __u32 res2:1; /* reserved */ | |
249 | __u32 c64:1; /* IDAW/QDIO 64 bit control */ | |
250 | __u32 i2k:1; /* IDAW 2/4kB block size control */ | |
251 | __u32 lpm:8; /* logical path mask */ | |
252 | __u32 ils:1; /* incorrect length */ | |
253 | __u32 zero:6; /* reserved zeros */ | |
254 | __u32 orbx:1; /* ORB extension control */ | |
255 | __u32 cpa; /* channel program address */ | |
d96c5db7 | 256 | } __attribute__ ((packed, aligned(4))) CmdOrb; |
1e17c2c1 AG |
257 | |
258 | struct ciw { | |
259 | __u8 type; | |
260 | __u8 command; | |
261 | __u16 count; | |
262 | }; | |
263 | ||
3083a1bb JH |
264 | #define CU_TYPE_UNKNOWN 0x0000 |
265 | #define CU_TYPE_DASD_2107 0x2107 | |
266 | #define CU_TYPE_VIRTIO 0x3832 | |
267 | #define CU_TYPE_DASD_3990 0x3990 | |
268 | ||
1e17c2c1 AG |
269 | /* |
270 | * sense-id response buffer layout | |
271 | */ | |
d96c5db7 | 272 | typedef struct senseid { |
1e17c2c1 AG |
273 | /* common part */ |
274 | __u8 reserved; /* always 0x'FF' */ | |
275 | __u16 cu_type; /* control unit type */ | |
276 | __u8 cu_model; /* control unit model */ | |
277 | __u16 dev_type; /* device type */ | |
278 | __u8 dev_model; /* device model */ | |
279 | __u8 unused; /* padding byte */ | |
280 | /* extended part */ | |
281 | struct ciw ciw[62]; | |
d96c5db7 | 282 | } __attribute__ ((packed, aligned(4))) SenseId; |
1e17c2c1 | 283 | |
3083a1bb JH |
284 | /* |
285 | * architected values for first sense byte - common_status. Bits 0-5 of this | |
286 | * field are common to all device types. | |
287 | */ | |
288 | #define SNS_STAT0_CMD_REJECT 0x80 | |
289 | #define SNS_STAT0_INTERVENTION_REQ 0x40 | |
290 | #define SNS_STAT0_BUS_OUT_CHECK 0x20 | |
291 | #define SNS_STAT0_EQUIPMENT_CHECK 0x10 | |
292 | #define SNS_STAT0_DATA_CHECK 0x08 | |
293 | #define SNS_STAT0_OVERRUN 0x04 | |
294 | #define SNS_STAT0_INCOMPL_DOMAIN 0x01 | |
295 | ||
296 | /* ECKD DASD status[0] byte */ | |
297 | #define SNS_STAT1_PERM_ERR 0x80 | |
298 | #define SNS_STAT1_INV_TRACK_FORMAT 0x40 | |
299 | #define SNS_STAT1_EOC 0x20 | |
300 | #define SNS_STAT1_MESSAGE_TO_OPER 0x10 | |
301 | #define SNS_STAT1_NO_REC_FOUND 0x08 | |
302 | #define SNS_STAT1_FILE_PROTECTED 0x04 | |
303 | #define SNS_STAT1_WRITE_INHIBITED 0x02 | |
304 | #define SNS_STAT1_IMPRECISE_END 0x01 | |
305 | ||
306 | /* ECKD DASD status[1] byte */ | |
307 | #define SNS_STAT2_REQ_INH_WRITE 0x80 | |
308 | #define SNS_STAT2_CORRECTABLE 0x40 | |
309 | #define SNS_STAT2_FIRST_LOG_ERR 0x20 | |
310 | #define SNS_STAT2_ENV_DATA_PRESENT 0x10 | |
311 | #define SNS_STAT2_IMPRECISE_END 0x04 | |
312 | ||
313 | /* ECKD DASD 24-byte Sense fmt_msg codes */ | |
314 | #define SENSE24_FMT_PROG_SYS 0x0 | |
315 | #define SENSE24_FMT_EQUIPMENT 0x2 | |
316 | #define SENSE24_FMT_CONTROLLER 0x3 | |
317 | #define SENSE24_FMT_MISC 0xF | |
318 | ||
319 | /* basic sense response buffer layout */ | |
320 | typedef struct SenseDataEckdDasd { | |
321 | uint8_t common_status; | |
322 | uint8_t status[2]; | |
323 | uint8_t res_count; | |
324 | uint8_t phys_drive_id; | |
325 | uint8_t low_cyl_addr; | |
326 | uint8_t head_high_cyl_addr; | |
327 | uint8_t fmt_msg; | |
328 | uint64_t fmt_dependent_info[2]; | |
329 | uint8_t reserved; | |
330 | uint8_t program_action_code; | |
331 | uint16_t config_info; | |
332 | uint8_t mcode_hicyl; | |
333 | uint8_t cyl_head_addr[3]; | |
334 | } __attribute__ ((packed, aligned(4))) SenseDataEckdDasd; | |
335 | ||
336 | #define ECKD_SENSE24_GET_FMT(sd) (sd->fmt_msg & 0xF0 >> 4) | |
337 | #define ECKD_SENSE24_GET_MSG(sd) (sd->fmt_msg & 0x0F) | |
338 | ||
339 | #define unit_check(irb) ((irb)->scsw.dstat & SCSW_DSTAT_UCHK) | |
340 | #define iface_ctrl_check(irb) ((irb)->scsw.cstat & SCSW_CSTAT_ICCHK) | |
341 | ||
1e17c2c1 | 342 | /* interruption response block */ |
d96c5db7 | 343 | typedef struct irb { |
1e17c2c1 AG |
344 | struct scsw scsw; |
345 | __u32 esw[5]; | |
346 | __u32 ecw[8]; | |
347 | __u32 emw[8]; | |
d96c5db7 | 348 | } __attribute__ ((packed, aligned(4))) Irb; |
1e17c2c1 | 349 | |
69333c36 JH |
350 | /* Used for SEEK ccw commands */ |
351 | typedef struct CcwSeekData { | |
352 | uint16_t reserved; | |
353 | uint16_t cyl; | |
354 | uint16_t head; | |
355 | } __attribute__((packed)) CcwSeekData; | |
356 | ||
357 | /* Used for SEARCH ID ccw commands */ | |
358 | typedef struct CcwSearchIdData { | |
359 | uint16_t cyl; | |
360 | uint16_t head; | |
361 | uint8_t record; | |
362 | } __attribute__((packed)) CcwSearchIdData; | |
363 | ||
120d0410 JH |
364 | int enable_mss_facility(void); |
365 | void enable_subchannel(SubChannelId schid); | |
3083a1bb JH |
366 | uint16_t cu_type(SubChannelId schid); |
367 | int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data, | |
368 | uint16_t data_size); | |
369 | int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt); | |
120d0410 | 370 | |
1e17c2c1 AG |
371 | /* |
372 | * Some S390 specific IO instructions as inline | |
373 | */ | |
374 | ||
375 | static inline int stsch_err(struct subchannel_id schid, struct schib *addr) | |
376 | { | |
377 | register struct subchannel_id reg1 asm ("1") = schid; | |
378 | int ccode = -EIO; | |
379 | ||
380 | asm volatile( | |
381 | " stsch 0(%3)\n" | |
382 | "0: ipm %0\n" | |
383 | " srl %0,28\n" | |
384 | "1:\n" | |
385 | : "+d" (ccode), "=m" (*addr) | |
386 | : "d" (reg1), "a" (addr) | |
387 | : "cc"); | |
388 | return ccode; | |
389 | } | |
390 | ||
391 | static inline int msch(struct subchannel_id schid, struct schib *addr) | |
392 | { | |
393 | register struct subchannel_id reg1 asm ("1") = schid; | |
394 | int ccode; | |
395 | ||
396 | asm volatile( | |
397 | " msch 0(%2)\n" | |
398 | " ipm %0\n" | |
399 | " srl %0,28" | |
400 | : "=d" (ccode) | |
401 | : "d" (reg1), "a" (addr), "m" (*addr) | |
402 | : "cc"); | |
403 | return ccode; | |
404 | } | |
405 | ||
406 | static inline int msch_err(struct subchannel_id schid, struct schib *addr) | |
407 | { | |
408 | register struct subchannel_id reg1 asm ("1") = schid; | |
409 | int ccode = -EIO; | |
410 | ||
411 | asm volatile( | |
412 | " msch 0(%2)\n" | |
413 | "0: ipm %0\n" | |
414 | " srl %0,28\n" | |
415 | "1:\n" | |
416 | : "+d" (ccode) | |
417 | : "d" (reg1), "a" (addr), "m" (*addr) | |
418 | : "cc"); | |
419 | return ccode; | |
420 | } | |
421 | ||
422 | static inline int tsch(struct subchannel_id schid, struct irb *addr) | |
423 | { | |
424 | register struct subchannel_id reg1 asm ("1") = schid; | |
425 | int ccode; | |
426 | ||
427 | asm volatile( | |
428 | " tsch 0(%3)\n" | |
429 | " ipm %0\n" | |
430 | " srl %0,28" | |
431 | : "=d" (ccode), "=m" (*addr) | |
432 | : "d" (reg1), "a" (addr) | |
433 | : "cc"); | |
434 | return ccode; | |
435 | } | |
436 | ||
437 | static inline int ssch(struct subchannel_id schid, struct cmd_orb *addr) | |
438 | { | |
439 | register struct subchannel_id reg1 asm("1") = schid; | |
440 | int ccode = -EIO; | |
441 | ||
442 | asm volatile( | |
443 | " ssch 0(%2)\n" | |
444 | "0: ipm %0\n" | |
445 | " srl %0,28\n" | |
446 | "1:\n" | |
447 | : "+d" (ccode) | |
448 | : "d" (reg1), "a" (addr), "m" (*addr) | |
449 | : "cc", "memory"); | |
450 | return ccode; | |
451 | } | |
452 | ||
453 | static inline int csch(struct subchannel_id schid) | |
454 | { | |
455 | register struct subchannel_id reg1 asm("1") = schid; | |
456 | int ccode; | |
457 | ||
458 | asm volatile( | |
459 | " csch\n" | |
460 | " ipm %0\n" | |
461 | " srl %0,28" | |
462 | : "=d" (ccode) | |
463 | : "d" (reg1) | |
464 | : "cc"); | |
465 | return ccode; | |
466 | } | |
467 | ||
468 | static inline int tpi(struct tpi_info *addr) | |
469 | { | |
470 | int ccode; | |
471 | ||
472 | asm volatile( | |
473 | " tpi 0(%2)\n" | |
474 | " ipm %0\n" | |
475 | " srl %0,28" | |
476 | : "=d" (ccode), "=m" (*addr) | |
477 | : "a" (addr) | |
478 | : "cc"); | |
479 | return ccode; | |
480 | } | |
481 | ||
482 | static inline int chsc(void *chsc_area) | |
483 | { | |
484 | typedef struct { char _[4096]; } addr_type; | |
485 | int cc; | |
486 | ||
487 | asm volatile( | |
488 | " .insn rre,0xb25f0000,%2,0\n" | |
489 | " ipm %0\n" | |
490 | " srl %0,28\n" | |
491 | : "=d" (cc), "=m" (*(addr_type *) chsc_area) | |
492 | : "d" (chsc_area), "m" (*(addr_type *) chsc_area) | |
493 | : "cc"); | |
494 | return cc; | |
495 | } | |
496 | ||
497 | #endif /* CIO_H */ |