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
98*84b38f48SBui 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