📄 iucv.c
字号:
/* * $Id: iucv.c,v 1.45 2005/04/26 22:59:06 braunu Exp $ * * 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: 1.45 $ * *//* #define DEBUG */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/config.h>#include <linux/spinlock.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/list.h>#include <linux/errno.h>#include <linux/err.h>#include <linux/device.h>#include <asm/atomic.h>#include "iucv.h"#include <asm/io.h>#include <asm/s390_ext.h>#include <asm/ebcdic.h>#include <asm/smp.h>#include <asm/ccwdev.h> //for root device stuff/* 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 0x40static intiucv_bus_match (struct device *dev, struct device_driver *drv){ return 0;}struct bus_type iucv_bus = { .name = "iucv", .match = iucv_bus_match,}; struct device *iucv_root;/* 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 = NULL;/* Spin Lock declaration */static DEFINE_SPINLOCK(iucv_lock);static int messagesDisabled = 0;/***************INTERRUPT HANDLING ***************/typedef struct { struct list_head queue; iucv_GeneralInterrupt data;} iucv_irqdata;static struct list_head iucv_irq_queue;static DEFINE_SPINLOCK(iucv_irq_queue_lock);/* *Internal function prototypes */static void iucv_tasklet_handler(unsigned long);static void iucv_irq_handler(struct pt_regs *, __u16);static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0);/************ 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;/** * iucv_cpuid: contains the logical cpu number of the cpu which * has declared the iucv buffer by issuing DECLARE_BUFFER. * If no cpu has done the initialization iucv_cpuid contains -1. */static int iucv_cpuid = -1;/** * register_flag: is 0 when external interrupt has not been registered */static int register_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; __u32 res;} __attribute__ ((aligned(8))) iucv_param;#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param))static iucv_param * iucv_param_pool;MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");MODULE_LICENSE("GPL");/* * Debugging stuff *******************************************************************************/#ifdef DEBUGstatic int debuglevel = 0;module_param(debuglevel, int, 0);MODULE_PARM_DESC(debuglevel, "Specifies the debug level (0=off ... 3=all)");static voidiucv_dumpit(char *title, void *buf, int len){ int i; __u8 *p = (__u8 *)buf; if (debuglevel < 3) return; printk(KERN_DEBUG "%s\n", title); printk(" "); 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(lvl, fmt, args...) \do { \ if (debuglevel >= lvl) \ printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \} while (0)#else#define iucv_debug(lvl, fmt, args...)#define iucv_dumpit(title, buf, len)#endif/* * Internal functions *******************************************************************************//** * print start banner */static voidiucv_banner(void){ char vbuf[] = "$Revision: 1.45 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { char *p = strchr(version + 1, '$'); if (p) *p = '\0'; } else version = " ??? "; printk(KERN_INFO "IUCV lowlevel driver Version%s initialized\n", version);}/** * iucv_init - Initialization * * Allocates and initializes various data structures. */static intiucv_init(void){ int ret; if (iucv_external_int_buffer) return 0; if (!MACHINE_IS_VM) { printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n"); return -EPROTONOSUPPORT; } ret = bus_register(&iucv_bus); if (ret) { printk(KERN_ERR "IUCV: failed to register bus.\n"); return ret; } iucv_root = s390_root_dev_register("iucv"); if (IS_ERR(iucv_root)) { printk(KERN_ERR "IUCV: failed to register iucv root.\n"); bus_unregister(&iucv_bus); return PTR_ERR(iucv_root); } /* 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__); s390_root_dev_unregister(iucv_root); bus_unregister(&iucv_bus); 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; s390_root_dev_unregister(iucv_root); bus_unregister(&iucv_bus); return -ENOMEM; } memset(iucv_param_pool, 0, sizeof(iucv_param) * PARAM_POOL_SIZE); /* Initialize irq queue */ INIT_LIST_HEAD(&iucv_irq_queue); /* Initialize handler table */ INIT_LIST_HEAD(&iucv_handler_table); iucv_banner(); return 0;}/** * iucv_exit - De-Initialization * * Frees everything allocated from iucv_init. */static int iucv_retrieve_buffer (void);static voidiucv_exit(void){ iucv_retrieve_buffer(); kfree(iucv_external_int_buffer); iucv_external_int_buffer = NULL; kfree(iucv_param_pool); iucv_param_pool = NULL; s390_root_dev_unregister(iucv_root); bus_unregister(&iucv_bus); printk(KERN_INFO "IUCV lowlevel driver unloaded\n");}/** * grab_param: - Get a parameter buffer from the pre-allocated pool. * * This function searches for an unused element in 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 *ptr; static int hint = 0; ptr = iucv_param_pool + hint; do { ptr++; if (ptr >= iucv_param_pool + PARAM_POOL_SIZE) ptr = iucv_param_pool; } while (atomic_compare_and_swap(0, 1, &ptr->in_use)); hint = ptr - iucv_param_pool; memset(&ptr->param, 0, sizeof(ptr->param)); return ptr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -