[go: nahoru, domu]

11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Character device driver for reading z/VM *MONITOR service records.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
42b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer * Copyright IBM Corp. 2004, 2009
52b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer *
62b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer#define KMSG_COMPONENT "monreader"
10a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ctype.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
222ca5b6e288d02503cba5a6d3409cb9a0600e01ddGerald Schaefer#include <linux/poll.h>
232b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer#include <linux/device.h>
245a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
252ca5b6e288d02503cba5a6d3409cb9a0600e01ddGerald Schaefer#include <net/iucv/iucv.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/ebcdic.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/extmem.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MON_COLLECT_SAMPLE 0x80
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MON_COLLECT_EVENT  0x40
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MON_SERVICE	   "*MONITOR"
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MON_IN_USE	   0x01
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MON_MSGLIM	   255
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char mon_dcss_name[9] = "MONDCSS\0";
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mon_msg {
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pos;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 mca_offset;
42c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	struct iucv_message msg;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char msglim_reached;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char replied_msglim;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mon_private {
48c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	struct iucv_path *path;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mon_msg *msg_array[MON_MSGLIM];
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int   write_index;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int   read_index;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_t msglim_count;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_t read_ready;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_t iucv_connected;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_t iucv_severed;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long mon_in_use = 0;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long mon_dcss_start;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long mon_dcss_end;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 user_data_connect[16] = {
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Version code, must be 0x01 for shared mode */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x01,
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* what to collect */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MON_COLLECT_SAMPLE | MON_COLLECT_EVENT,
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DCSS name in EBCDIC, 8 bytes padded with blanks */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 user_data_sever[16] = {
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
812b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferstatic struct device *monreader_device;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************************************************************
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                             helper functions                               *
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create the 8 bytes EBCDIC DCSS segment name from
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an ASCII name, incl. padding
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
909b0c455a04d73d8ffa388a1006925620ad684ad8Martin Schwidefskystatic void dcss_mkname(char *ascii_name, char *ebcdic_name)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 8; i++) {
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ascii_name[i] == '\0')
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ebcdic_name[i] = toupper(ascii_name[i]);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; i < 8; i++)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ebcdic_name[i] = ' ';
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ASCEBC(ebcdic_name, 8);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
104c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic inline unsigned long mon_mca_start(struct mon_msg *monmsg)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
106c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	return *(u32 *) &monmsg->msg.rmmsg;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
109c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic inline unsigned long mon_mca_end(struct mon_msg *monmsg)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
111c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	return *(u32 *) &monmsg->msg.rmmsg[4];
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
114c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
119c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic inline u32 mon_mca_size(struct mon_msg *monmsg)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
124c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic inline u32 mon_rec_start(struct mon_msg *monmsg)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4));
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
129c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic inline u32 mon_rec_end(struct mon_msg *monmsg)
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1349b0c455a04d73d8ffa388a1006925620ad684ad8Martin Schwidefskystatic int mon_check_mca(struct mon_msg *monmsg)
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (mon_rec_start(monmsg) < mon_dcss_start) ||
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (mon_rec_end(monmsg) > mon_dcss_end) ||
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (mon_mca_type(monmsg, 0) == 0) ||
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (mon_mca_size(monmsg) % 12 != 0) ||
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (mon_mca_end(monmsg) <= mon_mca_start(monmsg)) ||
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (mon_mca_end(monmsg) > mon_dcss_end) ||
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (mon_mca_start(monmsg) < mon_dcss_start) ||
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0)))
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1499b0c455a04d73d8ffa388a1006925620ad684ad8Martin Schwidefskystatic int mon_send_reply(struct mon_msg *monmsg,
1509b0c455a04d73d8ffa388a1006925620ad684ad8Martin Schwidefsky			  struct mon_private *monpriv)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
154c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	rc = iucv_message_reply(monpriv->path, &monmsg->msg,
155c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky				IUCV_IPRMDATA, NULL, 0);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_dec(&monpriv->msglim_count);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(!monmsg->msglim_reached)) {
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->pos = 0;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->mca_offset = 0;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monpriv->read_index = (monpriv->read_index + 1) %
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      MON_MSGLIM;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_dec(&monpriv->read_ready);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->replied_msglim = 1;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
166a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		pr_err("Reading monitor data failed with rc=%i\n", rc);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1729b0c455a04d73d8ffa388a1006925620ad684ad8Martin Schwidefskystatic void mon_free_mem(struct mon_private *monpriv)
173c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky{
174c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	int i;
175c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky
176c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	for (i = 0; i < MON_MSGLIM; i++)
177a75a282d7238f6020957b14d8a14a1e851b9e1ddSyam Sidhardhan		kfree(monpriv->msg_array[i]);
178c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	kfree(monpriv);
179c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky}
180c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky
1819b0c455a04d73d8ffa388a1006925620ad684ad8Martin Schwidefskystatic struct mon_private *mon_alloc_mem(void)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
183c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	int i;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mon_private *monpriv;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18688abaab4f9b08381e30e737980a1c49d6b524dfcEric Sesterhenn	monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
1872ca5b6e288d02503cba5a6d3409cb9a0600e01ddGerald Schaefer	if (!monpriv)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MON_MSGLIM; i++) {
19088abaab4f9b08381e30e737980a1c49d6b524dfcEric Sesterhenn		monpriv->msg_array[i] = kzalloc(sizeof(struct mon_msg),
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    GFP_KERNEL);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!monpriv->msg_array[i]) {
193c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky			mon_free_mem(monpriv);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return NULL;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return monpriv;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
200c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic inline void mon_next_mca(struct mon_msg *monmsg)
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12))
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	monmsg->mca_offset += 12;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	monmsg->pos = 0;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2089b0c455a04d73d8ffa388a1006925620ad684ad8Martin Schwidefskystatic struct mon_msg *mon_next_message(struct mon_private *monpriv)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mon_msg *monmsg;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!atomic_read(&monpriv->read_ready))
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	monmsg = monpriv->msg_array[monpriv->read_index];
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(monmsg->replied_msglim)) {
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->replied_msglim = 0;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->msglim_reached = 0;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->pos = 0;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->mca_offset = 0;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monpriv->read_index = (monpriv->read_index + 1) %
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      MON_MSGLIM;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_dec(&monpriv->read_ready);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-EOVERFLOW);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return monmsg;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************************************************************
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                               IUCV handler                                 *
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
232c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
234c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	struct mon_private *monpriv = path->private;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&monpriv->iucv_connected, 1);
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up(&mon_conn_wait_queue);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
240c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
242c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	struct mon_private *monpriv = path->private;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
244a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer	pr_err("z/VM *MONITOR system service disconnected with rc=%i\n",
245a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer	       ipuser[0]);
246c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	iucv_path_sever(path, NULL);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&monpriv->iucv_severed, 1);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up(&mon_conn_wait_queue);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up_interruptible(&mon_read_wait_queue);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
252c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic void mon_iucv_message_pending(struct iucv_path *path,
253c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky				     struct iucv_message *msg)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
255c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	struct mon_private *monpriv = path->private;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
257c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
258c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	       msg, sizeof(*msg));
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
260a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		pr_warning("The read queue for monitor data is full\n");
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monpriv->msg_array[monpriv->write_index]->msglim_reached = 1;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_inc(&monpriv->read_ready);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up_interruptible(&mon_read_wait_queue);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic struct iucv_handler monreader_iucv_handler = {
269c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	.path_complete	 = mon_iucv_path_complete,
270c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	.path_severed	 = mon_iucv_path_severed,
271c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	.message_pending = mon_iucv_message_pending,
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************************************************************
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                               file operations                              *
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
277c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic int mon_open(struct inode *inode, struct file *filp)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mon_private *monpriv;
280c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	int rc;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * only one user allowed
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
285c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	rc = -EBUSY;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_set_bit(MON_IN_USE, &mon_in_use))
287c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky		goto out;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
289c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	rc = -ENOMEM;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	monpriv = mon_alloc_mem();
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!monpriv)
292c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky		goto out_use;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
295c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	 * Connect to *MONITOR service
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
297c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
298c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	if (!monpriv->path)
299c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky		goto out_priv;
300c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
301c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky			       MON_SERVICE, NULL, user_data_connect, monpriv);
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
303a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		pr_err("Connecting to the z/VM *MONITOR system service "
304a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		       "failed with rc=%i\n", rc);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EIO;
306c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky		goto out_path;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Wait for connection confirmation
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_event(mon_conn_wait_queue,
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   atomic_read(&monpriv->iucv_connected) ||
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   atomic_read(&monpriv->iucv_severed));
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_read(&monpriv->iucv_severed)) {
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set(&monpriv->iucv_severed, 0);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		atomic_set(&monpriv->iucv_connected, 0);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EIO;
318c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky		goto out_path;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	filp->private_data = monpriv;
3219935774217afd4cdda81ffd70e56dc6406710b06Heiko Carstens	dev_set_drvdata(monreader_device, monpriv);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return nonseekable_open(inode, filp);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
324c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskyout_path:
3252b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	iucv_path_free(monpriv->path);
326c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskyout_priv:
327c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	mon_free_mem(monpriv);
328c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskyout_use:
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clear_bit(MON_IN_USE, &mon_in_use);
330c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskyout:
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
334c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic int mon_close(struct inode *inode, struct file *filp)
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc, i;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mon_private *monpriv = filp->private_data;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Close IUCV connection and unregister
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3422b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (monpriv->path) {
3432b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		rc = iucv_path_sever(monpriv->path, user_data_sever);
3442b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		if (rc)
3452b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer			pr_warning("Disconnecting the z/VM *MONITOR system "
3462b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer				   "service failed with rc=%i\n", rc);
3472b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		iucv_path_free(monpriv->path);
3482b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	}
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&monpriv->iucv_severed, 0);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&monpriv->iucv_connected, 0);
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&monpriv->read_ready, 0);
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_set(&monpriv->msglim_count, 0);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	monpriv->write_index  = 0;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	monpriv->read_index   = 0;
356ccaf6553963bc6304d5820962a08a4397d0a2dc2Gerald Schaefer	dev_set_drvdata(monreader_device, NULL);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MON_MSGLIM; i++)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(monpriv->msg_array[i]);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(monpriv);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clear_bit(MON_IN_USE, &mon_in_use);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
365c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic ssize_t mon_read(struct file *filp, char __user *data,
366c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky			size_t count, loff_t *ppos)
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mon_private *monpriv = filp->private_data;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mon_msg *monmsg;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 mce_start;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	monmsg = mon_next_message(monpriv);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(monmsg))
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(monmsg);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!monmsg) {
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (filp->f_flags & O_NONBLOCK)
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EAGAIN;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = wait_event_interruptible(mon_read_wait_queue,
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					atomic_read(&monpriv->read_ready) ||
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					atomic_read(&monpriv->iucv_severed));
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret)
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely(atomic_read(&monpriv->iucv_severed)))
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EIO;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg = monpriv->msg_array[monpriv->read_index];
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3902ca5b6e288d02503cba5a6d3409cb9a0600e01ddGerald Schaefer	if (!monmsg->pos)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->pos = mon_mca_start(monmsg) + monmsg->mca_offset;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mon_check_mca(monmsg))
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto reply;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* read monitor control element (12 bytes) first */
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mce_start = mon_mca_start(monmsg) + monmsg->mca_offset;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((monmsg->pos >= mce_start) && (monmsg->pos < mce_start + 12)) {
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = min(count, (size_t) mce_start + 12 - monmsg->pos);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = copy_to_user(data, (void *) (unsigned long) monmsg->pos,
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   count);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret)
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->pos += count;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (monmsg->pos == mce_start + 12)
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			monmsg->pos = mon_rec_start(monmsg);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_copy;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* read records */
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (monmsg->pos <= mon_rec_end(monmsg)) {
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = min(count, (size_t) mon_rec_end(monmsg) - monmsg->pos
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    + 1);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = copy_to_user(data, (void *) (unsigned long) monmsg->pos,
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   count);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret)
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		monmsg->pos += count;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (monmsg->pos > mon_rec_end(monmsg))
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mon_next_mca(monmsg);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_copy;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreply:
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = mon_send_reply(monmsg, monpriv);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_copy:
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ppos += count;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic unsigned int mon_poll(struct file *filp, struct poll_table_struct *p)
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mon_private *monpriv = filp->private_data;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	poll_wait(filp, &mon_read_wait_queue, p);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(atomic_read(&monpriv->iucv_severed)))
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return POLLERR;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_read(&monpriv->read_ready))
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return POLLIN | POLLRDNORM;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
443d54b1fdb1d9f82e375a299e22bd366aad52d4c34Arjan van de Venstatic const struct file_operations mon_fops = {
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner   = THIS_MODULE,
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open    = &mon_open,
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = &mon_close,
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read    = &mon_read,
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.poll    = &mon_poll,
4496038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek  = noop_llseek,
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct miscdevice mon_dev = {
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name       = "monreader",
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fops       = &mon_fops,
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.minor      = MISC_DYNAMIC_MINOR,
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4582b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
4592b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer/******************************************************************************
4602b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer *				suspend / resume			      *
4612b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer *****************************************************************************/
4622b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferstatic int monreader_freeze(struct device *dev)
4632b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer{
4649935774217afd4cdda81ffd70e56dc6406710b06Heiko Carstens	struct mon_private *monpriv = dev_get_drvdata(dev);
4652b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	int rc;
4662b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
4672b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (!monpriv)
4682b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		return 0;
4692b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (monpriv->path) {
4702b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		rc = iucv_path_sever(monpriv->path, user_data_sever);
4712b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		if (rc)
4722b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer			pr_warning("Disconnecting the z/VM *MONITOR system "
4732b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer				   "service failed with rc=%i\n", rc);
4742b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		iucv_path_free(monpriv->path);
4752b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	}
4762b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	atomic_set(&monpriv->iucv_severed, 0);
4772b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	atomic_set(&monpriv->iucv_connected, 0);
4782b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	atomic_set(&monpriv->read_ready, 0);
4792b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	atomic_set(&monpriv->msglim_count, 0);
4802b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monpriv->write_index  = 0;
4812b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monpriv->read_index   = 0;
4822b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monpriv->path = NULL;
4832b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	return 0;
4842b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer}
4852b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
4862b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferstatic int monreader_thaw(struct device *dev)
4872b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer{
4884f0076f77fb64889d4e5e425b63333e5764b446dMartin Schwidefsky	struct mon_private *monpriv = dev_get_drvdata(dev);
4892b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	int rc;
4902b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
4912b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (!monpriv)
4922b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		return 0;
4932b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	rc = -ENOMEM;
4942b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
4952b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (!monpriv->path)
4962b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out;
4972b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
4982b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer			       MON_SERVICE, NULL, user_data_connect, monpriv);
4992b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (rc) {
5002b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		pr_err("Connecting to the z/VM *MONITOR system service "
5012b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		       "failed with rc=%i\n", rc);
5022b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out_path;
5032b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	}
5042b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	wait_event(mon_conn_wait_queue,
5052b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		   atomic_read(&monpriv->iucv_connected) ||
5062b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		   atomic_read(&monpriv->iucv_severed));
5072b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (atomic_read(&monpriv->iucv_severed))
5082b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out_path;
5092b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	return 0;
5102b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferout_path:
5112b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	rc = -EIO;
5122b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	iucv_path_free(monpriv->path);
5132b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monpriv->path = NULL;
5142b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferout:
5152b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	atomic_set(&monpriv->iucv_severed, 1);
5162b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	return rc;
5172b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer}
5182b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
5192b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferstatic int monreader_restore(struct device *dev)
5202b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer{
5212b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	int rc;
5222b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
5232b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	segment_unload(mon_dcss_name);
5242b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
5252b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer			  &mon_dcss_start, &mon_dcss_end);
5262b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (rc < 0) {
5272b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		segment_warning(rc, mon_dcss_name);
5282b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		panic("fatal monreader resume error: no monitor dcss\n");
5292b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	}
5302b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	return monreader_thaw(dev);
5312b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer}
5322b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
533471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops monreader_pm_ops = {
5342b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	.freeze  = monreader_freeze,
5352b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	.thaw	 = monreader_thaw,
5362b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	.restore = monreader_restore,
5372b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer};
5382b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
5392b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferstatic struct device_driver monreader_driver = {
5402b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	.name = "monreader",
5412b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	.bus  = &iucv_bus,
5422b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	.pm   = &monreader_pm_ops,
5432b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer};
5442b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
5452b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/******************************************************************************
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *                              module init/exit                              *
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *****************************************************************************/
549c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic int __init mon_init(void)
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MACHINE_IS_VM) {
554a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		pr_err("The z/VM *MONITOR record device driver cannot be "
555a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		       "loaded without z/VM\n");
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
559c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	/*
560c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	 * Register with IUCV and connect to *MONITOR service
561c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	 */
562c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	rc = iucv_register(&monreader_iucv_handler, 1);
563c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	if (rc) {
564a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		pr_err("The z/VM *MONITOR record device driver failed to "
565a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		       "register with IUCV\n");
566c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky		return rc;
567c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	}
568c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky
5692b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	rc = driver_register(&monreader_driver);
5702b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (rc)
5712b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out_iucv;
5722b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL);
57372abaadf25f2bc6098740622e4ed526775b197f9Peter Senna Tschudin	if (!monreader_device) {
57472abaadf25f2bc6098740622e4ed526775b197f9Peter Senna Tschudin		rc = -ENOMEM;
5752b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out_driver;
57672abaadf25f2bc6098740622e4ed526775b197f9Peter Senna Tschudin	}
57772abaadf25f2bc6098740622e4ed526775b197f9Peter Senna Tschudin
5782b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	dev_set_name(monreader_device, "monreader-dev");
5792b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monreader_device->bus = &iucv_bus;
5802b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monreader_device->parent = iucv_root;
5812b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monreader_device->driver = &monreader_driver;
5822b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	monreader_device->release = (void (*)(struct device *))kfree;
5832b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	rc = device_register(monreader_device);
5842b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	if (rc) {
585c6304933274f8e3cc6983d496456757ac8ab2e0bSebastian Ott		put_device(monreader_device);
5862b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out_driver;
5872b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	}
5882b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = segment_type(mon_dcss_name);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc < 0) {
591ca68305bf3c76c4a7cd1c77d5423219f39164df8Martin Schwidefsky		segment_warning(rc, mon_dcss_name);
5922b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out_device;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc != SEG_TYPE_SC) {
595a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		pr_err("The specified *MONITOR DCSS %s does not have the "
596a4f5a299cf8468619dc17f0711017c6d72d6ab94Gerald Schaefer		       "required type SC\n", mon_dcss_name);
597c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky		rc = -EINVAL;
5982b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out_device;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  &mon_dcss_start, &mon_dcss_end);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc < 0) {
604ca68305bf3c76c4a7cd1c77d5423219f39164df8Martin Schwidefsky		segment_warning(rc, mon_dcss_name);
605c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky		rc = -EINVAL;
6062b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer		goto out_device;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dcss_mkname(mon_dcss_name, &user_data_connect[8]);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6101963403aae0fc5a4e20cf2e51e4f0148fdf938b4Gerald Schaefer	/*
6111963403aae0fc5a4e20cf2e51e4f0148fdf938b4Gerald Schaefer	 * misc_register() has to be the last action in module_init(), because
6121963403aae0fc5a4e20cf2e51e4f0148fdf938b4Gerald Schaefer	 * file operations will be available right after this.
6131963403aae0fc5a4e20cf2e51e4f0148fdf938b4Gerald Schaefer	 */
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = misc_register(&mon_dev);
6152ca5b6e288d02503cba5a6d3409cb9a0600e01ddGerald Schaefer	if (rc < 0 )
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	segment_unload(mon_dcss_name);
6212b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferout_device:
6222b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	device_unregister(monreader_device);
6232b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaeferout_driver:
6242b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	driver_unregister(&monreader_driver);
625c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskyout_iucv:
626c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	iucv_unregister(&monreader_iucv_handler, 1);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
630c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefskystatic void __exit mon_exit(void)
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	segment_unload(mon_dcss_name);
633547415d5edf8660aee040dc81d8c71b081a59bdaAkinobu Mita	misc_deregister(&mon_dev);
6342b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	device_unregister(monreader_device);
6352b1e3e5558b9de0f85ed9183a7adb2d61aab363bGerald Schaefer	driver_unregister(&monreader_driver);
636c667aac8009b41ecaecb1fc72476553cf12d4732Martin Schwidefsky	iucv_unregister(&monreader_iucv_handler, 1);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mon_init);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mon_exit);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_string(mondcss, mon_dcss_name, 9, 0444);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(mondcss, "Name of DCSS segment to be used for *MONITOR "
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "service, max. 8 chars. Default is MONDCSS");
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Gerald Schaefer <geraldsc@de.ibm.com>");
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Character device driver for reading z/VM "
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   "monitor service records.");
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
652