xref: /openbmc/linux/drivers/s390/char/monwriter.c (revision 2359ccdd)
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/platform_device.h>
24 #include <linux/slab.h>
25 #include <linux/uaccess.h>
26 #include <asm/ebcdic.h>
27 #include <asm/io.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 static LIST_HEAD(mon_priv_list);
44 
45 struct mon_private {
46 	struct list_head priv_list;
47 	struct list_head list;
48 	struct monwrite_hdr hdr;
49 	size_t hdr_to_read;
50 	size_t data_to_read;
51 	struct mon_buf *current_buf;
52 	struct mutex thread_mutex;
53 };
54 
55 /*
56  * helper functions
57  */
58 
59 static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
60 {
61 	struct appldata_product_id id;
62 	int rc;
63 
64 	strncpy(id.prod_nr, "LNXAPPL", 7);
65 	id.prod_fn = myhdr->applid;
66 	id.record_nr = myhdr->record_num;
67 	id.version_nr = myhdr->version;
68 	id.release_nr = myhdr->release;
69 	id.mod_lvl = myhdr->mod_level;
70 	rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
71 	if (rc <= 0)
72 		return rc;
73 	pr_err("Writing monitor data failed with rc=%i\n", rc);
74 	if (rc == 5)
75 		return -EPERM;
76 	return -EINVAL;
77 }
78 
79 static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
80 					 struct monwrite_hdr *monhdr)
81 {
82 	struct mon_buf *entry, *next;
83 
84 	list_for_each_entry_safe(entry, next, &monpriv->list, list)
85 		if ((entry->hdr.mon_function == monhdr->mon_function ||
86 		     monhdr->mon_function == MONWRITE_STOP_INTERVAL) &&
87 		    entry->hdr.applid == monhdr->applid &&
88 		    entry->hdr.record_num == monhdr->record_num &&
89 		    entry->hdr.version == monhdr->version &&
90 		    entry->hdr.release == monhdr->release &&
91 		    entry->hdr.mod_level == monhdr->mod_level)
92 			return entry;
93 
94 	return NULL;
95 }
96 
97 static int monwrite_new_hdr(struct mon_private *monpriv)
98 {
99 	struct monwrite_hdr *monhdr = &monpriv->hdr;
100 	struct mon_buf *monbuf;
101 	int rc = 0;
102 
103 	if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
104 	    monhdr->mon_function > MONWRITE_START_CONFIG ||
105 	    monhdr->hdrlen != sizeof(struct monwrite_hdr))
106 		return -EINVAL;
107 	monbuf = NULL;
108 	if (monhdr->mon_function != MONWRITE_GEN_EVENT)
109 		monbuf = monwrite_find_hdr(monpriv, monhdr);
110 	if (monbuf) {
111 		if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) {
112 			monhdr->datalen = monbuf->hdr.datalen;
113 			rc = monwrite_diag(monhdr, monbuf->data,
114 					   APPLDATA_STOP_REC);
115 			list_del(&monbuf->list);
116 			mon_buf_count--;
117 			kfree(monbuf->data);
118 			kfree(monbuf);
119 			monbuf = NULL;
120 		}
121 	} else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) {
122 		if (mon_buf_count >= mon_max_bufs)
123 			return -ENOSPC;
124 		monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL);
125 		if (!monbuf)
126 			return -ENOMEM;
127 		monbuf->data = kzalloc(monhdr->datalen,
128 				       GFP_KERNEL | GFP_DMA);
129 		if (!monbuf->data) {
130 			kfree(monbuf);
131 			return -ENOMEM;
132 		}
133 		monbuf->hdr = *monhdr;
134 		list_add_tail(&monbuf->list, &monpriv->list);
135 		if (monhdr->mon_function != MONWRITE_GEN_EVENT)
136 			mon_buf_count++;
137 	}
138 	monpriv->current_buf = monbuf;
139 	return rc;
140 }
141 
142 static int monwrite_new_data(struct mon_private *monpriv)
143 {
144 	struct monwrite_hdr *monhdr = &monpriv->hdr;
145 	struct mon_buf *monbuf = monpriv->current_buf;
146 	int rc = 0;
147 
148 	switch (monhdr->mon_function) {
149 	case MONWRITE_START_INTERVAL:
150 		if (!monbuf->diag_done) {
151 			rc = monwrite_diag(monhdr, monbuf->data,
152 					   APPLDATA_START_INTERVAL_REC);
153 			monbuf->diag_done = 1;
154 		}
155 		break;
156 	case MONWRITE_START_CONFIG:
157 		if (!monbuf->diag_done) {
158 			rc = monwrite_diag(monhdr, monbuf->data,
159 					   APPLDATA_START_CONFIG_REC);
160 			monbuf->diag_done = 1;
161 		}
162 		break;
163 	case MONWRITE_GEN_EVENT:
164 		rc = monwrite_diag(monhdr, monbuf->data,
165 				   APPLDATA_GEN_EVENT_REC);
166 		list_del(&monpriv->current_buf->list);
167 		kfree(monpriv->current_buf->data);
168 		kfree(monpriv->current_buf);
169 		monpriv->current_buf = NULL;
170 		break;
171 	default:
172 		/* monhdr->mon_function is checked in monwrite_new_hdr */
173 		BUG();
174 	}
175 	return rc;
176 }
177 
178 /*
179  * file operations
180  */
181 
182 static int monwrite_open(struct inode *inode, struct file *filp)
183 {
184 	struct mon_private *monpriv;
185 
186 	monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
187 	if (!monpriv)
188 		return -ENOMEM;
189 	INIT_LIST_HEAD(&monpriv->list);
190 	monpriv->hdr_to_read = sizeof(monpriv->hdr);
191 	mutex_init(&monpriv->thread_mutex);
192 	filp->private_data = monpriv;
193 	list_add_tail(&monpriv->priv_list, &mon_priv_list);
194 	return nonseekable_open(inode, filp);
195 }
196 
197 static int monwrite_close(struct inode *inode, struct file *filp)
198 {
199 	struct mon_private *monpriv = filp->private_data;
200 	struct mon_buf *entry, *next;
201 
202 	list_for_each_entry_safe(entry, next, &monpriv->list, list) {
203 		if (entry->hdr.mon_function != MONWRITE_GEN_EVENT)
204 			monwrite_diag(&entry->hdr, entry->data,
205 				      APPLDATA_STOP_REC);
206 		mon_buf_count--;
207 		list_del(&entry->list);
208 		kfree(entry->data);
209 		kfree(entry);
210 	}
211 	list_del(&monpriv->priv_list);
212 	kfree(monpriv);
213 	return 0;
214 }
215 
216 static ssize_t monwrite_write(struct file *filp, const char __user *data,
217 			      size_t count, loff_t *ppos)
218 {
219 	struct mon_private *monpriv = filp->private_data;
220 	size_t len, written;
221 	void *to;
222 	int rc;
223 
224 	mutex_lock(&monpriv->thread_mutex);
225 	for (written = 0; written < count; ) {
226 		if (monpriv->hdr_to_read) {
227 			len = min(count - written, monpriv->hdr_to_read);
228 			to = (char *) &monpriv->hdr +
229 				sizeof(monpriv->hdr) - monpriv->hdr_to_read;
230 			if (copy_from_user(to, data + written, len)) {
231 				rc = -EFAULT;
232 				goto out_error;
233 			}
234 			monpriv->hdr_to_read -= len;
235 			written += len;
236 			if (monpriv->hdr_to_read > 0)
237 				continue;
238 			rc = monwrite_new_hdr(monpriv);
239 			if (rc)
240 				goto out_error;
241 			monpriv->data_to_read = monpriv->current_buf ?
242 				monpriv->current_buf->hdr.datalen : 0;
243 		}
244 
245 		if (monpriv->data_to_read) {
246 			len = min(count - written, monpriv->data_to_read);
247 			to = monpriv->current_buf->data +
248 				monpriv->hdr.datalen - monpriv->data_to_read;
249 			if (copy_from_user(to, data + written, len)) {
250 				rc = -EFAULT;
251 				goto out_error;
252 			}
253 			monpriv->data_to_read -= len;
254 			written += len;
255 			if (monpriv->data_to_read > 0)
256 				continue;
257 			rc = monwrite_new_data(monpriv);
258 			if (rc)
259 				goto out_error;
260 		}
261 		monpriv->hdr_to_read = sizeof(monpriv->hdr);
262 	}
263 	mutex_unlock(&monpriv->thread_mutex);
264 	return written;
265 
266 out_error:
267 	monpriv->data_to_read = 0;
268 	monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
269 	mutex_unlock(&monpriv->thread_mutex);
270 	return rc;
271 }
272 
273 static const struct file_operations monwrite_fops = {
274 	.owner	 = THIS_MODULE,
275 	.open	 = &monwrite_open,
276 	.release = &monwrite_close,
277 	.write	 = &monwrite_write,
278 	.llseek  = noop_llseek,
279 };
280 
281 static struct miscdevice mon_dev = {
282 	.name	= "monwriter",
283 	.fops	= &monwrite_fops,
284 	.minor	= MISC_DYNAMIC_MINOR,
285 };
286 
287 /*
288  * suspend/resume
289  */
290 
291 static int monwriter_freeze(struct device *dev)
292 {
293 	struct mon_private *monpriv;
294 	struct mon_buf *monbuf;
295 
296 	list_for_each_entry(monpriv, &mon_priv_list, priv_list) {
297 		list_for_each_entry(monbuf, &monpriv->list, list) {
298 			if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT)
299 				monwrite_diag(&monbuf->hdr, monbuf->data,
300 					      APPLDATA_STOP_REC);
301 		}
302 	}
303 	return 0;
304 }
305 
306 static int monwriter_restore(struct device *dev)
307 {
308 	struct mon_private *monpriv;
309 	struct mon_buf *monbuf;
310 
311 	list_for_each_entry(monpriv, &mon_priv_list, priv_list) {
312 		list_for_each_entry(monbuf, &monpriv->list, list) {
313 			if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL)
314 				monwrite_diag(&monbuf->hdr, monbuf->data,
315 					      APPLDATA_START_INTERVAL_REC);
316 			if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG)
317 				monwrite_diag(&monbuf->hdr, monbuf->data,
318 					      APPLDATA_START_CONFIG_REC);
319 		}
320 	}
321 	return 0;
322 }
323 
324 static int monwriter_thaw(struct device *dev)
325 {
326 	return monwriter_restore(dev);
327 }
328 
329 static const struct dev_pm_ops monwriter_pm_ops = {
330 	.freeze		= monwriter_freeze,
331 	.thaw		= monwriter_thaw,
332 	.restore	= monwriter_restore,
333 };
334 
335 static struct platform_driver monwriter_pdrv = {
336 	.driver = {
337 		.name	= "monwriter",
338 		.pm	= &monwriter_pm_ops,
339 	},
340 };
341 
342 static struct platform_device *monwriter_pdev;
343 
344 /*
345  * module init/exit
346  */
347 
348 static int __init mon_init(void)
349 {
350 	int rc;
351 
352 	if (!MACHINE_IS_VM)
353 		return -ENODEV;
354 
355 	rc = platform_driver_register(&monwriter_pdrv);
356 	if (rc)
357 		return rc;
358 
359 	monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL,
360 							0);
361 	if (IS_ERR(monwriter_pdev)) {
362 		rc = PTR_ERR(monwriter_pdev);
363 		goto out_driver;
364 	}
365 
366 	/*
367 	 * misc_register() has to be the last action in module_init(), because
368 	 * file operations will be available right after this.
369 	 */
370 	rc = misc_register(&mon_dev);
371 	if (rc)
372 		goto out_device;
373 	return 0;
374 
375 out_device:
376 	platform_device_unregister(monwriter_pdev);
377 out_driver:
378 	platform_driver_unregister(&monwriter_pdrv);
379 	return rc;
380 }
381 
382 static void __exit mon_exit(void)
383 {
384 	misc_deregister(&mon_dev);
385 	platform_device_unregister(monwriter_pdev);
386 	platform_driver_unregister(&monwriter_pdrv);
387 }
388 
389 module_init(mon_init);
390 module_exit(mon_exit);
391 
392 module_param_named(max_bufs, mon_max_bufs, int, 0644);
393 MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
394 		 "that can be active at one time");
395 
396 MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
397 MODULE_DESCRIPTION("Character device driver for writing z/VM "
398 		   "APPLDATA monitor records.");
399 MODULE_LICENSE("GPL");
400