aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/char/monreader.c140
1 files changed, 128 insertions, 12 deletions
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index 97e63cf46944..75a8831eebbc 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -1,10 +1,9 @@
1/* 1/*
2 * drivers/s390/char/monreader.c
3 *
4 * Character device driver for reading z/VM *MONITOR service records. 2 * Character device driver for reading z/VM *MONITOR service records.
5 * 3 *
6 * Copyright IBM Corp. 2004, 2008 4 * Copyright IBM Corp. 2004, 2009
7 * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> 5 *
6 * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
8 */ 7 */
9 8
10#define KMSG_COMPONENT "monreader" 9#define KMSG_COMPONENT "monreader"
@@ -22,6 +21,7 @@
22#include <linux/spinlock.h> 21#include <linux/spinlock.h>
23#include <linux/interrupt.h> 22#include <linux/interrupt.h>
24#include <linux/poll.h> 23#include <linux/poll.h>
24#include <linux/device.h>
25#include <net/iucv/iucv.h> 25#include <net/iucv/iucv.h>
26#include <asm/uaccess.h> 26#include <asm/uaccess.h>
27#include <asm/ebcdic.h> 27#include <asm/ebcdic.h>
@@ -78,6 +78,7 @@ static u8 user_data_sever[16] = {
78 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 78 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
79}; 79};
80 80
81static struct device *monreader_device;
81 82
82/****************************************************************************** 83/******************************************************************************
83 * helper functions * 84 * helper functions *
@@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp)
319 goto out_path; 320 goto out_path;
320 } 321 }
321 filp->private_data = monpriv; 322 filp->private_data = monpriv;
323 monreader_device->driver_data = monpriv;
322 unlock_kernel(); 324 unlock_kernel();
323 return nonseekable_open(inode, filp); 325 return nonseekable_open(inode, filp);
324 326
325out_path: 327out_path:
326 kfree(monpriv->path); 328 iucv_path_free(monpriv->path);
327out_priv: 329out_priv:
328 mon_free_mem(monpriv); 330 mon_free_mem(monpriv);
329out_use: 331out_use:
@@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp)
341 /* 343 /*
342 * Close IUCV connection and unregister 344 * Close IUCV connection and unregister
343 */ 345 */
344 rc = iucv_path_sever(monpriv->path, user_data_sever); 346 if (monpriv->path) {
345 if (rc) 347 rc = iucv_path_sever(monpriv->path, user_data_sever);
346 pr_warning("Disconnecting the z/VM *MONITOR system service " 348 if (rc)
347 "failed with rc=%i\n", rc); 349 pr_warning("Disconnecting the z/VM *MONITOR system "
350 "service failed with rc=%i\n", rc);
351 iucv_path_free(monpriv->path);
352 }
348 353
349 atomic_set(&monpriv->iucv_severed, 0); 354 atomic_set(&monpriv->iucv_severed, 0);
350 atomic_set(&monpriv->iucv_connected, 0); 355 atomic_set(&monpriv->iucv_connected, 0);
@@ -452,6 +457,94 @@ static struct miscdevice mon_dev = {
452 .minor = MISC_DYNAMIC_MINOR, 457 .minor = MISC_DYNAMIC_MINOR,
453}; 458};
454 459
460
461/******************************************************************************
462 * suspend / resume *
463 *****************************************************************************/
464static int monreader_freeze(struct device *dev)
465{
466 struct mon_private *monpriv = dev->driver_data;
467 int rc;
468
469 if (!monpriv)
470 return 0;
471 if (monpriv->path) {
472 rc = iucv_path_sever(monpriv->path, user_data_sever);
473 if (rc)
474 pr_warning("Disconnecting the z/VM *MONITOR system "
475 "service failed with rc=%i\n", rc);
476 iucv_path_free(monpriv->path);
477 }
478 atomic_set(&monpriv->iucv_severed, 0);
479 atomic_set(&monpriv->iucv_connected, 0);
480 atomic_set(&monpriv->read_ready, 0);
481 atomic_set(&monpriv->msglim_count, 0);
482 monpriv->write_index = 0;
483 monpriv->read_index = 0;
484 monpriv->path = NULL;
485 return 0;
486}
487
488static int monreader_thaw(struct device *dev)
489{
490 struct mon_private *monpriv = dev->driver_data;
491 int rc;
492
493 if (!monpriv)
494 return 0;
495 rc = -ENOMEM;
496 monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
497 if (!monpriv->path)
498 goto out;
499 rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
500 MON_SERVICE, NULL, user_data_connect, monpriv);
501 if (rc) {
502 pr_err("Connecting to the z/VM *MONITOR system service "
503 "failed with rc=%i\n", rc);
504 goto out_path;
505 }
506 wait_event(mon_conn_wait_queue,
507 atomic_read(&monpriv->iucv_connected) ||
508 atomic_read(&monpriv->iucv_severed));
509 if (atomic_read(&monpriv->iucv_severed))
510 goto out_path;
511 return 0;
512out_path:
513 rc = -EIO;
514 iucv_path_free(monpriv->path);
515 monpriv->path = NULL;
516out:
517 atomic_set(&monpriv->iucv_severed, 1);
518 return rc;
519}
520
521static int monreader_restore(struct device *dev)
522{
523 int rc;
524
525 segment_unload(mon_dcss_name);
526 rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
527 &mon_dcss_start, &mon_dcss_end);
528 if (rc < 0) {
529 segment_warning(rc, mon_dcss_name);
530 panic("fatal monreader resume error: no monitor dcss\n");
531 }
532 return monreader_thaw(dev);
533}
534
535static struct dev_pm_ops monreader_pm_ops = {
536 .freeze = monreader_freeze,
537 .thaw = monreader_thaw,
538 .restore = monreader_restore,
539};
540
541static struct device_driver monreader_driver = {
542 .name = "monreader",
543 .bus = &iucv_bus,
544 .pm = &monreader_pm_ops,
545};
546
547
455/****************************************************************************** 548/******************************************************************************
456 * module init/exit * 549 * module init/exit *
457 *****************************************************************************/ 550 *****************************************************************************/
@@ -475,16 +568,33 @@ static int __init mon_init(void)
475 return rc; 568 return rc;
476 } 569 }
477 570
571 rc = driver_register(&monreader_driver);
572 if (rc)
573 goto out_iucv;
574 monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL);
575 if (!monreader_device)
576 goto out_driver;
577 dev_set_name(monreader_device, "monreader-dev");
578 monreader_device->bus = &iucv_bus;
579 monreader_device->parent = iucv_root;
580 monreader_device->driver = &monreader_driver;
581 monreader_device->release = (void (*)(struct device *))kfree;
582 rc = device_register(monreader_device);
583 if (rc) {
584 kfree(monreader_device);
585 goto out_driver;
586 }
587
478 rc = segment_type(mon_dcss_name); 588 rc = segment_type(mon_dcss_name);
479 if (rc < 0) { 589 if (rc < 0) {
480 segment_warning(rc, mon_dcss_name); 590 segment_warning(rc, mon_dcss_name);
481 goto out_iucv; 591 goto out_device;
482 } 592 }
483 if (rc != SEG_TYPE_SC) { 593 if (rc != SEG_TYPE_SC) {
484 pr_err("The specified *MONITOR DCSS %s does not have the " 594 pr_err("The specified *MONITOR DCSS %s does not have the "
485 "required type SC\n", mon_dcss_name); 595 "required type SC\n", mon_dcss_name);
486 rc = -EINVAL; 596 rc = -EINVAL;
487 goto out_iucv; 597 goto out_device;
488 } 598 }
489 599
490 rc = segment_load(mon_dcss_name, SEGMENT_SHARED, 600 rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
@@ -492,7 +602,7 @@ static int __init mon_init(void)
492 if (rc < 0) { 602 if (rc < 0) {
493 segment_warning(rc, mon_dcss_name); 603 segment_warning(rc, mon_dcss_name);
494 rc = -EINVAL; 604 rc = -EINVAL;
495 goto out_iucv; 605 goto out_device;
496 } 606 }
497 dcss_mkname(mon_dcss_name, &user_data_connect[8]); 607 dcss_mkname(mon_dcss_name, &user_data_connect[8]);
498 608
@@ -503,6 +613,10 @@ static int __init mon_init(void)
503 613
504out: 614out:
505 segment_unload(mon_dcss_name); 615 segment_unload(mon_dcss_name);
616out_device:
617 device_unregister(monreader_device);
618out_driver:
619 driver_unregister(&monreader_driver);
506out_iucv: 620out_iucv:
507 iucv_unregister(&monreader_iucv_handler, 1); 621 iucv_unregister(&monreader_iucv_handler, 1);
508 return rc; 622 return rc;
@@ -512,6 +626,8 @@ static void __exit mon_exit(void)
512{ 626{
513 segment_unload(mon_dcss_name); 627 segment_unload(mon_dcss_name);
514 WARN_ON(misc_deregister(&mon_dev) != 0); 628 WARN_ON(misc_deregister(&mon_dev) != 0);
629 device_unregister(monreader_device);
630 driver_unregister(&monreader_driver);
515 iucv_unregister(&monreader_iucv_handler, 1); 631 iucv_unregister(&monreader_iucv_handler, 1);
516 return; 632 return;
517} 633}