xref: /kvm-unit-tests/s390x/css.c (revision a6e5e596cce508a7cde2338cdff801d63edee566)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Channel Subsystem tests
4  *
5  * Copyright (c) 2020 IBM Corp
6  *
7  * Authors:
8  *  Pierre Morel <pmorel@linux.ibm.com>
9  */
10 
11 #include <libcflat.h>
12 #include <alloc_phys.h>
13 #include <asm/page.h>
14 #include <string.h>
15 #include <interrupt.h>
16 #include <asm/arch_def.h>
17 
18 #include <malloc_io.h>
19 #include <css.h>
20 #include <asm/barrier.h>
21 
22 #define DEFAULT_CU_TYPE		0x3832 /* virtio-ccw */
23 static unsigned long cu_type = DEFAULT_CU_TYPE;
24 
25 static int test_device_sid;
26 static struct senseid *senseid;
27 
28 static void test_enumerate(void)
29 {
30 	test_device_sid = css_enumerate();
31 	if (test_device_sid & SCHID_ONE) {
32 		report(1, "Schid of first I/O device: 0x%08x", test_device_sid);
33 		return;
34 	}
35 	report(0, "No I/O device found");
36 }
37 
38 static void test_enable(void)
39 {
40 	int cc;
41 
42 	if (!test_device_sid) {
43 		report_skip("No device");
44 		return;
45 	}
46 
47 	cc = css_enable(test_device_sid, IO_SCH_ISC);
48 
49 	report(cc == 0, "Enable subchannel %08x", test_device_sid);
50 }
51 
52 /*
53  * test_sense
54  * Pre-requisites:
55  * - We need the test device as the first recognized
56  *   device by the enumeration.
57  */
58 static void test_sense(void)
59 {
60 	struct ccw1 *ccw;
61 	int ret;
62 	int len;
63 
64 	if (!test_device_sid) {
65 		report_skip("No device");
66 		return;
67 	}
68 
69 	ret = css_enable(test_device_sid, IO_SCH_ISC);
70 	if (ret) {
71 		report(0, "Could not enable the subchannel: %08x",
72 		       test_device_sid);
73 		return;
74 	}
75 
76 	ret = register_io_int_func(css_irq_io);
77 	if (ret) {
78 		report(0, "Could not register IRQ handler");
79 		return;
80 	}
81 
82 	lowcore_ptr->io_int_param = 0;
83 
84 	senseid = alloc_io_mem(sizeof(*senseid), 0);
85 	if (!senseid) {
86 		report(0, "Allocation of senseid");
87 		goto error_senseid;
88 	}
89 
90 	ccw = ccw_alloc(CCW_CMD_SENSE_ID, senseid, sizeof(*senseid), CCW_F_SLI);
91 	if (!ccw) {
92 		report(0, "Allocation of CCW");
93 		goto error_ccw;
94 	}
95 
96 	ret = start_ccw1_chain(test_device_sid, ccw);
97 	if (ret) {
98 		report(0, "Starting CCW chain");
99 		goto error;
100 	}
101 
102 	if (wait_and_check_io_completion(test_device_sid) < 0)
103 		goto error;
104 
105 	/* Test transfer completion */
106 	report_prefix_push("ssch transfer completion");
107 
108 	ret = css_residual_count(test_device_sid);
109 
110 	if (ret < 0) {
111 		report_info("no valid residual count");
112 	} else if (ret != 0) {
113 		len = sizeof(*senseid) - ret;
114 		if (ret && len < CSS_SENSEID_COMMON_LEN) {
115 			report(0, "transferred a too short length: %d", ret);
116 			goto error;
117 		} else if (ret && len)
118 			report_info("transferred a shorter length: %d", len);
119 	}
120 
121 	if (senseid->reserved != 0xff) {
122 		report(0, "transferred garbage: 0x%02x", senseid->reserved);
123 		goto error;
124 	}
125 
126 	report_prefix_pop();
127 
128 	report_info("reserved 0x%02x cu_type 0x%04x cu_model 0x%02x dev_type 0x%04x dev_model 0x%02x",
129 		    senseid->reserved, senseid->cu_type, senseid->cu_model,
130 		    senseid->dev_type, senseid->dev_model);
131 
132 	report(senseid->cu_type == cu_type, "cu_type expected 0x%04x got 0x%04x",
133 	       (uint16_t)cu_type, senseid->cu_type);
134 
135 error:
136 	free_io_mem(ccw, sizeof(*ccw));
137 error_ccw:
138 	free_io_mem(senseid, sizeof(*senseid));
139 error_senseid:
140 	unregister_io_int_func(css_irq_io);
141 }
142 
143 static struct {
144 	const char *name;
145 	void (*func)(void);
146 } tests[] = {
147 	{ "enumerate (stsch)", test_enumerate },
148 	{ "enable (msch)", test_enable },
149 	{ "sense (ssch/tsch)", test_sense },
150 	{ NULL, NULL }
151 };
152 
153 int main(int argc, char *argv[])
154 {
155 	int i;
156 
157 	report_prefix_push("Channel Subsystem");
158 	enable_io_isc(0x80 >> IO_SCH_ISC);
159 	for (i = 0; tests[i].name; i++) {
160 		report_prefix_push(tests[i].name);
161 		tests[i].func();
162 		report_prefix_pop();
163 	}
164 	report_prefix_pop();
165 
166 	return report_summary();
167 }
168