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