Loading drivers/s390/char/monreader.c +128 −12 Original line number Diff line number Diff line /* * drivers/s390/char/monreader.c * * Character device driver for reading z/VM *MONITOR service records. * * Copyright IBM Corp. 2004, 2008 * Copyright IBM Corp. 2004, 2009 * * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> */ Loading @@ -22,6 +21,7 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/poll.h> #include <linux/device.h> #include <net/iucv/iucv.h> #include <asm/uaccess.h> #include <asm/ebcdic.h> Loading Loading @@ -78,6 +78,7 @@ static u8 user_data_sever[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; static struct device *monreader_device; /****************************************************************************** * helper functions * Loading Loading @@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp) goto out_path; } filp->private_data = monpriv; monreader_device->driver_data = monpriv; unlock_kernel(); return nonseekable_open(inode, filp); out_path: kfree(monpriv->path); iucv_path_free(monpriv->path); out_priv: mon_free_mem(monpriv); out_use: Loading @@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp) /* * Close IUCV connection and unregister */ if (monpriv->path) { rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) pr_warning("Disconnecting the z/VM *MONITOR system service " "failed with rc=%i\n", rc); pr_warning("Disconnecting the z/VM *MONITOR system " "service failed with rc=%i\n", rc); iucv_path_free(monpriv->path); } atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); Loading Loading @@ -452,6 +457,94 @@ static struct miscdevice mon_dev = { .minor = MISC_DYNAMIC_MINOR, }; /****************************************************************************** * suspend / resume * *****************************************************************************/ static int monreader_freeze(struct device *dev) { struct mon_private *monpriv = dev->driver_data; int rc; if (!monpriv) return 0; if (monpriv->path) { rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) pr_warning("Disconnecting the z/VM *MONITOR system " "service failed with rc=%i\n", rc); iucv_path_free(monpriv->path); } atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); atomic_set(&monpriv->read_ready, 0); atomic_set(&monpriv->msglim_count, 0); monpriv->write_index = 0; monpriv->read_index = 0; monpriv->path = NULL; return 0; } static int monreader_thaw(struct device *dev) { struct mon_private *monpriv = dev->driver_data; int rc; if (!monpriv) return 0; rc = -ENOMEM; monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); if (!monpriv->path) goto out; rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, MON_SERVICE, NULL, user_data_connect, monpriv); if (rc) { pr_err("Connecting to the z/VM *MONITOR system service " "failed with rc=%i\n", rc); goto out_path; } wait_event(mon_conn_wait_queue, atomic_read(&monpriv->iucv_connected) || atomic_read(&monpriv->iucv_severed)); if (atomic_read(&monpriv->iucv_severed)) goto out_path; return 0; out_path: rc = -EIO; iucv_path_free(monpriv->path); monpriv->path = NULL; out: atomic_set(&monpriv->iucv_severed, 1); return rc; } static int monreader_restore(struct device *dev) { int rc; segment_unload(mon_dcss_name); rc = segment_load(mon_dcss_name, SEGMENT_SHARED, &mon_dcss_start, &mon_dcss_end); if (rc < 0) { segment_warning(rc, mon_dcss_name); panic("fatal monreader resume error: no monitor dcss\n"); } return monreader_thaw(dev); } static struct dev_pm_ops monreader_pm_ops = { .freeze = monreader_freeze, .thaw = monreader_thaw, .restore = monreader_restore, }; static struct device_driver monreader_driver = { .name = "monreader", .bus = &iucv_bus, .pm = &monreader_pm_ops, }; /****************************************************************************** * module init/exit * *****************************************************************************/ Loading @@ -475,16 +568,33 @@ static int __init mon_init(void) return rc; } rc = driver_register(&monreader_driver); if (rc) goto out_iucv; monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); if (!monreader_device) goto out_driver; dev_set_name(monreader_device, "monreader-dev"); monreader_device->bus = &iucv_bus; monreader_device->parent = iucv_root; monreader_device->driver = &monreader_driver; monreader_device->release = (void (*)(struct device *))kfree; rc = device_register(monreader_device); if (rc) { kfree(monreader_device); goto out_driver; } rc = segment_type(mon_dcss_name); if (rc < 0) { segment_warning(rc, mon_dcss_name); goto out_iucv; goto out_device; } if (rc != SEG_TYPE_SC) { pr_err("The specified *MONITOR DCSS %s does not have the " "required type SC\n", mon_dcss_name); rc = -EINVAL; goto out_iucv; goto out_device; } rc = segment_load(mon_dcss_name, SEGMENT_SHARED, Loading @@ -492,7 +602,7 @@ static int __init mon_init(void) if (rc < 0) { segment_warning(rc, mon_dcss_name); rc = -EINVAL; goto out_iucv; goto out_device; } dcss_mkname(mon_dcss_name, &user_data_connect[8]); Loading @@ -503,6 +613,10 @@ static int __init mon_init(void) out: segment_unload(mon_dcss_name); out_device: device_unregister(monreader_device); out_driver: driver_unregister(&monreader_driver); out_iucv: iucv_unregister(&monreader_iucv_handler, 1); return rc; Loading @@ -512,6 +626,8 @@ static void __exit mon_exit(void) { segment_unload(mon_dcss_name); WARN_ON(misc_deregister(&mon_dev) != 0); device_unregister(monreader_device); driver_unregister(&monreader_driver); iucv_unregister(&monreader_iucv_handler, 1); return; } Loading Loading
drivers/s390/char/monreader.c +128 −12 Original line number Diff line number Diff line /* * drivers/s390/char/monreader.c * * Character device driver for reading z/VM *MONITOR service records. * * Copyright IBM Corp. 2004, 2008 * Copyright IBM Corp. 2004, 2009 * * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> */ Loading @@ -22,6 +21,7 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/poll.h> #include <linux/device.h> #include <net/iucv/iucv.h> #include <asm/uaccess.h> #include <asm/ebcdic.h> Loading Loading @@ -78,6 +78,7 @@ static u8 user_data_sever[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; static struct device *monreader_device; /****************************************************************************** * helper functions * Loading Loading @@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp) goto out_path; } filp->private_data = monpriv; monreader_device->driver_data = monpriv; unlock_kernel(); return nonseekable_open(inode, filp); out_path: kfree(monpriv->path); iucv_path_free(monpriv->path); out_priv: mon_free_mem(monpriv); out_use: Loading @@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp) /* * Close IUCV connection and unregister */ if (monpriv->path) { rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) pr_warning("Disconnecting the z/VM *MONITOR system service " "failed with rc=%i\n", rc); pr_warning("Disconnecting the z/VM *MONITOR system " "service failed with rc=%i\n", rc); iucv_path_free(monpriv->path); } atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); Loading Loading @@ -452,6 +457,94 @@ static struct miscdevice mon_dev = { .minor = MISC_DYNAMIC_MINOR, }; /****************************************************************************** * suspend / resume * *****************************************************************************/ static int monreader_freeze(struct device *dev) { struct mon_private *monpriv = dev->driver_data; int rc; if (!monpriv) return 0; if (monpriv->path) { rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) pr_warning("Disconnecting the z/VM *MONITOR system " "service failed with rc=%i\n", rc); iucv_path_free(monpriv->path); } atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); atomic_set(&monpriv->read_ready, 0); atomic_set(&monpriv->msglim_count, 0); monpriv->write_index = 0; monpriv->read_index = 0; monpriv->path = NULL; return 0; } static int monreader_thaw(struct device *dev) { struct mon_private *monpriv = dev->driver_data; int rc; if (!monpriv) return 0; rc = -ENOMEM; monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); if (!monpriv->path) goto out; rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, MON_SERVICE, NULL, user_data_connect, monpriv); if (rc) { pr_err("Connecting to the z/VM *MONITOR system service " "failed with rc=%i\n", rc); goto out_path; } wait_event(mon_conn_wait_queue, atomic_read(&monpriv->iucv_connected) || atomic_read(&monpriv->iucv_severed)); if (atomic_read(&monpriv->iucv_severed)) goto out_path; return 0; out_path: rc = -EIO; iucv_path_free(monpriv->path); monpriv->path = NULL; out: atomic_set(&monpriv->iucv_severed, 1); return rc; } static int monreader_restore(struct device *dev) { int rc; segment_unload(mon_dcss_name); rc = segment_load(mon_dcss_name, SEGMENT_SHARED, &mon_dcss_start, &mon_dcss_end); if (rc < 0) { segment_warning(rc, mon_dcss_name); panic("fatal monreader resume error: no monitor dcss\n"); } return monreader_thaw(dev); } static struct dev_pm_ops monreader_pm_ops = { .freeze = monreader_freeze, .thaw = monreader_thaw, .restore = monreader_restore, }; static struct device_driver monreader_driver = { .name = "monreader", .bus = &iucv_bus, .pm = &monreader_pm_ops, }; /****************************************************************************** * module init/exit * *****************************************************************************/ Loading @@ -475,16 +568,33 @@ static int __init mon_init(void) return rc; } rc = driver_register(&monreader_driver); if (rc) goto out_iucv; monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); if (!monreader_device) goto out_driver; dev_set_name(monreader_device, "monreader-dev"); monreader_device->bus = &iucv_bus; monreader_device->parent = iucv_root; monreader_device->driver = &monreader_driver; monreader_device->release = (void (*)(struct device *))kfree; rc = device_register(monreader_device); if (rc) { kfree(monreader_device); goto out_driver; } rc = segment_type(mon_dcss_name); if (rc < 0) { segment_warning(rc, mon_dcss_name); goto out_iucv; goto out_device; } if (rc != SEG_TYPE_SC) { pr_err("The specified *MONITOR DCSS %s does not have the " "required type SC\n", mon_dcss_name); rc = -EINVAL; goto out_iucv; goto out_device; } rc = segment_load(mon_dcss_name, SEGMENT_SHARED, Loading @@ -492,7 +602,7 @@ static int __init mon_init(void) if (rc < 0) { segment_warning(rc, mon_dcss_name); rc = -EINVAL; goto out_iucv; goto out_device; } dcss_mkname(mon_dcss_name, &user_data_connect[8]); Loading @@ -503,6 +613,10 @@ static int __init mon_init(void) out: segment_unload(mon_dcss_name); out_device: device_unregister(monreader_device); out_driver: driver_unregister(&monreader_driver); out_iucv: iucv_unregister(&monreader_iucv_handler, 1); return rc; Loading @@ -512,6 +626,8 @@ static void __exit mon_exit(void) { segment_unload(mon_dcss_name); WARN_ON(misc_deregister(&mon_dev) != 0); device_unregister(monreader_device); driver_unregister(&monreader_driver); iucv_unregister(&monreader_iucv_handler, 1); return; } Loading