xref: /kvm-unit-tests/s390x/css.c (revision 1b53866b0b494277ab41c7c0cec4ee00969dd32e)
1 /*
2  * Channel Subsystem tests
3  *
4  * Copyright (c) 2020 IBM Corp
5  *
6  * Authors:
7  *  Pierre Morel <pmorel@linux.ibm.com>
8  *
9  * This code is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License version 2.
11  */
12 
13 #include <libcflat.h>
14 #include <alloc_phys.h>
15 #include <asm/page.h>
16 #include <string.h>
17 #include <interrupt.h>
18 #include <asm/arch_def.h>
19 
20 #include <css.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 	int ret;
61 	int len;
62 
63 	if (!test_device_sid) {
64 		report_skip("No device");
65 		return;
66 	}
67 
68 	ret = css_enable(test_device_sid, IO_SCH_ISC);
69 	if (ret) {
70 		report(0, "Could not enable the subchannel: %08x",
71 		       test_device_sid);
72 		return;
73 	}
74 
75 	ret = register_io_int_func(css_irq_io);
76 	if (ret) {
77 		report(0, "Could not register IRQ handler");
78 		return;
79 	}
80 
81 	lowcore_ptr->io_int_param = 0;
82 
83 	memset(&senseid, 0, sizeof(senseid));
84 	ret = start_single_ccw(test_device_sid, CCW_CMD_SENSE_ID,
85 			       &senseid, sizeof(senseid), CCW_F_SLI);
86 	if (ret)
87 		goto error;
88 
89 	if (wait_and_check_io_completion(test_device_sid) < 0)
90 		goto error;
91 
92 	/* Test transfer completion */
93 	report_prefix_push("ssch transfer completion");
94 
95 	ret = css_residual_count(test_device_sid);
96 
97 	if (ret < 0) {
98 		report_info("no valid residual count");
99 	} else if (ret != 0) {
100 		len = sizeof(senseid) - ret;
101 		if (ret && len < CSS_SENSEID_COMMON_LEN) {
102 			report(0, "transferred a too short length: %d", ret);
103 			goto error;
104 		} else if (ret && len)
105 			report_info("transferred a shorter length: %d", len);
106 	}
107 
108 	if (senseid.reserved != 0xff) {
109 		report(0, "transferred garbage: 0x%02x", senseid.reserved);
110 		goto error;
111 	}
112 
113 	report_prefix_pop();
114 
115 	report_info("reserved 0x%02x cu_type 0x%04x cu_model 0x%02x dev_type 0x%04x dev_model 0x%02x",
116 		    senseid.reserved, senseid.cu_type, senseid.cu_model,
117 		    senseid.dev_type, senseid.dev_model);
118 
119 	report(senseid.cu_type == cu_type, "cu_type expected 0x%04x got 0x%04x",
120 	       (uint16_t) cu_type, senseid.cu_type);
121 
122 error:
123 	unregister_io_int_func(css_irq_io);
124 }
125 
126 static struct {
127 	const char *name;
128 	void (*func)(void);
129 } tests[] = {
130 	{ "enumerate (stsch)", test_enumerate },
131 	{ "enable (msch)", test_enable },
132 	{ "sense (ssch/tsch)", test_sense },
133 	{ NULL, NULL }
134 };
135 
136 int main(int argc, char *argv[])
137 {
138 	int i;
139 
140 	report_prefix_push("Channel Subsystem");
141 	enable_io_isc(0x80 >> IO_SCH_ISC);
142 	for (i = 0; tests[i].name; i++) {
143 		report_prefix_push(tests[i].name);
144 		tests[i].func();
145 		report_prefix_pop();
146 	}
147 	report_prefix_pop();
148 
149 	return report_summary();
150 }
151