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