Merge remote-tracking branches 'asoc/topic/cs42l73', 'asoc/topic/cs47l24', 'asoc...
[sfrench/cifs-2.6.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_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");