提交 33a67fe8 编写于 作者: M Martin Schwidefsky 提交者: David S. Miller

[S390]: Rewrite of the IUCV base code, part 1

Remove the old IUCV code from drivers/s390/net
Remove approprirate IUCV entries from drivers/s390/net/Makefile,
drivers/s390/net/Kconfig and arch/s390/defconfig
Signed-off-by: NFrank Pavlic <fpavlic@de.ibm.com>
Signed-off-by: NMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 c9c2e9dc
......@@ -508,7 +508,6 @@ CONFIG_NET_ETHERNET=y
#
CONFIG_LCS=m
CONFIG_CTC=m
CONFIG_IUCV=m
# CONFIG_NETIUCV is not set
# CONFIG_SMSGIUCV is not set
# CONFIG_CLAW is not set
......
......@@ -22,13 +22,6 @@ config CTC
available. This option is also available as a module which will be
called ctc.ko. If you do not know what it is, it's safe to say "Y".
config IUCV
tristate "IUCV support (VM only)"
help
Select this option if you want to use inter-user communication
under VM or VIF. If unsure, say "Y" to enable a fast communication
link between VM guests.
config NETIUCV
tristate "IUCV network device support (VM only)"
depends on IUCV && NETDEVICES
......
......@@ -4,7 +4,6 @@
ctc-objs := ctcmain.o ctcdbug.o
obj-$(CONFIG_IUCV) += iucv.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
......
/*
* 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.
*
*/
/* #define DEBUG */
#include <linux/module.h>
#include <linux/moduleparam.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/s390_rdev.h>
/* 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
static int
iucv_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(__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 DEBUG
static int debuglevel = 0;
module_param(debuglevel, int, 0);
MODULE_PARM_DESC(debuglevel,
"Specifies the debug level (0=off ... 3=all)");
static void
iucv_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...) do { } while (0)
#define iucv_dumpit(title, buf, len) do { } while (0)
#endif
/*
* Internal functions
*******************************************************************************/
/**
* print start banner
*/
static void
iucv_banner(void)
{
printk(KERN_INFO "IUCV lowlevel driver initialized\n");
}
/**
* iucv_init - Initialization
*
* Allocates and initializes various data structures.
*/
static int
iucv_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 = kzalloc(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;
}
/* Initialize parameter pool */
iucv_param_pool = kzalloc(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;
}
/* 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 void
iucv_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_cmpxchg(&ptr->in_use, 0, 1) != 0);
hint = ptr - iucv_param_pool;
memset(&ptr->param, 0, sizeof(ptr->param));
return ptr;
}
/**
* 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__ void
release_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 int
iucv_add_handler (handler *new)
{
ulong flags;
iucv_debug(1, "entering");
iucv_dumpit("handler:", 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))) {
iucv_debug(1, "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(1, "exiting");
return 0;
}
/**
* b2f0:
* @code: identifier of IUCV call to CP.
* @parm: pointer to 40 byte iparml area passed to CP
*
* Calls CP to execute IUCV commands.
*
* Returns: return code from CP's IUCV call
*/
static inline ulong b2f0(__u32 code, void *parm)
{
register unsigned long reg0 asm ("0");
register unsigned long reg1 asm ("1");
iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
reg0 = code;
reg1 = virt_to_phys(parm);
asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1));
iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
return (unsigned long)*((__u8 *)(parm + 3));
}
/*
* Name: iucv_add_pathid
* Purpose: Adds a path id to the system.
* Input: pathid - pathid that is going to be entered into system
* handle - address of handler that the pathid will be associated
* with.
* pgm_data - token passed in by application.
* Output: 0: successful addition of pathid
* - EINVAL - pathid entry is being used by another application
* - ENOMEM - storage allocation for a new pathid table failed
*/
static int
__iucv_add_pathid(__u16 pathid, handler *handler)
{
iucv_debug(1, "entering");
iucv_debug(1, "handler is pointing to %p", handler);
if (pathid > (max_connections - 1))
return -EINVAL;
if (iucv_pathid_table[pathid]) {
iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]);
printk(KERN_WARNING
"%s: Pathid being used, error.\n", __FUNCTION__);
return -EINVAL;
}
iucv_pathid_table[pathid] = handler;
iucv_debug(1, "exiting");
return 0;
} /* end of add_pathid function */
static int
iucv_add_pathid(__u16 pathid, handler *handler)
{
ulong flags;
int rc;
spin_lock_irqsave (&iucv_lock, flags);
rc = __iucv_add_pathid(pathid, handler);
spin_unlock_irqrestore (&iucv_lock, flags);
return rc;
}
static void
iucv_remove_pathid(__u16 pathid)
{
ulong flags;
if (pathid > (max_connections - 1))
return;
spin_lock_irqsave (&iucv_lock, flags);
iucv_pathid_table[pathid] = NULL;
spin_unlock_irqrestore (&iucv_lock, flags);
}
/**
* iucv_declare_buffer_cpuid
* Register at VM for subsequent IUCV operations. This is executed
* on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer().
*/
static void
iucv_declare_buffer_cpuid (void *result)
{
iparml_db *parm;
parm = (iparml_db *)grab_param();
parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)
*((ulong *)result) = parm->iprcode;
release_param(parm);
}
/**
* iucv_retrieve_buffer_cpuid:
* Unregister IUCV usage at VM. This is always executed on the same
* cpu that registered the buffer to VM.
* Called from iucv_retrieve_buffer().
*/
static void
iucv_retrieve_buffer_cpuid (void *cpu)
{
iparml_control *parm;
parm = (iparml_control *)grab_param();
b2f0(RETRIEVE_BUFFER, parm);
release_param(parm);
}
/**
* Name: iucv_declare_buffer
* Purpose: Specifies the guests real address of an external
* interrupt.
* Input: void
* Output: iprcode - return code from b2f0 call
*/
static int
iucv_declare_buffer (void)
{
unsigned long flags;
ulong b2f0_result;
iucv_debug(1, "entering");
b2f0_result = -ENODEV;
spin_lock_irqsave (&iucv_lock, flags);
if (iucv_cpuid == -1) {
/* Reserve any cpu for use by iucv. */
iucv_cpuid = smp_get_cpu(CPU_MASK_ALL);
spin_unlock_irqrestore (&iucv_lock, flags);
smp_call_function_on(iucv_declare_buffer_cpuid,
&b2f0_result, 0, 1, iucv_cpuid);
if (b2f0_result) {
smp_put_cpu(iucv_cpuid);
iucv_cpuid = -1;
}
iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
} else {
spin_unlock_irqrestore (&iucv_lock, flags);
b2f0_result = 0;
}
iucv_debug(1, "exiting");
return b2f0_result;
}
/**
* iucv_retrieve_buffer:
*
* Terminates all use of IUCV.
* Returns: return code from CP
*/
static int
iucv_retrieve_buffer (void)
{
iucv_debug(1, "entering");
if (iucv_cpuid != -1) {
smp_call_function_on(iucv_retrieve_buffer_cpuid,
NULL, 0, 1, iucv_cpuid);
/* Release the cpu reserved by iucv_declare_buffer. */
smp_put_cpu(iucv_cpuid);
iucv_cpuid = -1;
}
iucv_debug(1, "exiting");
return 0;
}
/**
* iucv_remove_handler:
* @users_handler: handler to be removed
*
* Remove handler when application unregisters.
*/
static void
iucv_remove_handler(handler *handler)
{
unsigned long flags;
if ((!iucv_pathid_table) || (!handler))
return;
iucv_debug(1, "entering");
spin_lock_irqsave (&iucv_lock, flags);
list_del(&handler->list);
if (list_empty(&iucv_handler_table)) {
if (register_flag) {
unregister_external_interrupt(0x4000, iucv_irq_handler);
register_flag = 0;
}
}
spin_unlock_irqrestore (&iucv_lock, flags);
iucv_debug(1, "exiting");
return;
}
/**
* iucv_register_program:
* @pgmname: user identification
* @userid: machine identification
* @pgmmask: Indicates which bits in the pgmname and userid combined will be
* used to determine who is given control.
* @ops: Address of interrupt handler table.
* @pgm_data: Application data to be passed to interrupt handlers.
*
* Registers an application with IUCV.
* Returns:
* The address of handler, or NULL on failure.
* NOTE on pgmmask:
* If pgmname, userid and pgmmask are provided, pgmmask is entered into the
* handler as is.
* If pgmmask is NULL, the internal mask is set to all 0xff's
* When userid is NULL, the first 8 bytes of the internal mask are forced
* to 0x00.
* If pgmmask and userid are NULL, the first 8 bytes of the internal mask
* are forced to 0x00 and the last 16 bytes to 0xff.
*/
iucv_handle_t
iucv_register_program (__u8 pgmname[16],
__u8 userid[8],
__u8 pgmmask[24],
iucv_interrupt_ops_t * ops, void *pgm_data)
{
ulong rc = 0; /* return code from function calls */
handler *new_handler;
iucv_debug(1, "entering");
if (ops == NULL) {
/* interrupt table is not defined */
printk(KERN_WARNING "%s: Interrupt table is not defined, "
"exiting\n", __FUNCTION__);
return NULL;
}
if (!pgmname) {
printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__);
return NULL;
}
/* Allocate handler entry */
new_handler = kmalloc(sizeof(handler), GFP_ATOMIC);
if (new_handler == NULL) {
printk(KERN_WARNING "%s: storage allocation for new handler "
"failed.\n", __FUNCTION__);
return NULL;
}
if (!iucv_pathid_table) {
if (iucv_init()) {
kfree(new_handler);
return NULL;
}
max_connections = iucv_query_maxconn();
iucv_pathid_table = kcalloc(max_connections, sizeof(handler *),
GFP_ATOMIC);
if (iucv_pathid_table == NULL) {
printk(KERN_WARNING "%s: iucv_pathid_table storage "
"allocation failed\n", __FUNCTION__);
kfree(new_handler);
return NULL;
}
}
memset(new_handler, 0, sizeof (handler));
memcpy(new_handler->id.user_data, pgmname,
sizeof (new_handler->id.user_data));
if (userid) {
memcpy (new_handler->id.userid, userid,
sizeof (new_handler->id.userid));
ASCEBC (new_handler->id.userid,
sizeof (new_handler->id.userid));
EBC_TOUPPER (new_handler->id.userid,
sizeof (new_handler->id.userid));
if (pgmmask) {
memcpy (new_handler->id.mask, pgmmask,
sizeof (new_handler->id.mask));
} else {
memset (new_handler->id.mask, 0xFF,
sizeof (new_handler->id.mask));
}
} else {
if (pgmmask) {
memcpy (new_handler->id.mask, pgmmask,
sizeof (new_handler->id.mask));
} else {
memset (new_handler->id.mask, 0xFF,
sizeof (new_handler->id.mask));
}
memset (new_handler->id.userid, 0x00,
sizeof (new_handler->id.userid));
}
/* fill in the rest of handler */
new_handler->pgm_data = pgm_data;
new_handler->interrupt_table = ops;
/*
* Check if someone else is registered with same pgmname, userid
* and mask. If someone is already registered with same pgmname,
* userid and mask, registration will fail and NULL will be returned
* to the application.
* If identical handler not found, then handler is added to list.
*/
rc = iucv_add_handler(new_handler);
if (rc) {
printk(KERN_WARNING "%s: Someone already registered with same "
"pgmname, userid, pgmmask\n", __FUNCTION__);
kfree (new_handler);
return NULL;
}
rc = iucv_declare_buffer();
if (rc) {
char *err = "Unknown";
iucv_remove_handler(new_handler);
kfree(new_handler);
switch(rc) {
case 0x03:
err = "Directory error";
break;
case 0x0a:
err = "Invalid length";
break;
case 0x13:
err = "Buffer already exists";
break;
case 0x3e:
err = "Buffer overlap";
break;
case 0x5c:
err = "Paging or storage error";
break;
}
printk(KERN_WARNING "%s: iucv_declare_buffer "
"returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err);
return NULL;
}
if (!register_flag) {
/* request the 0x4000 external interrupt */
rc = register_external_interrupt (0x4000, iucv_irq_handler);
if (rc) {
iucv_remove_handler(new_handler);
kfree (new_handler);
printk(KERN_WARNING "%s: "
"register_external_interrupt returned %ld\n",
__FUNCTION__, rc);
return NULL;
}
register_flag = 1;
}
iucv_debug(1, "exiting");
return new_handler;
} /* end of register function */
/**
* iucv_unregister_program:
* @handle: address of handler
*
* Unregister application with IUCV.
* Returns:
* 0 on success, -EINVAL, if specified handle is invalid.
*/
int
iucv_unregister_program (iucv_handle_t handle)
{
handler *h = NULL;
struct list_head *lh;
int i;
ulong flags;
iucv_debug(1, "entering");
iucv_debug(1, "address of handler is %p", h);
/* Checking if handle is valid */
spin_lock_irqsave (&iucv_lock, flags);
list_for_each(lh, &iucv_handler_table) {
if ((handler *)handle == list_entry(lh, handler, list)) {
h = (handler *)handle;
break;
}
}
if (!h) {
spin_unlock_irqrestore (&iucv_lock, flags);
if (handle)
printk(KERN_WARNING
"%s: Handler not found in iucv_handler_table.\n",
__FUNCTION__);
else
printk(KERN_WARNING
"%s: NULL handle passed by application.\n",
__FUNCTION__);
return -EINVAL;
}
/**
* First, walk thru iucv_pathid_table and sever any pathid which is
* still pointing to the handler to be removed.
*/
for (i = 0; i < max_connections; i++)
if (iucv_pathid_table[i] == h) {
spin_unlock_irqrestore (&iucv_lock, flags);
iucv_sever(i, h->id.user_data);
spin_lock_irqsave(&iucv_lock, flags);
}
spin_unlock_irqrestore (&iucv_lock, flags);
iucv_remove_handler(h);
kfree(h);
iucv_debug(1, "exiting");
return 0;
}
/**
* iucv_accept:
* @pathid: Path identification number
* @msglim_reqstd: The number of outstanding messages requested.
* @user_data: Data specified by the iucv_connect function.
* @flags1: Contains options for this path.
* - IPPRTY (0x20) Specifies if you want to send priority message.
* - IPRMDATA (0x80) Specifies whether your program can handle a message
* in the parameter list.
* - IPQUSCE (0x40) Specifies whether you want to quiesce the path being
* established.
* @handle: Address of handler.
* @pgm_data: Application data passed to interrupt handlers.
* @flags1_out: Pointer to an int. If not NULL, on return the options for
* the path are stored at the given location:
* - IPPRTY (0x20) Indicates you may send a priority message.
* @msglim: Pointer to an __u16. If not NULL, on return the maximum
* number of outstanding messages is stored at the given
* location.
*
* This function is issued after the user receives a Connection Pending external
* interrupt and now wishes to complete the IUCV communication path.
* Returns:
* return code from CP
*/
int
iucv_accept(__u16 pathid, __u16 msglim_reqstd,
__u8 user_data[16], int flags1,
iucv_handle_t handle, void *pgm_data,
int *flags1_out, __u16 * msglim)
{
ulong b2f0_result = 0;
ulong flags;
struct list_head *lh;
handler *h = NULL;
iparml_control *parm;
iucv_debug(1, "entering");
iucv_debug(1, "pathid = %d", pathid);
/* Checking if handle is valid */
spin_lock_irqsave (&iucv_lock, flags);
list_for_each(lh, &iucv_handler_table) {
if ((handler *)handle == list_entry(lh, handler, list)) {
h = (handler *)handle;
break;
}
}
spin_unlock_irqrestore (&iucv_lock, flags);
if (!h) {
if (handle)
printk(KERN_WARNING
"%s: Handler not found in iucv_handler_table.\n",
__FUNCTION__);
else
printk(KERN_WARNING
"%s: NULL handle passed by application.\n",
__FUNCTION__);
return -EINVAL;
}
parm = (iparml_control *)grab_param();
parm->ippathid = pathid;
parm->ipmsglim = msglim_reqstd;
if (user_data)
memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
parm->ipflags1 = (__u8)flags1;
b2f0_result = b2f0(ACCEPT, parm);
if (!b2f0_result) {
if (msglim)
*msglim = parm->ipmsglim;
if (pgm_data)
h->pgm_data = pgm_data;
if (flags1_out)
*flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
}
release_param(parm);
iucv_debug(1, "exiting");
return b2f0_result;
}
/**
* iucv_connect:
* @pathid: Path identification number
* @msglim_reqstd: Number of outstanding messages requested
* @user_data: 16-byte user data
* @userid: 8-byte of user identification
* @system_name: 8-byte identifying the system name
* @flags1: Specifies options for this path:
* - IPPRTY (0x20) Specifies if you want to send priority message.
* - IPRMDATA (0x80) Specifies whether your program can handle a message
* in the parameter list.
* - IPQUSCE (0x40) Specifies whether you want to quiesce the path being
* established.
* - IPLOCAL (0x01) Allows an application to force the partner to be on the
* local system. If local is specified then target class
* cannot be specified.
* @flags1_out: Pointer to an int. If not NULL, on return the options for
* the path are stored at the given location:
* - IPPRTY (0x20) Indicates you may send a priority message.
* @msglim: Pointer to an __u16. If not NULL, on return the maximum
* number of outstanding messages is stored at the given
* location.
* @handle: Address of handler.
* @pgm_data: Application data to be passed to interrupt handlers.
*
* This function establishes an IUCV path. Although the connect may complete
* successfully, you are not able to use the path until you receive an IUCV
* Connection Complete external interrupt.
* Returns: return code from CP, or one of the following
* - ENOMEM
* - return code from iucv_declare_buffer
* - EINVAL - invalid handle passed by application
* - EINVAL - pathid address is NULL
* - ENOMEM - pathid table storage allocation failed
* - return code from internal function add_pathid
*/
int
iucv_connect (__u16 *pathid, __u16 msglim_reqstd,
__u8 user_data[16], __u8 userid[8],
__u8 system_name[8], int flags1,
int *flags1_out, __u16 * msglim,
iucv_handle_t handle, void *pgm_data)
{
iparml_control *parm;
iparml_control local_parm;
struct list_head *lh;
ulong b2f0_result = 0;
ulong flags;
int add_pathid_result = 0;
handler *h = NULL;
__u8 no_memory[16] = "NO MEMORY";
iucv_debug(1, "entering");
/* Checking if handle is valid */
spin_lock_irqsave (&iucv_lock, flags);
list_for_each(lh, &iucv_handler_table) {
if ((handler *)handle == list_entry(lh, handler, list)) {
h = (handler *)handle;
break;
}
}
spin_unlock_irqrestore (&iucv_lock, flags);
if (!h) {
if (handle)
printk(KERN_WARNING
"%s: Handler not found in iucv_handler_table.\n",
__FUNCTION__);
else
printk(KERN_WARNING
"%s: NULL handle passed by application.\n",
__FUNCTION__);
return -EINVAL;
}
if (pathid == NULL) {
printk(KERN_WARNING "%s: NULL pathid pointer\n",
__FUNCTION__);
return -EINVAL;
}
parm = (iparml_control *)grab_param();
parm->ipmsglim = msglim_reqstd;
if (user_data)
memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
if (userid) {
memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid));
ASCEBC(parm->ipvmid, sizeof(parm->ipvmid));
EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid));
}
if (system_name) {
memcpy(parm->iptarget, system_name, sizeof(parm->iptarget));
ASCEBC(parm->iptarget, sizeof(parm->iptarget));
EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget));
}
/* In order to establish an IUCV connection, the procedure is:
*
* b2f0(CONNECT)
* take the ippathid from the b2f0 call
* register the handler to the ippathid
*
* Unfortunately, the ConnectionEstablished message gets sent after the
* b2f0(CONNECT) call but before the register is handled.
*
* In order for this race condition to be eliminated, the IUCV Control
* Interrupts must be disabled for the above procedure.
*
* David Kennedy <dkennedy@linuxcare.com>
*/
/* Enable everything but IUCV Control messages */
iucv_setmask(~(AllInterrupts));
messagesDisabled = 1;
spin_lock_irqsave (&iucv_lock, flags);
parm->ipflags1 = (__u8)flags1;
b2f0_result = b2f0(CONNECT, parm);
memcpy(&local_parm, parm, sizeof(local_parm));
release_param(parm);
parm = &local_parm;
if (!b2f0_result)
add_pathid_result = __iucv_add_pathid(parm->ippathid, h);
spin_unlock_irqrestore (&iucv_lock, flags);
if (b2f0_result) {
iucv_setmask(~0);
messagesDisabled = 0;
return b2f0_result;
}
*pathid = parm->ippathid;
/* Enable everything again */
iucv_setmask(IUCVControlInterruptsFlag);
if (msglim)
*msglim = parm->ipmsglim;
if (flags1_out)
*flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
if (add_pathid_result) {
iucv_sever(*pathid, no_memory);
printk(KERN_WARNING "%s: add_pathid failed with rc ="
" %d\n", __FUNCTION__, add_pathid_result);
return(add_pathid_result);
}
iucv_debug(1, "exiting");
return b2f0_result;
}
/**
* iucv_purge:
* @pathid: Path identification number
* @msgid: Message ID of message to purge.
* @srccls: Message class of the message to purge.
* @audit: Pointer to an __u32. If not NULL, on return, information about
* asynchronous errors that may have affected the normal completion
* of this message ist stored at the given location.
*
* Cancels a message you have sent.
* Returns: return code from CP
*/
int
iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
{
iparml_purge *parm;
ulong b2f0_result = 0;
iucv_debug(1, "entering");
iucv_debug(1, "pathid = %d", pathid);
parm = (iparml_purge *)grab_param();
parm->ipmsgid = msgid;
parm->ippathid = pathid;
parm->ipsrccls = srccls;
parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
b2f0_result = b2f0(PURGE, parm);
if (!b2f0_result && audit) {
memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit));
/* parm->ipaudit has only 3 bytes */
*audit >>= 8;
}
release_param(parm);
iucv_debug(1, "b2f0_result = %ld", b2f0_result);
iucv_debug(1, "exiting");
return b2f0_result;
}
/**
* iucv_query_generic:
* @want_maxconn: Flag, describing which value is to be returned.
*
* Helper function for iucv_query_maxconn() and iucv_query_bufsize().
*
* Returns: The buffersize, if want_maxconn is 0; the maximum number of
* connections, if want_maxconn is 1 or an error-code < 0 on failure.
*/
static int
iucv_query_generic(int want_maxconn)
{
register unsigned long reg0 asm ("0");
register unsigned long reg1 asm ("1");
iparml_purge *parm = (iparml_purge *)grab_param();
int bufsize, maxconn;
int ccode;
/**
* Call b2f0 and store R0 (max buffer size),
* R1 (max connections) and CC.
*/
reg0 = QUERY;
reg1 = virt_to_phys(parm);
asm volatile(
" .long 0xb2f01000\n"
" ipm %0\n"
" srl %0,28\n"
: "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
bufsize = reg0;
maxconn = reg1;
release_param(parm);
if (ccode)
return -EPERM;
if (want_maxconn)
return maxconn;
return bufsize;
}
/**
* iucv_query_maxconn:
*
* Determines the maximum number of connections thay may be established.
*
* Returns: Maximum number of connections that can be.
*/
ulong
iucv_query_maxconn(void)
{
return iucv_query_generic(1);
}
/**
* iucv_query_bufsize:
*
* Determines the size of the external interrupt buffer.
*
* Returns: Size of external interrupt buffer.
*/
ulong
iucv_query_bufsize (void)
{
return iucv_query_generic(0);
}
/**
* iucv_quiesce:
* @pathid: Path identification number
* @user_data: 16-byte user data
*
* Temporarily suspends incoming messages on an IUCV path.
* You can later reactivate the path by invoking the iucv_resume function.
* Returns: return code from CP
*/
int
iucv_quiesce (__u16 pathid, __u8 user_data[16])
{
iparml_control *parm;
ulong b2f0_result = 0;
iucv_debug(1, "entering");
iucv_debug(1, "pathid = %d", pathid);
parm = (iparml_control *)grab_param();
memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
parm->ippathid = pathid;
b2f0_result = b2f0(QUIESCE, parm);
release_param(parm);
iucv_debug(1, "b2f0_result = %ld", b2f0_result);
iucv_debug(1, "exiting");
return b2f0_result;
}
/**
* iucv_receive:
* @pathid: Path identification number.
* @buffer: Address of buffer to receive. Must be below 2G.
* @buflen: Length of buffer to receive.
* @msgid: Specifies the message ID.
* @trgcls: Specifies target class.
* @flags1_out: Receives options for path on return.
* - IPNORPY (0x10) Specifies whether a reply is required
* - IPPRTY (0x20) Specifies if you want to send priority message
* - IPRMDATA (0x80) Specifies the data is contained in the parameter list
* @residual_buffer: Receives the address of buffer updated by the number
* of bytes you have received on return.
* @residual_length: On return, receives one of the following values:
* - 0 If the receive buffer is the same length as
* the message.
* - Remaining bytes in buffer If the receive buffer is longer than the
* message.
* - Remaining bytes in message If the receive buffer is shorter than the
* message.
*
* This function receives messages that are being sent to you over established
* paths.
* Returns: return code from CP IUCV call; If the receive buffer is shorter
* than the message, always 5
* -EINVAL - buffer address is pointing to NULL
*/
int
iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls,
void *buffer, ulong buflen,
int *flags1_out, ulong * residual_buffer, ulong * residual_length)
{
iparml_db *parm;
ulong b2f0_result;
int moved = 0; /* number of bytes moved from parmlist to buffer */
iucv_debug(2, "entering");
if (!buffer)
return -EINVAL;
parm = (iparml_db *)grab_param();
parm->ipbfadr1 = (__u32) (addr_t) buffer;
parm->ipbfln1f = (__u32) ((ulong) buflen);
parm->ipmsgid = msgid;
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
b2f0_result = b2f0(RECEIVE, parm);
if (!b2f0_result || b2f0_result == 5) {
if (flags1_out) {
iucv_debug(2, "*flags1_out = %d", *flags1_out);
*flags1_out = (parm->ipflags1 & (~0x07));
iucv_debug(2, "*flags1_out = %d", *flags1_out);
}
if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */
if (residual_length)
*residual_length = parm->ipbfln1f;
if (residual_buffer)
*residual_buffer = parm->ipbfadr1;
} else {
moved = min_t (unsigned long, buflen, 8);
memcpy ((char *) buffer,
(char *) &parm->ipbfadr1, moved);
if (buflen < 8)
b2f0_result = 5;
if (residual_length)
*residual_length = abs (buflen - 8);
if (residual_buffer)
*residual_buffer = (ulong) (buffer + moved);
}
}
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_receive_array
* Purpose: This function receives messages that are being sent to you
* over established paths.
* Input: pathid - path identification number
* buffer - address of array of buffers
* buflen - total length of buffers
* msgid - specifies the message ID.
* trgcls - specifies target class
* Output:
* flags1_out: Options for path.
* IPNORPY - 0x10 specifies whether a reply is required
* IPPRTY - 0x20 specifies if you want to send priority message
* IPRMDATA - 0x80 specifies the data is contained in the parameter list
* residual_buffer - address points to the current list entry IUCV
* is working on.
* residual_length -
* Contains one of the following values, if the receive buffer is:
* The same length as the message, this field is zero.
* Longer than the message, this field contains the number of
* bytes remaining in the buffer.
* Shorter than the message, this field contains the residual
* count (that is, the number of bytes remaining in the
* message that does not fit into the buffer. In this case
* b2f0_result = 5.
* Return: b2f0_result - return code from CP
* (-EINVAL) - buffer address is NULL
*/
int
iucv_receive_array (__u16 pathid,
__u32 msgid, __u32 trgcls,
iucv_array_t * buffer, ulong buflen,
int *flags1_out,
ulong * residual_buffer, ulong * residual_length)
{
iparml_db *parm;
ulong b2f0_result;
int i = 0, moved = 0, need_to_move = 8, dyn_len;
iucv_debug(2, "entering");
if (!buffer)
return -EINVAL;
parm = (iparml_db *)grab_param();
parm->ipbfadr1 = (__u32) ((ulong) buffer);
parm->ipbfln1f = (__u32) buflen;
parm->ipmsgid = msgid;
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
b2f0_result = b2f0(RECEIVE, parm);
if (!b2f0_result || b2f0_result == 5) {
if (flags1_out) {
iucv_debug(2, "*flags1_out = %d", *flags1_out);
*flags1_out = (parm->ipflags1 & (~0x07));
iucv_debug(2, "*flags1_out = %d", *flags1_out);
}
if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */
if (residual_length)
*residual_length = parm->ipbfln1f;
if (residual_buffer)
*residual_buffer = parm->ipbfadr1;
} else {
/* copy msg from parmlist to users array. */
while ((moved < 8) && (moved < buflen)) {
dyn_len =
min_t (unsigned int,
(buffer + i)->length, need_to_move);
memcpy ((char *)((ulong)((buffer + i)->address)),
((char *) &parm->ipbfadr1) + moved,
dyn_len);
moved += dyn_len;
need_to_move -= dyn_len;
(buffer + i)->address =
(__u32)
((ulong)(__u8 *) ((ulong)(buffer + i)->address)
+ dyn_len);
(buffer + i)->length -= dyn_len;
i++;
}
if (need_to_move) /* buflen < 8 bytes */
b2f0_result = 5;
if (residual_length)
*residual_length = abs (buflen - 8);
if (residual_buffer) {
if (!moved)
*residual_buffer = (ulong) buffer;
else
*residual_buffer =
(ulong) (buffer + (i - 1));
}
}
}
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/**
* iucv_reject:
* @pathid: Path identification number.
* @msgid: Message ID of the message to reject.
* @trgcls: Target class of the message to reject.
* Returns: return code from CP
*
* Refuses a specified message. Between the time you are notified of a
* message and the time that you complete the message, the message may
* be rejected.
*/
int
iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls)
{
iparml_db *parm;
ulong b2f0_result = 0;
iucv_debug(1, "entering");
iucv_debug(1, "pathid = %d", pathid);
parm = (iparml_db *)grab_param();
parm->ippathid = pathid;
parm->ipmsgid = msgid;
parm->iptrgcls = trgcls;
parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
b2f0_result = b2f0(REJECT, parm);
release_param(parm);
iucv_debug(1, "b2f0_result = %ld", b2f0_result);
iucv_debug(1, "exiting");
return b2f0_result;
}
/*
* Name: iucv_reply
* Purpose: This function responds to the two-way messages that you
* receive. You must identify completely the message to
* which you wish to reply. ie, pathid, msgid, and trgcls.
* Input: pathid - path identification number
* msgid - specifies the message ID.
* trgcls - specifies target class
* flags1 - option for path
* IPPRTY- 0x20 - specifies if you want to send priority message
* buffer - address of reply buffer
* buflen - length of reply buffer
* Output: ipbfadr2 - Address of buffer updated by the number
* of bytes you have moved.
* ipbfln2f - Contains one of the following values:
* If the answer buffer is the same length as the reply, this field
* contains zero.
* If the answer buffer is longer than the reply, this field contains
* the number of bytes remaining in the buffer.
* If the answer buffer is shorter than the reply, this field contains
* a residual count (that is, the number of bytes remianing in the
* reply that does not fit into the buffer. In this
* case b2f0_result = 5.
* Return: b2f0_result - return code from CP
* (-EINVAL) - buffer address is NULL
*/
int
iucv_reply (__u16 pathid,
__u32 msgid, __u32 trgcls,
int flags1,
void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
{
iparml_db *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
if (!buffer)
return -EINVAL;
parm = (iparml_db *)grab_param();
parm->ipbfadr2 = (__u32) ((ulong) buffer);
parm->ipbfln2f = (__u32) buflen; /* length of message */
parm->ippathid = pathid;
parm->ipmsgid = msgid;
parm->iptrgcls = trgcls;
parm->ipflags1 = (__u8) flags1; /* priority message */
b2f0_result = b2f0(REPLY, parm);
if ((!b2f0_result) || (b2f0_result == 5)) {
if (ipbfadr2)
*ipbfadr2 = parm->ipbfadr2;
if (ipbfln2f)
*ipbfln2f = parm->ipbfln2f;
}
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_reply_array
* Purpose: This function responds to the two-way messages that you
* receive. You must identify completely the message to
* which you wish to reply. ie, pathid, msgid, and trgcls.
* The array identifies a list of addresses and lengths of
* discontiguous buffers that contains the reply data.
* Input: pathid - path identification number
* msgid - specifies the message ID.
* trgcls - specifies target class
* flags1 - option for path
* IPPRTY- specifies if you want to send priority message
* buffer - address of array of reply buffers
* buflen - total length of reply buffers
* Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
* ipbfln2f - Contains one of the following values:
* If the answer buffer is the same length as the reply, this field
* contains zero.
* If the answer buffer is longer than the reply, this field contains
* the number of bytes remaining in the buffer.
* If the answer buffer is shorter than the reply, this field contains
* a residual count (that is, the number of bytes remianing in the
* reply that does not fit into the buffer. In this
* case b2f0_result = 5.
* Return: b2f0_result - return code from CP
* (-EINVAL) - buffer address is NULL
*/
int
iucv_reply_array (__u16 pathid,
__u32 msgid, __u32 trgcls,
int flags1,
iucv_array_t * buffer,
ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
{
iparml_db *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
if (!buffer)
return -EINVAL;
parm = (iparml_db *)grab_param();
parm->ipbfadr2 = (__u32) ((ulong) buffer);
parm->ipbfln2f = buflen; /* length of message */
parm->ippathid = pathid;
parm->ipmsgid = msgid;
parm->iptrgcls = trgcls;
parm->ipflags1 = (IPANSLST | flags1);
b2f0_result = b2f0(REPLY, parm);
if ((!b2f0_result) || (b2f0_result == 5)) {
if (ipbfadr2)
*ipbfadr2 = parm->ipbfadr2;
if (ipbfln2f)
*ipbfln2f = parm->ipbfln2f;
}
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_reply_prmmsg
* Purpose: This function responds to the two-way messages that you
* receive. You must identify completely the message to
* which you wish to reply. ie, pathid, msgid, and trgcls.
* Prmmsg signifies the data is moved into the
* parameter list.
* Input: pathid - path identification number
* msgid - specifies the message ID.
* trgcls - specifies target class
* flags1 - option for path
* IPPRTY- specifies if you want to send priority message
* prmmsg - 8-bytes of data to be placed into the parameter
* list.
* Output: NA
* Return: b2f0_result - return code from CP
*/
int
iucv_reply_prmmsg (__u16 pathid,
__u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8])
{
iparml_dpl *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
parm = (iparml_dpl *)grab_param();
parm->ippathid = pathid;
parm->ipmsgid = msgid;
parm->iptrgcls = trgcls;
memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg));
parm->ipflags1 = (IPRMDATA | flags1);
b2f0_result = b2f0(REPLY, parm);
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/**
* iucv_resume:
* @pathid: Path identification number
* @user_data: 16-byte of user data
*
* This function restores communication over a quiesced path.
* Returns: return code from CP
*/
int
iucv_resume (__u16 pathid, __u8 user_data[16])
{
iparml_control *parm;
ulong b2f0_result = 0;
iucv_debug(1, "entering");
iucv_debug(1, "pathid = %d", pathid);
parm = (iparml_control *)grab_param();
memcpy (parm->ipuser, user_data, sizeof (*user_data));
parm->ippathid = pathid;
b2f0_result = b2f0(RESUME, parm);
release_param(parm);
iucv_debug(1, "exiting");
return b2f0_result;
}
/*
* Name: iucv_send
* Purpose: sends messages
* Input: pathid - ushort, pathid
* msgid - ulong *, id of message returned to caller
* trgcls - ulong, target message class
* srccls - ulong, source message class
* msgtag - ulong, message tag
* flags1 - Contains options for this path.
* IPPRTY - Ox20 - specifies if you want to send a priority message.
* buffer - pointer to buffer
* buflen - ulong, length of buffer
* Output: b2f0_result - return code from b2f0 call
* msgid - returns message id
*/
int
iucv_send (__u16 pathid, __u32 * msgid,
__u32 trgcls, __u32 srccls,
__u32 msgtag, int flags1, void *buffer, ulong buflen)
{
iparml_db *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
if (!buffer)
return -EINVAL;
parm = (iparml_db *)grab_param();
parm->ipbfadr1 = (__u32) ((ulong) buffer);
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipbfln1f = (__u32) buflen; /* length of message */
parm->ipsrccls = srccls;
parm->ipmsgtag = msgtag;
parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */
b2f0_result = b2f0(SEND, parm);
if ((!b2f0_result) && (msgid))
*msgid = parm->ipmsgid;
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_send_array
* Purpose: This function transmits data to another application.
* The contents of buffer is the address of the array of
* addresses and lengths of discontiguous buffers that hold
* the message text. This is a one-way message and the
* receiver will not reply to the message.
* Input: pathid - path identification number
* trgcls - specifies target class
* srccls - specifies the source message class
* msgtag - specifies a tag to be associated witht the message
* flags1 - option for path
* IPPRTY- specifies if you want to send priority message
* buffer - address of array of send buffers
* buflen - total length of send buffers
* Output: msgid - specifies the message ID.
* Return: b2f0_result - return code from CP
* (-EINVAL) - buffer address is NULL
*/
int
iucv_send_array (__u16 pathid,
__u32 * msgid,
__u32 trgcls,
__u32 srccls,
__u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
{
iparml_db *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
if (!buffer)
return -EINVAL;
parm = (iparml_db *)grab_param();
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipbfadr1 = (__u32) ((ulong) buffer);
parm->ipbfln1f = (__u32) buflen; /* length of message */
parm->ipsrccls = srccls;
parm->ipmsgtag = msgtag;
parm->ipflags1 = (IPNORPY | IPBUFLST | flags1);
b2f0_result = b2f0(SEND, parm);
if ((!b2f0_result) && (msgid))
*msgid = parm->ipmsgid;
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_send_prmmsg
* Purpose: This function transmits data to another application.
* Prmmsg specifies that the 8-bytes of data are to be moved
* into the parameter list. This is a one-way message and the
* receiver will not reply to the message.
* Input: pathid - path identification number
* trgcls - specifies target class
* srccls - specifies the source message class
* msgtag - specifies a tag to be associated with the message
* flags1 - option for path
* IPPRTY- specifies if you want to send priority message
* prmmsg - 8-bytes of data to be placed into parameter list
* Output: msgid - specifies the message ID.
* Return: b2f0_result - return code from CP
*/
int
iucv_send_prmmsg (__u16 pathid,
__u32 * msgid,
__u32 trgcls,
__u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8])
{
iparml_dpl *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
parm = (iparml_dpl *)grab_param();
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipsrccls = srccls;
parm->ipmsgtag = msgtag;
parm->ipflags1 = (IPRMDATA | IPNORPY | flags1);
memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
b2f0_result = b2f0(SEND, parm);
if ((!b2f0_result) && (msgid))
*msgid = parm->ipmsgid;
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_send2way
* Purpose: This function transmits data to another application.
* Data to be transmitted is in a buffer. The receiver
* of the send is expected to reply to the message and
* a buffer is provided into which IUCV moves the reply
* to this message.
* Input: pathid - path identification number
* trgcls - specifies target class
* srccls - specifies the source message class
* msgtag - specifies a tag associated with the message
* flags1 - option for path
* IPPRTY- specifies if you want to send priority message
* buffer - address of send buffer
* buflen - length of send buffer
* ansbuf - address of buffer to reply with
* anslen - length of buffer to reply with
* Output: msgid - specifies the message ID.
* Return: b2f0_result - return code from CP
* (-EINVAL) - buffer or ansbuf address is NULL
*/
int
iucv_send2way (__u16 pathid,
__u32 * msgid,
__u32 trgcls,
__u32 srccls,
__u32 msgtag,
int flags1,
void *buffer, ulong buflen, void *ansbuf, ulong anslen)
{
iparml_db *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
if (!buffer || !ansbuf)
return -EINVAL;
parm = (iparml_db *)grab_param();
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipbfadr1 = (__u32) ((ulong) buffer);
parm->ipbfln1f = (__u32) buflen; /* length of message */
parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
parm->ipbfln2f = (__u32) anslen;
parm->ipsrccls = srccls;
parm->ipmsgtag = msgtag;
parm->ipflags1 = flags1; /* priority message */
b2f0_result = b2f0(SEND, parm);
if ((!b2f0_result) && (msgid))
*msgid = parm->ipmsgid;
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_send2way_array
* Purpose: This function transmits data to another application.
* The contents of buffer is the address of the array of
* addresses and lengths of discontiguous buffers that hold
* the message text. The receiver of the send is expected to
* reply to the message and a buffer is provided into which
* IUCV moves the reply to this message.
* Input: pathid - path identification number
* trgcls - specifies target class
* srccls - specifies the source message class
* msgtag - spcifies a tag to be associated with the message
* flags1 - option for path
* IPPRTY- specifies if you want to send priority message
* buffer - address of array of send buffers
* buflen - total length of send buffers
* ansbuf - address of buffer to reply with
* anslen - length of buffer to reply with
* Output: msgid - specifies the message ID.
* Return: b2f0_result - return code from CP
* (-EINVAL) - buffer address is NULL
*/
int
iucv_send2way_array (__u16 pathid,
__u32 * msgid,
__u32 trgcls,
__u32 srccls,
__u32 msgtag,
int flags1,
iucv_array_t * buffer,
ulong buflen, iucv_array_t * ansbuf, ulong anslen)
{
iparml_db *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
if (!buffer || !ansbuf)
return -EINVAL;
parm = (iparml_db *)grab_param();
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipbfadr1 = (__u32) ((ulong) buffer);
parm->ipbfln1f = (__u32) buflen; /* length of message */
parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
parm->ipbfln2f = (__u32) anslen;
parm->ipsrccls = srccls;
parm->ipmsgtag = msgtag;
parm->ipflags1 = (IPBUFLST | IPANSLST | flags1);
b2f0_result = b2f0(SEND, parm);
if ((!b2f0_result) && (msgid))
*msgid = parm->ipmsgid;
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_send2way_prmmsg
* Purpose: This function transmits data to another application.
* Prmmsg specifies that the 8-bytes of data are to be moved
* into the parameter list. This is a two-way message and the
* receiver of the message is expected to reply. A buffer
* is provided into which IUCV moves the reply to this
* message.
* Input: pathid - path identification number
* trgcls - specifies target class
* srccls - specifies the source message class
* msgtag - specifies a tag to be associated with the message
* flags1 - option for path
* IPPRTY- specifies if you want to send priority message
* prmmsg - 8-bytes of data to be placed in parameter list
* ansbuf - address of buffer to reply with
* anslen - length of buffer to reply with
* Output: msgid - specifies the message ID.
* Return: b2f0_result - return code from CP
* (-EINVAL) - buffer address is NULL
*/
int
iucv_send2way_prmmsg (__u16 pathid,
__u32 * msgid,
__u32 trgcls,
__u32 srccls,
__u32 msgtag,
ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen)
{
iparml_dpl *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
if (!ansbuf)
return -EINVAL;
parm = (iparml_dpl *)grab_param();
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipsrccls = srccls;
parm->ipmsgtag = msgtag;
parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
parm->ipbfln2f = (__u32) anslen;
parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */
memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
b2f0_result = b2f0(SEND, parm);
if ((!b2f0_result) && (msgid))
*msgid = parm->ipmsgid;
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
/*
* Name: iucv_send2way_prmmsg_array
* Purpose: This function transmits data to another application.
* Prmmsg specifies that the 8-bytes of data are to be moved
* into the parameter list. This is a two-way message and the
* receiver of the message is expected to reply. A buffer
* is provided into which IUCV moves the reply to this
* message. The contents of ansbuf is the address of the
* array of addresses and lengths of discontiguous buffers
* that contain the reply.
* Input: pathid - path identification number
* trgcls - specifies target class
* srccls - specifies the source message class
* msgtag - specifies a tag to be associated with the message
* flags1 - option for path
* IPPRTY- specifies if you want to send priority message
* prmmsg - 8-bytes of data to be placed into the parameter list
* ansbuf - address of buffer to reply with
* anslen - length of buffer to reply with
* Output: msgid - specifies the message ID.
* Return: b2f0_result - return code from CP
* (-EINVAL) - ansbuf address is NULL
*/
int
iucv_send2way_prmmsg_array (__u16 pathid,
__u32 * msgid,
__u32 trgcls,
__u32 srccls,
__u32 msgtag,
int flags1,
__u8 prmmsg[8],
iucv_array_t * ansbuf, ulong anslen)
{
iparml_dpl *parm;
ulong b2f0_result;
iucv_debug(2, "entering");
if (!ansbuf)
return -EINVAL;
parm = (iparml_dpl *)grab_param();
parm->ippathid = pathid;
parm->iptrgcls = trgcls;
parm->ipsrccls = srccls;
parm->ipmsgtag = msgtag;
parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
parm->ipbfln2f = (__u32) anslen;
parm->ipflags1 = (IPRMDATA | IPANSLST | flags1);
memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
b2f0_result = b2f0(SEND, parm);
if ((!b2f0_result) && (msgid))
*msgid = parm->ipmsgid;
release_param(parm);
iucv_debug(2, "exiting");
return b2f0_result;
}
void
iucv_setmask_cpuid (void *result)
{
iparml_set_mask *parm;
iucv_debug(1, "entering");
parm = (iparml_set_mask *)grab_param();
parm->ipmask = *((__u8*)result);
*((ulong *)result) = b2f0(SETMASK, parm);
release_param(parm);
iucv_debug(1, "b2f0_result = %ld", *((ulong *)result));
iucv_debug(1, "exiting");
}
/*
* Name: iucv_setmask
* Purpose: This function enables or disables the following IUCV
* external interruptions: Nonpriority and priority message
* interrupts, nonpriority and priority reply interrupts.
* Input: SetMaskFlag - options for interrupts
* 0x80 - Nonpriority_MessagePendingInterruptsFlag
* 0x40 - Priority_MessagePendingInterruptsFlag
* 0x20 - Nonpriority_MessageCompletionInterruptsFlag
* 0x10 - Priority_MessageCompletionInterruptsFlag
* 0x08 - IUCVControlInterruptsFlag
* Output: NA
* Return: b2f0_result - return code from CP
*/
int
iucv_setmask (int SetMaskFlag)
{
union {
ulong result;
__u8 param;
} u;
int cpu;
u.param = SetMaskFlag;
cpu = get_cpu();
smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid);
put_cpu();
return u.result;
}
/**
* iucv_sever:
* @pathid: Path identification number
* @user_data: 16-byte of user data
*
* This function terminates an iucv path.
* Returns: return code from CP
*/
int
iucv_sever(__u16 pathid, __u8 user_data[16])
{
iparml_control *parm;
ulong b2f0_result = 0;
iucv_debug(1, "entering");
parm = (iparml_control *)grab_param();
memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
parm->ippathid = pathid;
b2f0_result = b2f0(SEVER, parm);
if (!b2f0_result)
iucv_remove_pathid(pathid);
release_param(parm);
iucv_debug(1, "exiting");
return b2f0_result;
}
/*
* Interrupt Handlers
*******************************************************************************/
/**
* iucv_irq_handler:
* @regs: Current registers
* @code: irq code
*
* Handles external interrupts coming in from CP.
* Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
*/
static void
iucv_irq_handler(__u16 code)
{
iucv_irqdata *irqdata;
irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC);
if (!irqdata) {
printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__);
return;
}
memcpy(&irqdata->data, iucv_external_int_buffer,
sizeof(iucv_GeneralInterrupt));
spin_lock(&iucv_irq_queue_lock);
list_add_tail(&irqdata->queue, &iucv_irq_queue);
spin_unlock(&iucv_irq_queue_lock);
tasklet_schedule(&iucv_tasklet);
}
/**
* iucv_do_int:
* @int_buf: Pointer to copy of external interrupt buffer
*
* The workhorse for handling interrupts queued by iucv_irq_handler().
* This function is called from the bottom half iucv_tasklet_handler().
*/
static void
iucv_do_int(iucv_GeneralInterrupt * int_buf)
{
handler *h = NULL;
struct list_head *lh;
ulong flags;
iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */
__u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */
int rc = 0, j = 0;
__u8 no_listener[16] = "NO LISTENER";
iucv_debug(2, "entering, pathid %d, type %02X",
int_buf->ippathid, int_buf->iptype);
iucv_dumpit("External Interrupt Buffer:",
int_buf, sizeof(iucv_GeneralInterrupt));
ASCEBC (no_listener, 16);
if (int_buf->iptype != 01) {
if ((int_buf->ippathid) > (max_connections - 1)) {
printk(KERN_WARNING "%s: Got interrupt with pathid %d"
" > max_connections (%ld)\n", __FUNCTION__,
int_buf->ippathid, max_connections - 1);
} else {
h = iucv_pathid_table[int_buf->ippathid];
interrupt = h->interrupt_table;
iucv_dumpit("Handler:", h, sizeof(handler));
}
}
/* end of if statement */
switch (int_buf->iptype) {
case 0x01: /* connection pending */
if (messagesDisabled) {
iucv_setmask(~0);
messagesDisabled = 0;
}
spin_lock_irqsave(&iucv_lock, flags);
list_for_each(lh, &iucv_handler_table) {
h = list_entry(lh, handler, list);
memcpy(temp_buff1, &(int_buf->ipvmid), 24);
memcpy(temp_buff2, &(h->id.userid), 24);
for (j = 0; j < 24; j++) {
temp_buff1[j] &= (h->id.mask)[j];
temp_buff2[j] &= (h->id.mask)[j];
}
iucv_dumpit("temp_buff1:",
temp_buff1, sizeof(temp_buff1));
iucv_dumpit("temp_buff2",
temp_buff2, sizeof(temp_buff2));
if (!memcmp (temp_buff1, temp_buff2, 24)) {
iucv_debug(2,
"found a matching handler");
break;
} else
h = NULL;
}
spin_unlock_irqrestore (&iucv_lock, flags);
if (h) {
/* ADD PATH TO PATHID TABLE */
rc = iucv_add_pathid(int_buf->ippathid, h);
if (rc) {
iucv_sever (int_buf->ippathid,
no_listener);
iucv_debug(1,
"add_pathid failed, rc = %d",
rc);
} else {
interrupt = h->interrupt_table;
if (interrupt->ConnectionPending) {
EBCASC (int_buf->ipvmid, 8);
interrupt->ConnectionPending(
(iucv_ConnectionPending *)int_buf,
h->pgm_data);
} else
iucv_sever(int_buf->ippathid,
no_listener);
}
} else
iucv_sever(int_buf->ippathid, no_listener);
break;
case 0x02: /*connection complete */
if (messagesDisabled) {
iucv_setmask(~0);
messagesDisabled = 0;
}
if (h) {
if (interrupt->ConnectionComplete)
{
interrupt->ConnectionComplete(
(iucv_ConnectionComplete *)int_buf,
h->pgm_data);
}
else
iucv_debug(1,
"ConnectionComplete not called");
} else
iucv_sever(int_buf->ippathid, no_listener);
break;
case 0x03: /* connection severed */
if (messagesDisabled) {
iucv_setmask(~0);
messagesDisabled = 0;
}
if (h) {
if (interrupt->ConnectionSevered)
interrupt->ConnectionSevered(
(iucv_ConnectionSevered *)int_buf,
h->pgm_data);
else
iucv_sever (int_buf->ippathid, no_listener);
} else
iucv_sever(int_buf->ippathid, no_listener);
break;
case 0x04: /* connection quiesced */
if (messagesDisabled) {
iucv_setmask(~0);
messagesDisabled = 0;
}
if (h) {
if (interrupt->ConnectionQuiesced)
interrupt->ConnectionQuiesced(
(iucv_ConnectionQuiesced *)int_buf,
h->pgm_data);
else
iucv_debug(1,
"ConnectionQuiesced not called");
}
break;
case 0x05: /* connection resumed */
if (messagesDisabled) {
iucv_setmask(~0);
messagesDisabled = 0;
}
if (h) {
if (interrupt->ConnectionResumed)
interrupt->ConnectionResumed(
(iucv_ConnectionResumed *)int_buf,
h->pgm_data);
else
iucv_debug(1,
"ConnectionResumed not called");
}
break;
case 0x06: /* priority message complete */
case 0x07: /* nonpriority message complete */
if (h) {
if (interrupt->MessageComplete)
interrupt->MessageComplete(
(iucv_MessageComplete *)int_buf,
h->pgm_data);
else
iucv_debug(2,
"MessageComplete not called");
}
break;
case 0x08: /* priority message pending */
case 0x09: /* nonpriority message pending */
if (h) {
if (interrupt->MessagePending)
interrupt->MessagePending(
(iucv_MessagePending *) int_buf,
h->pgm_data);
else
iucv_debug(2,
"MessagePending not called");
}
break;
default: /* unknown iucv type */
printk(KERN_WARNING "%s: unknown iucv interrupt\n",
__FUNCTION__);
break;
} /* end switch */
iucv_debug(2, "exiting pathid %d, type %02X",
int_buf->ippathid, int_buf->iptype);
return;
}
/**
* iucv_tasklet_handler:
*
* This function loops over the queue of irq buffers and runs iucv_do_int()
* on every queue element.
*/
static void
iucv_tasklet_handler(unsigned long ignored)
{
struct list_head head;
struct list_head *next;
ulong flags;
spin_lock_irqsave(&iucv_irq_queue_lock, flags);
list_add(&head, &iucv_irq_queue);
list_del_init(&iucv_irq_queue);
spin_unlock_irqrestore (&iucv_irq_queue_lock, flags);
next = head.next;
while (next != &head) {
iucv_irqdata *p = list_entry(next, iucv_irqdata, queue);
next = next->next;
iucv_do_int(&p->data);
kfree(p);
}
return;
}
subsys_initcall(iucv_init);
module_exit(iucv_exit);
/**
* Export all public stuff
*/
EXPORT_SYMBOL (iucv_bus);
EXPORT_SYMBOL (iucv_root);
EXPORT_SYMBOL (iucv_accept);
EXPORT_SYMBOL (iucv_connect);
#if 0
EXPORT_SYMBOL (iucv_purge);
EXPORT_SYMBOL (iucv_query_maxconn);
EXPORT_SYMBOL (iucv_query_bufsize);
EXPORT_SYMBOL (iucv_quiesce);
#endif
EXPORT_SYMBOL (iucv_receive);
#if 0
EXPORT_SYMBOL (iucv_receive_array);
#endif
EXPORT_SYMBOL (iucv_reject);
#if 0
EXPORT_SYMBOL (iucv_reply);
EXPORT_SYMBOL (iucv_reply_array);
EXPORT_SYMBOL (iucv_resume);
#endif
EXPORT_SYMBOL (iucv_reply_prmmsg);
EXPORT_SYMBOL (iucv_send);
EXPORT_SYMBOL (iucv_send2way);
EXPORT_SYMBOL (iucv_send2way_array);
EXPORT_SYMBOL (iucv_send2way_prmmsg);
EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
#if 0
EXPORT_SYMBOL (iucv_send_array);
EXPORT_SYMBOL (iucv_send_prmmsg);
EXPORT_SYMBOL (iucv_setmask);
#endif
EXPORT_SYMBOL (iucv_sever);
EXPORT_SYMBOL (iucv_register_program);
EXPORT_SYMBOL (iucv_unregister_program);
/*
* drivers/s390/net/iucv.h
* IUCV base support.
*
* S390 version
* Copyright (C) 2000 IBM Corporation
* Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
* Xenia Tkatschow (xenia@us.ibm.com)
*
*
* Functionality:
* To explore any of the IUCV functions, one must first register
* their program using iucv_register_program(). Once your program has
* successfully completed a register, it can exploit the other functions.
* For furthur reference on all IUCV functionality, refer to the
* CP Programming Services book, also available on the web
* thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
*
* Definition of Return Codes
* -All positive return codes including zero are reflected back
* from CP except for iucv_register_program. The definition of each
* return code can be found in CP Programming Services book.
* Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
* - Return Code of:
* (-EINVAL) Invalid value
* (-ENOMEM) storage allocation failed
* pgmask defined in iucv_register_program will be set depending on input
* paramters.
*
*/
#include <linux/types.h>
#include <asm/debug.h>
/**
* Debug Facility stuff
*/
#define IUCV_DBF_SETUP_NAME "iucv_setup"
#define IUCV_DBF_SETUP_LEN 32
#define IUCV_DBF_SETUP_PAGES 2
#define IUCV_DBF_SETUP_NR_AREAS 1
#define IUCV_DBF_SETUP_LEVEL 3
#define IUCV_DBF_DATA_NAME "iucv_data"
#define IUCV_DBF_DATA_LEN 128
#define IUCV_DBF_DATA_PAGES 2
#define IUCV_DBF_DATA_NR_AREAS 1
#define IUCV_DBF_DATA_LEVEL 2
#define IUCV_DBF_TRACE_NAME "iucv_trace"
#define IUCV_DBF_TRACE_LEN 16
#define IUCV_DBF_TRACE_PAGES 4
#define IUCV_DBF_TRACE_NR_AREAS 1
#define IUCV_DBF_TRACE_LEVEL 3
#define IUCV_DBF_TEXT(name,level,text) \
do { \
debug_text_event(iucv_dbf_##name,level,text); \
} while (0)
#define IUCV_DBF_HEX(name,level,addr,len) \
do { \
debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
} while (0)
DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
#define IUCV_DBF_TEXT_(name,level,text...) \
do { \
char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \
sprintf(iucv_dbf_txt_buf, text); \
debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
put_cpu_var(iucv_dbf_txt_buf); \
} while (0)
#define IUCV_DBF_SPRINTF(name,level,text...) \
do { \
debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
debug_sprintf_event(iucv_dbf_trace, level, text ); \
} while (0)
/**
* some more debug stuff
*/
#define IUCV_HEXDUMP16(importance,header,ptr) \
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
*(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
*(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
*(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
*(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
*(((char*)ptr)+12),*(((char*)ptr)+13), \
*(((char*)ptr)+14),*(((char*)ptr)+15)); \
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
*(((char*)ptr)+16),*(((char*)ptr)+17), \
*(((char*)ptr)+18),*(((char*)ptr)+19), \
*(((char*)ptr)+20),*(((char*)ptr)+21), \
*(((char*)ptr)+22),*(((char*)ptr)+23), \
*(((char*)ptr)+24),*(((char*)ptr)+25), \
*(((char*)ptr)+26),*(((char*)ptr)+27), \
*(((char*)ptr)+28),*(((char*)ptr)+29), \
*(((char*)ptr)+30),*(((char*)ptr)+31));
static inline void
iucv_hex_dump(unsigned char *buf, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
if (i && !(i % 16))
printk("\n");
printk("%02x ", *(buf + i));
}
printk("\n");
}
/**
* end of debug stuff
*/
#define uchar unsigned char
#define ushort unsigned short
#define ulong unsigned long
#define iucv_handle_t void *
/* flags1:
* All flags are defined in the field IPFLAGS1 of each function
* and can be found in CP Programming Services.
* IPLOCAL - Indicates the connect can only be satisfied on the
* local system
* IPPRTY - Indicates a priority message
* IPQUSCE - Indicates you do not want to receive messages on a
* path until an iucv_resume is issued
* IPRMDATA - Indicates that the message is in the parameter list
*/
#define IPLOCAL 0x01
#define IPPRTY 0x20
#define IPQUSCE 0x40
#define IPRMDATA 0x80
/* flags1_out:
* All flags are defined in the output field of IPFLAGS1 for each function
* and can be found in CP Programming Services.
* IPNORPY - Specifies this is a one-way message and no reply is expected.
* IPPRTY - Indicates a priority message is permitted. Defined in flags1.
*/
#define IPNORPY 0x10
#define Nonpriority_MessagePendingInterruptsFlag 0x80
#define Priority_MessagePendingInterruptsFlag 0x40
#define Nonpriority_MessageCompletionInterruptsFlag 0x20
#define Priority_MessageCompletionInterruptsFlag 0x10
#define IUCVControlInterruptsFlag 0x08
#define AllInterrupts 0xf8
/*
* Mapping of external interrupt buffers should be used with the corresponding
* interrupt types.
* Names: iucv_ConnectionPending -> connection pending
* iucv_ConnectionComplete -> connection complete
* iucv_ConnectionSevered -> connection severed
* iucv_ConnectionQuiesced -> connection quiesced
* iucv_ConnectionResumed -> connection resumed
* iucv_MessagePending -> message pending
* iucv_MessageComplete -> message complete
*/
typedef struct {
u16 ippathid;
uchar ipflags1;
uchar iptype;
u16 ipmsglim;
u16 res1;
uchar ipvmid[8];
uchar ipuser[16];
u32 res3;
uchar ippollfg;
uchar res4[3];
} iucv_ConnectionPending;
typedef struct {
u16 ippathid;
uchar ipflags1;
uchar iptype;
u16 ipmsglim;
u16 res1;
uchar res2[8];
uchar ipuser[16];
u32 res3;
uchar ippollfg;
uchar res4[3];
} iucv_ConnectionComplete;
typedef struct {
u16 ippathid;
uchar res1;
uchar iptype;
u32 res2;
uchar res3[8];
uchar ipuser[16];
u32 res4;
uchar ippollfg;
uchar res5[3];
} iucv_ConnectionSevered;
typedef struct {
u16 ippathid;
uchar res1;
uchar iptype;
u32 res2;
uchar res3[8];
uchar ipuser[16];
u32 res4;
uchar ippollfg;
uchar res5[3];
} iucv_ConnectionQuiesced;
typedef struct {
u16 ippathid;
uchar res1;
uchar iptype;
u32 res2;
uchar res3[8];
uchar ipuser[16];
u32 res4;
uchar ippollfg;
uchar res5[3];
} iucv_ConnectionResumed;
typedef struct {
u16 ippathid;
uchar ipflags1;
uchar iptype;
u32 ipmsgid;
u32 iptrgcls;
union u2 {
u32 iprmmsg1_u32;
uchar iprmmsg1[4];
} ln1msg1;
union u1 {
u32 ipbfln1f;
uchar iprmmsg2[4];
} ln1msg2;
u32 res1[3];
u32 ipbfln2f;
uchar ippollfg;
uchar res2[3];
} iucv_MessagePending;
typedef struct {
u16 ippathid;
uchar ipflags1;
uchar iptype;
u32 ipmsgid;
u32 ipaudit;
uchar iprmmsg[8];
u32 ipsrccls;
u32 ipmsgtag;
u32 res;
u32 ipbfln2f;
uchar ippollfg;
uchar res2[3];
} iucv_MessageComplete;
/*
* iucv_interrupt_ops_t: Is a vector of functions that handle
* IUCV interrupts.
* Parameter list:
* eib - is a pointer to a 40-byte area described
* with one of the structures above.
* pgm_data - this data is strictly for the
* interrupt handler that is passed by
* the application. This may be an address
* or token.
*/
typedef struct {
void (*ConnectionPending) (iucv_ConnectionPending * eib,
void *pgm_data);
void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
void *pgm_data);
void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
void *pgm_data);
void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
void *pgm_data);
void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
void *pgm_data);
void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
} iucv_interrupt_ops_t;
/*
*iucv_array_t : Defines buffer array.
* Inside the array may be 31- bit addresses and 31-bit lengths.
*/
typedef struct {
u32 address;
u32 length;
} iucv_array_t __attribute__ ((aligned (8)));
extern struct bus_type iucv_bus;
extern struct device *iucv_root;
/* -prototypes- */
/*
* Name: iucv_register_program
* Purpose: Registers an application with IUCV
* Input: prmname - user identification
* userid - machine identification
* pgmmask - indicates which bits in the prmname and userid combined will be
* used to determine who is given control
* ops - address of vector of interrupt handlers
* pgm_data- application data passed to interrupt handlers
* Output: NA
* Return: address of handler
* (0) - Error occurred, registration not completed.
* NOTE: Exact cause of failure will be recorded in syslog.
*/
iucv_handle_t iucv_register_program (uchar pgmname[16],
uchar userid[8],
uchar pgmmask[24],
iucv_interrupt_ops_t * ops,
void *pgm_data);
/*
* Name: iucv_unregister_program
* Purpose: Unregister application with IUCV
* Input: address of handler
* Output: NA
* Return: (0) - Normal return
* (-EINVAL) - Internal error, wild pointer
*/
int iucv_unregister_program (iucv_handle_t handle);
/*
* Name: iucv_accept
* Purpose: This function is issued after the user receives a Connection Pending external
* interrupt and now wishes to complete the IUCV communication path.
* Input: pathid - u16 , Path identification number
* msglim_reqstd - u16, The number of outstanding messages requested.
* user_data - uchar[16], Data specified by the iucv_connect function.
* flags1 - int, Contains options for this path.
* -IPPRTY - 0x20- Specifies if you want to send priority message.
* -IPRMDATA - 0x80, Specifies whether your program can handle a message
* in the parameter list.
* -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
* established.
* handle - iucv_handle_t, Address of handler.
* pgm_data - void *, Application data passed to interrupt handlers.
* flags1_out - int * Contains information about the path
* - IPPRTY - 0x20, Indicates you may send priority messages.
* msglim - *u16, Number of outstanding messages.
* Output: return code from CP IUCV call.
*/
int iucv_accept (u16 pathid,
u16 msglim_reqstd,
uchar user_data[16],
int flags1,
iucv_handle_t handle,
void *pgm_data, int *flags1_out, u16 * msglim);
/*
* Name: iucv_connect
* Purpose: This function establishes an IUCV path. Although the connect may complete
* successfully, you are not able to use the path until you receive an IUCV
* Connection Complete external interrupt.
* Input: pathid - u16 *, Path identification number
* msglim_reqstd - u16, Number of outstanding messages requested
* user_data - uchar[16], 16-byte user data
* userid - uchar[8], User identification
* system_name - uchar[8], 8-byte identifying the system name
* flags1 - int, Contains options for this path.
* -IPPRTY - 0x20, Specifies if you want to send priority message.
* -IPRMDATA - 0x80, Specifies whether your program can handle a message
* in the parameter list.
* -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
* established.
* -IPLOCAL - 0X01, Allows an application to force the partner to be on
* the local system. If local is specified then target class cannot be
* specified.
* flags1_out - int * Contains information about the path
* - IPPRTY - 0x20, Indicates you may send priority messages.
* msglim - * u16, Number of outstanding messages
* handle - iucv_handle_t, Address of handler
* pgm_data - void *, Application data passed to interrupt handlers
* Output: return code from CP IUCV call
* rc - return code from iucv_declare_buffer
* -EINVAL - Invalid handle passed by application
* -EINVAL - Pathid address is NULL
* add_pathid_result - Return code from internal function add_pathid
*/
int
iucv_connect (u16 * pathid,
u16 msglim_reqstd,
uchar user_data[16],
uchar userid[8],
uchar system_name[8],
int flags1,
int *flags1_out,
u16 * msglim, iucv_handle_t handle, void *pgm_data);
/*
* Name: iucv_purge
* Purpose: This function cancels a message that you have sent.
* Input: pathid - Path identification number.
* msgid - Specifies the message ID of the message to be purged.
* srccls - Specifies the source message class.
* Output: audit - Contains information about asynchronous error
* that may have affected the normal completion
* of this message.
* Return: Return code from CP IUCV call.
*/
int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit);
/*
* Name: iucv_query_maxconn
* Purpose: This function determines the maximum number of communication paths you
* may establish.
* Return: maxconn - ulong, Maximum number of connection the virtual machine may
* establish.
*/
ulong iucv_query_maxconn (void);
/*
* Name: iucv_query_bufsize
* Purpose: This function determines how large an external interrupt
* buffer IUCV requires to store information.
* Return: bufsize - ulong, Size of external interrupt buffer.
*/
ulong iucv_query_bufsize (void);
/*
* Name: iucv_quiesce
* Purpose: This function temporarily suspends incoming messages on an
* IUCV path. You can later reactivate the path by invoking
* the iucv_resume function.
* Input: pathid - Path identification number
* user_data - 16-bytes of user data
* Output: NA
* Return: Return code from CP IUCV call.
*/
int iucv_quiesce (u16 pathid, uchar user_data[16]);
/*
* Name: iucv_receive
* Purpose: This function receives messages that are being sent to you
* over established paths. Data will be returned in buffer for length of
* buflen.
* Input:
* pathid - Path identification number.
* buffer - Address of buffer to receive.
* buflen - Length of buffer to receive.
* msgid - Specifies the message ID.
* trgcls - Specifies target class.
* Output:
* flags1_out: int *, Contains information about this path.
* IPNORPY - 0x10 Specifies this is a one-way message and no reply is
* expected.
* IPPRTY - 0x20 Specifies if you want to send priority message.
* IPRMDATA - 0x80 specifies the data is contained in the parameter list
* residual_buffer - address of buffer updated by the number
* of bytes you have received.
* residual_length -
* Contains one of the following values, if the receive buffer is:
* The same length as the message, this field is zero.
* Longer than the message, this field contains the number of
* bytes remaining in the buffer.
* Shorter than the message, this field contains the residual
* count (that is, the number of bytes remaining in the
* message that does not fit into the buffer. In this
* case b2f0_result = 5.
* Return: Return code from CP IUCV call.
* (-EINVAL) - buffer address is pointing to NULL
*/
int iucv_receive (u16 pathid,
u32 msgid,
u32 trgcls,
void *buffer,
ulong buflen,
int *flags1_out,
ulong * residual_buffer, ulong * residual_length);
/*
* Name: iucv_receive_array
* Purpose: This function receives messages that are being sent to you
* over established paths. Data will be returned in first buffer for
* length of first buffer.
* Input: pathid - Path identification number.
* msgid - specifies the message ID.
* trgcls - Specifies target class.
* buffer - Address of array of buffers.
* buflen - Total length of buffers.
* Output:
* flags1_out: int *, Contains information about this path.
* IPNORPY - 0x10 Specifies this is a one-way message and no reply is
* expected.
* IPPRTY - 0x20 Specifies if you want to send priority message.
* IPRMDATA - 0x80 specifies the data is contained in the parameter list
* residual_buffer - address points to the current list entry IUCV
* is working on.
* residual_length -
* Contains one of the following values, if the receive buffer is:
* The same length as the message, this field is zero.
* Longer than the message, this field contains the number of
* bytes remaining in the buffer.
* Shorter than the message, this field contains the residual
* count (that is, the number of bytes remaining in the
* message that does not fit into the buffer. In this
* case b2f0_result = 5.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Buffer address is NULL.
*/
int iucv_receive_array (u16 pathid,
u32 msgid,
u32 trgcls,
iucv_array_t * buffer,
ulong buflen,
int *flags1_out,
ulong * residual_buffer, ulong * residual_length);
/*
* Name: iucv_reject
* Purpose: The reject function refuses a specified message. Between the
* time you are notified of a message and the time that you
* complete the message, the message may be rejected.
* Input: pathid - Path identification number.
* msgid - Specifies the message ID.
* trgcls - Specifies target class.
* Output: NA
* Return: Return code from CP IUCV call.
*/
int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
/*
* Name: iucv_reply
* Purpose: This function responds to the two-way messages that you
* receive. You must identify completely the message to
* which you wish to reply. ie, pathid, msgid, and trgcls.
* Input: pathid - Path identification number.
* msgid - Specifies the message ID.
* trgcls - Specifies target class.
* flags1 - Option for path.
* IPPRTY- 0x20, Specifies if you want to send priority message.
* buffer - Address of reply buffer.
* buflen - Length of reply buffer.
* Output: residual_buffer - Address of buffer updated by the number
* of bytes you have moved.
* residual_length - Contains one of the following values:
* If the answer buffer is the same length as the reply, this field
* contains zero.
* If the answer buffer is longer than the reply, this field contains
* the number of bytes remaining in the buffer.
* If the answer buffer is shorter than the reply, this field contains
* a residual count (that is, the number of bytes remianing in the
* reply that does not fit into the buffer. In this
* case b2f0_result = 5.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Buffer address is NULL.
*/
int iucv_reply (u16 pathid,
u32 msgid,
u32 trgcls,
int flags1,
void *buffer, ulong buflen, ulong * residual_buffer,
ulong * residual_length);
/*
* Name: iucv_reply_array
* Purpose: This function responds to the two-way messages that you
* receive. You must identify completely the message to
* which you wish to reply. ie, pathid, msgid, and trgcls.
* The array identifies a list of addresses and lengths of
* discontiguous buffers that contains the reply data.
* Input: pathid - Path identification number
* msgid - Specifies the message ID.
* trgcls - Specifies target class.
* flags1 - Option for path.
* IPPRTY- 0x20, Specifies if you want to send priority message.
* buffer - Address of array of reply buffers.
* buflen - Total length of reply buffers.
* Output: residual_buffer - Address of buffer which IUCV is currently working on.
* residual_length - Contains one of the following values:
* If the answer buffer is the same length as the reply, this field
* contains zero.
* If the answer buffer is longer than the reply, this field contains
* the number of bytes remaining in the buffer.
* If the answer buffer is shorter than the reply, this field contains
* a residual count (that is, the number of bytes remianing in the
* reply that does not fit into the buffer. In this
* case b2f0_result = 5.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Buffer address is NULL.
*/
int iucv_reply_array (u16 pathid,
u32 msgid,
u32 trgcls,
int flags1,
iucv_array_t * buffer,
ulong buflen, ulong * residual_address,
ulong * residual_length);
/*
* Name: iucv_reply_prmmsg
* Purpose: This function responds to the two-way messages that you
* receive. You must identify completely the message to
* which you wish to reply. ie, pathid, msgid, and trgcls.
* Prmmsg signifies the data is moved into the
* parameter list.
* Input: pathid - Path identification number.
* msgid - Specifies the message ID.
* trgcls - Specifies target class.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
* prmmsg - 8-bytes of data to be placed into the parameter.
* list.
* Output: NA
* Return: Return code from CP IUCV call.
*/
int iucv_reply_prmmsg (u16 pathid,
u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
/*
* Name: iucv_resume
* Purpose: This function restores communications over a quiesced path
* Input: pathid - Path identification number.
* user_data - 16-bytes of user data.
* Output: NA
* Return: Return code from CP IUCV call.
*/
int iucv_resume (u16 pathid, uchar user_data[16]);
/*
* Name: iucv_send
* Purpose: This function transmits data to another application.
* Data to be transmitted is in a buffer and this is a
* one-way message and the receiver will not reply to the
* message.
* Input: pathid - Path identification number.
* trgcls - Specifies target class.
* srccls - Specifies the source message class.
* msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
* buffer - Address of send buffer.
* buflen - Length of send buffer.
* Output: msgid - Specifies the message ID.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Buffer address is NULL.
*/
int iucv_send (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
/*
* Name: iucv_send_array
* Purpose: This function transmits data to another application.
* The contents of buffer is the address of the array of
* addresses and lengths of discontiguous buffers that hold
* the message text. This is a one-way message and the
* receiver will not reply to the message.
* Input: pathid - Path identification number.
* trgcls - Specifies target class.
* srccls - Specifies the source message class.
* msgtag - Specifies a tag to be associated witht the message.
* flags1 - Option for path.
* IPPRTY- specifies if you want to send priority message.
* buffer - Address of array of send buffers.
* buflen - Total length of send buffers.
* Output: msgid - Specifies the message ID.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Buffer address is NULL.
*/
int iucv_send_array (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls,
u32 msgtag,
int flags1, iucv_array_t * buffer, ulong buflen);
/*
* Name: iucv_send_prmmsg
* Purpose: This function transmits data to another application.
* Prmmsg specifies that the 8-bytes of data are to be moved
* into the parameter list. This is a one-way message and the
* receiver will not reply to the message.
* Input: pathid - Path identification number.
* trgcls - Specifies target class.
* srccls - Specifies the source message class.
* msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 specifies if you want to send priority message.
* prmmsg - 8-bytes of data to be placed into parameter list.
* Output: msgid - Specifies the message ID.
* Return: Return code from CP IUCV call.
*/
int iucv_send_prmmsg (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
/*
* Name: iucv_send2way
* Purpose: This function transmits data to another application.
* Data to be transmitted is in a buffer. The receiver
* of the send is expected to reply to the message and
* a buffer is provided into which IUCV moves the reply
* to this message.
* Input: pathid - Path identification number.
* trgcls - Specifies target class.
* srccls - Specifies the source message class.
* msgtag - Specifies a tag associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
* buffer - Address of send buffer.
* buflen - Length of send buffer.
* ansbuf - Address of buffer into which IUCV moves the reply of
* this message.
* anslen - Address of length of buffer.
* Output: msgid - Specifies the message ID.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Buffer or ansbuf address is NULL.
*/
int iucv_send2way (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls,
u32 msgtag,
int flags1,
void *buffer, ulong buflen, void *ansbuf, ulong anslen);
/*
* Name: iucv_send2way_array
* Purpose: This function transmits data to another application.
* The contents of buffer is the address of the array of
* addresses and lengths of discontiguous buffers that hold
* the message text. The receiver of the send is expected to
* reply to the message and a buffer is provided into which
* IUCV moves the reply to this message.
* Input: pathid - Path identification number.
* trgcls - Specifies target class.
* srccls - Specifies the source message class.
* msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
* buffer - Sddress of array of send buffers.
* buflen - Total length of send buffers.
* ansbuf - Address of array of buffer into which IUCV moves the reply
* of this message.
* anslen - Address of length reply buffers.
* Output: msgid - Specifies the message ID.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Buffer address is NULL.
*/
int iucv_send2way_array (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls,
u32 msgtag,
int flags1,
iucv_array_t * buffer,
ulong buflen, iucv_array_t * ansbuf, ulong anslen);
/*
* Name: iucv_send2way_prmmsg
* Purpose: This function transmits data to another application.
* Prmmsg specifies that the 8-bytes of data are to be moved
* into the parameter list. This is a two-way message and the
* receiver of the message is expected to reply. A buffer
* is provided into which IUCV moves the reply to this
* message.
* Input: pathid - Rath identification number.
* trgcls - Specifies target class.
* srccls - Specifies the source message class.
* msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 Specifies if you want to send priority message.
* prmmsg - 8-bytes of data to be placed in parameter list.
* ansbuf - Address of buffer into which IUCV moves the reply of
* this message.
* anslen - Address of length of buffer.
* Output: msgid - Specifies the message ID.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Buffer address is NULL.
*/
int iucv_send2way_prmmsg (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls,
u32 msgtag,
ulong flags1,
uchar prmmsg[8], void *ansbuf, ulong anslen);
/*
* Name: iucv_send2way_prmmsg_array
* Purpose: This function transmits data to another application.
* Prmmsg specifies that the 8-bytes of data are to be moved
* into the parameter list. This is a two-way message and the
* receiver of the message is expected to reply. A buffer
* is provided into which IUCV moves the reply to this
* message. The contents of ansbuf is the address of the
* array of addresses and lengths of discontiguous buffers
* that contain the reply.
* Input: pathid - Path identification number.
* trgcls - Specifies target class.
* srccls - Specifies the source message class.
* msgtag - Specifies a tag to be associated with the message.
* flags1 - Option for path.
* IPPRTY- 0x20 specifies if you want to send priority message.
* prmmsg - 8-bytes of data to be placed into the parameter list.
* ansbuf - Address of array of buffer into which IUCV moves the reply
* of this message.
* anslen - Address of length of reply buffers.
* Output: msgid - Specifies the message ID.
* Return: Return code from CP IUCV call.
* (-EINVAL) - Ansbuf address is NULL.
*/
int iucv_send2way_prmmsg_array (u16 pathid,
u32 * msgid,
u32 trgcls,
u32 srccls,
u32 msgtag,
int flags1,
uchar prmmsg[8],
iucv_array_t * ansbuf, ulong anslen);
/*
* Name: iucv_setmask
* Purpose: This function enables or disables the following IUCV
* external interruptions: Nonpriority and priority message
* interrupts, nonpriority and priority reply interrupts.
* Input: SetMaskFlag - options for interrupts
* 0x80 - Nonpriority_MessagePendingInterruptsFlag
* 0x40 - Priority_MessagePendingInterruptsFlag
* 0x20 - Nonpriority_MessageCompletionInterruptsFlag
* 0x10 - Priority_MessageCompletionInterruptsFlag
* 0x08 - IUCVControlInterruptsFlag
* Output: NA
* Return: Return code from CP IUCV call.
*/
int iucv_setmask (int SetMaskFlag);
/*
* Name: iucv_sever
* Purpose: This function terminates an IUCV path.
* Input: pathid - Path identification number.
* user_data - 16-bytes of user data.
* Output: NA
* Return: Return code from CP IUCV call.
* (-EINVAL) - Interal error, wild pointer.
*/
int iucv_sever (u16 pathid, uchar user_data[16]);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册