📄 iucv.c
字号:
/* * $Id$ * * IUCV network driver * * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): * Original source: * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 * Xenia Tkatschow (xenia@us.ibm.com) * 2Gb awareness and general cleanup: * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * * Documentation used: * The original source * CP Programming Service, IBM document # SC24-5760 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * RELEASE-TAG: IUCV lowlevel driver $Revision$ * */#include <linux/module.h>#include <linux/config.h>#include <linux/version.h>#include <linux/spinlock.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/tqueue.h>#include <linux/interrupt.h>#include <linux/list.h>#include <asm/atomic.h>#include "iucv.h"#include <asm/io.h>#include <asm/irq.h>#include <asm/s390_ext.h>#include <asm/ebcdic.h>#undef DEBUG/* FLAGS: * All flags are defined in the field IPFLAGS1 of each function * and can be found in CP Programming Services. * IPSRCCLS - Indicates you have specified a source class * IPFGMCL - Indicates you have specified a target class * IPFGPID - Indicates you have specified a pathid * IPFGMID - Indicates you have specified a message ID * IPANSLST - Indicates that you are using an address list for * reply data * IPBUFLST - Indicates that you are using an address list for * message data */#define IPSRCCLS 0x01#define IPFGMCL 0x01#define IPFGPID 0x02#define IPFGMID 0x04#define IPANSLST 0x08#define IPBUFLST 0x40/* General IUCV interrupt structure */typedef struct { __u16 ippathid; __u8 res1; __u8 iptype; __u32 res2; __u8 ipvmid[8]; __u8 res3[24];} iucv_GeneralInterrupt;static iucv_GeneralInterrupt *iucv_external_int_buffer;/* Spin Lock declaration */static spinlock_t iucv_lock = SPIN_LOCK_UNLOCKED;/***************INTERRUPT HANDLING ***************/typedef struct { struct list_head queue; iucv_GeneralInterrupt data;} iucv_irqdata;struct list_head iucv_irq_queue;static spinlock_t iucv_irq_queue_lock = SPIN_LOCK_UNLOCKED;struct tq_struct iucv_tq;static atomic_t iucv_bh_scheduled = ATOMIC_INIT (0);/* *Internal function prototypes */static void iucv_bh_handler(void);static void iucv_irq_handler(struct pt_regs *, __u16);/************ FUNCTION ID'S ****************************/#define ACCEPT 10#define CONNECT 11#define DECLARE_BUFFER 12#define PURGE 9#define QUERY 0#define QUIESCE 13#define RECEIVE 5#define REJECT 8#define REPLY 6#define RESUME 14#define RETRIEVE_BUFFER 2#define SEND 4#define SETMASK 16#define SEVER 15/** * Structure: handler * members: list - list management. * structure: id * userid - 8 char array of machine identification * user_data - 16 char array for user identification * mask - 24 char array used to compare the 2 previous * interrupt_table - vector of interrupt functions. * pgm_data - ulong, application data that is passed * to the interrupt handlers*/typedef struct handler_t { struct list_head list; struct { __u8 userid[8]; __u8 user_data[16]; __u8 mask[24]; } id; iucv_interrupt_ops_t *interrupt_table; void *pgm_data;} handler;/** * iucv_handler_table: List of registered handlers. */static struct list_head iucv_handler_table;/** * iucv_pathid_table: an array of *handler pointing into * iucv_handler_table for fast indexing by pathid; */static handler **iucv_pathid_table;static unsigned long max_connections;/** * declare_flag: is 0 when iucv_declare_buffer has not been called */static int declare_flag;/****************FIVE 40-BYTE PARAMETER STRUCTURES******************//* Data struct 1: iparml_control * Used for iucv_accept * iucv_connect * iucv_quiesce * iucv_resume * iucv_sever * iucv_retrieve_buffer * Data struct 2: iparml_dpl (data in parameter list) * Used for iucv_send_prmmsg * iucv_send2way_prmmsg * iucv_send2way_prmmsg_array * iucv_reply_prmmsg * Data struct 3: iparml_db (data in a buffer) * Used for iucv_receive * iucv_receive_array * iucv_reject * iucv_reply * iucv_reply_array * iucv_send * iucv_send_array * iucv_send2way * iucv_send2way_array * iucv_declare_buffer * Data struct 4: iparml_purge * Used for iucv_purge * iucv_query * Data struct 5: iparml_set_mask * Used for iucv_set_mask */typedef struct { __u16 ippathid; __u8 ipflags1; __u8 iprcode; __u16 ipmsglim; __u16 res1; __u8 ipvmid[8]; __u8 ipuser[16]; __u8 iptarget[8];} iparml_control;typedef struct { __u16 ippathid; __u8 ipflags1; __u8 iprcode; __u32 ipmsgid; __u32 iptrgcls; __u8 iprmmsg[8]; __u32 ipsrccls; __u32 ipmsgtag; __u32 ipbfadr2; __u32 ipbfln2f; __u32 res;} iparml_dpl;typedef struct { __u16 ippathid; __u8 ipflags1; __u8 iprcode; __u32 ipmsgid; __u32 iptrgcls; __u32 ipbfadr1; __u32 ipbfln1f; __u32 ipsrccls; __u32 ipmsgtag; __u32 ipbfadr2; __u32 ipbfln2f; __u32 res;} iparml_db;typedef struct { __u16 ippathid; __u8 ipflags1; __u8 iprcode; __u32 ipmsgid; __u8 ipaudit[3]; __u8 res1[5]; __u32 res2; __u32 ipsrccls; __u32 ipmsgtag; __u32 res3[3];} iparml_purge;typedef struct { __u8 ipmask; __u8 res1[2]; __u8 iprcode; __u32 res2[9];} iparml_set_mask;typedef struct { union { iparml_control p_ctrl; iparml_dpl p_dpl; iparml_db p_db; iparml_purge p_purge; iparml_set_mask p_set_mask; } param; atomic_t in_use;} __attribute__ ((aligned(8))) iucv_param;#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param))static iucv_param * iucv_param_pool;/* * Debugging stuff *******************************************************************************/#ifdef DEBUGstatic voidiucv_dumpit(void *buf, int len){ int i; __u8 *p = (__u8 *)buf; printk(KERN_DEBUG " "); for (i = 0; i < len; i++) { if (!(i % 16) && i != 0) printk ("\n "); else if (!(i % 4) && i != 0) printk (" "); printk ("%02X", *p++); } if (len % 16) printk ("\n"); return;}#define iucv_debug(fmt, args...) \printk(KERN_DEBUG __FUNCTION__ ": " fmt "\n" , ## args);#else#define iucv_debug(fmt, args...)#define iucv_dumpit(buf, len)#endif/* * Internal functions *******************************************************************************//** * iucv_init - Initialization * * Allocates and initializes various data structures. */static intiucv_init(void){ if (iucv_external_int_buffer) return 0; /* Note: GFP_DMA used used to get memory below 2G */ iucv_external_int_buffer = kmalloc(sizeof(iucv_GeneralInterrupt), GFP_KERNEL|GFP_DMA); if (!iucv_external_int_buffer) { printk(KERN_WARNING "%s: Could not allocate external interrupt buffer\n", __FUNCTION__); return -ENOMEM; } memset(iucv_external_int_buffer, 0, sizeof(iucv_GeneralInterrupt)); /* Initialize parameter pool */ iucv_param_pool = kmalloc(sizeof(iucv_param) * PARAM_POOL_SIZE, GFP_KERNEL|GFP_DMA); if (!iucv_param_pool) { printk(KERN_WARNING "%s: Could not allocate param pool\n", __FUNCTION__); kfree(iucv_external_int_buffer); iucv_external_int_buffer = NULL; return -ENOMEM; } memset(iucv_param_pool, 0, sizeof(iucv_param) * PARAM_POOL_SIZE); /* Initialize task queue */ INIT_LIST_HEAD(&iucv_tq.list); iucv_tq.sync = 0; iucv_tq.routine = (void *)iucv_bh_handler; /* Initialize irq queue */ INIT_LIST_HEAD(&iucv_irq_queue); /* Initialize handler table */ INIT_LIST_HEAD(&iucv_handler_table); return 0;}/** * grab_param: - Get a parameter buffer from the pre-allocated pool. * * This function searches for an unused element in the the pre-allocated pool * of parameter buffers. If one is found, it marks it "in use" and returns * a pointer to it. The calling function is responsible for releasing it * when it has finished its usage. * * Returns: A pointer to iucv_param. */static __inline__ iucv_param *grab_param(void){ iucv_param *ret; static int i = 0; while (atomic_compare_and_swap(0, 1, &iucv_param_pool[i].in_use)) { i++; if (i >= PARAM_POOL_SIZE) i = 0; } ret = &iucv_param_pool[i]; memset(&ret->param, 0, sizeof(ret->param)); return ret;}/** * release_param - Release a parameter buffer. * @p: A pointer to a struct iucv_param, previously obtained by calling * grab_param(). * * This function marks the specified parameter buffer "unused". */static __inline__ voidrelease_param(void *p){ atomic_set(&((iucv_param *)p)->in_use, 0);}/** * iucv_add_handler: - Add a new handler * @new_handler: handle that is being entered into chain. * * Places new handle on iucv_handler_table, if identical handler is not * found. * * Returns: 0 on success, !0 on failure (handler already in chain). */static intiucv_add_handler (handler *new){ ulong flags; iucv_debug("entering"); iucv_dumpit(new, sizeof(handler)); spin_lock_irqsave (&iucv_lock, flags); if (!list_empty(&iucv_handler_table)) { struct list_head *lh; /** * Search list for handler with identical id. If one * is found, the new handler is _not_ added. */ list_for_each(lh, &iucv_handler_table) { handler *h = list_entry(lh, handler, list); if (memcmp(&new->id, &h->id, sizeof(h->id)) == 0) { iucv_debug("ret 1"); spin_unlock_irqrestore (&iucv_lock, flags); return 1; } } } /** * If we get here, no handler was found. */ INIT_LIST_HEAD(&new->list); list_add(&new->list, &iucv_handler_table); spin_unlock_irqrestore (&iucv_lock, flags); iucv_debug("exiting"); return 0;}/** * iucv_remove_handler: * @users_handler: handler to be removed * * Remove handler when application unregisters. */static voidiucv_remove_handler(handler *handler){ unsigned long flags; if ((!iucv_pathid_table) || (!handler)) return; iucv_debug("entering");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -