📄 monreader.c
字号:
/* * drivers/s390/char/monreader.c * * Character device driver for reading z/VM *MONITOR service records. * * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer <geraldsc@de.ibm.com> */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/miscdevice.h>#include <linux/ctype.h>#include <linux/spinlock.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <asm/ebcdic.h>#include <asm/extmem.h>#include <linux/poll.h>#include "../net/iucv.h"//#define MON_DEBUG /* Debug messages on/off */#define MON_NAME "monreader"#define P_INFO(x...) printk(KERN_INFO MON_NAME " info: " x)#define P_ERROR(x...) printk(KERN_ERR MON_NAME " error: " x)#define P_WARNING(x...) printk(KERN_WARNING MON_NAME " warning: " x)#ifdef MON_DEBUG#define P_DEBUG(x...) printk(KERN_DEBUG MON_NAME " debug: " x)#else#define P_DEBUG(x...) do {} while (0)#endif#define MON_COLLECT_SAMPLE 0x80#define MON_COLLECT_EVENT 0x40#define MON_SERVICE "*MONITOR"#define MON_IN_USE 0x01#define MON_MSGLIM 255static char mon_dcss_name[9] = "MONDCSS\0";struct mon_msg { u32 pos; u32 mca_offset; iucv_MessagePending local_eib; char msglim_reached; char replied_msglim;};struct mon_private { u16 pathid; iucv_handle_t iucv_handle; struct mon_msg *msg_array[MON_MSGLIM]; unsigned int write_index; unsigned int read_index; atomic_t msglim_count; atomic_t read_ready; atomic_t iucv_connected; atomic_t iucv_severed;};static unsigned long mon_in_use = 0;static unsigned long mon_dcss_start;static unsigned long mon_dcss_end;static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue);static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue);static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};static u8 user_data_connect[16] = { /* Version code, must be 0x01 for shared mode */ 0x01, /* what to collect */ MON_COLLECT_SAMPLE | MON_COLLECT_EVENT, /* DCSS name in EBCDIC, 8 bytes padded with blanks */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,};static u8 user_data_sever[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,};/****************************************************************************** * helper functions * *****************************************************************************//* * Create the 8 bytes EBCDIC DCSS segment name from * an ASCII name, incl. padding */static inline voiddcss_mkname(char *ascii_name, char *ebcdic_name){ int i; for (i = 0; i < 8; i++) { if (ascii_name[i] == '\0') break; ebcdic_name[i] = toupper(ascii_name[i]); }; for (; i < 8; i++) ebcdic_name[i] = ' '; ASCEBC(ebcdic_name, 8);}/* * print appropriate error message for segment_load()/segment_type() * return code */static voidmon_segment_warn(int rc, char* seg_name){ switch (rc) { case -ENOENT: P_WARNING("cannot load/query segment %s, does not exist\n", seg_name); break; case -ENOSYS: P_WARNING("cannot load/query segment %s, not running on VM\n", seg_name); break; case -EIO: P_WARNING("cannot load/query segment %s, hardware error\n", seg_name); break; case -ENOTSUPP: P_WARNING("cannot load/query segment %s, is a multi-part " "segment\n", seg_name); break; case -ENOSPC: P_WARNING("cannot load/query segment %s, overlaps with " "storage\n", seg_name); break; case -EBUSY: P_WARNING("cannot load/query segment %s, overlaps with " "already loaded dcss\n", seg_name); break; case -EPERM: P_WARNING("cannot load/query segment %s, already loaded in " "incompatible mode\n", seg_name); break; case -ENOMEM: P_WARNING("cannot load/query segment %s, out of memory\n", seg_name); break; case -ERANGE: P_WARNING("cannot load/query segment %s, exceeds kernel " "mapping range\n", seg_name); break; default: P_WARNING("cannot load/query segment %s, return value %i\n", seg_name, rc); break; }}static inline unsigned longmon_mca_start(struct mon_msg *monmsg){ return monmsg->local_eib.ln1msg1.iprmmsg1_u32;}static inline unsigned longmon_mca_end(struct mon_msg *monmsg){ return monmsg->local_eib.ln1msg2.ipbfln1f;}static inline u8mon_mca_type(struct mon_msg *monmsg, u8 index){ return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index);}static inline u32mon_mca_size(struct mon_msg *monmsg){ return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1;}static inline u32mon_rec_start(struct mon_msg *monmsg){ return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4));}static inline u32mon_rec_end(struct mon_msg *monmsg){ return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));}static inline intmon_check_mca(struct mon_msg *monmsg){ if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) || (mon_rec_start(monmsg) < mon_dcss_start) || (mon_rec_end(monmsg) > mon_dcss_end) || (mon_mca_type(monmsg, 0) == 0) || (mon_mca_size(monmsg) % 12 != 0) || (mon_mca_end(monmsg) <= mon_mca_start(monmsg)) || (mon_mca_end(monmsg) > mon_dcss_end) || (mon_mca_start(monmsg) < mon_dcss_start) || ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0))) { P_DEBUG("READ, IGNORED INVALID MCA\n\n"); return -EINVAL; } return 0;}static inline intmon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv){ u8 prmmsg[8]; int rc; P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " "0x%08X\n\n", monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, monmsg->local_eib.iptrgcls); rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, monmsg->local_eib.iptrgcls, 0, prmmsg); atomic_dec(&monpriv->msglim_count); if (likely(!monmsg->msglim_reached)) { monmsg->pos = 0; monmsg->mca_offset = 0; monpriv->read_index = (monpriv->read_index + 1) % MON_MSGLIM; atomic_dec(&monpriv->read_ready); } else monmsg->replied_msglim = 1; if (rc) { P_ERROR("read, IUCV reply failed with rc = %i\n\n", rc); return -EIO; } return 0;}static inline struct mon_private *mon_alloc_mem(void){ int i,j; struct mon_private *monpriv; monpriv = kmalloc(sizeof(struct mon_private), GFP_KERNEL); if (!monpriv) { P_ERROR("no memory for monpriv\n"); return NULL; } memset(monpriv, 0, sizeof(struct mon_private)); for (i = 0; i < MON_MSGLIM; i++) { monpriv->msg_array[i] = kmalloc(sizeof(struct mon_msg), GFP_KERNEL); if (!monpriv->msg_array[i]) { P_ERROR("open, no memory for msg_array\n"); for (j = 0; j < i; j++) kfree(monpriv->msg_array[j]); return NULL; } memset(monpriv->msg_array[i], 0, sizeof(struct mon_msg)); } return monpriv;}static inline voidmon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv){#ifdef MON_DEBUG u8 msg_type[2], mca_type; unsigned long records_len; records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2); EBCASC(msg_type, 2); mca_type = mon_mca_type(monmsg, 0); EBCASC(&mca_type, 1); P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", monpriv->read_index, monpriv->write_index); P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, monmsg->local_eib.iptrgcls); P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", msg_type[0], msg_type[1], mca_type ? mca_type : 'X', mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); P_DEBUG("read, MCA: start = 0x%lX, end = 0x%lX\n", mon_mca_start(monmsg), mon_mca_end(monmsg)); P_DEBUG("read, REC: start = 0x%X, end = 0x%X, len = %lu\n\n", mon_rec_start(monmsg), mon_rec_end(monmsg), records_len); if (mon_mca_size(monmsg) > 12) P_DEBUG("READ, MORE THAN ONE MCA\n\n");#endif}static inline voidmon_next_mca(struct mon_msg *monmsg){ if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) return; P_DEBUG("READ, NEXT MCA\n\n"); monmsg->mca_offset += 12; monmsg->pos = 0;}static inline struct mon_msg *mon_next_message(struct mon_private *monpriv){ struct mon_msg *monmsg; if (!atomic_read(&monpriv->read_ready)) return NULL; monmsg = monpriv->msg_array[monpriv->read_index]; if (unlikely(monmsg->replied_msglim)) { monmsg->replied_msglim = 0; monmsg->msglim_reached = 0; monmsg->pos = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -