fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / s390 / net / iucv.c
index 5771fb3..229aeb5 100644 (file)
@@ -1,6 +1,4 @@
-/* 
- * $Id: iucv.c,v 1.28 2004/04/15 06:34:58 braunu Exp $
- *
+/*
  * IUCV network driver
  *
  * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
  * 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.28 $
- *
  */
-\f
+
 /* #define DEBUG */
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/config.h>
 
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
@@ -53,7 +48,8 @@
 #include <asm/io.h>
 #include <asm/s390_ext.h>
 #include <asm/ebcdic.h>
-#include <asm/ccwdev.h> //for root device stuff
+#include <asm/smp.h>
+#include <asm/s390_rdev.h>
 
 /* FLAGS:
  * All flags are defined in the field IPFLAGS1 of each function
@@ -84,7 +80,7 @@ iucv_bus_match (struct device *dev, struct device_driver *drv)
 struct bus_type iucv_bus = {
        .name = "iucv",
        .match = iucv_bus_match,
-};     
+};
 
 struct device *iucv_root;
 
@@ -98,11 +94,11 @@ typedef struct {
        __u8  res3[24];
 } iucv_GeneralInterrupt;
 
-static iucv_GeneralInterrupt *iucv_external_int_buffer;
+static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL;
 
 /* Spin Lock declaration */
 
-static spinlock_t iucv_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(iucv_lock);
 
 static int messagesDisabled = 0;
 
@@ -114,13 +110,13 @@ typedef struct {
 } iucv_irqdata;
 
 static struct list_head  iucv_irq_queue;
-static spinlock_t iucv_irq_queue_lock = SPIN_LOCK_UNLOCKED;
+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 void iucv_irq_handler(__u16);
 
 static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0);
 
@@ -177,9 +173,11 @@ static handler **iucv_pathid_table;
 static unsigned long max_connections;
 
 /**
- * declare_flag: is 0 when iucv_declare_buffer has not been called
+ * 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 declare_flag;
+static int iucv_cpuid = -1;
 /**
  * register_flag: is 0 when external interrupt has not been registered
  */
@@ -285,6 +283,7 @@ typedef struct {
                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))
 
@@ -297,7 +296,7 @@ MODULE_LICENSE("GPL");
 /*
  * Debugging stuff
  *******************************************************************************/
-\f
+
 
 #ifdef DEBUG
 static int debuglevel = 0;
@@ -336,32 +335,22 @@ do { \
 
 #else
 
-#define iucv_debug(lvl, fmt, args...)
-#define iucv_dumpit(title, buf, len)
+#define iucv_debug(lvl, fmt, args...)  do { } while (0)
+#define iucv_dumpit(title, buf, len)   do { } while (0)
 
 #endif
 
 /*
  * Internal functions
  *******************************************************************************/
-\f
+
 /**
  * print start banner
  */
 static void
 iucv_banner(void)
 {
-       char vbuf[] = "$Revision: 1.28 $";
-       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);
+       printk(KERN_INFO "IUCV lowlevel driver initialized\n");
 }
 
 /**
@@ -383,7 +372,7 @@ iucv_init(void)
        }
 
        ret = bus_register(&iucv_bus);
-       if (ret != 0) {
+       if (ret) {
                printk(KERN_ERR "IUCV: failed to register bus.\n");
                return ret;
        }
@@ -396,19 +385,19 @@ iucv_init(void)
        }
 
        /* Note: GFP_DMA used used to get memory below 2G */
-       iucv_external_int_buffer = kmalloc(sizeof(iucv_GeneralInterrupt),
+       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;
        }
-       memset(iucv_external_int_buffer, 0, sizeof(iucv_GeneralInterrupt));
 
        /* Initialize parameter pool */
-       iucv_param_pool = kmalloc(sizeof(iucv_param) * PARAM_POOL_SIZE,
+       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",
@@ -416,9 +405,9 @@ iucv_init(void)
                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);
@@ -441,10 +430,10 @@ static void
 iucv_exit(void)
 {
        iucv_retrieve_buffer();
-       if (iucv_external_int_buffer)
-               kfree(iucv_external_int_buffer);
-       if (iucv_param_pool)
-               kfree(iucv_param_pool);
+       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");
@@ -463,17 +452,19 @@ iucv_exit(void)
 static __inline__ iucv_param *
 grab_param(void)
 {
-       iucv_param *ret;
-       static int i = 0;
-
-       while (atomic_compare_and_swap(0, 1, &iucv_param_pool[i].in_use)) {
-               i++;
-               if (i >= PARAM_POOL_SIZE)
-                       i = 0;
-       }
-       ret = &iucv_param_pool[i];
-       memset(&ret->param, 0, sizeof(ret->param));
-       return ret;
+       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;
 }
 
 /**
@@ -516,7 +507,7 @@ iucv_add_handler (handler *new)
                 */
                list_for_each(lh, &iucv_handler_table) {
                        handler *h = list_entry(lh, handler, list);
-                       if (memcmp(&new->id, &h->id, sizeof(h->id)) == 0) {
+                       if (!memcmp(&new->id, &h->id, sizeof(h->id))) {
                                iucv_debug(1, "ret 1");
                                spin_unlock_irqrestore (&iucv_lock, flags);
                                return 1;
@@ -543,19 +534,15 @@ iucv_add_handler (handler *new)
  *
  * Returns: return code from CP's IUCV call
  */
-static __inline__ ulong
-b2f0(__u32 code, void *parm)
+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));
 
-       asm volatile (
-               "LRA   1,0(%1)\n\t"
-               "LR    0,%0\n\t"
-               ".long 0xb2f01000"
-               :
-               : "d" (code), "a" (parm)
-               : "0", "1"
-               );
+       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));
 
@@ -622,17 +609,15 @@ iucv_remove_pathid(__u16 pathid)
 }
 
 /**
- * iucv_declare_buffer_cpu0
- * Register at VM for subsequent IUCV operations. This is always
- * executed on CPU 0. Called from iucv_declare_buffer().
+ * 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_cpu0 (void *result)
+iucv_declare_buffer_cpuid (void *result)
 {
        iparml_db *parm;
 
-       if (!(result && (smp_processor_id() == 0)))
-               return;
        parm = (iparml_db *)grab_param();
        parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
        if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)
@@ -641,17 +626,16 @@ iucv_declare_buffer_cpu0 (void *result)
 }
 
 /**
- * iucv_retrieve_buffer_cpu0:
- * Unregister IUCV usage at VM. This is always executed on CPU 0.
+ * 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_cpu0 (void *result)
+iucv_retrieve_buffer_cpuid (void *cpu)
 {
        iparml_control *parm;
 
-       if (smp_processor_id() != 0)
-               return;
        parm = (iparml_control *)grab_param();
        b2f0(RETRIEVE_BUFFER, parm);
        release_param(parm);
@@ -667,18 +651,27 @@ iucv_retrieve_buffer_cpu0 (void *result)
 static int
 iucv_declare_buffer (void)
 {
-       ulong b2f0_result = 0x0deadbeef;
+       unsigned long flags;
+       ulong b2f0_result;
 
        iucv_debug(1, "entering");
-       preempt_disable();
-       if (smp_processor_id() == 0)
-               iucv_declare_buffer_cpu0(&b2f0_result);
-       else
-               smp_call_function(iucv_declare_buffer_cpu0, &b2f0_result, 0, 1);
-       preempt_enable();
-       iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
-       if (b2f0_result == 0x0deadbeef)
-           b2f0_result = 0xaa;
+       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;
 }
@@ -693,14 +686,12 @@ static int
 iucv_retrieve_buffer (void)
 {
        iucv_debug(1, "entering");
-       if (declare_flag) {
-               preempt_disable();
-               if (smp_processor_id() == 0)
-                       iucv_retrieve_buffer_cpu0(0);
-               else
-                       smp_call_function(iucv_retrieve_buffer_cpu0, 0, 0, 1);
-               declare_flag = 0;
-               preempt_enable();
+       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;
@@ -781,7 +772,7 @@ iucv_register_program (__u8 pgmname[16],
        }
 
        /* Allocate handler entry */
-       new_handler = (handler *)kmalloc(sizeof(handler), GFP_ATOMIC);
+       new_handler = kmalloc(sizeof(handler), GFP_ATOMIC);
        if (new_handler == NULL) {
                printk(KERN_WARNING "%s: storage allocation for new handler "
                       "failed.\n", __FUNCTION__);
@@ -795,15 +786,14 @@ iucv_register_program (__u8 pgmname[16],
                }
 
                max_connections = iucv_query_maxconn();
-               iucv_pathid_table = kmalloc(max_connections * sizeof(handler *),
-                                      GFP_ATOMIC);
+               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 (iucv_pathid_table, 0, max_connections * sizeof(handler *));
        }
        memset(new_handler, 0, sizeof (handler));
        memcpy(new_handler->id.user_data, pgmname,
@@ -815,7 +805,7 @@ iucv_register_program (__u8 pgmname[16],
                        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));
@@ -853,40 +843,33 @@ iucv_register_program (__u8 pgmname[16],
                return NULL;
        }
 
-       if (declare_flag == 0) {
-               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;
-                               case 0xaa:
-                                       err = "Function not called";
-                                       break;
-                       }
-                       printk(KERN_WARNING "%s: iucv_declare_buffer "
-                              "returned error 0x%02lx (%s)\n", __FUNCTION__, rc,
-                              err);
-                       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;
                }
-               declare_flag = 1;
+               printk(KERN_WARNING "%s: iucv_declare_buffer "
+                      "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err);
+               return NULL;
        }
-       if (register_flag == 0) {
+       if (!register_flag) {
                /* request the 0x4000 external interrupt */
                rc = register_external_interrupt (0x4000, iucv_irq_handler);
                if (rc) {
@@ -1036,7 +1019,7 @@ iucv_accept(__u16 pathid, __u16 msglim_reqstd,
        parm->ipflags1 = (__u8)flags1;
        b2f0_result = b2f0(ACCEPT, parm);
 
-       if (b2f0_result == 0) {
+       if (!b2f0_result) {
                if (msglim)
                        *msglim = parm->ipmsglim;
                if (pgm_data)
@@ -1176,7 +1159,7 @@ iucv_connect (__u16 *pathid, __u16 msglim_reqstd,
        memcpy(&local_parm, parm, sizeof(local_parm));
        release_param(parm);
        parm = &local_parm;
-       if (b2f0_result == 0)
+       if (!b2f0_result)
                add_pathid_result = __iucv_add_pathid(parm->ippathid, h);
        spin_unlock_irqrestore (&iucv_lock, flags);
 
@@ -1236,12 +1219,12 @@ iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
        parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
        b2f0_result = b2f0(PURGE, parm);
 
-       if ((b2f0_result == 0) && audit) {
+       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);
@@ -1261,6 +1244,8 @@ iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
 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;
@@ -1269,18 +1254,15 @@ iucv_query_generic(int want_maxconn)
         * Call b2f0 and store R0 (max buffer size),
         * R1 (max connections) and CC.
         */
-       asm volatile (
-               "LRA   1,0(%4)\n\t"
-               "LR    0,%3\n\t"
-               ".long 0xb2f01000\n\t"
-               "IPM   %0\n\t"
-               "SRL   %0,28\n\t"
-               "ST    0,%1\n\t"
-               "ST    1,%2\n\t"
-               : "=d" (ccode), "=m" (bufsize), "=m" (maxconn)
-               : "d" (QUERY), "a" (parm)
-               : "0", "1", "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)
@@ -1400,7 +1382,7 @@ iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls,
 
        b2f0_result = b2f0(RECEIVE, parm);
 
-       if (b2f0_result == 0 || b2f0_result == 5) {
+       if (!b2f0_result || b2f0_result == 5) {
                if (flags1_out) {
                        iucv_debug(2, "*flags1_out = %d", *flags1_out);
                        *flags1_out = (parm->ipflags1 & (~0x07));
@@ -1490,7 +1472,7 @@ iucv_receive_array (__u16 pathid,
 
        b2f0_result = b2f0(RECEIVE, parm);
 
-       if (b2f0_result == 0 || b2f0_result == 5) {
+       if (!b2f0_result || b2f0_result == 5) {
 
                if (flags1_out) {
                        iucv_debug(2, "*flags1_out = %d", *flags1_out);
@@ -1537,7 +1519,7 @@ iucv_receive_array (__u16 pathid,
                                *residual_length = abs (buflen - 8);
 
                        if (residual_buffer) {
-                               if (moved == 0)
+                               if (!moved)
                                        *residual_buffer = (ulong) buffer;
                                else
                                        *residual_buffer =
@@ -1639,7 +1621,7 @@ iucv_reply (__u16 pathid,
 
        b2f0_result = b2f0(REPLY, parm);
 
-       if ((b2f0_result == 0) || (b2f0_result == 5)) {
+       if ((!b2f0_result) || (b2f0_result == 5)) {
                if (ipbfadr2)
                        *ipbfadr2 = parm->ipbfadr2;
                if (ipbfln2f)
@@ -1705,7 +1687,7 @@ iucv_reply_array (__u16 pathid,
 
        b2f0_result = b2f0(REPLY, parm);
 
-       if ((b2f0_result == 0) || (b2f0_result == 5)) {
+       if ((!b2f0_result) || (b2f0_result == 5)) {
 
                if (ipbfadr2)
                        *ipbfadr2 = parm->ipbfadr2;
@@ -1831,7 +1813,7 @@ iucv_send (__u16 pathid, __u32 * msgid,
 
        b2f0_result = b2f0(SEND, parm);
 
-       if ((b2f0_result == 0) && (msgid))
+       if ((!b2f0_result) && (msgid))
                *msgid = parm->ipmsgid;
        release_param(parm);
 
@@ -1885,7 +1867,7 @@ iucv_send_array (__u16 pathid,
        parm->ipflags1 = (IPNORPY | IPBUFLST | flags1);
        b2f0_result = b2f0(SEND, parm);
 
-       if ((b2f0_result == 0) && (msgid))
+       if ((!b2f0_result) && (msgid))
                *msgid = parm->ipmsgid;
        release_param(parm);
 
@@ -1931,7 +1913,7 @@ iucv_send_prmmsg (__u16 pathid,
 
        b2f0_result = b2f0(SEND, parm);
 
-       if ((b2f0_result == 0) && (msgid))
+       if ((!b2f0_result) && (msgid))
                *msgid = parm->ipmsgid;
        release_param(parm);
 
@@ -1992,7 +1974,7 @@ iucv_send2way (__u16 pathid,
 
        b2f0_result = b2f0(SEND, parm);
 
-       if ((b2f0_result == 0) && (msgid))
+       if ((!b2f0_result) && (msgid))
                *msgid = parm->ipmsgid;
        release_param(parm);
 
@@ -2053,7 +2035,7 @@ iucv_send2way_array (__u16 pathid,
        parm->ipmsgtag = msgtag;
        parm->ipflags1 = (IPBUFLST | IPANSLST | flags1);
        b2f0_result = b2f0(SEND, parm);
-       if ((b2f0_result == 0) && (msgid))
+       if ((!b2f0_result) && (msgid))
                *msgid = parm->ipmsgid;
        release_param(parm);
 
@@ -2111,7 +2093,7 @@ iucv_send2way_prmmsg (__u16 pathid,
 
        b2f0_result = b2f0(SEND, parm);
 
-       if ((b2f0_result == 0) && (msgid))
+       if ((!b2f0_result) && (msgid))
                *msgid = parm->ipmsgid;
        release_param(parm);
 
@@ -2172,7 +2154,7 @@ iucv_send2way_prmmsg_array (__u16 pathid,
        parm->ipflags1 = (IPRMDATA | IPANSLST | flags1);
        memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
        b2f0_result = b2f0(SEND, parm);
-       if ((b2f0_result == 0) && (msgid))
+       if ((!b2f0_result) && (msgid))
                *msgid = parm->ipmsgid;
        release_param(parm);
 
@@ -2181,13 +2163,10 @@ iucv_send2way_prmmsg_array (__u16 pathid,
 }
 
 void
-iucv_setmask_cpu0 (void *result)
+iucv_setmask_cpuid (void *result)
 {
         iparml_set_mask *parm;
 
-        if (smp_processor_id() != 0)
-                return;
-
         iucv_debug(1, "entering");
         parm = (iparml_set_mask *)grab_param();
         parm->ipmask = *((__u8*)result);
@@ -2219,14 +2198,12 @@ iucv_setmask (int SetMaskFlag)
                ulong result;
                __u8  param;
        } u;
+       int cpu;
 
        u.param = SetMaskFlag;
-       preempt_disable();
-       if (smp_processor_id() == 0)
-               iucv_setmask_cpu0(&u);
-       else
-               smp_call_function(iucv_setmask_cpu0, &u, 0, 1);
-       preempt_enable();
+       cpu = get_cpu();
+       smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid);
+       put_cpu();
 
        return u.result;
 }
@@ -2274,14 +2251,13 @@ iucv_sever(__u16 pathid, __u8 user_data[16])
  * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
  */
 static void
-iucv_irq_handler(struct pt_regs *regs, __u16 code)
+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__);
-               irq_exit();
                return;
        }
 
@@ -2348,18 +2324,19 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
                                        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) == 0) {
-                                       
+
+                               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) {
@@ -2385,7 +2362,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
                        } else
                                iucv_sever(int_buf->ippathid, no_listener);
                        break;
-                       
+
                case 0x02:              /*connection complete */
                        if (messagesDisabled) {
                            iucv_setmask(~0);
@@ -2404,7 +2381,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
                        } else
                                iucv_sever(int_buf->ippathid, no_listener);
                        break;
-                       
+
                case 0x03:              /* connection severed */
                        if (messagesDisabled) {
                            iucv_setmask(~0);
@@ -2415,13 +2392,13 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
                                        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);
@@ -2437,7 +2414,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
                                                   "ConnectionQuiesced not called");
                        }
                        break;
-                       
+
                case 0x05:              /* connection resumed */
                        if (messagesDisabled) {
                            iucv_setmask(~0);
@@ -2453,7 +2430,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
                                                   "ConnectionResumed not called");
                        }
                        break;
-                       
+
                case 0x06:              /* priority message complete */
                case 0x07:              /* nonpriority message complete */
                        if (h) {
@@ -2466,7 +2443,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
                                                   "MessageComplete not called");
                        }
                        break;
-                       
+
                case 0x08:              /* priority message pending  */
                case 0x09:              /* nonpriority message pending  */
                        if (h) {
@@ -2484,7 +2461,7 @@ iucv_do_int(iucv_GeneralInterrupt * int_buf)
                               __FUNCTION__);
                        break;
        }                       /* end switch */
-       
+
        iucv_debug(2, "exiting pathid %d, type %02X",
                 int_buf->ippathid, int_buf->iptype);
 
@@ -2521,7 +2498,7 @@ iucv_tasklet_handler(unsigned long ignored)
        return;
 }
 
-module_init(iucv_init);
+subsys_initcall(iucv_init);
 module_exit(iucv_exit);
 
 /**
@@ -2545,16 +2522,16 @@ EXPORT_SYMBOL (iucv_reject);
 #if 0
 EXPORT_SYMBOL (iucv_reply);
 EXPORT_SYMBOL (iucv_reply_array);
-EXPORT_SYMBOL (iucv_reply_prmmsg);
 EXPORT_SYMBOL (iucv_resume);
 #endif
+EXPORT_SYMBOL (iucv_reply_prmmsg);
 EXPORT_SYMBOL (iucv_send);
-#if 0
 EXPORT_SYMBOL (iucv_send2way);
 EXPORT_SYMBOL (iucv_send2way_array);
-EXPORT_SYMBOL (iucv_send_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