1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Character device driver for writing z/VM *MONITOR service records.
4 *
5 * Copyright IBM Corp. 2006, 2009
6 *
7 * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com>
8 */
9
10 #define KMSG_COMPONENT "monwriter"
11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/init.h>
16 #include <linux/errno.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/miscdevice.h>
20 #include <linux/ctype.h>
21 #include <linux/poll.h>
22 #include <linux/mutex.h>
23 #include <linux/slab.h>
24 #include <linux/uaccess.h>
25 #include <linux/io.h>
26 #include <asm/machine.h>
27 #include <asm/ebcdic.h>
28 #include <asm/appldata.h>
29 #include <asm/monwriter.h>
30
31 #define MONWRITE_MAX_DATALEN 4010
32
33 static int mon_max_bufs = 255;
34 static int mon_buf_count;
35
36 struct mon_buf {
37 struct list_head list;
38 struct monwrite_hdr hdr;
39 int diag_done;
40 char *data;
41 };
42
43 struct mon_private {
44 struct list_head list;
45 struct monwrite_hdr hdr;
46 size_t hdr_to_read;
47 size_t data_to_read;
48 struct mon_buf *current_buf;
49 struct mutex thread_mutex;
50 };
51
52 /*
53 * helper functions
54 */
55
monwrite_diag(struct monwrite_hdr * myhdr,char * buffer,int fcn)56 static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
57 {
58 struct appldata_parameter_list *parm_list;
59 struct appldata_product_id *id;
60 int rc;
61
62 id = kmalloc(sizeof(*id), GFP_KERNEL);
63 parm_list = kmalloc(sizeof(*parm_list), GFP_KERNEL);
64 rc = -ENOMEM;
65 if (!id || !parm_list)
66 goto out;
67 memcpy(id->prod_nr, "LNXAPPL", 7);
68 id->prod_fn = myhdr->applid;
69 id->record_nr = myhdr->record_num;
70 id->version_nr = myhdr->version;
71 id->release_nr = myhdr->release;
72 id->mod_lvl = myhdr->mod_level;
73 rc = appldata_asm(parm_list, id, fcn,
74 (void *) buffer, myhdr->datalen);
75 if (rc <= 0)
76 goto out;
77 pr_err("Writing monitor data failed with rc=%i\n", rc);
78 rc = (rc == 5) ? -EPERM : -EINVAL;
79 out:
80 kfree(id);
81 kfree(parm_list);
82 return rc;
83 }
84
monwrite_find_hdr(struct mon_private * monpriv,struct monwrite_hdr * monhdr)85 static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
86 struct monwrite_hdr *monhdr)
87 {
88 struct mon_buf *entry, *next;
89
90 list_for_each_entry_safe(entry, next, &monpriv->list, list)
91 if ((entry->hdr.mon_function == monhdr->mon_function ||
92 monhdr->mon_function == MONWRITE_STOP_INTERVAL) &&
93 entry->hdr.applid == monhdr->applid &&
94 entry->hdr.record_num == monhdr->record_num &&
95 entry->hdr.version == monhdr->version &&
96 entry->hdr.release == monhdr->release &&
97 entry->hdr.mod_level == monhdr->mod_level)
98 return entry;
99
100 return NULL;
101 }
102
monwrite_new_hdr(struct mon_private * monpriv)103 static int monwrite_new_hdr(struct mon_private *monpriv)
104 {
105 struct monwrite_hdr *monhdr = &monpriv->hdr;
106 struct mon_buf *monbuf;
107 int rc = 0;
108
109 if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
110 monhdr->mon_function > MONWRITE_START_CONFIG ||
111 monhdr->hdrlen != sizeof(struct monwrite_hdr))
112 return -EINVAL;
113 monbuf = NULL;
114 if (monhdr->mon_function != MONWRITE_GEN_EVENT)
115 monbuf = monwrite_find_hdr(monpriv, monhdr);
116 if (monbuf) {
117 if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) {
118 monhdr->datalen = monbuf->hdr.datalen;
119 rc = monwrite_diag(monhdr, monbuf->data,
120 APPLDATA_STOP_REC);
121 list_del(&monbuf->list);
122 mon_buf_count--;
123 kfree(monbuf->data);
124 kfree(monbuf);
125 monbuf = NULL;
126 }
127 } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) {
128 if (mon_buf_count >= mon_max_bufs)
129 return -ENOSPC;
130 monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL);
131 if (!monbuf)
132 return -ENOMEM;
133 monbuf->data = kzalloc(monhdr->datalen,
134 GFP_KERNEL | GFP_DMA);
135 if (!monbuf->data) {
136 kfree(monbuf);
137 return -ENOMEM;
138 }
139 monbuf->hdr = *monhdr;
140 list_add_tail(&monbuf->list, &monpriv->list);
141 if (monhdr->mon_function != MONWRITE_GEN_EVENT)
142 mon_buf_count++;
143 }
144 monpriv->current_buf = monbuf;
145 return rc;
146 }
147
monwrite_new_data(struct mon_private * monpriv)148 static int monwrite_new_data(struct mon_private *monpriv)
149 {
150 struct monwrite_hdr *monhdr = &monpriv->hdr;
151 struct mon_buf *monbuf = monpriv->current_buf;
152 int rc = 0;
153
154 switch (monhdr->mon_function) {
155 case MONWRITE_START_INTERVAL:
156 if (!monbuf->diag_done) {
157 rc = monwrite_diag(monhdr, monbuf->data,
158 APPLDATA_START_INTERVAL_REC);
159 monbuf->diag_done = 1;
160 }
161 break;
162 case MONWRITE_START_CONFIG:
163 if (!monbuf->diag_done) {
164 rc = monwrite_diag(monhdr, monbuf->data,
165 APPLDATA_START_CONFIG_REC);
166 monbuf->diag_done = 1;
167 }
168 break;
169 case MONWRITE_GEN_EVENT:
170 rc = monwrite_diag(monhdr, monbuf->data,
171 APPLDATA_GEN_EVENT_REC);
172 list_del(&monpriv->current_buf->list);
173 kfree(monpriv->current_buf->data);
174 kfree(monpriv->current_buf);
175 monpriv->current_buf = NULL;
176 break;
177 default:
178 /* monhdr->mon_function is checked in monwrite_new_hdr */
179 BUG();
180 }
181 return rc;
182 }
183
184 /*
185 * file operations
186 */
187
monwrite_open(struct inode * inode,struct file * filp)188 static int monwrite_open(struct inode *inode, struct file *filp)
189 {
190 struct mon_private *monpriv;
191
192 monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
193 if (!monpriv)
194 return -ENOMEM;
195 INIT_LIST_HEAD(&monpriv->list);
196 monpriv->hdr_to_read = sizeof(monpriv->hdr);
197 mutex_init(&monpriv->thread_mutex);
198 filp->private_data = monpriv;
199 return nonseekable_open(inode, filp);
200 }
201
monwrite_close(struct inode * inode,struct file * filp)202 static int monwrite_close(struct inode *inode, struct file *filp)
203 {
204 struct mon_private *monpriv = filp->private_data;
205 struct mon_buf *entry, *next;
206
207 list_for_each_entry_safe(entry, next, &monpriv->list, list) {
208 if (entry->hdr.mon_function != MONWRITE_GEN_EVENT)
209 monwrite_diag(&entry->hdr, entry->data,
210 APPLDATA_STOP_REC);
211 mon_buf_count--;
212 list_del(&entry->list);
213 kfree(entry->data);
214 kfree(entry);
215 }
216 kfree(monpriv);
217 return 0;
218 }
219
monwrite_write(struct file * filp,const char __user * data,size_t count,loff_t * ppos)220 static ssize_t monwrite_write(struct file *filp, const char __user *data,
221 size_t count, loff_t *ppos)
222 {
223 struct mon_private *monpriv = filp->private_data;
224 size_t len, written;
225 void *to;
226 int rc;
227
228 mutex_lock(&monpriv->thread_mutex);
229 for (written = 0; written < count; ) {
230 if (monpriv->hdr_to_read) {
231 len = min(count - written, monpriv->hdr_to_read);
232 to = (char *) &monpriv->hdr +
233 sizeof(monpriv->hdr) - monpriv->hdr_to_read;
234 if (copy_from_user(to, data + written, len)) {
235 rc = -EFAULT;
236 goto out_error;
237 }
238 monpriv->hdr_to_read -= len;
239 written += len;
240 if (monpriv->hdr_to_read > 0)
241 continue;
242 rc = monwrite_new_hdr(monpriv);
243 if (rc)
244 goto out_error;
245 monpriv->data_to_read = monpriv->current_buf ?
246 monpriv->current_buf->hdr.datalen : 0;
247 }
248
249 if (monpriv->data_to_read) {
250 len = min(count - written, monpriv->data_to_read);
251 to = monpriv->current_buf->data +
252 monpriv->hdr.datalen - monpriv->data_to_read;
253 if (copy_from_user(to, data + written, len)) {
254 rc = -EFAULT;
255 goto out_error;
256 }
257 monpriv->data_to_read -= len;
258 written += len;
259 if (monpriv->data_to_read > 0)
260 continue;
261 rc = monwrite_new_data(monpriv);
262 if (rc)
263 goto out_error;
264 }
265 monpriv->hdr_to_read = sizeof(monpriv->hdr);
266 }
267 mutex_unlock(&monpriv->thread_mutex);
268 return written;
269
270 out_error:
271 monpriv->data_to_read = 0;
272 monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
273 mutex_unlock(&monpriv->thread_mutex);
274 return rc;
275 }
276
277 static const struct file_operations monwrite_fops = {
278 .owner = THIS_MODULE,
279 .open = &monwrite_open,
280 .release = &monwrite_close,
281 .write = &monwrite_write,
282 .llseek = noop_llseek,
283 };
284
285 static struct miscdevice mon_dev = {
286 .name = "monwriter",
287 .fops = &monwrite_fops,
288 .minor = MISC_DYNAMIC_MINOR,
289 };
290
291 /*
292 * module init/exit
293 */
294
mon_init(void)295 static int __init mon_init(void)
296 {
297 if (!machine_is_vm())
298 return -ENODEV;
299 /*
300 * misc_register() has to be the last action in module_init(), because
301 * file operations will be available right after this.
302 */
303 return misc_register(&mon_dev);
304 }
305
mon_exit(void)306 static void __exit mon_exit(void)
307 {
308 misc_deregister(&mon_dev);
309 }
310
311 module_init(mon_init);
312 module_exit(mon_exit);
313
314 module_param_named(max_bufs, mon_max_bufs, int, 0644);
315 MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
316 "that can be active at one time");
317
318 MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
319 MODULE_DESCRIPTION("Character device driver for writing z/VM "
320 "APPLDATA monitor records.");
321 MODULE_LICENSE("GPL");
322