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