linux/drivers/s390/char/monwriter.c
<<
>>
Prefs
   1/*
   2 * Character device driver for writing z/VM *MONITOR service records.
   3 *
   4 * Copyright IBM Corp. 2006, 2009
   5 *
   6 * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com>
   7 */
   8
   9#define KMSG_COMPONENT "monwriter"
  10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  11
  12#include <linux/module.h>
  13#include <linux/moduleparam.h>
  14#include <linux/init.h>
  15#include <linux/errno.h>
  16#include <linux/smp_lock.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 <asm/uaccess.h>
  25#include <asm/ebcdic.h>
  26#include <asm/io.h>
  27#include <asm/appldata.h>
  28#include <asm/monwriter.h>
  29
  30#define MONWRITE_MAX_DATALEN    4010
  31
  32static int mon_max_bufs = 255;
  33static int mon_buf_count;
  34
  35struct mon_buf {
  36        struct list_head list;
  37        struct monwrite_hdr hdr;
  38        int diag_done;
  39        char *data;
  40};
  41
  42static LIST_HEAD(mon_priv_list);
  43
  44struct mon_private {
  45        struct list_head priv_list;
  46        struct list_head list;
  47        struct monwrite_hdr hdr;
  48        size_t hdr_to_read;
  49        size_t data_to_read;
  50        struct mon_buf *current_buf;
  51        struct mutex thread_mutex;
  52};
  53
  54/*
  55 * helper functions
  56 */
  57
  58static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
  59{
  60        struct appldata_product_id id;
  61        int rc;
  62
  63        strcpy(id.prod_nr, "LNXAPPL");
  64        id.prod_fn = myhdr->applid;
  65        id.record_nr = myhdr->record_num;
  66        id.version_nr = myhdr->version;
  67        id.release_nr = myhdr->release;
  68        id.mod_lvl = myhdr->mod_level;
  69        rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
  70        if (rc <= 0)
  71                return rc;
  72        pr_err("Writing monitor data failed with rc=%i\n", rc);
  73        if (rc == 5)
  74                return -EPERM;
  75        return -EINVAL;
  76}
  77
  78static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
  79                                         struct monwrite_hdr *monhdr)
  80{
  81        struct mon_buf *entry, *next;
  82
  83        list_for_each_entry_safe(entry, next, &monpriv->list, list)
  84                if ((entry->hdr.mon_function == monhdr->mon_function ||
  85                     monhdr->mon_function == MONWRITE_STOP_INTERVAL) &&
  86                    entry->hdr.applid == monhdr->applid &&
  87                    entry->hdr.record_num == monhdr->record_num &&
  88                    entry->hdr.version == monhdr->version &&
  89                    entry->hdr.release == monhdr->release &&
  90                    entry->hdr.mod_level == monhdr->mod_level)
  91                        return entry;
  92
  93        return NULL;
  94}
  95
  96static int monwrite_new_hdr(struct mon_private *monpriv)
  97{
  98        struct monwrite_hdr *monhdr = &monpriv->hdr;
  99        struct mon_buf *monbuf;
 100        int rc;
 101
 102        if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
 103            monhdr->mon_function > MONWRITE_START_CONFIG ||
 104            monhdr->hdrlen != sizeof(struct monwrite_hdr))
 105                return -EINVAL;
 106        monbuf = NULL;
 107        if (monhdr->mon_function != MONWRITE_GEN_EVENT)
 108                monbuf = monwrite_find_hdr(monpriv, monhdr);
 109        if (monbuf) {
 110                if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) {
 111                        monhdr->datalen = monbuf->hdr.datalen;
 112                        rc = monwrite_diag(monhdr, monbuf->data,
 113                                           APPLDATA_STOP_REC);
 114                        list_del(&monbuf->list);
 115                        mon_buf_count--;
 116                        kfree(monbuf->data);
 117                        kfree(monbuf);
 118                        monbuf = NULL;
 119                }
 120        } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) {
 121                if (mon_buf_count >= mon_max_bufs)
 122                        return -ENOSPC;
 123                monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL);
 124                if (!monbuf)
 125                        return -ENOMEM;
 126                monbuf->data = kzalloc(monhdr->datalen,
 127                                       GFP_KERNEL | GFP_DMA);
 128                if (!monbuf->data) {
 129                        kfree(monbuf);
 130                        return -ENOMEM;
 131                }
 132                monbuf->hdr = *monhdr;
 133                list_add_tail(&monbuf->list, &monpriv->list);
 134                if (monhdr->mon_function != MONWRITE_GEN_EVENT)
 135                        mon_buf_count++;
 136        }
 137        monpriv->current_buf = monbuf;
 138        return 0;
 139}
 140
 141static int monwrite_new_data(struct mon_private *monpriv)
 142{
 143        struct monwrite_hdr *monhdr = &monpriv->hdr;
 144        struct mon_buf *monbuf = monpriv->current_buf;
 145        int rc = 0;
 146
 147        switch (monhdr->mon_function) {
 148        case MONWRITE_START_INTERVAL:
 149                if (!monbuf->diag_done) {
 150                        rc = monwrite_diag(monhdr, monbuf->data,
 151                                           APPLDATA_START_INTERVAL_REC);
 152                        monbuf->diag_done = 1;
 153                }
 154                break;
 155        case MONWRITE_START_CONFIG:
 156                if (!monbuf->diag_done) {
 157                        rc = monwrite_diag(monhdr, monbuf->data,
 158                                           APPLDATA_START_CONFIG_REC);
 159                        monbuf->diag_done = 1;
 160                }
 161                break;
 162        case MONWRITE_GEN_EVENT:
 163                rc = monwrite_diag(monhdr, monbuf->data,
 164                                   APPLDATA_GEN_EVENT_REC);
 165                list_del(&monpriv->current_buf->list);
 166                kfree(monpriv->current_buf->data);
 167                kfree(monpriv->current_buf);
 168                monpriv->current_buf = NULL;
 169                break;
 170        default:
 171                /* monhdr->mon_function is checked in monwrite_new_hdr */
 172                BUG();
 173        }
 174        return rc;
 175}
 176
 177/*
 178 * file operations
 179 */
 180
 181static int monwrite_open(struct inode *inode, struct file *filp)
 182{
 183        struct mon_private *monpriv;
 184
 185        monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
 186        if (!monpriv)
 187                return -ENOMEM;
 188        lock_kernel();
 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        unlock_kernel();
 195        return nonseekable_open(inode, filp);
 196}
 197
 198static int monwrite_close(struct inode *inode, struct file *filp)
 199{
 200        struct mon_private *monpriv = filp->private_data;
 201        struct mon_buf *entry, *next;
 202
 203        list_for_each_entry_safe(entry, next, &monpriv->list, list) {
 204                if (entry->hdr.mon_function != MONWRITE_GEN_EVENT)
 205                        monwrite_diag(&entry->hdr, entry->data,
 206                                      APPLDATA_STOP_REC);
 207                mon_buf_count--;
 208                list_del(&entry->list);
 209                kfree(entry->data);
 210                kfree(entry);
 211        }
 212        list_del(&monpriv->priv_list);
 213        kfree(monpriv);
 214        return 0;
 215}
 216
 217static ssize_t monwrite_write(struct file *filp, const char __user *data,
 218                              size_t count, loff_t *ppos)
 219{
 220        struct mon_private *monpriv = filp->private_data;
 221        size_t len, written;
 222        void *to;
 223        int rc;
 224
 225        mutex_lock(&monpriv->thread_mutex);
 226        for (written = 0; written < count; ) {
 227                if (monpriv->hdr_to_read) {
 228                        len = min(count - written, monpriv->hdr_to_read);
 229                        to = (char *) &monpriv->hdr +
 230                                sizeof(monpriv->hdr) - monpriv->hdr_to_read;
 231                        if (copy_from_user(to, data + written, len)) {
 232                                rc = -EFAULT;
 233                                goto out_error;
 234                        }
 235                        monpriv->hdr_to_read -= len;
 236                        written += len;
 237                        if (monpriv->hdr_to_read > 0)
 238                                continue;
 239                        rc = monwrite_new_hdr(monpriv);
 240                        if (rc)
 241                                goto out_error;
 242                        monpriv->data_to_read = monpriv->current_buf ?
 243                                monpriv->current_buf->hdr.datalen : 0;
 244                }
 245
 246                if (monpriv->data_to_read) {
 247                        len = min(count - written, monpriv->data_to_read);
 248                        to = monpriv->current_buf->data +
 249                                monpriv->hdr.datalen - monpriv->data_to_read;
 250                        if (copy_from_user(to, data + written, len)) {
 251                                rc = -EFAULT;
 252                                goto out_error;
 253                        }
 254                        monpriv->data_to_read -= len;
 255                        written += len;
 256                        if (monpriv->data_to_read > 0)
 257                                continue;
 258                        rc = monwrite_new_data(monpriv);
 259                        if (rc)
 260                                goto out_error;
 261                }
 262                monpriv->hdr_to_read = sizeof(monpriv->hdr);
 263        }
 264        mutex_unlock(&monpriv->thread_mutex);
 265        return written;
 266
 267out_error:
 268        monpriv->data_to_read = 0;
 269        monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
 270        mutex_unlock(&monpriv->thread_mutex);
 271        return rc;
 272}
 273
 274static const struct file_operations monwrite_fops = {
 275        .owner   = THIS_MODULE,
 276        .open    = &monwrite_open,
 277        .release = &monwrite_close,
 278        .write   = &monwrite_write,
 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 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                .owner  = THIS_MODULE,
 339                .pm     = &monwriter_pm_ops,
 340        },
 341};
 342
 343static struct platform_device *monwriter_pdev;
 344
 345/*
 346 * module init/exit
 347 */
 348
 349static int __init mon_init(void)
 350{
 351        int rc;
 352
 353        if (!MACHINE_IS_VM)
 354                return -ENODEV;
 355
 356        rc = platform_driver_register(&monwriter_pdrv);
 357        if (rc)
 358                return rc;
 359
 360        monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL,
 361                                                        0);
 362        if (IS_ERR(monwriter_pdev)) {
 363                rc = PTR_ERR(monwriter_pdev);
 364                goto out_driver;
 365        }
 366
 367        rc = misc_register(&mon_dev);
 368        if (rc)
 369                goto out_device;
 370        return 0;
 371
 372out_device:
 373        platform_device_unregister(monwriter_pdev);
 374out_driver:
 375        platform_driver_unregister(&monwriter_pdrv);
 376        return rc;
 377}
 378
 379static void __exit mon_exit(void)
 380{
 381        WARN_ON(misc_deregister(&mon_dev) != 0);
 382        platform_device_unregister(monwriter_pdev);
 383        platform_driver_unregister(&monwriter_pdrv);
 384}
 385
 386module_init(mon_init);
 387module_exit(mon_exit);
 388
 389module_param_named(max_bufs, mon_max_bufs, int, 0644);
 390MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
 391                 "that can be active at one time");
 392
 393MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
 394MODULE_DESCRIPTION("Character device driver for writing z/VM "
 395                   "APPLDATA monitor records.");
 396MODULE_LICENSE("GPL");
 397