1 /*
2 * S390 Channel I/O
3 *
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5 * Copyright (c) 2019 IBM Corp.
6 *
7 * Author(s): Jason J. Herne <jjherne@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or (at
10 * your option) any later version. See the COPYING file in the top-level
11 * directory.
12 */
13
14 #include <string.h>
15 #include <stdio.h>
16 #include "s390-ccw.h"
17 #include "s390-arch.h"
18 #include "helper.h"
19 #include "cio.h"
20
21 static char chsc_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
22
23 static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb);
24
enable_mss_facility(void)25 int enable_mss_facility(void)
26 {
27 int ret;
28 ChscAreaSda *sda_area = (ChscAreaSda *) chsc_page;
29
30 memset(sda_area, 0, PAGE_SIZE);
31 sda_area->request.length = 0x0400;
32 sda_area->request.code = 0x0031;
33 sda_area->operation_code = 0x2;
34
35 ret = chsc(sda_area);
36 if ((ret == 0) && (sda_area->response.code == 0x0001)) {
37 return 0;
38 }
39 return -EIO;
40 }
41
enable_subchannel(SubChannelId schid)42 void enable_subchannel(SubChannelId schid)
43 {
44 Schib schib;
45
46 stsch_err(schid, &schib);
47 schib.pmcw.ena = 1;
48 msch(schid, &schib);
49 }
50
cu_type(SubChannelId schid)51 uint16_t cu_type(SubChannelId schid)
52 {
53 SenseId sense_data;
54 Ccw1 sense_id_ccw = {
55 .cmd_code = CCW_CMD_SENSE_ID,
56 .flags = CCW_FLAG_SLI,
57 .count = sizeof(sense_data),
58 .cda = ptr2u32(&sense_data),
59 };
60
61 if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
62 puts("Failed to run SenseID CCW");
63 return CU_TYPE_UNKNOWN;
64 }
65
66 return sense_data.cu_type;
67 }
68
basic_sense(SubChannelId schid,uint16_t cutype,void * sense_data,uint16_t data_size)69 int basic_sense(SubChannelId schid, uint16_t cutype, void *sense_data,
70 uint16_t data_size)
71 {
72 Ccw1 senseCcw = {
73 .cmd_code = CCW_CMD_BASIC_SENSE,
74 .count = data_size,
75 .cda = ptr2u32(sense_data),
76 };
77 Irb irb;
78
79 return __do_cio(schid, ptr2u32(&senseCcw), CCW_FMT1, &irb);
80 }
81
irb_error(Irb * irb)82 static bool irb_error(Irb *irb)
83 {
84 if (irb->scsw.cstat) {
85 return true;
86 }
87 return irb->scsw.dstat != (SCSW_DSTAT_DEVEND | SCSW_DSTAT_CHEND);
88 }
89
print_eckd_dasd_sense_data(SenseDataEckdDasd * sd)90 static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
91 {
92 char msgline[512];
93
94 if (sd->config_info & 0x8000) {
95 puts("Eckd Dasd Sense Data (fmt 24-bytes):");
96 } else {
97 puts("Eckd Dasd Sense Data (fmt 32-bytes):");
98 }
99
100 strcat(msgline, " Sense Condition Flags :");
101 if (sd->common_status & SNS_STAT0_CMD_REJECT) {
102 strcat(msgline, " [Cmd-Reject]");
103 }
104 if (sd->common_status & SNS_STAT0_INTERVENTION_REQ) {
105 strcat(msgline, " [Intervention-Required]");
106 }
107 if (sd->common_status & SNS_STAT0_BUS_OUT_CHECK) {
108 strcat(msgline, " [Bus-Out-Parity-Check]");
109 }
110 if (sd->common_status & SNS_STAT0_EQUIPMENT_CHECK) {
111 strcat(msgline, " [Equipment-Check]");
112 }
113 if (sd->common_status & SNS_STAT0_DATA_CHECK) {
114 strcat(msgline, " [Data-Check]");
115 }
116 if (sd->common_status & SNS_STAT0_OVERRUN) {
117 strcat(msgline, " [Overrun]");
118 }
119 if (sd->common_status & SNS_STAT0_INCOMPL_DOMAIN) {
120 strcat(msgline, " [Incomplete-Domain]");
121 }
122
123 if (sd->status[0] & SNS_STAT1_PERM_ERR) {
124 strcat(msgline, " [Permanent-Error]");
125 }
126 if (sd->status[0] & SNS_STAT1_INV_TRACK_FORMAT) {
127 strcat(msgline, " [Invalid-Track-Fmt]");
128 }
129 if (sd->status[0] & SNS_STAT1_EOC) {
130 strcat(msgline, " [End-of-Cyl]");
131 }
132 if (sd->status[0] & SNS_STAT1_MESSAGE_TO_OPER) {
133 strcat(msgline, " [Operator-Msg]");
134 }
135 if (sd->status[0] & SNS_STAT1_NO_REC_FOUND) {
136 strcat(msgline, " [No-Record-Found]");
137 }
138 if (sd->status[0] & SNS_STAT1_FILE_PROTECTED) {
139 strcat(msgline, " [File-Protected]");
140 }
141 if (sd->status[0] & SNS_STAT1_WRITE_INHIBITED) {
142 strcat(msgline, " [Write-Inhibited]");
143 }
144 if (sd->status[0] & SNS_STAT1_IMPRECISE_END) {
145 strcat(msgline, " [Imprecise-Ending]");
146 }
147
148 if (sd->status[1] & SNS_STAT2_REQ_INH_WRITE) {
149 strcat(msgline, " [Req-Inhibit-Write]");
150 }
151 if (sd->status[1] & SNS_STAT2_CORRECTABLE) {
152 strcat(msgline, " [Correctable-Data-Check]");
153 }
154 if (sd->status[1] & SNS_STAT2_FIRST_LOG_ERR) {
155 strcat(msgline, " [First-Error-Log]");
156 }
157 if (sd->status[1] & SNS_STAT2_ENV_DATA_PRESENT) {
158 strcat(msgline, " [Env-Data-Present]");
159 }
160 if (sd->status[1] & SNS_STAT2_IMPRECISE_END) {
161 strcat(msgline, " [Imprecise-End]");
162 }
163 puts(msgline);
164
165 printf(" Residual Count = 0x%X\n", sd->res_count);
166 printf(" Phys Drive ID = 0x%X\n", sd->phys_drive_id);
167 printf(" low cyl address = 0x%X\n", sd->low_cyl_addr);
168 printf(" head addr & hi cyl = 0x%X\n", sd->head_high_cyl_addr);
169 printf(" format/message = 0x%X\n", sd->fmt_msg);
170 printf(" fmt-dependent[0-7] = 0x%llX\n", sd->fmt_dependent_info[0]);
171 printf(" fmt-dependent[8-15]= 0x%llX\n", sd->fmt_dependent_info[1]);
172 printf(" prog action code = 0x%X\n", sd->program_action_code);
173 printf(" Configuration info = 0x%X\n", sd->config_info);
174 printf(" mcode / hi-cyl = 0x%X\n", sd->mcode_hicyl);
175 printf(" cyl & head addr [0]= 0x%X\n", sd->cyl_head_addr[0]);
176 printf(" cyl & head addr [1]= 0x%X\n", sd->cyl_head_addr[1]);
177 printf(" cyl & head addr [2]= 0x%X\n", sd->cyl_head_addr[2]);
178 }
179
print_irb_err(Irb * irb)180 static void print_irb_err(Irb *irb)
181 {
182 uint64_t this_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa);
183 uint64_t prev_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa - 8);
184 char msgline[256];
185
186 puts("Interrupt Response Block Data:");
187
188 strcat(msgline, " Function Ctrl :");
189 if (irb->scsw.ctrl & SCSW_FCTL_START_FUNC) {
190 strcat(msgline, " [Start]");
191 }
192 if (irb->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
193 strcat(msgline, " [Halt]");
194 }
195 if (irb->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
196 strcat(msgline, " [Clear]");
197 }
198 puts(msgline);
199
200 msgline[0] = '\0';
201 strcat(msgline, " Activity Ctrl :");
202 if (irb->scsw.ctrl & SCSW_ACTL_RESUME_PEND) {
203 strcat(msgline, " [Resume-Pending]");
204 }
205 if (irb->scsw.ctrl & SCSW_ACTL_START_PEND) {
206 strcat(msgline, " [Start-Pending]");
207 }
208 if (irb->scsw.ctrl & SCSW_ACTL_HALT_PEND) {
209 strcat(msgline, " [Halt-Pending]");
210 }
211 if (irb->scsw.ctrl & SCSW_ACTL_CLEAR_PEND) {
212 strcat(msgline, " [Clear-Pending]");
213 }
214 if (irb->scsw.ctrl & SCSW_ACTL_CH_ACTIVE) {
215 strcat(msgline, " [Channel-Active]");
216 }
217 if (irb->scsw.ctrl & SCSW_ACTL_DEV_ACTIVE) {
218 strcat(msgline, " [Device-Active]");
219 }
220 if (irb->scsw.ctrl & SCSW_ACTL_SUSPENDED) {
221 strcat(msgline, " [Suspended]");
222 }
223 puts(msgline);
224
225 msgline[0] = '\0';
226 strcat(msgline, " Status Ctrl :");
227 if (irb->scsw.ctrl & SCSW_SCTL_ALERT) {
228 strcat(msgline, " [Alert]");
229 }
230 if (irb->scsw.ctrl & SCSW_SCTL_INTERMED) {
231 strcat(msgline, " [Intermediate]");
232 }
233 if (irb->scsw.ctrl & SCSW_SCTL_PRIMARY) {
234 strcat(msgline, " [Primary]");
235 }
236 if (irb->scsw.ctrl & SCSW_SCTL_SECONDARY) {
237 strcat(msgline, " [Secondary]");
238 }
239 if (irb->scsw.ctrl & SCSW_SCTL_STATUS_PEND) {
240 strcat(msgline, " [Status-Pending]");
241 }
242 puts(msgline);
243
244 msgline[0] = '\0';
245 strcat(msgline, " Device Status :");
246 if (irb->scsw.dstat & SCSW_DSTAT_ATTN) {
247 strcat(msgline, " [Attention]");
248 }
249 if (irb->scsw.dstat & SCSW_DSTAT_STATMOD) {
250 strcat(msgline, " [Status-Modifier]");
251 }
252 if (irb->scsw.dstat & SCSW_DSTAT_CUEND) {
253 strcat(msgline, " [Ctrl-Unit-End]");
254 }
255 if (irb->scsw.dstat & SCSW_DSTAT_BUSY) {
256 strcat(msgline, " [Busy]");
257 }
258 if (irb->scsw.dstat & SCSW_DSTAT_CHEND) {
259 strcat(msgline, " [Channel-End]");
260 }
261 if (irb->scsw.dstat & SCSW_DSTAT_DEVEND) {
262 strcat(msgline, " [Device-End]");
263 }
264 if (irb->scsw.dstat & SCSW_DSTAT_UCHK) {
265 strcat(msgline, " [Unit-Check]");
266 }
267 if (irb->scsw.dstat & SCSW_DSTAT_UEXCP) {
268 strcat(msgline, " [Unit-Exception]");
269 }
270 puts(msgline);
271
272 msgline[0] = '\0';
273 strcat(msgline, " Channel Status :");
274 if (irb->scsw.cstat & SCSW_CSTAT_PCINT) {
275 strcat(msgline, " [Program-Ctrl-Interruption]");
276 }
277 if (irb->scsw.cstat & SCSW_CSTAT_BADLEN) {
278 strcat(msgline, " [Incorrect-Length]");
279 }
280 if (irb->scsw.cstat & SCSW_CSTAT_PROGCHK) {
281 strcat(msgline, " [Program-Check]");
282 }
283 if (irb->scsw.cstat & SCSW_CSTAT_PROTCHK) {
284 strcat(msgline, " [Protection-Check]");
285 }
286 if (irb->scsw.cstat & SCSW_CSTAT_CHDCHK) {
287 strcat(msgline, " [Channel-Data-Check]");
288 }
289 if (irb->scsw.cstat & SCSW_CSTAT_CHCCHK) {
290 strcat(msgline, " [Channel-Ctrl-Check]");
291 }
292 if (irb->scsw.cstat & SCSW_CSTAT_ICCHK) {
293 strcat(msgline, " [Interface-Ctrl-Check]");
294 }
295 if (irb->scsw.cstat & SCSW_CSTAT_CHAINCHK) {
296 strcat(msgline, " [Chaining-Check]");
297 }
298 puts(msgline);
299
300 printf(" cpa= 0x%X\n", irb->scsw.cpa);
301 printf(" prev_ccw= 0x%llX\n", prev_ccw);
302 printf(" this_ccw= 0x%llX\n", this_ccw);
303 }
304
305 /*
306 * Handles executing ssch, tsch and returns the irb obtained from tsch.
307 * Returns 0 on success, -1 if unexpected status pending and we need to retry,
308 * otherwise returns condition code from ssch/tsch for error cases.
309 */
__do_cio(SubChannelId schid,uint32_t ccw_addr,int fmt,Irb * irb)310 static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
311 {
312 /*
313 * QEMU's CIO implementation requires prefetch and 64-bit idaws. We
314 * allow all paths.
315 */
316 CmdOrb orb = {
317 .fmt = fmt,
318 .pfch = 1,
319 .c64 = 1,
320 .lpm = 0xFF,
321 .cpa = ccw_addr,
322 };
323 int rc;
324
325 IPL_assert(fmt == 0 || fmt == 1, "Invalid ccw format");
326
327 /* ccw_addr must be <= 24 bits and point to at least one whole ccw. */
328 if (fmt == 0) {
329 IPL_assert(ccw_addr <= 0xFFFFFF - 8, "Invalid ccw address");
330 }
331
332 rc = ssch(schid, &orb);
333 if (rc == 1 || rc == 2) {
334 /* Subchannel status pending or busy. Eat status and ask for retry. */
335 tsch(schid, irb);
336 return -1;
337 }
338 if (rc) {
339 printf("ssch failed with cc= 0x%x\n", rc);
340 return rc;
341 }
342
343 consume_io_int();
344
345 /* collect status */
346 rc = tsch(schid, irb);
347 if (rc) {
348 printf("tsch failed with cc= 0x%X\n", rc);
349 }
350
351 return rc;
352 }
353
354 /*
355 * Executes a channel program at a given subchannel. The request to run the
356 * channel program is sent to the subchannel, we then wait for the interrupt
357 * signaling completion of the I/O operation(s) performed by the channel
358 * program. Lastly we verify that the i/o operation completed without error and
359 * that the interrupt we received was for the subchannel used to run the
360 * channel program.
361 *
362 * Note: This function assumes it is running in an environment where no other
363 * cpus are generating or receiving I/O interrupts. So either run it in a
364 * single-cpu environment or make sure all other cpus are not doing I/O and
365 * have I/O interrupts masked off. We also assume that only one device is
366 * active (generating i/o interrupts).
367 *
368 * Returns non-zero on error.
369 */
do_cio(SubChannelId schid,uint16_t cutype,uint32_t ccw_addr,int fmt)370 int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
371 {
372 Irb irb = {};
373 SenseDataEckdDasd sd;
374 int rc, retries = 0;
375
376 while (true) {
377 rc = __do_cio(schid, ccw_addr, fmt, &irb);
378
379 if (rc == -1) {
380 retries++;
381 continue;
382 }
383 if (rc) {
384 /* ssch/tsch error. Message already reported by __do_cio */
385 break;
386 }
387
388 if (!irb_error(&irb)) {
389 break;
390 }
391
392 /*
393 * Unexpected unit check, or interface-control-check. Use sense to
394 * clear (unit check only) then retry.
395 */
396 if ((unit_check(&irb) || iface_ctrl_check(&irb)) && retries <= 2) {
397 if (unit_check(&irb)) {
398 basic_sense(schid, cutype, &sd, sizeof(sd));
399 }
400 retries++;
401 continue;
402 }
403
404 printf("cio device error\n");
405 printf(" ssid 0x%X\n", schid.ssid);
406 printf(" cssid 0x%X\n", schid.cssid);
407 printf(" sch_no 0x%X\n", schid.sch_no);
408 printf(" ctrl-unit type 0x%X\n", cutype);
409 printf("\n");
410 print_irb_err(&irb);
411 if (cutype == CU_TYPE_DASD_3990 || cutype == CU_TYPE_DASD_2107 ||
412 cutype == CU_TYPE_UNKNOWN) {
413 if (!basic_sense(schid, cutype, &sd, sizeof(sd))) {
414 print_eckd_dasd_sense_data(&sd);
415 }
416 }
417 rc = -1;
418 break;
419 }
420
421 return rc;
422 }
423