root/drivers/s390/char/monwriter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. monwrite_diag
  2. monwrite_find_hdr
  3. monwrite_new_hdr
  4. monwrite_new_data
  5. monwrite_open
  6. monwrite_close
  7. monwrite_write
  8. monwriter_freeze
  9. monwriter_restore
  10. monwriter_thaw
  11. mon_init
  12. mon_exit

   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");

/* [<][>][^][v][top][bottom][index][help] */