linux/drivers/s390/char/monwriter.c
<<
>>
Prefs
   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
  33static int mon_max_bufs = 255;
  34static int mon_buf_count;
  35
  36struct mon_buf {
  37        struct list_head list;
  38        struct monwrite_hdr hdr;
  39        int diag_done;
  40        char *data;
  41};
  42
  43static LIST_HEAD(mon_priv_list);
  44
  45struct 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
  59static 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
  79static 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
  97static 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
 142static 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
 182static 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
 197static 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
 216static 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
 266out_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
 273static 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
 281static struct miscdevice mon_dev = {
 282        .name   = "monwriter",
 283        .fops   = &monwrite_fops,
 284        .minor  = MISC_DYNAMIC_MINOR,
 285};
 286
 287/*
 288 * suspend/resume
 289 */
 290
 291static 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
 306static 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
 324static int monwriter_thaw(struct device *dev)
 325{
 326        return monwriter_restore(dev);
 327}
 328
 329static const struct dev_pm_ops monwriter_pm_ops = {
 330        .freeze         = monwriter_freeze,
 331        .thaw           = monwriter_thaw,
 332        .restore        = monwriter_restore,
 333};
 334
 335static struct platform_driver monwriter_pdrv = {
 336        .driver = {
 337                .name   = "monwriter",
 338                .pm     = &monwriter_pm_ops,
 339        },
 340};
 341
 342static struct platform_device *monwriter_pdev;
 343
 344/*
 345 * module init/exit
 346 */
 347
 348static 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
 375out_device:
 376        platform_device_unregister(monwriter_pdev);
 377out_driver:
 378        platform_driver_unregister(&monwriter_pdrv);
 379        return rc;
 380}
 381
 382static 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
 389module_init(mon_init);
 390module_exit(mon_exit);
 391
 392module_param_named(max_bufs, mon_max_bufs, int, 0644);
 393MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
 394                 "that can be active at one time");
 395
 396MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
 397MODULE_DESCRIPTION("Character device driver for writing z/VM "
 398                   "APPLDATA monitor records.");
 399MODULE_LICENSE("GPL");
 400