xref: /linux/drivers/s390/cio/cio_inject.c (revision c441bfb5f2866de71e092c1b9d866a65978dfe1a)
1*a4f17cc7SVineeth Vijayan // SPDX-License-Identifier: GPL-2.0
2*a4f17cc7SVineeth Vijayan /*
3*a4f17cc7SVineeth Vijayan  *   CIO inject interface
4*a4f17cc7SVineeth Vijayan  *
5*a4f17cc7SVineeth Vijayan  *    Copyright IBM Corp. 2021
6*a4f17cc7SVineeth Vijayan  *    Author(s): Vineeth Vijayan <vneethv@linux.ibm.com>
7*a4f17cc7SVineeth Vijayan  */
8*a4f17cc7SVineeth Vijayan 
9*a4f17cc7SVineeth Vijayan #define KMSG_COMPONENT "cio"
10*a4f17cc7SVineeth Vijayan #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11*a4f17cc7SVineeth Vijayan 
12*a4f17cc7SVineeth Vijayan #include <linux/slab.h>
13*a4f17cc7SVineeth Vijayan #include <linux/spinlock.h>
14*a4f17cc7SVineeth Vijayan #include <linux/mm.h>
15*a4f17cc7SVineeth Vijayan #include <linux/debugfs.h>
16*a4f17cc7SVineeth Vijayan #include <asm/chpid.h>
17*a4f17cc7SVineeth Vijayan 
18*a4f17cc7SVineeth Vijayan #include "cio_inject.h"
19*a4f17cc7SVineeth Vijayan #include "cio_debug.h"
20*a4f17cc7SVineeth Vijayan 
21*a4f17cc7SVineeth Vijayan static DEFINE_SPINLOCK(crw_inject_lock);
22*a4f17cc7SVineeth Vijayan DEFINE_STATIC_KEY_FALSE(cio_inject_enabled);
23*a4f17cc7SVineeth Vijayan static struct crw *crw_inject_data;
24*a4f17cc7SVineeth Vijayan 
25*a4f17cc7SVineeth Vijayan /**
26*a4f17cc7SVineeth Vijayan  * crw_inject : Initiate the artificial CRW inject
27*a4f17cc7SVineeth Vijayan  * @crw: The data which needs to be injected as new CRW.
28*a4f17cc7SVineeth Vijayan  *
29*a4f17cc7SVineeth Vijayan  * The CRW handler is called, which will use the provided artificial
30*a4f17cc7SVineeth Vijayan  * data instead of the CRW from the underlying hardware.
31*a4f17cc7SVineeth Vijayan  *
32*a4f17cc7SVineeth Vijayan  * Return: 0 on success
33*a4f17cc7SVineeth Vijayan  */
34*a4f17cc7SVineeth Vijayan static int crw_inject(struct crw *crw)
35*a4f17cc7SVineeth Vijayan {
36*a4f17cc7SVineeth Vijayan 	int rc = 0;
37*a4f17cc7SVineeth Vijayan 	struct crw *copy;
38*a4f17cc7SVineeth Vijayan 	unsigned long flags;
39*a4f17cc7SVineeth Vijayan 
40*a4f17cc7SVineeth Vijayan 	copy = kmemdup(crw, sizeof(*crw), GFP_KERNEL);
41*a4f17cc7SVineeth Vijayan 	if (!copy)
42*a4f17cc7SVineeth Vijayan 		return -ENOMEM;
43*a4f17cc7SVineeth Vijayan 
44*a4f17cc7SVineeth Vijayan 	spin_lock_irqsave(&crw_inject_lock, flags);
45*a4f17cc7SVineeth Vijayan 	if (crw_inject_data) {
46*a4f17cc7SVineeth Vijayan 		kfree(copy);
47*a4f17cc7SVineeth Vijayan 		rc = -EBUSY;
48*a4f17cc7SVineeth Vijayan 	} else {
49*a4f17cc7SVineeth Vijayan 		crw_inject_data = copy;
50*a4f17cc7SVineeth Vijayan 	}
51*a4f17cc7SVineeth Vijayan 	spin_unlock_irqrestore(&crw_inject_lock, flags);
52*a4f17cc7SVineeth Vijayan 
53*a4f17cc7SVineeth Vijayan 	if (!rc)
54*a4f17cc7SVineeth Vijayan 		crw_handle_channel_report();
55*a4f17cc7SVineeth Vijayan 
56*a4f17cc7SVineeth Vijayan 	return rc;
57*a4f17cc7SVineeth Vijayan }
58*a4f17cc7SVineeth Vijayan 
59*a4f17cc7SVineeth Vijayan /**
60*a4f17cc7SVineeth Vijayan  * stcrw_get_injected: Copy the artificial CRW data to CRW struct.
61*a4f17cc7SVineeth Vijayan  * @crw: The target CRW pointer.
62*a4f17cc7SVineeth Vijayan  *
63*a4f17cc7SVineeth Vijayan  * Retrieve an injected CRW data. Return 0 on success, 1 if no
64*a4f17cc7SVineeth Vijayan  * injected-CRW is available. The function reproduces the return
65*a4f17cc7SVineeth Vijayan  * code of the actual STCRW function.
66*a4f17cc7SVineeth Vijayan  */
67*a4f17cc7SVineeth Vijayan int stcrw_get_injected(struct crw *crw)
68*a4f17cc7SVineeth Vijayan {
69*a4f17cc7SVineeth Vijayan 	int rc = 1;
70*a4f17cc7SVineeth Vijayan 	unsigned long flags;
71*a4f17cc7SVineeth Vijayan 
72*a4f17cc7SVineeth Vijayan 	spin_lock_irqsave(&crw_inject_lock, flags);
73*a4f17cc7SVineeth Vijayan 	if (crw_inject_data) {
74*a4f17cc7SVineeth Vijayan 		memcpy(crw, crw_inject_data, sizeof(*crw));
75*a4f17cc7SVineeth Vijayan 		kfree(crw_inject_data);
76*a4f17cc7SVineeth Vijayan 		crw_inject_data = NULL;
77*a4f17cc7SVineeth Vijayan 		rc = 0;
78*a4f17cc7SVineeth Vijayan 	}
79*a4f17cc7SVineeth Vijayan 	spin_unlock_irqrestore(&crw_inject_lock, flags);
80*a4f17cc7SVineeth Vijayan 
81*a4f17cc7SVineeth Vijayan 	return rc;
82*a4f17cc7SVineeth Vijayan }
83*a4f17cc7SVineeth Vijayan 
84*a4f17cc7SVineeth Vijayan /* The debugfs write handler for crw_inject nodes operation */
85*a4f17cc7SVineeth Vijayan static ssize_t crw_inject_write(struct file *file, const char __user *buf,
86*a4f17cc7SVineeth Vijayan 				size_t lbuf, loff_t *ppos)
87*a4f17cc7SVineeth Vijayan {
88*a4f17cc7SVineeth Vijayan 	u32 slct, oflw, chn, rsc, anc, erc, rsid;
89*a4f17cc7SVineeth Vijayan 	struct crw crw;
90*a4f17cc7SVineeth Vijayan 	char *buffer;
91*a4f17cc7SVineeth Vijayan 	int rc;
92*a4f17cc7SVineeth Vijayan 
93*a4f17cc7SVineeth Vijayan 	if (!static_branch_likely(&cio_inject_enabled)) {
94*a4f17cc7SVineeth Vijayan 		pr_warn("CIO inject is not enabled - ignoring CRW inject\n");
95*a4f17cc7SVineeth Vijayan 		return -EINVAL;
96*a4f17cc7SVineeth Vijayan 	}
97*a4f17cc7SVineeth Vijayan 
98*a4f17cc7SVineeth Vijayan 	buffer = vmemdup_user(buf, lbuf);
99*a4f17cc7SVineeth Vijayan 	if (IS_ERR(buffer))
100*a4f17cc7SVineeth Vijayan 		return -ENOMEM;
101*a4f17cc7SVineeth Vijayan 
102*a4f17cc7SVineeth Vijayan 	rc = sscanf(buffer, "%x %x %x %x %x %x %x", &slct, &oflw, &chn, &rsc, &anc,
103*a4f17cc7SVineeth Vijayan 		    &erc, &rsid);
104*a4f17cc7SVineeth Vijayan 
105*a4f17cc7SVineeth Vijayan 	kvfree(buffer);
106*a4f17cc7SVineeth Vijayan 	if (rc != 7) {
107*a4f17cc7SVineeth Vijayan 		pr_warn("crw_inject: Invalid format (need <solicited> <overflow> <chaining> <rsc> <ancillary> <erc> <rsid>)\n");
108*a4f17cc7SVineeth Vijayan 		return -EINVAL;
109*a4f17cc7SVineeth Vijayan 	}
110*a4f17cc7SVineeth Vijayan 
111*a4f17cc7SVineeth Vijayan 	memset(&crw, 0, sizeof(crw));
112*a4f17cc7SVineeth Vijayan 	crw.slct = slct;
113*a4f17cc7SVineeth Vijayan 	crw.oflw = oflw;
114*a4f17cc7SVineeth Vijayan 	crw.chn = chn;
115*a4f17cc7SVineeth Vijayan 	crw.rsc = rsc;
116*a4f17cc7SVineeth Vijayan 	crw.anc = anc;
117*a4f17cc7SVineeth Vijayan 	crw.erc = erc;
118*a4f17cc7SVineeth Vijayan 	crw.rsid = rsid;
119*a4f17cc7SVineeth Vijayan 
120*a4f17cc7SVineeth Vijayan 	rc = crw_inject(&crw);
121*a4f17cc7SVineeth Vijayan 	if (rc)
122*a4f17cc7SVineeth Vijayan 		return rc;
123*a4f17cc7SVineeth Vijayan 
124*a4f17cc7SVineeth Vijayan 	return lbuf;
125*a4f17cc7SVineeth Vijayan }
126*a4f17cc7SVineeth Vijayan 
127*a4f17cc7SVineeth Vijayan /* Debugfs write handler for inject_enable node*/
128*a4f17cc7SVineeth Vijayan static ssize_t enable_inject_write(struct file *file, const char __user *buf,
129*a4f17cc7SVineeth Vijayan 				   size_t lbuf, loff_t *ppos)
130*a4f17cc7SVineeth Vijayan {
131*a4f17cc7SVineeth Vijayan 	unsigned long en = 0;
132*a4f17cc7SVineeth Vijayan 	int rc;
133*a4f17cc7SVineeth Vijayan 
134*a4f17cc7SVineeth Vijayan 	rc = kstrtoul_from_user(buf, lbuf, 10, &en);
135*a4f17cc7SVineeth Vijayan 	if (rc)
136*a4f17cc7SVineeth Vijayan 		return rc;
137*a4f17cc7SVineeth Vijayan 
138*a4f17cc7SVineeth Vijayan 	switch (en) {
139*a4f17cc7SVineeth Vijayan 	case 0:
140*a4f17cc7SVineeth Vijayan 		static_branch_disable(&cio_inject_enabled);
141*a4f17cc7SVineeth Vijayan 		break;
142*a4f17cc7SVineeth Vijayan 	case 1:
143*a4f17cc7SVineeth Vijayan 		static_branch_enable(&cio_inject_enabled);
144*a4f17cc7SVineeth Vijayan 		break;
145*a4f17cc7SVineeth Vijayan 	}
146*a4f17cc7SVineeth Vijayan 
147*a4f17cc7SVineeth Vijayan 	return lbuf;
148*a4f17cc7SVineeth Vijayan }
149*a4f17cc7SVineeth Vijayan 
150*a4f17cc7SVineeth Vijayan static const struct file_operations crw_fops = {
151*a4f17cc7SVineeth Vijayan 	.owner = THIS_MODULE,
152*a4f17cc7SVineeth Vijayan 	.write = crw_inject_write,
153*a4f17cc7SVineeth Vijayan };
154*a4f17cc7SVineeth Vijayan 
155*a4f17cc7SVineeth Vijayan static const struct file_operations cio_en_fops = {
156*a4f17cc7SVineeth Vijayan 	.owner = THIS_MODULE,
157*a4f17cc7SVineeth Vijayan 	.write = enable_inject_write,
158*a4f17cc7SVineeth Vijayan };
159*a4f17cc7SVineeth Vijayan 
160*a4f17cc7SVineeth Vijayan static int __init cio_inject_init(void)
161*a4f17cc7SVineeth Vijayan {
162*a4f17cc7SVineeth Vijayan 	/* enable_inject node enables the static branching */
163*a4f17cc7SVineeth Vijayan 	debugfs_create_file("enable_inject", 0200, cio_debugfs_dir,
164*a4f17cc7SVineeth Vijayan 			    NULL, &cio_en_fops);
165*a4f17cc7SVineeth Vijayan 
166*a4f17cc7SVineeth Vijayan 	debugfs_create_file("crw_inject", 0200, cio_debugfs_dir,
167*a4f17cc7SVineeth Vijayan 			    NULL, &crw_fops);
168*a4f17cc7SVineeth Vijayan 	return 0;
169*a4f17cc7SVineeth Vijayan }
170*a4f17cc7SVineeth Vijayan 
171*a4f17cc7SVineeth Vijayan device_initcall(cio_inject_init);
172