1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Channel Subsystem tests library
4 *
5 * Copyright (c) 2020 IBM Corp
6 *
7 * Authors:
8 * Pierre Morel <pmorel@linux.ibm.com>
9 */
10 #include <libcflat.h>
11 #include <alloc_phys.h>
12 #include <asm/page.h>
13 #include <string.h>
14 #include <interrupt.h>
15 #include <asm/arch_def.h>
16 #include <asm/time.h>
17 #include <asm/arch_def.h>
18 #include <alloc_page.h>
19 #include <malloc_io.h>
20 #include <css.h>
21
22 struct schib schib;
23 struct chsc_scsc *chsc_scsc;
24
25 static const char * const chsc_rsp_description[] = {
26 "CHSC unknown error",
27 "Command executed",
28 "Invalid command",
29 "Request-block error",
30 "Command not installed",
31 "Data not available",
32 "Absolute address of channel-subsystem communication block exceeds 2G - 1.",
33 "Invalid command format",
34 "Invalid channel-subsystem identification (CSSID)",
35 "The command-request block specified an invalid format for the command response block.",
36 "Invalid subchannel-set identification (SSID)",
37 "A busy condition precludes execution.",
38 };
39
check_response(void * p)40 static bool check_response(void *p)
41 {
42 struct chsc_header *h = p;
43
44 if (h->code == CHSC_RSP_OK)
45 return true;
46
47 if (h->code > CHSC_RSP_MAX)
48 h->code = 0;
49
50 report_abort("Response code %04x: %s", h->code,
51 chsc_rsp_description[h->code]);
52 return false;
53 }
54
chsc(void * p,uint16_t code,uint16_t len)55 bool chsc(void *p, uint16_t code, uint16_t len)
56 {
57 struct chsc_header *h = p;
58
59 h->code = code;
60 h->len = len;
61
62 switch (_chsc(p)) {
63 case 3:
64 report_abort("Subchannel invalid or not enabled.");
65 break;
66 case 2:
67 report_abort("CHSC subchannel busy.");
68 break;
69 case 1:
70 report_abort("Subchannel invalid or not enabled.");
71 break;
72 case 0:
73 return check_response(p + len);
74 }
75 return false;
76 }
77
get_chsc_scsc(void)78 bool get_chsc_scsc(void)
79 {
80 int i, n;
81 char buffer[510];
82 char *p;
83
84 if (chsc_scsc) /* chsc_scsc already initialized */
85 return true;
86
87 chsc_scsc = alloc_page();
88 if (!chsc_scsc) {
89 report_abort("could not allocate chsc_scsc page!");
90 return false;
91 }
92
93 if (!chsc(chsc_scsc, CHSC_SCSC, CHSC_SCSC_LEN))
94 return false;
95
96 for (i = 0, p = buffer; i < CSS_GENERAL_FEAT_BITLEN; i++) {
97 if (css_test_general_feature(i)) {
98 n = snprintf(p, sizeof(buffer), "%d,", i);
99 p += n;
100 }
101 }
102 report_info("General features: %s", buffer);
103
104 for (i = 0, p = buffer; i < CSS_CHSC_FEAT_BITLEN; i++) {
105 if (css_test_chsc_feature(i)) {
106 n = snprintf(p, sizeof(buffer), "%d,", i);
107 p += n;
108 }
109 }
110 report_info("CHSC features: %s", buffer);
111
112 return true;
113 }
114
115 /*
116 * css_enumerate:
117 * On success return the first subchannel ID found.
118 * On error return an invalid subchannel ID containing cc
119 */
css_enumerate(void)120 int css_enumerate(void)
121 {
122 struct pmcw *pmcw = &schib.pmcw;
123 int scn_found = 0;
124 int dev_found = 0;
125 int schid = 0;
126 int cc;
127 int scn;
128
129 for (scn = 0; scn < 0xffff; scn++) {
130 cc = stsch(scn | SCHID_ONE, &schib);
131 switch (cc) {
132 case 0: /* 0 means SCHIB stored */
133 break;
134 case 3: /* 3 means no more channels */
135 goto out;
136 default: /* 1 or 2 should never happen for STSCH */
137 report_abort("Unexpected error %d on subchannel %08x",
138 cc, scn | SCHID_ONE);
139 return cc;
140 }
141
142 /* We currently only support type 0, a.k.a. I/O channels */
143 if (PMCW_CHANNEL_TYPE(pmcw) != 0)
144 continue;
145
146 /* We ignore I/O channels without valid devices */
147 scn_found++;
148 if (!(pmcw->flags & PMCW_DNV))
149 continue;
150
151 /* We keep track of the first device as our test device */
152 if (!schid)
153 schid = scn | SCHID_ONE;
154 report_info("Found subchannel %08x", scn | SCHID_ONE);
155 dev_found++;
156 }
157
158 out:
159 report_info("Tested subchannels: %d, I/O subchannels: %d, I/O devices: %d",
160 scn, scn_found, dev_found);
161 return schid;
162 }
163
164 /*
165 * css_enabled: report if the subchannel is enabled
166 * @schid: Subchannel Identifier
167 * Return value:
168 * true if the subchannel is enabled
169 * false otherwise
170 */
css_enabled(int schid)171 bool css_enabled(int schid)
172 {
173 struct pmcw *pmcw = &schib.pmcw;
174 int cc;
175
176 cc = stsch(schid, &schib);
177 if (cc) {
178 report_info("stsch: updating sch %08x failed with cc=%d",
179 schid, cc);
180 return false;
181 }
182
183 if (!(pmcw->flags & PMCW_ENABLE)) {
184 report_info("stsch: sch %08x not enabled", schid);
185 return false;
186 }
187 return true;
188 }
189 /*
190 * css_enable: enable the subchannel with the specified ISC
191 * @schid: Subchannel Identifier
192 * @isc : number of the interruption subclass to use
193 * Return value:
194 * On success: 0
195 * On error the CC of the faulty instruction
196 * or -1 if the retry count is exceeded.
197 */
css_enable(int schid,int isc)198 int css_enable(int schid, int isc)
199 {
200 struct pmcw *pmcw = &schib.pmcw;
201 int retry_count = 0;
202 uint16_t flags;
203 int cc;
204
205 /* Read the SCHIB for this subchannel */
206 cc = stsch(schid, &schib);
207 if (cc) {
208 report_info("stsch: sch %08x failed with cc=%d", schid, cc);
209 return cc;
210 }
211
212 flags = PMCW_ENABLE | (isc << PMCW_ISC_SHIFT);
213 if ((pmcw->flags & (PMCW_ISC_MASK | PMCW_ENABLE)) == flags) {
214 report_info("stsch: sch %08x already enabled", schid);
215 return 0;
216 }
217
218 retry:
219 /* Update the SCHIB to enable the channel and set the ISC */
220 pmcw->flags &= ~PMCW_ISC_MASK;
221 pmcw->flags |= flags;
222
223 /* Tell the CSS we want to modify the subchannel */
224 cc = msch(schid, &schib);
225 if (cc) {
226 /*
227 * If the subchannel is status pending or
228 * if a function is in progress,
229 * we consider both cases as errors.
230 */
231 report_info("msch: sch %08x failed with cc=%d", schid, cc);
232 return cc;
233 }
234
235 /*
236 * Read the SCHIB again to verify the enablement
237 */
238 if (css_enabled(schid))
239 return 0;
240
241 if (retry_count++ < MAX_ENABLE_RETRIES) {
242 mdelay(10); /* the hardware was not ready, give it some time */
243 goto retry;
244 }
245
246 report_info("msch: modifying sch %08x failed after %d retries. pmcw flags: %04x",
247 schid, retry_count, pmcw->flags);
248 return -1;
249 }
250
251 /*
252 * schib_update_mb: update the subchannel Measurement Block
253 * @schid: Subchannel Identifier
254 * @mb : 64bit address of the measurement block
255 * @mbi : the measurement block offset
256 * @flags : PMCW_MBUE to enable measurement block update
257 * PMCW_DCTME to enable device connect time
258 * 0 to disable measurement
259 * @format1: set if format 1 is to be used
260 */
schib_update_mb(int schid,uint64_t mb,uint16_t mbi,uint16_t flags,bool format1)261 static bool schib_update_mb(int schid, uint64_t mb, uint16_t mbi,
262 uint16_t flags, bool format1)
263 {
264 struct pmcw *pmcw = &schib.pmcw;
265 int cc;
266
267 /* Read the SCHIB for this subchannel */
268 cc = stsch(schid, &schib);
269 if (cc) {
270 report_info("stsch: sch %08x failed with cc=%d", schid, cc);
271 return false;
272 }
273
274 /* Update the SCHIB to enable the measurement block */
275 if (flags) {
276 pmcw->flags |= flags;
277
278 if (format1)
279 pmcw->flags2 |= PMCW_MBF1;
280 else
281 pmcw->flags2 &= ~PMCW_MBF1;
282
283 pmcw->mbi = mbi;
284 schib.mbo = mb & ~0x3f;
285 } else {
286 pmcw->flags &= ~(PMCW_MBUE | PMCW_DCTME);
287 }
288
289 /* Tell the CSS we want to modify the subchannel */
290 cc = msch(schid, &schib);
291 if (cc) {
292 /*
293 * If the subchannel is status pending or
294 * if a function is in progress,
295 * we consider both cases as errors.
296 */
297 report_info("msch: sch %08x failed with cc=%d", schid, cc);
298 return false;
299 }
300
301 /*
302 * Read the SCHIB again
303 */
304 cc = stsch(schid, &schib);
305 if (cc) {
306 report_info("stsch: updating sch %08x failed with cc=%d",
307 schid, cc);
308 return false;
309 }
310
311 return true;
312 }
313
314 /*
315 * css_enable_mb: enable the subchannel Measurement Block
316 * @schid: Subchannel Identifier
317 * @mb : 64bit address of the measurement block
318 * @format1: set if format 1 is to be used
319 * @mbi : the measurement block offset
320 * @flags : PMCW_MBUE to enable measurement block update
321 * PMCW_DCTME to enable device connect time
322 */
css_enable_mb(int schid,uint64_t mb,uint16_t mbi,uint16_t flags,bool format1)323 bool css_enable_mb(int schid, uint64_t mb, uint16_t mbi, uint16_t flags,
324 bool format1)
325 {
326 int retry_count = MAX_ENABLE_RETRIES;
327 struct pmcw *pmcw = &schib.pmcw;
328
329 while (retry_count-- &&
330 !schib_update_mb(schid, mb, mbi, flags, format1))
331 mdelay(10); /* the hardware was not ready, give it some time */
332
333 return schib.mbo == mb && pmcw->mbi == mbi;
334 }
335
336 /*
337 * css_disable_mb: disable the subchannel Measurement Block
338 * @schid: Subchannel Identifier
339 */
css_disable_mb(int schid)340 bool css_disable_mb(int schid)
341 {
342 int retry_count = MAX_ENABLE_RETRIES;
343
344 while (retry_count-- &&
345 !schib_update_mb(schid, 0, 0, 0, 0))
346 mdelay(10); /* the hardware was not ready, give it some time */
347
348 return retry_count > 0;
349 }
350
351 static struct irb irb;
352
css_irq_io(void)353 void css_irq_io(void)
354 {
355 int ret = 0;
356 char *flags;
357 int sid;
358
359 report_prefix_push("Interrupt");
360 sid = lowcore.subsys_id_word;
361 /* Lowlevel set the SID as interrupt parameter. */
362 if (lowcore.io_int_param != sid) {
363 report_fail("io_int_param: %x differs from subsys_id_word: %x",
364 lowcore.io_int_param, sid);
365 goto pop;
366 }
367 report_prefix_pop();
368
369 report_prefix_push("tsch");
370 ret = tsch(sid, &irb);
371 switch (ret) {
372 case 1:
373 dump_irb(&irb);
374 flags = dump_scsw_flags(irb.scsw.ctrl);
375 report_fail("I/O interrupt, but tsch returns CC 1 for subchannel %08x.SCSW flags: %s",
376 sid, flags);
377 break;
378 case 2:
379 report_fail("tsch returns unexpected CC 2");
380 break;
381 case 3:
382 report_fail("tsch reporting sch %08x as not operational", sid);
383 break;
384 case 0:
385 /* Stay humble on success */
386 break;
387 }
388 pop:
389 report_prefix_pop();
390 lowcore.io_old_psw.mask &= ~PSW_MASK_WAIT;
391 }
392
start_ccw1_chain(unsigned int sid,struct ccw1 * ccw)393 int start_ccw1_chain(unsigned int sid, struct ccw1 *ccw)
394 {
395 struct orb orb = {
396 .intparm = sid,
397 .ctrl = ORB_CTRL_ISIC|ORB_CTRL_FMT|ORB_LPM_DFLT,
398 .cpa = (unsigned int) (unsigned long)ccw,
399 };
400
401 return ssch(sid, &orb);
402 }
403
ccw_alloc(int code,void * data,int count,unsigned char flags)404 struct ccw1 *ccw_alloc(int code, void *data, int count, unsigned char flags)
405 {
406 struct ccw1 *ccw;
407
408 ccw = alloc_io_mem(sizeof(*ccw), 0);
409 if (!ccw)
410 return NULL;
411
412 ccw->code = code;
413 ccw->flags = flags;
414 ccw->count = count;
415 ccw->data_address = (int)(unsigned long)data;
416
417 return ccw;
418 }
419
420 /* wait_and_check_io_completion:
421 * @schid: the subchannel ID
422 *
423 * Makes the most common check to validate a successful I/O
424 * completion.
425 * Only report failures.
426 */
wait_and_check_io_completion(int schid)427 int wait_and_check_io_completion(int schid)
428 {
429 int ret = 0;
430
431 wait_for_interrupt(PSW_MASK_IO);
432
433 report_prefix_push("check I/O completion");
434
435 if (lowcore.io_int_param != schid) {
436 report_fail("interrupt parameter: expected %08x got %08x",
437 schid, lowcore.io_int_param);
438 ret = -1;
439 goto end;
440 }
441
442 /* Verify that device status is valid */
443 if (!(irb.scsw.ctrl & SCSW_SC_PENDING)) {
444 report_fail("No status pending after interrupt. Subch Ctrl: %08x",
445 irb.scsw.ctrl);
446 ret = -1;
447 goto end;
448 }
449
450 if (!(irb.scsw.ctrl & (SCSW_SC_SECONDARY | SCSW_SC_PRIMARY))) {
451 report_fail("Primary or secondary status missing. Subch Ctrl: %08x",
452 irb.scsw.ctrl);
453 ret = -1;
454 goto end;
455 }
456
457 if (!(irb.scsw.dev_stat & (SCSW_DEVS_DEV_END | SCSW_DEVS_SCH_END))) {
458 report_fail("No device end or sch end. Dev. status: %02x",
459 irb.scsw.dev_stat);
460 ret = -1;
461 goto end;
462 }
463
464 if (irb.scsw.sch_stat & ~SCSW_SCHS_IL) {
465 report_info("Unexpected Subch. status %02x", irb.scsw.sch_stat);
466 ret = -1;
467 goto end;
468 }
469
470 end:
471 report_prefix_pop();
472 return ret;
473 }
474
475 /*
476 * css_residual_count
477 * Return the residual count, if it is valid.
478 *
479 * Return value:
480 * Success: the residual count
481 * Not meaningful: -1 (-1 can not be a valid count)
482 */
css_residual_count(unsigned int schid)483 int css_residual_count(unsigned int schid)
484 {
485
486 if (!(irb.scsw.ctrl & (SCSW_SC_PENDING | SCSW_SC_PRIMARY)))
487 return -1;
488
489 if (irb.scsw.dev_stat)
490 if (irb.scsw.sch_stat & ~(SCSW_SCHS_PCI | SCSW_SCHS_IL))
491 return -1;
492
493 return irb.scsw.count;
494 }
495
496 /*
497 * enable_io_isc: setup ISC in Control Register 6
498 * @isc: The interruption Sub Class as a bitfield
499 */
enable_io_isc(uint8_t isc)500 void enable_io_isc(uint8_t isc)
501 {
502 uint64_t value;
503
504 value = (uint64_t)isc << 24;
505 lctlg(6, value);
506 }
507
is_path_installed(struct schib * schib,int chp_idx)508 static int is_path_installed(struct schib *schib, int chp_idx)
509 {
510 return schib->pmcw.pim & BIT(7 - chp_idx);
511 }
512
513 /*
514 * css_find_installed_chpid: find any installed CHPID
515 * @sid: subsystem-identification word
516 * @chpid_out: store the found chpid here, left alone if none found
517 *
518 * returns 0 on success, -1 if no chpid found any other value
519 * indicates the condition code of a failing STSCH instruction
520 */
css_find_installed_chpid(int sid,uint8_t * chpid_out)521 int css_find_installed_chpid(int sid, uint8_t *chpid_out)
522 {
523 int cc;
524
525 cc = stsch(sid, &schib);
526 if (cc) {
527 report_fail("%s: sch %08x failed with cc=%d", __func__, sid, cc);
528 return cc;
529 }
530
531 for (int i = 0; i < ARRAY_SIZE(schib.pmcw.chpid); i++) {
532 if (is_path_installed(&schib, i)) {
533 *chpid_out = schib.pmcw.chpid[i];
534 return 0;
535 }
536 }
537
538 return -1;
539 }
540
541 /*
542 * css_generate_crw: Generate a CRW by issuing RCHP on any channel path
543 * @sid: subsystem-identification word
544 *
545 * returns 0 when a CRW was generated, -1 if no chpid found.
546 */
css_generate_crw(int sid)547 int css_generate_crw(int sid)
548 {
549 int ret, cc;
550 uint8_t chpid;
551
552 report_prefix_push("Generate CRW");
553
554 ret = css_find_installed_chpid(sid, &chpid);
555 if (ret) {
556 report_fail("No CHPID found: ret=%d", ret);
557 return -1;
558 }
559
560 cc = rchp(chpid);
561 report(!cc, "rhcp cc != 0");
562
563 report_prefix_pop();
564
565 return 0;
566 }
567