Whamcloud - gitweb
b=16395
[fs/lustre-release.git] / lustre / kernel_patches / patches / qsnet-rhel4-2.6.patch
index a17f058..f198a43 100644 (file)
@@ -1,7 +1,79 @@
-diff -urN clean/arch/i386/defconfig linux-2.6.9/arch/i386/defconfig
---- clean/arch/i386/defconfig  2004-10-18 17:54:38.000000000 -0400
-+++ linux-2.6.9/arch/i386/defconfig    2005-10-10 17:47:17.000000000 -0400
-@@ -119,6 +119,8 @@
+Index: linux-269-5502/fs/open.c
+===================================================================
+--- linux-269-5502.orig/fs/open.c
++++ linux-269-5502/fs/open.c
+@@ -1029,6 +1029,8 @@ out_error:
+       goto out;
+ }
++EXPORT_SYMBOL(sys_open);
++
+ #ifndef __alpha__
+ /*
+Index: linux-269-5502/fs/read_write.c
+===================================================================
+--- linux-269-5502.orig/fs/read_write.c
++++ linux-269-5502/fs/read_write.c
+@@ -145,6 +145,7 @@ asmlinkage off_t sys_lseek(unsigned int 
+ bad:
+       return retval;
+ }
++EXPORT_SYMBOL(sys_lseek);
+ #ifdef __ARCH_WANT_SYS_LLSEEK
+ asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
+Index: linux-269-5502/fs/select.c
+===================================================================
+--- linux-269-5502.orig/fs/select.c
++++ linux-269-5502/fs/select.c
+@@ -539,3 +539,4 @@ out_fds:
+       poll_freewait(&table);
+       return err;
+ }
++EXPORT_SYMBOL_GPL(sys_poll);
+Index: linux-269-5502/fs/exec.c
+===================================================================
+--- linux-269-5502.orig/fs/exec.c
++++ linux-269-5502/fs/exec.c
+@@ -56,6 +56,8 @@
+ #include <linux/kmod.h>
+ #endif
++#include <linux/ptrack.h>
++
+ int core_uses_pid;
+ char core_pattern[65] = "core";
+ int suid_dumpable = 0;
+@@ -1214,6 +1216,9 @@ int do_execve(char * filename,
+       if (retval < 0)
+               goto out;
++      /* notify any ptrack callbacks of the process exec */
++      ptrack_call_callbacks(PTRACK_PHASE_EXEC, NULL);
++
+       retval = search_binary_handler(bprm,regs);
+       if (retval >= 0) {
+               free_arg_pages(bprm);
+Index: linux-269-5502/arch/i386/Kconfig
+===================================================================
+--- linux-269-5502.orig/arch/i386/Kconfig
++++ linux-269-5502/arch/i386/Kconfig
+@@ -960,6 +960,9 @@ config REGPARM
+       generate incorrect output with certain kernel constructs when
+       -mregparm=3 is used.
++source "mm/Kconfig"
++source "kernel/Kconfig"
++      
+ endmenu
+Index: linux-269-5502/arch/i386/defconfig
+===================================================================
+--- linux-269-5502.orig/arch/i386/defconfig
++++ linux-269-5502/arch/i386/defconfig
+@@ -119,6 +119,8 @@ CONFIG_MTRR=y
  CONFIG_IRQBALANCE=y
  CONFIG_HAVE_DEC_LOCK=y
  # CONFIG_REGPARM is not set
@@ -10,23 +82,25 @@ diff -urN clean/arch/i386/defconfig linux-2.6.9/arch/i386/defconfig
  
  #
  # Power management options (ACPI, APM)
-diff -urN clean/arch/i386/Kconfig linux-2.6.9/arch/i386/Kconfig
---- clean/arch/i386/Kconfig    2005-05-13 13:39:03.000000000 -0400
-+++ linux-2.6.9/arch/i386/Kconfig      2005-10-10 17:47:17.000000000 -0400
-@@ -946,6 +946,9 @@
-         support.  As of this writing the exact hardware interface is
-         strongly in flux, so no good recommendation can be made.
+Index: linux-269-5502/arch/ia64/Kconfig
+===================================================================
+--- linux-269-5502.orig/arch/ia64/Kconfig
++++ linux-269-5502/arch/ia64/Kconfig
+@@ -316,6 +316,9 @@ config IA64_PALINFO
+         To use this option, you have to ensure that the "/proc file system
+         support" (CONFIG_PROC_FS) is enabled, too.
  
 +source "mm/Kconfig"
 +source "kernel/Kconfig"
-+      
- endmenu
++
+ source "drivers/firmware/Kconfig"
  
-diff -urN clean/arch/ia64/defconfig linux-2.6.9/arch/ia64/defconfig
---- clean/arch/ia64/defconfig  2004-10-18 17:53:12.000000000 -0400
-+++ linux-2.6.9/arch/ia64/defconfig    2005-10-10 17:47:17.000000000 -0400
-@@ -83,6 +83,8 @@
+ source "fs/Kconfig.binfmt"
+Index: linux-269-5502/arch/ia64/defconfig
+===================================================================
+--- linux-269-5502.orig/arch/ia64/defconfig
++++ linux-269-5502/arch/ia64/defconfig
+@@ -83,6 +83,8 @@ CONFIG_IA32_SUPPORT=y
  CONFIG_COMPAT=y
  CONFIG_PERFMON=y
  CONFIG_IA64_PALINFO=y
@@ -35,23 +109,25 @@ diff -urN clean/arch/ia64/defconfig linux-2.6.9/arch/ia64/defconfig
  
  #
  # Firmware Drivers
-diff -urN clean/arch/ia64/Kconfig linux-2.6.9/arch/ia64/Kconfig
---- clean/arch/ia64/Kconfig    2005-05-13 13:39:00.000000000 -0400
-+++ linux-2.6.9/arch/ia64/Kconfig      2005-10-10 17:47:17.000000000 -0400
-@@ -299,6 +299,9 @@
-         To use this option, you have to ensure that the "/proc file system
-         support" (CONFIG_PROC_FS) is enabled, too.
+Index: linux-269-5502/arch/x86_64/Kconfig
+===================================================================
+--- linux-269-5502.orig/arch/x86_64/Kconfig
++++ linux-269-5502/arch/x86_64/Kconfig
+@@ -401,6 +401,9 @@ config X86_MCE_AMD
+          Additional support for AMD specific MCE features such as
+          the DRAM Error Threshold.
  
 +source "mm/Kconfig"
 +source "kernel/Kconfig"
 +
- source "drivers/firmware/Kconfig"
+ endmenu
  
- source "fs/Kconfig.binfmt"
-diff -urN clean/arch/x86_64/defconfig linux-2.6.9/arch/x86_64/defconfig
---- clean/arch/x86_64/defconfig        2004-10-18 17:54:39.000000000 -0400
-+++ linux-2.6.9/arch/x86_64/defconfig  2005-10-10 17:47:17.000000000 -0400
-@@ -87,6 +87,8 @@
+Index: linux-269-5502/arch/x86_64/defconfig
+===================================================================
+--- linux-269-5502.orig/arch/x86_64/defconfig
++++ linux-269-5502/arch/x86_64/defconfig
+@@ -87,6 +87,8 @@ CONFIG_NR_CPUS=8
  CONFIG_GART_IOMMU=y
  CONFIG_SWIOTLB=y
  CONFIG_X86_MCE=y
@@ -60,106 +136,357 @@ diff -urN clean/arch/x86_64/defconfig linux-2.6.9/arch/x86_64/defconfig
  
  #
  # Power management options
-diff -urN clean/arch/x86_64/Kconfig linux-2.6.9/arch/x86_64/Kconfig
---- clean/arch/x86_64/Kconfig  2005-05-13 13:39:03.000000000 -0400
-+++ linux-2.6.9/arch/x86_64/Kconfig    2005-10-10 17:47:17.000000000 -0400
-@@ -327,6 +327,9 @@
-          machine check error logs. See
-          ftp://ftp.x86-64.org/pub/linux/tools/mcelog
-+source "mm/Kconfig"
-+source "kernel/Kconfig"
-+
- endmenu
-diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.txt
---- clean/Documentation/vm/ioproc.txt  1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/Documentation/vm/ioproc.txt    2005-10-10 17:47:17.000000000 -0400
-@@ -0,0 +1,468 @@
-+Linux IOPROC patch overview
-+===========================
+Index: linux-269-5502/kernel/ptrack.c
+===================================================================
+--- /dev/null
++++ linux-269-5502/kernel/ptrack.c
+@@ -0,0 +1,145 @@
++/*
++ *    Copyright (C) 2000  Regents of the University of California
++ *
++ *    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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ * Derived from exit_actn.c by
++ *    Copyright (C) 2003 Quadrics Ltd.
++ */
 +
-+The network interface for an HPC network differs significantly from
-+network interfaces for traditional IP networks. HPC networks tend to
-+be used directly from user processes and perform large RDMA transfers
-+between theses processes address space. They also have a requirement
-+for low latency communication, and typically achieve this by OS bypass
-+techniques.  This then requires a different model to traditional
-+interconnects, in that a process may need to expose a large amount of
-+it's address space to the network RDMA.
 +
-+Locking down of memory has been a common mechanism for performing
-+this, together with a pin-down cache implemented in user
-+libraries. The disadvantage of this method is that large portions of
-+the physical memory can be locked down for a single process, even if
-+it's working set changes over the different phases of it's
-+execution. This leads to inefficient memory utilisation - akin to the
-+disadvantage of swapping compared to paging.
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/ptrack.h>
++#include <linux/slab.h>
++#include <linux/list.h>
 +
-+This model also has problems where memory is being dynamically
-+allocated and freed, since the pin down cache is unaware that memory
-+may have been released by a call to munmap() and so it will still be
-+locking down the now unused pages.
++#include <asm/errno.h>
 +
-+Some modern HPC network interfaces implement their own MMU and are
-+able to handle a translation fault during a network access. The
-+Quadrics (http://www.quadrics.com) devices (Elan3 and Elan4) have done
-+this for some time and we expect others to follow the same route in
-+the relatively near future. These NICs are able to operate in an
-+environment where paging occurs and do not require memory to be locked
-+down. The advantage of this is that the user process can expose large
-+portions of it's address space without having to worry about physical
-+memory constraints.
++int
++ptrack_register (ptrack_callback_t callback, void *arg)
++{
++       struct ptrack_desc *desc = kmalloc (sizeof (struct ptrack_desc), GFP_KERNEL);
++       
++       if (desc == NULL)
++               return -ENOMEM;
 +
-+However should the operating system decide to swap a page to disk,
-+then the NIC must be made aware that it should no longer read/write
-+from this memory, but should generate a translation fault instead.
++      desc->callback = callback;
++      desc->arg      = arg;
++       
++       list_add_tail (&desc->link, &current->ptrack_list);
++       
++       return 0;
++}
 +
-+The ioproc patch has been developed to provide a mechanism whereby the
-+device driver for a NIC can be aware of when a user process's address
-+translations change, either by paging or by explicitly mapping or
-+unmapping memory.
++void
++ptrack_deregister (ptrack_callback_t callback, void *arg)
++{      
++       struct list_head *el, *nel;
++       
++       list_for_each_safe (el, nel, &current->ptrack_list) {
++               struct ptrack_desc *desc = list_entry (el, struct ptrack_desc, link);
++               
++               if (desc->callback == callback && desc->arg == arg) {
++                       list_del (&desc->link);
++                       kfree (desc);
++               }
++       }
++}
 +
-+The patch involves inserting callbacks where translations are being
-+invalidated to notify the NIC that the memory behind those
-+translations is no longer visible to the application (and so should
-+not be visible to the NIC). This callback is then responsible for
-+ensuring that the NIC will not access the physical memory that was
-+being mapped.
++int
++ptrack_registered (ptrack_callback_t callback, void *arg)
++{
++       struct list_head *el;
++       
++       list_for_each (el, &current->ptrack_list) {
++               struct ptrack_desc *desc = list_entry (el, struct ptrack_desc, link);
++               
++               if (desc->callback == callback && desc->arg == arg)
++                       return 1;
++       }
++       return 0;
++}      
++        
++int
++ptrack_call_callbacks (int phase, struct task_struct *child)
++{
++       struct list_head *el, *nel;
++       struct ptrack_desc *new;
++      int res;
 +
-+An ioproc invalidate callback in the kswapd code could be utilised to
-+prevent memory from being paged out if the NIC is unable to support
-+network page faulting.
++       if (phase == PTRACK_PHASE_CLONE)
++               INIT_LIST_HEAD (&child->ptrack_list);
 +
-+For NICs which support network page faulting, there is no requirement
-+for a user level pin down cache, since they are able to page-in their
-+translations on the first communication using a buffer. However this
-+is likely to be inefficient, resulting in slow first use of the
-+buffer. If the communication buffers were continually allocated and
-+freed using mmap based malloc() calls then this would lead to all
-+communications being slower than desirable.
++       list_for_each_safe (el, nel, &current->ptrack_list) {
++               struct ptrack_desc *desc = list_entry (el, struct ptrack_desc, link);
++               
++             res = desc->callback (desc->arg, phase, child);
++               
++               switch (phase)
++               {
++               case PTRACK_PHASE_EXIT:
++                       list_del (&desc->link);
++                       kfree (desc);
++                       break;
++                       
++               case PTRACK_PHASE_CLONE:
++                     switch (res)
++                     {
++                     case PTRACK_FINISHED:
++                             break;
 +
-+To optimise these warm-up cases the ioproc patch adds calls to
-+ioproc_update wherever the kernel is creating translations for a user
-+process. These then allows the device driver to preload translations
-+so that they are already present for the first network communication
-+from a buffer.
++                     case PTRACK_INNHERIT:
++                             if ((new = kmalloc (sizeof (struct ptrack_desc), GFP_ATOMIC)) == NULL)
++                             {
++                                     /* allocation failed - notify that this process is not going
++                                      * to be started by signalling clone failure.
++                                      */
++                                     desc->callback (desc->arg, PTRACK_PHASE_CLONE_FAIL, child);
++                                     
++                                     goto failed;
++                             }
 +
-+Linux 2.6 IOPROC implementation details
-+=======================================
++                              new->callback = desc->callback;
++                              new->arg      = desc->arg;
++                               
++                               list_add_tail (&new->link, &child->ptrack_list);
++                             break;
 +
-+The Linux IOPROC patch adds hooks to the Linux VM code whenever page
-+table entries are being created and/or invalidated. IOPROC device
-+drivers can register their interest in being informed of such changes
-+by registering an ioproc_ops structure which is defined as follows;
++                     case PTRACK_DENIED:
++                             goto failed;
++                       }
++                     break;
++               }
++       }
 +
-+extern int ioproc_register_ops(struct mm_struct *mm, struct ioproc_ops *ip);
-+extern int ioproc_unregister_ops(struct mm_struct *mm, struct ioproc_ops *ip);
++       return 0;
 +
-+typedef struct ioproc_ops {
-+      struct ioproc_ops *next;
-+      void *arg;
++ failed:
++       while (! list_empty (&child->ptrack_list))
++       {
++             struct ptrack_desc *desc = list_entry (child->ptrack_list.next, struct ptrack_desc, link);
++             
++             desc->callback (desc->arg, PTRACK_PHASE_CLONE_FAIL, child);
++
++             list_del (&desc->link);
++             kfree (desc);
++       }
++       return 1;
++}
++EXPORT_SYMBOL(ptrack_register);
++EXPORT_SYMBOL(ptrack_deregister);
++EXPORT_SYMBOL(ptrack_registered);
+Index: linux-269-5502/kernel/signal.c
+===================================================================
+--- linux-269-5502.orig/kernel/signal.c
++++ linux-269-5502/kernel/signal.c
+@@ -2329,6 +2329,7 @@ sys_kill(int pid, int sig)
+       return kill_something_info(sig, &info, pid);
+ }
++EXPORT_SYMBOL_GPL(sys_kill);
+ /**
+  *  sys_tgkill - send signal to one specific thread
+Index: linux-269-5502/kernel/Kconfig
+===================================================================
+--- /dev/null
++++ linux-269-5502/kernel/Kconfig
+@@ -0,0 +1,14 @@
++#
++# Kernel subsystem specific config
++# 
++
++# Support for Process Tracking callbacks
++#
++config PTRACK
++      bool "Enable PTRACK process tracking hooks"
++      default y
++      help
++      This option enables hooks to be called when processes are
++      created and destoryed in order for a resource management 
++      system to know which processes are a member of a "job" and 
++      to be able to clean up when the job is terminated.
+Index: linux-269-5502/kernel/Makefile
+===================================================================
+--- linux-269-5502.orig/kernel/Makefile
++++ linux-269-5502/kernel/Makefile
+@@ -26,6 +26,7 @@ obj-$(CONFIG_AUDIT) += audit.o
+ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
+ obj-$(CONFIG_AUDITFILESYSTEM) += auditfs.o
+ obj-$(CONFIG_KPROBES) += kprobes.o
++obj-$(CONFIG_PTRACK) += ptrack.o
+ ifneq ($(CONFIG_IA64),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+Index: linux-269-5502/kernel/exit.c
+===================================================================
+--- linux-269-5502.orig/kernel/exit.c
++++ linux-269-5502/kernel/exit.c
+@@ -32,6 +32,8 @@
+ #include <asm/pgtable.h>
+ #include <asm/mmu_context.h>
++#include <linux/ptrack.h>
++
+ extern void sem_exit (void);
+ extern struct task_struct *child_reaper;
+@@ -825,6 +827,9 @@ asmlinkage NORET_TYPE void do_exit(long 
+               current->tux_exit();
+       }
++      /* Notify any ptrack callbacks of the process exit */
++      ptrack_call_callbacks(PTRACK_PHASE_EXIT, NULL);
++
+       if (unlikely(tsk->audit_context))
+               audit_free(tsk);
+       __exit_mm(tsk);
+Index: linux-269-5502/kernel/fork.c
+===================================================================
+--- linux-269-5502.orig/kernel/fork.c
++++ linux-269-5502/kernel/fork.c
+@@ -14,6 +14,7 @@
+ #include <linux/config.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
++#include <linux/ptrack.h>
+ #include <linux/unistd.h>
+ #include <linux/smp_lock.h>
+ #include <linux/module.h>
+@@ -443,6 +444,9 @@ static struct mm_struct * mm_init(struct
+       mm->page_table_lock = SPIN_LOCK_UNLOCKED;
+       mm->ioctx_list_lock = RW_LOCK_UNLOCKED;
+       mm->ioctx_list = NULL;
++#ifdef CONFIG_IOPROC
++      mm->ioproc_ops = NULL;
++#endif
+       mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm);
+       mm->free_area_cache = TASK_UNMAPPED_BASE;
+@@ -1312,6 +1316,11 @@ long do_fork(unsigned long clone_flags,
+                       set_tsk_thread_flag(p, TIF_SIGPENDING);
+               }
++              if (ptrack_call_callbacks(PTRACK_PHASE_CLONE, p)) {
++                      sigaddset(&p->pending.signal, SIGKILL);
++                      set_tsk_thread_flag(p, TIF_SIGPENDING);
++              }
++
+               if (!(clone_flags & CLONE_STOPPED))
+                       wake_up_new_task(p, clone_flags);
+               else
+Index: linux-269-5502/Makefile
+===================================================================
+--- linux-269-5502.orig/Makefile
++++ linux-269-5502/Makefile
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 9
+-EXTRAVERSION = -prep
++EXTRAVERSION = -prep.qp3.5.34.4qsnet
+ RHEL_VERSION = 4
+ RHEL_UPDATE = 5
+ NAME=AC 1
+Index: linux-269-5502/Documentation/vm/ioproc.txt
+===================================================================
+--- /dev/null
++++ linux-269-5502/Documentation/vm/ioproc.txt
+@@ -0,0 +1,467 @@
++Linux IOPROC patch overview
++===========================
++
++The network interface for an HPC network differs significantly from
++network interfaces for traditional IP networks. HPC networks tend to
++be used directly from user processes and perform large RDMA transfers
++between theses processes address space. They also have a requirement
++for low latency communication, and typically achieve this by OS bypass
++techniques.  This then requires a different model to traditional
++interconnects, in that a process may need to expose a large amount of
++it's address space to the network RDMA.
++
++Locking down of memory has been a common mechanism for performing
++this, together with a pin-down cache implemented in user
++libraries. The disadvantage of this method is that large portions of
++the physical memory can be locked down for a single process, even if
++it's working set changes over the different phases of it's
++execution. This leads to inefficient memory utilisation - akin to the
++disadvantage of swapping compared to paging.
++
++This model also has problems where memory is being dynamically
++allocated and freed, since the pin down cache is unaware that memory
++may have been released by a call to munmap() and so it will still be
++locking down the now unused pages.
++
++Some modern HPC network interfaces implement their own MMU and are
++able to handle a translation fault during a network access. The
++Quadrics (http://www.quadrics.com) devices (Elan3 and Elan4) have done
++this for some time and we expect others to follow the same route in
++the relatively near future. These NICs are able to operate in an
++environment where paging occurs and do not require memory to be locked
++down. The advantage of this is that the user process can expose large
++portions of it's address space without having to worry about physical
++memory constraints.
++
++However should the operating system decide to swap a page to disk,
++then the NIC must be made aware that it should no longer read/write
++from this memory, but should generate a translation fault instead.
++
++The ioproc patch has been developed to provide a mechanism whereby the
++device driver for a NIC can be aware of when a user process's address
++translations change, either by paging or by explicitly mapping or
++unmapping memory.
++
++The patch involves inserting callbacks where translations are being
++invalidated to notify the NIC that the memory behind those
++translations is no longer visible to the application (and so should
++not be visible to the NIC). This callback is then responsible for
++ensuring that the NIC will not access the physical memory that was
++being mapped.
++
++An ioproc invalidate callback in the kswapd code could be utilised to
++prevent memory from being paged out if the NIC is unable to support
++network page faulting.
++
++For NICs which support network page faulting, there is no requirement
++for a user level pin down cache, since they are able to page-in their
++translations on the first communication using a buffer. However this
++is likely to be inefficient, resulting in slow first use of the
++buffer. If the communication buffers were continually allocated and
++freed using mmap based malloc() calls then this would lead to all
++communications being slower than desirable.
++
++To optimise these warm-up cases the ioproc patch adds calls to
++ioproc_update wherever the kernel is creating translations for a user
++process. These then allows the device driver to preload translations
++so that they are already present for the first network communication
++from a buffer.
++
++Linux 2.6 IOPROC implementation details
++=======================================
++
++The Linux IOPROC patch adds hooks to the Linux VM code whenever page
++table entries are being created and/or invalidated. IOPROC device
++drivers can register their interest in being informed of such changes
++by registering an ioproc_ops structure which is defined as follows;
++
++extern int ioproc_register_ops(struct mm_struct *mm, struct ioproc_ops *ip);
++extern int ioproc_unregister_ops(struct mm_struct *mm, struct ioproc_ops *ip);
++
++typedef struct ioproc_ops {
++      struct ioproc_ops *next;
++      void *arg;
 +
 +      void (*release)(void *arg, struct mm_struct *mm);
 +      void (*sync_range)(void *arg, struct vm_area_struct *vma, unsigned long start, unsigned long end);
@@ -177,7 +504,7 @@ diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.
 +ioproc_register_ops
 +===================
 +This function should be called by the IOPROC device driver to register
-+its interest in PTE changes for the process associated with the passed
++it's interest in PTE changes for the process associated with the passed
 +in mm_struct.
 +
 +The ioproc registration is not inherited across fork() and should be
@@ -200,7 +527,7 @@ diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.
 +ioproc_ops struct
 +=================
 +A linked list ioproc_ops structures is hung off the user process
-+mm_struct (linux/sched.h). At each hook point in the patched kernel
++mm_struct (linux/sched.h). At each hook point in the patched kernel,
 +the ioproc patch will call the associated ioproc_ops callback function
 +pointer in turn for each registered structure.
 +
@@ -209,12 +536,12 @@ diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.
 +(e.g. find_pte_map()). These callbacks should not modify the Linux
 +kernel VM state or PTE entries.
 +
-+The ioproc_ops callback function pointers are defined as follows;
++The ioproc_ops callback function pointers are:
 +
 +ioproc_release
 +==============
-+The release hook is called when a program exits and all its vma areas
-+are torn down and unmapped. i.e. during exit_mmap(). Before each
++The release hook is called when a program exits and all it's vma areas
++are torn down and unmapped, i.e. during exit_mmap(). Before each
 +release hook is called the ioproc_ops structure is unlinked from the
 +mm_struct.
 +
@@ -228,7 +555,7 @@ diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.
 +or write by the IOPROC device to the associated pages should cause the
 +page to be marked as referenced or modified.
 +
-+Called holding the mm->page_table_lock
++Called holding the mm->page_table_lock.
 +
 +ioproc_invalidate_[range|page]
 +==============================
@@ -237,7 +564,7 @@ diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.
 +kernel. After this call the IOPROC must not access the physical memory
 +again unless a new translation is loaded.
 +
-+Called holding the mm->page_table_lock
++Called holding the mm->page_table_lock.
 +
 +ioproc_update_[range|page]
 +==========================
@@ -247,7 +574,7 @@ diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.
 +opportunity to load translations speculatively, which can improve
 +performance by avoiding device translation faults.
 +
-+Called holding the mm->page_table_lock
++Called holding the mm->page_table_lock.
 +
 +ioproc_change_protection
 +========================
@@ -257,16 +584,16 @@ diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.
 +The IOPROC must not be able to write to a read-only page, so if the
 +permissions are downgraded then it must honour them. If they are
 +upgraded it can treat this in the same way as the
-+ioproc_update_[range|page]() calls
++ioproc_update_[range|page]() calls.
 +
-+Called holding the mm->page_table_lock
++Called holding the mm->page_table_lock.
 +
 +
 +Linux 2.6 IOPROC patch details
 +==============================
 +
 +Here are the specific details of each ioproc hook added to the Linux
-+2.6 VM system and the reasons for doing so;
++2.6 VM system and the reasons for doing so:
 +
 +++++ FILE
 +      mm/fremap.c
@@ -543,96440 +870,381 @@ diff -urN clean/Documentation/vm/ioproc.txt linux-2.6.9/Documentation/vm/ioproc.
 +ADDED HOOK
 +      ioproc_invalidate_range
 +
-+
-+-- Last update DavidAddison - 17 Aug 2004
-diff -urN clean/drivers/net/qsnet/eip/eip_linux.c linux-2.6.9/drivers/net/qsnet/eip/eip_linux.c
---- clean/drivers/net/qsnet/eip/eip_linux.c    1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/eip/eip_linux.c      2005-09-07 10:34:58.000000000 -0400
-@@ -0,0 +1,1575 @@
++-- Last update Daniel J Blueman - 24 Mar 2006
+Index: linux-269-5502/mm/ioproc.c
+===================================================================
+--- /dev/null
++++ linux-269-5502/mm/ioproc.c
+@@ -0,0 +1,52 @@
 +/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
++ *    Copyright (C) 2006 Quadrics Ltd
++ *
++ *    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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 + */
 +
-+#ident "@(#)$Id: eip_linux.c,v 1.96.2.3 2005/09/07 14:34:58 mike Exp $"
-+
-+#include <qsnet/kernel.h>
-+#include <qsnet/debug.h>
++/*
++ * Registration for IO processor page table updates.
++ */
 +
-+#include <qsnet/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
 +#include <linux/kernel.h>
-+#include <linux/proc_fs.h>
-+#include <linux/time.h>
-+#include <linux/version.h>
-+
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#undef ASSERT
-+#include <net/sock.h>
-+#include <net/ip.h>
-+
-+
-+
-+#include <elan/epcomms.h>
-+#include <elan/epsvc.h>
-+
-+#include "eip_linux.h"
-+#include "eip_stats.h"
-+
-+#ifdef UNUSED
-+static void eip_skb_display(struct sk_buff *);
-+#endif
-+static void eip_iph_display(struct iphdr *);
-+#ifdef UNUSED
-+static void eip_eiph_display(EIP_HEADER *);
-+static void eip_packet_display(unsigned char *);
-+#endif
-+static void eip_tmd_display(EIP_TMD *);
-+static void eip_tmd_head_display(EIP_TMD_HEAD *);
-+static void eip_rmd_display(EIP_RMD *);
-+static void eip_rmd_head_display(EIP_RMD_HEAD *);
-+
-+static void eip_rmd_reclaim(EIP_RMD *);
-+
-+static inline EP_NMH *eip_dma_reserve(int, int);
-+static inline void __eip_tmd_load(EIP_TMD *, EP_RAILMASK *);
-+static inline void __eip_tmd_unload(EIP_TMD *);
-+static inline unsigned long eip_buff_alloc(int, int);
-+static inline void eip_buff_free(unsigned long, int);
-+static struct iphdr *eip_ipfrag_get(char *);
-+static inline void eip_rmd_free(EIP_RMD *);
-+static inline void eip_skb_load(EIP_RMD *);
-+static inline void eip_skb_unload(EIP_RMD *);
-+static inline void eip_rmd_requeue(EIP_RMD *);
-+static EIP_RMD *eip_rmd_alloc(int, int);
-+static int eip_rmd_alloc_replace(EIP_RMD *, int, int);
-+static int eip_rmd_alloc_queue(int, int, int, int);
-+static int eip_rmds_alloc(void);
-+static void eip_rxhandler(EP_RXD *);
-+static void eip_rx_tasklet(unsigned long);
-+static inline void eip_tmd_init(EIP_TMD *, unsigned long, EIP_TMD_HEAD *, unsigned long, int);
-+static inline EIP_TMD *eip_tmd_get(int);
-+static inline void eip_tmd_put(EIP_TMD *);
-+static inline void eip_tmd_load(EIP_TMD *);
-+static inline void eip_tmd_unload(EIP_TMD *);
-+static inline EIP_TMD *eip_tmd_alloc_queue(EIP_TMD *, EIP_TMD_HEAD *, int);
-+static inline EIP_TMD *eip_tmd_alloc_queue_copybreak(EIP_TMD_HEAD *, int);
-+static inline EIP_TMD *eip_tmd_alloc_queue_aggreg(EIP_TMD_HEAD *, int);
-+static int eip_tmds_alloc(void);
-+int eip_hard_start_xmit(struct sk_buff *, struct net_device *);
-+static inline int eip_do_xmit(EIP_TMD *, EP_NMD *i, EP_PAYLOAD *);
-+static void eip_txhandler(EP_TXD *, void *, EP_STATUS);
-+static void eip_tx_tasklet(unsigned long);
-+void eip_stop_queue(void);
-+void eip_start_queue(void);
-+static int eip_open(struct net_device *);
-+static int eip_close(struct net_device *);
-+static struct net_device_stats *eip_get_stats(struct net_device *);
-+static int eip_change_mtu(struct net_device *, int);
-+
-+static int eip_rx_dropping = 0;
-+static int eip_rx_tasklet_locked = 1;
-+
-+/* Global */
-+struct timer_list eip_rx_tasklet_timer;
-+      
-+EIP_RX *eip_rx = NULL;
-+EIP_TX *eip_tx = NULL;
-+int  eip_checksum_state=CHECKSUM_NONE;
++#include <linux/module.h>
 +
-+int tmd_max = EIP_TMD_MAX_NR;
-+int rmd_max = EIP_RMD_MAX_NR;
-+int rx_envelope_nr = EIP_RX_ENVELOPE_NR;
-+int rx_granularity = EIP_RX_GRANULARITY;
-+int tx_copybreak_max = EIP_TX_COPYBREAK_MAX;
-+EP_RAILMASK tx_railmask = EP_RAILMASK_ALL;
-+int eipdebug = 0;
++#include <linux/mm.h>
++#include <linux/ioproc.h>
 +
-+#ifdef UNUSED
-+static void eip_skb_display(struct sk_buff *skb)
-+{
-+      if (skb) {
-+              __EIP_DBG_PRINTF("SKB [%p] : len %d truesize %d  proto %x pkt type %x cloned %d users %d summed %d\n", 
-+                      skb, skb->len, skb->truesize, skb->protocol, skb->pkt_type, skb->cloned, atomic_read(&skb->users), skb->ip_summed);
-+              __EIP_DBG_PRINTF("SKB [%p] : skb_shinfo dataref %d nr_frags %d frag_list[%p] (device %p)\n", skb,
-+                       atomic_read(&skb_shinfo(skb)->dataref), skb_shinfo(skb)->nr_frags, skb_shinfo(skb)->frag_list, skb->dev);
-+              __EIP_DBG_PRINTF("SKB [%p] : head[%p] data[%p] tail [%p] end [%p] data_len [%d]\n", skb, skb->head, skb->data, 
-+                              skb->tail, skb->end, skb->data_len);
-+              __EIP_DBG_PRINTF("SKB [%p] : Transport Layer h.(th, uh, icmph, raw)[%p]\n", skb, skb->h.th);
-+              __EIP_DBG_PRINTF("SKB [%p] : Network Layer      nh.(iph, arph, raw)[%p]\n", skb, skb->nh.iph);
-+              __EIP_DBG_PRINTF("SKB [%p] : Link Layer         mac.(ethernet, raw)[%p]\n", skb, skb->mac.ethernet);
-+              return;
-+      }
-+      EIP_ERR_PRINTF("SKB IS NULL - NO SKB TO DISPLAY\n");
-+}
-+#endif
-+static void eip_iph_display(struct iphdr *iph)
-+{
-+      if (iph) {
-+              __EIP_DBG_PRINTF("IPH [%p] : version %d header len %d TOS 0x%x Total len %d\n", 
-+                      iph, iph->version, iph->ihl, htons(iph->tos), htons(iph->tot_len));
-+              __EIP_DBG_PRINTF("IPH [%p] : id %d frag flags 0x%x offset %d\n",
-+                              iph, htons(iph->id), (iph->frag_off & htons(IP_CE | IP_DF | IP_MF)) >> 4, 
-+                              (htons(iph->frag_off) << 3) & IP_OFFSET);
-+              __EIP_DBG_PRINTF("IPH [%p] : TTL %d proto %d header checksum 0x%x\n", iph, iph->ttl, iph->protocol, iph->check);
-+              __EIP_DBG_PRINTF("IPH [%p] : IP src %u.%u.%u.%u dest %u.%u.%u.%u\n", iph, 
-+                               ((unsigned char *)&(iph->saddr))[0],((unsigned char *)&(iph->saddr))[1], ((unsigned char *)&(iph->saddr))[2],((unsigned char *)&(iph->saddr))[3],
-+                               ((unsigned char *)&(iph->daddr))[0],((unsigned char *)&(iph->daddr))[1], ((unsigned char *)&(iph->daddr))[2],((unsigned char *)&(iph->daddr))[3]);
-+              return;
-+      }
-+      EIP_ERR_PRINTF("IPH IS NULL - NO IPH TO DISPLAY\n");
-+}
-+#ifdef UNUSED
-+static void eip_eiph_display(EIP_HEADER * eiph)
-+{
-+      if (eiph) {
-+              __EIP_DBG_PRINTF("EIPH [%p] : dhost %04x.%04x.%04x sap %x\n", eiph, eiph->h_dhost.ip_bcast, eiph->h_dhost.ip_inst, 
-+                              eiph->h_dhost.ip_addr, eiph->h_sap);
-+              __EIP_DBG_PRINTF("EIPH [%p] : shost %04x.%04x.%04x \n", eiph, eiph->h_shost.ip_bcast, eiph->h_shost.ip_inst,
-+                               eiph->h_shost.ip_addr);
-+              return;
-+      }
-+      EIP_ERR_PRINTF("EIPH IS NULL - NO EIPH TO DISPLAY\n");
-+}
-+static void eip_packet_display(unsigned char *data)
-+{
-+      eip_eiph_display((EIP_HEADER *) data);
-+      eip_iph_display((struct iphdr *) (data + EIP_HEADER_PAD + ETH_HLEN));
-+}
-+#endif
-+static void eip_tmd_display(EIP_TMD * tmd)
-+{
-+      if (tmd) {
-+              __EIP_DBG_PRINTF("\t\tTMD [%p] : next[%p] skb[%p] DVMA[%d]\n", tmd, tmd->chain.next, tmd->skb, tmd->dvma_idx);
-+              if (tmd->dma_base)
-+                      __EIP_DBG_PRINTF("TMD [%p] : head[%p] *data 0x%lx\n", tmd, tmd->head, *((unsigned long *) tmd->dma_base));
-+              else
-+                      __EIP_DBG_PRINTF("TMD [%p] : head[%p] NO DATA !!!\n", tmd, tmd->head);
-+              __EIP_DBG_PRINTF("TMD [%p] : DMA(%lx,%d,%d) ebase[%x]\n",tmd,  tmd->dma_base, tmd->dma_len, tmd->nmd.nmd_len,
-+                               tmd->nmd.nmd_addr);
-+              return;
-+      }
-+      EIP_ERR_PRINTF("TMD IS NULL - NO TMD TO DISPLAY\n");
-+      
-+}
-+static void eip_ipf_display(EIP_IPFRAG * ipf)
++int ioproc_register_ops(struct mm_struct *mm, struct ioproc_ops *ip)
 +{
-+      if (ipf) {
-+              __EIP_DBG_PRINTF("IPF[%p] : datagram len %d dma correction %d uts %lx frag_nr %d\n", ipf, ipf->datagram_len,
-+                              ipf->dma_correction, ipf->timestamp.tv_usec, ipf->frag_nr);
-+              eip_tmd_display((EIP_TMD *) ipf);
-+              return;
-+      }
-+      EIP_ERR_PRINTF("IPF IS NULL - NO IPF TO DISPLAY\n");
-+}
++      ip->next = mm->ioproc_ops;
++      mm->ioproc_ops = ip;
 +
-+static void eip_tmd_head_display(EIP_TMD_HEAD * head)
-+{
-+      if (head) {
-+              __EIP_DBG_PRINTF("TMD HEAD [%p] : handle[%p] tmds[%p] %3.3d/%3.3d/%3.3d\n", head, head->handle, head->tmd, 
-+                      EIP_STAT_QUEUED_GET(&head->stats), EIP_STAT_ALLOC_GET(&head->stats),
-+                      eip_tx->tmd_max_nr);
-+              return;
-+      }
-+      EIP_ERR_PRINTF("TMD HEAD IS NULL - NO TMD HEAD TO DISPLAY\n");
-+}
-+static void eip_rmd_display(EIP_RMD * rmd)
-+{
-+      if (rmd) {
-+              __EIP_DBG_PRINTF("RMD [%p] : next[%p] rxd[%p] DVMA[%d]\n", rmd, rmd->chain.next, rmd->rxd, rmd->dvma_idx);
-+              __EIP_DBG_PRINTF("RMD [%p] : head[%p]\n", rmd, rmd->head); 
-+              __EIP_DBG_PRINTF("RMD [%p] : ebase[%x]\n", rmd,  rmd->nmd.nmd_addr); 
-+              return;
-+      }
-+      EIP_ERR_PRINTF("RMD IS NULL - NO RMD TO DISPLAY\n");
-+}
-+static void eip_rmd_head_display(EIP_RMD_HEAD * head)
-+{
-+      if (head) {
-+              __EIP_DBG_PRINTF("RMD HEAD [%p] : rcvr[%p] handle[%p] busy list[%p]\n", head, head->rcvr, head->handle, head->busy_list);
-+              __EIP_DBG_PRINTF("RMD HEAD [%p] : %3.3d/%3.3d/%3.3d\n", head, 
-+                              EIP_STAT_QUEUED_GET(&head->stats), EIP_STAT_ALLOC_GET(&head->stats), eip_rx->rmd_max_nr);
-+              return;
-+      }
-+      EIP_ERR_PRINTF("RMD HEAD IS NULL - NO RMD HEAD TO DISPLAY\n");
++      return 0;
 +}
 +
-+/* END  - DISPLAY FUNCTIONS */
-+static inline EP_NMH *eip_dma_reserve(int pages_nr, int perm)
-+{
-+      EP_NMH *handle = ep_dvma_reserve(eip_tx->ep_system, pages_nr, perm);
-+      
-+      if (handle)
-+              EIP_DBG_PRINTF(EIP_DBG_EP_DVMA, "HANDLE [%p] %d pages of elan address space reserved\n", 
-+                              handle, pages_nr);
-+      else
-+              EIP_ERR_PRINTF("cannot reserve %d page(s) of elan address space\n", pages_nr);
-+
-+      return handle;
-+}
++EXPORT_SYMBOL_GPL(ioproc_register_ops);
 +
-+static inline void __eip_tmd_load(EIP_TMD * tmd, EP_RAILMASK *rmask)
++int ioproc_unregister_ops(struct mm_struct *mm, struct ioproc_ops *ip)
 +{
-+      EIP_ASSERT(tmd->nmd.nmd_len > 0);
-+      
-+      ep_dvma_load(eip_tx->ep_system, NULL, (caddr_t) tmd->dma_base, tmd->nmd.nmd_len, tmd->head->handle,
-+                      tmd->dvma_idx, rmask, &tmd->nmd);
-+}
++      struct ioproc_ops **tmp;
 +
-+static inline void __eip_tmd_unload(EIP_TMD * tmd)
-+{
-+      EIP_ASSERT(tmd->nmd.nmd_addr && tmd->head->handle);
-+      
-+      ep_dvma_unload(eip_tx->ep_system, tmd->head->handle, &tmd->nmd);
-+      tmd->nmd.nmd_addr = 0;
-+}
-+static inline unsigned long eip_buff_alloc(int buff_len, int gfp)
-+{
-+      unsigned long buff_base = (buff_len < PAGE_SIZE) ? 
-+                              (unsigned long) kmalloc(buff_len, gfp) :
-+                              __get_dma_pages(gfp, get_order(buff_len));
-+      
-+      if (likely(buff_base))
-+              return buff_base;
++      for (tmp = &mm->ioproc_ops; *tmp && *tmp != ip; tmp = &(*tmp)->next) ;
++      if (*tmp) {
++              *tmp = ip->next;
++              return 0;
++      }
 +
-+      EIP_ERR_PRINTF("cannot allocate %db of memory\n", buff_len);
-+      return 0;
-+}
-+static inline void eip_buff_free(unsigned long buff_base, int buff_len)
-+{
-+      (buff_len < PAGE_SIZE) ?  kfree((void *) buff_base) :
-+              free_pages(buff_base, get_order(buff_len));
++      return -EINVAL;
 +}
-+static struct iphdr *eip_ipfrag_get(char *data)
-+{
-+      struct ethhdr *eh = (struct ethhdr *) (data);
-+      struct iphdr *iph;
-+
-+      if (eh->h_proto == htons(ETH_P_IP)) {
-+              iph = (struct iphdr *) ((char *) eh + ETH_HLEN);
-+
-+              /* EIP_DBG(eip_iph_display(iph)); */
-+
-+              if ((iph->frag_off & htons(IP_MF | IP_OFFSET)))
-+                      return iph;
-+      }
-+      return NULL;
-+}
-+
-+static inline void eip_rmd_free(EIP_RMD * rmd)
-+{
-+      EIP_ASSERT2(rmd->nmd.nmd_addr == 0, eip_rmd_display, rmd);
-+      
-+      if ( rmd->skb != NULL) 
-+              kfree_skb (rmd->skb);
-+      
-+      kfree(rmd);
-+
-+      EIP_DBG_PRINTF(EIP_DBG_MEMFREE, "RMD [%p] : FREED\n", rmd);
-+}
-+static inline void eip_skb_load(EIP_RMD * rmd)
-+{
-+      EP_RAILMASK rmask = rmd->rxd ? ep_rxd_railmask (rmd->rxd) : 0;
-+
-+      EIP_ASSERT(skb_tailroom(rmd->skb) > 0);
-+
-+      ep_dvma_load(eip_tx->ep_system, NULL, (caddr_t) rmd->skb->data, skb_tailroom(rmd->skb), rmd->head->handle,
-+                   rmd->dvma_idx, &rmask, &rmd->nmd);
-+      
-+      EIP_DBG_PRINTF(EIP_DBG_RMD_EP_DVMA, "RMD [%p] : LOADED\n", rmd);
-+}
-+static inline void eip_skb_unload(EIP_RMD * rmd)
-+{
-+      EIP_ASSERT(rmd->nmd.nmd_addr && rmd->head->handle);
-+      
-+      ep_dvma_unload(eip_tx->ep_system, rmd->head->handle, &rmd->nmd);
-+      rmd->nmd.nmd_addr = 0;
-+      
-+      EIP_DBG_PRINTF(EIP_DBG_RMD_EP_DVMA, "RMD [%p] : UNLOADED\n", rmd);
-+}
-+static inline void eip_rmd_requeue(EIP_RMD * rmd)
-+{
-+      EIP_ASSERT(rmd->rxd);
-+
-+      rmd->chain.next    = NULL;
-+
-+      ep_requeue_receive(rmd->rxd, eip_rxhandler, rmd, &rmd->nmd, EP_NO_ALLOC|EP_NO_SLEEP );
-+
-+      atomic_inc(&rmd->head->stats);
-+      
-+      EIP_DBG_PRINTF(EIP_DBG_RMD_QUEUE, "RMD [%p] : REQUEUED\n", rmd);
-+}
-+static EIP_RMD * eip_rmd_alloc(int svc, int gfp)
-+{
-+      int buff_len = EIP_SVC_SMALLEST_LEN << svc;
-+      EIP_RMD *rmd;
-+      struct sk_buff *skb;
-+
-+      if (!(skb = alloc_skb((buff_len -  EIP_EXTRA), gfp)))
-+              return NULL;
-+      
-+      skb_reserve(skb, 2);
-+
-+      if (!(rmd = (EIP_RMD *) kmalloc(buff_len, gfp))) {
-+              kfree_skb(skb);
-+              return NULL;
-+      }
-+
-+      rmd->skb = skb;
-+
-+      rmd->chain.next = NULL;
-+      rmd->rxd = NULL;
-+      rmd->head = &eip_rx->head[svc];
-+
-+      return rmd;
-+}
-+
-+static int eip_rmd_alloc_replace(EIP_RMD *rmd, int svc, int gfp) 
-+{
-+      struct sk_buff *skb,*old;
-+      int buff_len = EIP_SVC_SMALLEST_LEN << svc;
-+
-+      if (!(skb = alloc_skb(buff_len, gfp)))
-+              return 1;
-+      
-+      skb_reserve(skb, 2);
-+
-+      eip_skb_unload(rmd);
-+
-+      old      = rmd->skb;
-+      rmd->skb = skb;
-+
-+      eip_skb_load(rmd);
-+
-+      eip_rmd_requeue(rmd);
-+
-+      kfree_skb(old);
-+
-+      return 0;
-+}
-+
-+static int eip_rmd_alloc_queue(int svc, int dvma_idx, int gfp, int attr)
-+{
-+      EIP_RMD * rmd = eip_rmd_alloc(svc, gfp);
-+
-+      if (!rmd)
-+              return 1;
-+
-+      EIP_STAT_ALLOC_ADD(&rmd->head->stats, 1);
-+
-+      rmd->dvma_idx = dvma_idx;
-+      eip_skb_load(rmd);
-+
-+      EIP_DBG2(EIP_DBG_RMD, eip_rmd_display, rmd, "RMD [%p] : ALLOCATED for SVC 0x%x\n", rmd, svc);
-+
-+      if (ep_queue_receive(rmd->head->rcvr, eip_rxhandler, (void *) rmd, &rmd->nmd, attr) == ESUCCESS) {
-+              atomic_inc(&rmd->head->stats);
-+              EIP_DBG_PRINTF(EIP_DBG_RMD_QUEUE, "RMD [%p] : QUEUED on SVC 0x%x\n", rmd, svc);
-+              return 0;
-+      }
-+      
-+      EIP_ERR_PRINTF("RMD [%p] : couldn't be QUEUED on SVC 0x%x\n", rmd, svc);
-+
-+      EIP_STAT_ALLOC_SUB(&rmd->head->stats, 1);
-+
-+      eip_skb_unload(rmd);
-+      eip_rmd_free(rmd);
-+
-+      return 1;
-+}
-+
-+static int eip_rmds_alloc(void)
-+{
-+      int idx, svc;
-+
-+      eip_rx->irq_list = NULL;
-+      eip_rx->irq_list_nr = 0;
-+
-+      for (svc = 0; svc < EIP_SVC_NR; svc++) {
-+              eip_rx->head[svc].rcvr = ep_alloc_rcvr(eip_tx->ep_system, EIP_SVC_EP(svc), rx_envelope_nr);
-+              if (!eip_rx->head[svc].rcvr) {
-+                      EIP_ERR_PRINTF("Cannot install receiver for SVC 0x%x - maybe cable is disconnected\n", svc);
-+                      return -EAGAIN;
-+              }
-+
-+              eip_rx->head[svc].handle =
-+                  eip_dma_reserve(EIP_DVMA_PAGES((EIP_SVC_SMALLEST_LEN << svc)) * eip_rx->rmd_max_nr,
-+                                  EP_PERM_WRITE);
-+              if (!eip_rx->head[svc].handle)
-+                      return -ENOMEM;
-+              
-+              EIP_DBG(EIP_DBG_RMD_HEAD, eip_rmd_head_display, &eip_rx->head[svc]);
-+
-+              for (idx = 0; idx < EIP_RMD_NR; idx++) {
-+                      if (eip_rmd_alloc_queue(svc, idx * EIP_DVMA_PAGES((EIP_SVC_SMALLEST_LEN << svc)), 
-+                                              GFP_KERNEL, EP_NO_SLEEP))
-+                              return -ENOMEM;
-+              }
-+      }
-+      return 0;
-+}
-+static void eip_rmds_free(void)
-+{
-+      unsigned long flags;
-+      EIP_RMD *rmd;
-+      int svc; 
-+      
-+      spin_lock_irqsave(&eip_rx->lock, flags);
-+      rmd = eip_rx->irq_list;
-+      eip_rx->irq_list = NULL;
-+      eip_rx->irq_list_nr = 0;
-+      spin_unlock_irqrestore(&eip_rx->lock, flags);
-+
-+      eip_rmd_reclaim(rmd);
-+      
-+      for (svc = 0; svc < EIP_SVC_NR ; svc++) {
-+              
-+              while ((rmd = eip_rx->head[svc].busy_list)) {
-+                      eip_rx->head[svc].busy_list = NULL;
-+                      eip_rmd_reclaim(rmd);
-+                      if (eip_rx->head[svc].busy_list) {
-+                              EIP_DBG_PRINTF(EIP_DBG_RMD_QUEUE, "Still RMD [%p] on BUSY list SVC 0x%d - Scheduling\n", rmd, svc);     
-+                              schedule();
-+                      }
-+              }
-+
-+              EIP_ASSERT(EIP_STAT_QUEUED_GET(&eip_rx->head[svc].stats) == EIP_STAT_ALLOC_GET(&eip_rx->head[svc].stats));
-+              
-+              EIP_DBG_PRINTF(EIP_DBG_GEN, "HEAD[%p] : FREEING RCVR [%p]\n", &eip_rx->head[svc],
-+                              eip_rx->head[svc].rcvr);
-+              
-+              ep_free_rcvr(eip_rx->head[svc].rcvr);
-+
-+              EIP_DBG_PRINTF(EIP_DBG_EP_DVMA, "HEAD[%p] : RELEASING DVMA [%p]\n", &eip_rx->head[svc], 
-+                              eip_rx->head[svc].handle);
-+
-+              ep_dvma_release(eip_tx->ep_system, eip_rx->head[svc].handle);
-+      }
-+
-+}
-+static int eip_rx_queues_low (void) {
-+      int svc;
-+      for (svc = 0; svc < EIP_SVC_NR; svc++) 
-+              if (EIP_STAT_QUEUED_GET(&eip_rx->head[svc].stats)  < EIP_RMD_ALLOC_THRESH) 
-+                      return (1);
-+      return (0);
-+}
-+static void eip_rxhandler(EP_RXD * rxd)
-+{
-+      EIP_RMD *rmd            = (EIP_RMD *) ep_rxd_arg(rxd);
-+      EP_STATUS ret           = ep_rxd_status(rxd);
-+      EP_PAYLOAD * payload    = ep_rxd_payload(rxd);
-+      unsigned long data      = (unsigned long) rmd->skb->data; 
-+      int frag_nr             = 0;
-+      int len;
-+
-+      struct sk_buff *skb;
-+      static char count = 0;
-+
-+      atomic_dec(&rmd->head->stats);
-+      rmd->rxd = rxd;
-+
-+      if (likely(ret == EP_SUCCESS)) {
-+
-+              rmd->head->dma++;
-+
-+              if ( eip_rx_dropping) {
-+                  eip_rmd_requeue(rmd);
-+                  return;
-+              }
-+
-+              len = (payload) ? payload->Data[frag_nr++] : ep_rxd_len(rxd);
-+
-+              EIP_DBG(EIP_DBG_RMD, eip_rmd_display, rmd);
-+
-+again:
-+              if ( (skb = skb_clone(rmd->skb, GFP_ATOMIC)) ) {
-+                      unsigned int off = (data - (unsigned long) rmd->skb->data);
-+
-+                      /* have to set the length before calling
-+                       * skb pull as it will not allow you to
-+                       * pull past the end */
-+
-+                      skb_put (skb, off + len);
-+                      skb_pull (skb, off);
-+
-+                      skb->protocol = eth_type_trans(skb, eip_rx->net_device);
-+                      skb->ip_summed = eip_checksum_state;
-+                      skb->dev = eip_rx->net_device;
-+
-+                      /* Fabien/David/Mike this is a hack/fix to allow aggrigation of packets to work.
-+                       * The problem is ip_frag looks at the truesize to see if it is caching too much space.
-+                       * As we are reusing a large skb (cloned) for a number of small fragments, they appear to take up alot of space.
-+                       * so ip_frag dropped them after 4 frags (not good). So we lie and set the truesize to just bigger than the data. 
-+                       */
-+                      if (payload) 
-+                              skb->truesize = SKB_DATA_ALIGN(skb->len + EIP_HEADER_PAD) +sizeof(struct sk_buff);
-+
-+              }
-+              if ( (skb) && 
-+                   (netif_rx(skb) != NET_RX_DROP)){
-+
-+                      eip_rx->bytes += len;
-+                      
-+                      if (payload && payload->Data[frag_nr] ) {
-+                              data += EIP_IP_ALIGN(len);
-+                              len   = payload->Data[frag_nr++];
-+                              goto again;
-+                      }
-+                      eip_rx->packets += ++frag_nr;
-+              } else if ( (eip_rx->dropped++ % 20) == 0)
-+                              __EIP_DBG_PRINTK("Packet dropped by the TCP/IP stack - increase /proc/sys/net/core/netdev_max_backlog\n");
-+      } else if (ret == EP_SHUTDOWN ) {
-+              EIP_DBG2(EIP_DBG_RMD, eip_rmd_display, rmd, "ABORTING\n");
-+                ep_complete_receive(rxd);
-+                eip_skb_unload(rmd);
-+              EIP_STAT_ALLOC_SUB(&rmd->head->stats, 1);
-+                eip_rmd_free(rmd);
-+              return;
-+      } else {
-+              EP_ENVELOPE *env = ep_rxd_envelope(rxd);
-+              EP_NMD *nmd ;
-+              
-+              EIP_ERR_PRINTF("RMD[%p] : RECEIVE ret = %d\n", rmd, ret);
-+
-+              for (len = 0 ; len < env->nFrags ; len++) {
-+                      nmd = &env->Frags[len];
-+                      EIP_ERR_PRINTF("RMD[%p] : ep_frag #%d nmd_addr [%x] nmd_len %d\n", rmd, len, 
-+                                      (unsigned int) nmd->nmd_addr, nmd->nmd_len);
-+              }
-+              eip_rx->errors++;
-+              EIP_ASSERT2(atomic_read(&skb_shinfo(rmd->skb)->dataref) == 1, eip_rmd_display, rmd);
-+      }
-+
-+      /* data is used to store the irq flags */
-+      spin_lock_irqsave(&eip_rx->lock, data);
-+      rmd->chain.next = eip_rx->irq_list;
-+      eip_rx->irq_list = rmd;
-+      eip_rx->irq_list_nr++;
-+      spin_unlock_irqrestore(&eip_rx->lock, data);
-+
-+      if (((count++ % eip_rx->sysctl_granularity) == 0) /* and either we have passed up a number of them */
-+          || eip_rx_queues_low())                       /* or we are low                                 */
-+              tasklet_schedule(&eip_rx->tasklet);
-+      else
-+      {
-+              if ( !timer_pending (&eip_rx_tasklet_timer)  )    /* the timer not already set  */
-+                      mod_timer (&eip_rx_tasklet_timer, lbolt);
-+      }
-+}
-+
-+/* dest ; if the buffer still reference on it mocve the rmd to the dest list */
-+static void eip_rmd_reclaim(EIP_RMD *rmd) 
-+{
-+      EIP_RMD *rmd_next = rmd;
-+      int dataref;
-+
-+      while (rmd_next) {
-+              rmd = rmd_next;
-+              rmd_next = rmd_next->chain.next;
-+
-+              dataref = atomic_read(&skb_shinfo(rmd->skb)->dataref);
-+              EIP_ASSERT(dataref > 0);
-+              
-+              if (dataref == 1) {
-+                      eip_rmd_requeue(rmd);
-+              } else {
-+                      rmd->chain.next = rmd->head->busy_list;
-+                      rmd->head->busy_list = rmd;
-+              }
-+      }
-+}
-+static void eip_rx_tasklet(unsigned long arg)
-+{
-+      EIP_RMD *rmd, *rmd_next;
-+      unsigned long flags;
-+      short svc, queued;
-+      int   needs_reschedule;
-+
-+      if (eip_rx_tasklet_locked) /* we dont want the tasklet to do anything when we are finishing */
-+          return;
-+
-+      for (svc = 0; svc < EIP_SVC_NR; svc++) {
-+              rmd = eip_rx->head[svc].busy_list;
-+              eip_rx->head[svc].busy_list = NULL;
-+              eip_rmd_reclaim(rmd);
-+      }
-+
-+      spin_lock_irqsave(&eip_rx->lock, flags);
-+      rmd = eip_rx->irq_list;
-+      eip_rx->irq_list = NULL;
-+      eip_rx->irq_list_nr = 0;
-+      spin_unlock_irqrestore(&eip_rx->lock, flags);
-+      
-+      eip_rmd_reclaim(rmd);
-+
-+      needs_reschedule = 0;
-+
-+      for (svc = 0; svc < EIP_SVC_NR; svc++) {
-+              /* the plan is : allocate some more if possible or steall some dvma space from those on the EIP_BUSY_LIST */
-+              queued = EIP_STAT_QUEUED_GET(&eip_rx->head[svc].stats);
-+
-+              EIP_ASSERT(queued >= 0 && queued <= EIP_RMD_MAX_NR);    
-+              
-+              if (queued < EIP_RMD_ALLOC_THRESH) {
-+                      short allocated = EIP_STAT_ALLOC_GET(&eip_rx->head[svc].stats);
-+                      short how_many; 
-+
-+                      EIP_ASSERT(allocated >= 0 && allocated <= EIP_RMD_MAX_NR);
-+                      
-+                      if (likely(allocated < eip_rx->rmd_max_nr)) {
-+
-+                              how_many = (((allocated / EIP_RMD_ALLOC_STEP) + 1) * EIP_RMD_ALLOC_STEP);
-+                              if (how_many > eip_rx->rmd_max_nr)
-+                                      how_many = eip_rx->rmd_max_nr;
-+
-+                              for (; allocated < how_many &&  
-+                                                      (eip_rmd_alloc_queue(svc, allocated * EIP_DVMA_PAGES((EIP_SVC_SMALLEST_LEN << svc)), 
-+                                                                            GFP_ATOMIC, EP_NO_ALLOC|EP_NO_SLEEP) == 0) ; allocated++);
-+                              if ( allocated != how_many ) {
-+                                      eip_rx->reschedule++;
-+                                      needs_reschedule = 1;
-+                              }
-+                      } else {
-+                              /* steal how_many rmds and put them on the aside list */
-+                              how_many = EIP_RMD_ALLOC_THRESH - queued;
-+
-+                              EIP_ASSERT(how_many >= 0 && how_many <= EIP_RMD_ALLOC_THRESH);
-+                              
-+                              rmd_next = eip_rx->head[svc].busy_list;
-+                              eip_rx->head[svc].busy_list = NULL;
-+
-+                              while (how_many-- && rmd_next) {
-+                                      rmd = rmd_next;
-+                                      rmd_next = rmd_next->chain.next;
-+
-+                                      if (eip_rmd_alloc_replace(rmd, svc, GFP_ATOMIC)) {
-+                                              rmd_next = rmd;
-+                                              break;
-+                                      }
-+                              }
-+                              eip_rx->head[svc].busy_list = rmd_next;
-+                              if ( how_many )
-+                                      needs_reschedule = 1;
-+                      }
-+              }
-+      }
-+      
-+      if (needs_reschedule) 
-+      {
-+              if ( !timer_pending (&eip_rx_tasklet_timer)) 
-+                      mod_timer (&eip_rx_tasklet_timer, lbolt);
-+      }
-+}
-+static void eip_rx_tasklet_resched(unsigned long arg)
-+{
-+      tasklet_schedule(&eip_rx->tasklet);     
-+}
-+
-+static inline void eip_tmd_init(EIP_TMD * tmd, unsigned long buff_base, EIP_TMD_HEAD * head, unsigned long buff_len,
-+                              int dvma_idx)
-+{
-+      tmd->dvma_idx = dvma_idx;
-+      tmd->dma_base = buff_base;
-+      tmd->dma_len = -1;
-+      tmd->skb = NULL;
-+      tmd->head = head;
-+      tmd->chain.next = NULL;
-+
-+      if (tmd->head != &eip_tx->head[EIP_TMD_STD]) {
-+              tmd->nmd.nmd_len = buff_len;
-+              eip_tmd_load(tmd);
-+      } else  {
-+              tmd->nmd.nmd_len  = -1;
-+              tmd->nmd.nmd_addr = 0;
-+      }
-+}
-+
-+static inline EIP_TMD *eip_tmd_get(int id)
-+{
-+      unsigned long flags;
-+      EIP_TMD *tmd = NULL;
-+      spin_lock_irqsave(&eip_tx->lock, flags);
-+      while ((tmd = eip_tx->head[id].tmd) == NULL) {
-+              spin_unlock_irqrestore(&eip_tx->lock, flags);
-+              if (ep_enable_txcallbacks(eip_tx->xmtr) == 0) {
-+
-+                      spin_lock_irqsave (&eip_tx->lock, flags);
-+                      if (eip_tx->head[id].tmd == NULL) {
-+                              __EIP_DBG_PRINTF("Cannot get a TMD on head %d ... stopping queue\n", id);
-+                              
-+                              eip_stop_queue ();
-+                              
-+                              spin_unlock_irqrestore (&eip_tx->lock, flags);
-+
-+                              return NULL;
-+                      }
-+                      spin_unlock_irqrestore (&eip_tx->lock, flags);
-+              }
-+
-+              ep_disable_txcallbacks(eip_tx->xmtr);
-+              spin_lock_irqsave(&eip_tx->lock, flags);
-+      }
-+      eip_tx->head[id].tmd = tmd->chain.next;
-+      spin_unlock_irqrestore(&eip_tx->lock, flags);
-+      atomic_dec(&tmd->head->stats);
-+      return tmd;
-+}
-+
-+static inline void eip_tmd_put(EIP_TMD * tmd)
-+{
-+      unsigned long flags;
-+
-+      tmd->skb = NULL;
-+
-+      spin_lock_irqsave(&eip_tx->lock, flags);
-+      tmd->chain.next = tmd->head->tmd;
-+      tmd->head->tmd = tmd;
-+      spin_unlock_irqrestore(&eip_tx->lock, flags);
-+      atomic_inc(&tmd->head->stats);
-+
-+      eip_start_queue();
-+
-+      EIP_DBG_PRINTF(EIP_DBG_TMD_QUEUE, "TMD [%p] : REQUEUED\n", tmd);
-+}
-+static inline void eip_tmd_load(EIP_TMD * tmd)
-+{
-+      EP_RAILMASK rmask = tx_railmask;
-+
-+      __eip_tmd_load(tmd, &rmask);
-+      
-+      EIP_DBG_PRINTF(EIP_DBG_EP_DVMA, "TMD [%p] : LOADED\n", tmd);
-+}
-+static inline void eip_tmd_unload(EIP_TMD * tmd)
-+{
-+      __eip_tmd_unload(tmd);
-+      
-+      EIP_DBG_PRINTF(EIP_DBG_EP_DVMA, "TMD [%p] : UNLOADED\n", tmd);
-+}
-+static inline void eip_tmd_free(EIP_TMD * tmd)
-+{
-+      eip_buff_free(tmd->dma_base, tmd->nmd.nmd_len);
-+      
-+      EIP_DBG_PRINTF(EIP_DBG_MEMFREE, "TMD [%p] : FREED\n", tmd);
-+      
-+      EIP_STAT_ALLOC_SUB(&tmd->head->stats, 1);
-+}
-+
-+/* tmd on a separate block */
-+static inline EIP_TMD *eip_tmd_alloc_queue(EIP_TMD * tmd, EIP_TMD_HEAD * head, int dvma_idx)
-+{
-+      eip_tmd_init(tmd, 0, head, -1, dvma_idx);
-+
-+      eip_tmd_put(tmd);
-+
-+      EIP_STAT_ALLOC_ADD(&tmd->head->stats, 1);
-+      EIP_DBG(EIP_DBG_TMD, eip_tmd_display, tmd);
-+      return tmd;
-+}
-+/* tmd on the buffer */
-+static inline EIP_TMD *eip_tmd_alloc_queue_copybreak(EIP_TMD_HEAD * head, int dvma_idx)
-+{
-+      EIP_TMD *tmd;
-+      unsigned long buff_base;
-+
-+      if (!(buff_base = eip_buff_alloc(tx_copybreak_max + sizeof(EIP_TMD), GFP_KERNEL)))
-+              return NULL;
-+
-+      tmd = (EIP_TMD *) (buff_base + tx_copybreak_max);
-+      eip_tmd_init(tmd, buff_base, head, tx_copybreak_max, dvma_idx);
-+
-+      eip_tmd_put(tmd);
-+      EIP_STAT_ALLOC_ADD(&tmd->head->stats, 1);
-+      EIP_DBG(EIP_DBG_TMD, eip_tmd_display, tmd);
-+      return tmd;
-+}
-+
-+/* ipf are on the buffer */
-+static inline EIP_TMD *eip_tmd_alloc_queue_aggreg(EIP_TMD_HEAD * head, int dvma_idx)
-+{
-+      EIP_TMD *tmd;
-+      unsigned long buff_base;
-+
-+      if (!(buff_base = eip_buff_alloc(EIP_SVC_BIGGEST_LEN, GFP_KERNEL)))
-+              return NULL;
-+
-+      tmd = (EIP_TMD *) (buff_base + EIP_SVC_BIGGEST_LEN - sizeof(EIP_IPFRAG));
-+      eip_tmd_init(tmd, buff_base, head, EIP_SVC_BIGGEST_LEN - sizeof(EIP_IPFRAG), dvma_idx);
-+
-+      eip_tmd_put(tmd);
-+      EIP_STAT_ALLOC_ADD(&tmd->head->stats, 1);
-+      EIP_DBG(EIP_DBG_TMD, eip_tmd_display, tmd);
-+      return tmd;
-+}
-+
-+static int eip_tmds_alloc()
-+{
-+      int i;
-+      int page_nr;
-+      EIP_TMD *tmd;
-+
-+      page_nr = EIP_DVMA_PAGES(tx_copybreak_max);
-+
-+      eip_tx->head[EIP_TMD_COPYBREAK].handle = eip_dma_reserve(page_nr * eip_tx->tmd_max_nr, EP_PERM_READ);
-+      
-+      EIP_DBG(EIP_DBG_TMD_HEAD, eip_tmd_head_display, &eip_tx->head[EIP_TMD_COPYBREAK]);
-+
-+      for (i = 0; i < EIP_TMD_NR; i++) {
-+              if (!eip_tmd_alloc_queue_copybreak(&eip_tx->head[EIP_TMD_COPYBREAK], i * page_nr))
-+                      return -ENOMEM;
-+      }
-+
-+      eip_tx->head[EIP_TMD_STD].handle =
-+          eip_dma_reserve(EIP_DVMA_PAGES(EIP_SVC_BIGGEST_LEN) * eip_tx->tmd_max_nr, EP_PERM_READ);
-+      
-+      EIP_DBG(EIP_DBG_TMD_HEAD, eip_tmd_head_display, &eip_tx->head[EIP_TMD_STD]);
-+
-+      tmd = kmalloc(sizeof(EIP_TMD) * EIP_TMD_NR, GFP_KERNEL);
-+      if (!tmd) {
-+              EIP_ERR_PRINTF("Cannot ALLOCATE %d of tmds\n", (int) sizeof(EIP_TMD) * EIP_TMD_NR);
-+              return -ENOMEM;
-+      }
-+      
-+      page_nr = EIP_DVMA_PAGES(EIP_SVC_BIGGEST_LEN);
-+      
-+      for (i = 0; i < EIP_TMD_NR; i++, tmd++) {
-+              if (!eip_tmd_alloc_queue(tmd, &eip_tx->head[EIP_TMD_STD], i * page_nr))
-+                      return -ENOMEM;
-+      }
-+
-+      page_nr = EIP_DVMA_PAGES(EIP_SVC_BIGGEST_LEN);
-+
-+      eip_tx->head[EIP_TMD_AGGREG].handle = eip_dma_reserve(page_nr * eip_tx->tmd_max_nr, EP_PERM_READ);
-+      EIP_DBG(EIP_DBG_TMD_HEAD, eip_tmd_head_display, &eip_tx->head[EIP_TMD_AGGREG]);
-+
-+      for (i = 0; i < EIP_TMD_NR; i++) {
-+              if (!eip_tmd_alloc_queue_aggreg(&eip_tx->head[EIP_TMD_AGGREG], i * page_nr))
-+                      return -ENOMEM;
-+      }
-+      return 0;
-+}
-+
-+static void eip_tmds_free(void) 
-+{
-+      EIP_TMD *tmd;
-+      EIP_TMD *tmd_next;
-+      int i;
-+      
-+      ep_poll_transmits(eip_tx->xmtr);
-+
-+      for (i = 0 ; i < 3 ; i++) {
-+again:
-+              if (EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats) < EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats)) {
-+                      EIP_DBG_PRINTF(EIP_DBG_TMD, "Polling XMTR [%p]\n", eip_tx->xmtr);       
-+                      ep_poll_transmits(eip_tx->xmtr);
-+                      goto again;
-+              }
-+      }
-+      /* everything should be queued */
-+        if ((tmd = eip_tx->head[EIP_TMD_COPYBREAK].tmd)) {
-+            do {
-+                      tmd_next = tmd->chain.next;
-+                        eip_tmd_unload(tmd);
-+                      
-+                      EIP_DBG(EIP_DBG_TMD, eip_tmd_display, tmd);
-+                      
-+                        eip_tmd_free(tmd);
-+            } while (tmd_next && (tmd = tmd_next));
-+        }
-+      
-+      EIP_DBG_PRINTF(EIP_DBG_TMD_EP_DVMA, "HEAD[EIP_TMD_COPYBREAK] release DVMA [%p]\n",
-+                      eip_tx->head[EIP_TMD_COPYBREAK].handle);        
-+      
-+        ep_dvma_release(eip_tx->ep_system, eip_tx->head[EIP_TMD_COPYBREAK].handle);
-+      
-+      /* these ones have been allocated as a block */
-+      if ((tmd = eip_tx->head[EIP_TMD_STD].tmd)) {
-+              do {
-+                      if (tmd->dvma_idx == 0 ) {
-+                              kfree(tmd);
-+                              /* eip_tmd_free(tmd); */
-+                              EIP_STAT_ALLOC_SUB(&tmd->head->stats, EIP_TMD_NR);
-+                              tmd_next = NULL;
-+                              EIP_DBG_PRINTF(EIP_DBG_TMD_EP_DVMA, "TMD HEAD[%p] : [EIP_TMD_STD] BLOCK FREED\n", tmd); 
-+                      } else 
-+                              tmd_next = tmd->chain.next;
-+              } while (tmd_next && (tmd = tmd_next));
-+      }
-+      EIP_DBG_PRINTF(EIP_DBG_TMD_EP_DVMA, "HEAD[EIP_TMD_STD] release DVMA [%p]\n", 
-+                      eip_tx->head[EIP_TMD_STD].handle);      
-+      
-+        ep_dvma_release(eip_tx->ep_system, eip_tx->head[EIP_TMD_STD].handle);
-+      
-+      if ((tmd = eip_tx->head[EIP_TMD_AGGREG].tmd)) {
-+              do {
-+                      tmd_next = tmd->chain.next;
-+
-+                      EIP_DBG(EIP_DBG_TMD, eip_tmd_display, tmd);
-+                      
-+                      eip_tmd_unload(tmd);
-+                      eip_tmd_free(tmd);
-+              } while (tmd_next && (tmd = tmd_next));
-+      }
-+      EIP_DBG_PRINTF(EIP_DBG_TMD_EP_DVMA, "TMD HEAD[%p] : [EIP_TMD_AGGREG] release DVMA\n", 
-+                      eip_tx->head[EIP_TMD_AGGREG].handle);   
-+      
-+        ep_dvma_release(eip_tx->ep_system, eip_tx->head[EIP_TMD_AGGREG].handle);
-+
-+      ep_free_xmtr(eip_tx->xmtr);
-+      EIP_DBG_PRINTF(EIP_DBG_TMD, "XMTR[%p] : FREED\n", eip_tx->xmtr);
-+}
-+
-+static inline void eip_ipf_skb_add(EIP_IPFRAG * ipf, struct sk_buff *skb)
-+{
-+      int align = EIP_IP_ALIGN(skb->len);
-+      
-+      
-+      if (ipf->dma_len == -1) {       /* like a virgin; touched for the very first time */
-+              do_gettimeofday(&ipf->timestamp);
-+              /* FIXE ME put that in release tmd code */
-+              ipf->frag_nr            = 0;
-+              ipf->dma_len            = 0;
-+              ipf->datagram_len       = -1;
-+              ipf->dma_correction     = 0;
-+      }
-+      
-+      memcpy((void *) (ipf->dma_base + ipf->dma_len), skb->data, skb->len);
-+      
-+      if (ipf->datagram_len == -1) {
-+              struct iphdr * iph = skb->nh.iph;
-+              int offset = ntohs(iph->frag_off);
-+
-+              /* last one ? ;  offset & ~IP_OFFSET = IP fragment flags */
-+              if (((offset & ~IP_OFFSET) & IP_MF) == 0) {
-+                      offset &= IP_OFFSET;
-+                      offset <<= 3;    
-+                      ipf->datagram_len = offset + htons(iph->tot_len) - sizeof(struct iphdr);
-+              }
-+      }
-+
-+      skb->next                       = ipf->skb;
-+      ipf->skb                        = skb;
-+      ipf->payload.Data[ipf->frag_nr] = skb->len;
-+      ipf->dma_len                   += align;
-+      ipf->dma_correction            += align - skb->len  + ETH_HLEN + sizeof(struct iphdr);
-+      /* FIXME ; Count got wrong if ip header has options */
-+
-+      ipf->frag_nr++;
-+
-+      EIP_DBG2(EIP_DBG_TMD, eip_ipf_display, ipf, "ADDED skb[%p] len %db ALIGNED(%db)\n", skb, skb->len, EIP_IP_ALIGN(skb->len));
-+}
-+
-+#define eip_ipf_hasroom(ipf, skb) ((ipf->dma_len + EIP_IP_ALIGN(skb->len) < eip_tx->sysctl_ipfrag_copybreak))
-+int eip_hard_start_xmit(struct sk_buff *skb, struct net_device *devnet) 
-+{
-+
-+      EIP_TMD *tmd;
-+      EP_NMD nmd;
-+      struct iphdr *iph;
-+      int j;
-+
-+      if (skb->destructor){
-+              atomic_inc(&eip_tx->destructor);
-+              tasklet_schedule(&eip_tx->tasklet);
-+      } 
-+
-+      if (!(iph = eip_ipfrag_get(skb->data)) || (eip_tx->sysctl_aggregation == 0)) { /* not ip fragment */
-+no_aggreg:
-+              j = (skb->len < eip_tx->sysctl_copybreak) ? EIP_TMD_COPYBREAK : EIP_TMD_STD; /* j = head id */
-+              
-+              if (!(tmd = eip_tmd_get(j))) {
-+                      if (skb->destructor)
-+                              atomic_dec(&eip_tx->destructor);
-+                      return 1;
-+              }
-+              
-+              tmd->dma_len    = skb->len;
-+              tmd->skb        = skb;
-+              tmd->skb->next  = NULL;
-+              tmd->chain.next = NULL;
-+              
-+              if (j == EIP_TMD_COPYBREAK) {
-+                      memcpy((void *) tmd->dma_base, skb->data, skb->len);
-+                      
-+                      ep_nmd_subset(&nmd, &tmd->nmd, 0, skb->len);
-+#ifdef EIP_MORE_STATS
-+                      eip_tx->sent_copybreak++;
-+#endif
-+                      return eip_do_xmit(tmd, &nmd, NULL);
-+              }
-+              tmd->dma_base           = (unsigned long) skb->data;
-+              tmd->nmd.nmd_len        = skb->len;
-+              eip_tmd_load(tmd);
-+
-+#ifdef EIP_MORE_STATS
-+              eip_tx->sent_std++;
-+#endif
-+              return eip_do_xmit(tmd, &tmd->nmd, NULL);
-+      } else if ( skb->len > EIP_SVC_BIGGEST_LEN/2 ) { 
-+              /* don't aggregate when we have a full mtu of data */
-+              /* or more than 32k ; in this case it is cheaper   */
-+              /* to just map the buffer and send it              */
-+              goto no_aggreg;
-+      } else {
-+              EIP_IPFRAG *ipf = NULL;
-+              unsigned long flags;
-+              struct list_head *l;
-+              struct iphdr *iph2;
-+              int i;
-+              __u16 id = iph->id;
-+              __u32 saddr = iph->saddr;
-+              __u32 daddr = iph->daddr;
-+              __u8 protocol = iph->protocol;
-+
-+                      EIP_DBG(EIP_DBG_IPH, eip_iph_display, iph);
-+
-+              j = 0;
-+
-+              /* here we can't have full mtu size aggregated packet */
-+              EIP_ASSERT_RET(skb->len < eip_tx->sysctl_ipfrag_copybreak, 0);
-+
-+              spin_lock_irqsave(&eip_tx->ipfraglock, flags);
-+              list_for_each(l, &eip_tx->ipfrag) {
-+                      ipf = list_entry(l, EIP_IPFRAG, list);
-+                      iph2 = eip_ipfrag_get((char *) ipf->dma_base);
-+                      
-+                        EIP_ASSERT(iph2);
-+                      
-+                      if ((iph2->id == id) && 
-+                                      (get_unaligned(&iph2->saddr) == saddr) && 
-+                                      (get_unaligned(&iph2->daddr) == daddr) && 
-+                                      (iph2->protocol == protocol)) {
-+                              /* || timeout */
-+                              if (eip_ipf_hasroom(ipf, skb)) {
-+                                      
-+                                      eip_ipf_skb_add(ipf, skb);
-+                                      
-+                                      if ((ipf->datagram_len != -1) && 
-+                                                      (ipf->dma_len == (ipf->datagram_len + ipf->dma_correction) || 
-+                                                       ipf->frag_nr == (128 / sizeof(uint32_t)))) {
-+send_aggreg:
-+                                              ipf->payload.Data[ipf->frag_nr] = 0;
-+                                              list_del(&ipf->list);
-+                                              eip_tx->ipfrag_count--;
-+                                              spin_unlock_irqrestore(&eip_tx->ipfraglock, flags);
-+                                      
-+                                              ep_nmd_subset(&nmd, &ipf->nmd, 0, ipf->dma_len);
-+                                              
-+#ifdef EIP_MORE_STATS
-+                                              eip_tx->sent_aggreg++;
-+#endif
-+                                              if ((i = eip_do_xmit((EIP_TMD *) ipf, &nmd, &ipf->payload)) != EP_SUCCESS)
-+                                                      return i;
-+                                              if (j)
-+                                                      goto new;
-+                                              return 0;
-+                                      }
-+                                      
-+                                      spin_unlock_irqrestore(&eip_tx->ipfraglock, flags);
-+                                      tasklet_schedule(&eip_tx->tasklet);
-+                                      return 0;
-+                              } else {
-+                                      EIP_DBG_PRINTF(EIP_DBG_TMD, "IPF[%p] : FULL %db full - sending it\n", ipf, ipf->dma_len);
-+                                      j = 1;
-+                                      goto send_aggreg;
-+                              }
-+                      }
-+              }
-+              spin_unlock_irqrestore(&eip_tx->ipfraglock, flags);
-+new:
-+              if (!(ipf = (EIP_IPFRAG *) eip_tmd_get(EIP_TMD_AGGREG)))
-+                      goto no_aggreg;
-+
-+              eip_ipf_skb_add(ipf, skb);
-+              
-+              spin_lock_irqsave(&eip_tx->ipfraglock, flags);
-+              list_add_tail(&ipf->list, &eip_tx->ipfrag);
-+              eip_tx->ipfrag_count++;
-+              spin_unlock_irqrestore(&eip_tx->ipfraglock, flags);
-+              tasklet_schedule(&eip_tx->tasklet);
-+      }
-+      return 0;
-+}
-+static int eip_do_xmit(EIP_TMD * tmd, EP_NMD *nmd, EP_PAYLOAD *payload)
-+{
-+      EIP_HEADER *eiph = (EIP_HEADER *) tmd->dma_base;
-+      int         attr = EP_SET_DATA((EP_NO_SLEEP | EP_NO_INTERRUPT | EP_NO_FAILOVER), EP_TYPE_SVC_INDICATOR, EP_SVC_EIP);
-+      unsigned long flags;
-+      int svc, rnum;
-+
-+      SIZE_TO_SVC(nmd->nmd_len, svc);
-+
-+      EIP_DBG(EIP_DBG_TMD, eip_tmd_display, tmd);
-+      /* EIP_DBG(eip_eiph_display(eiph)); */
-+      
-+      if (unlikely (eiph->h_dhost.ip_bcast))
-+              rnum = ep_pickRail (EP_NMD_RAILMASK (nmd) & tx_railmask & ep_xmtr_availrails(eip_tx->xmtr));
-+      else
-+              rnum = ep_pickRail (EP_NMD_RAILMASK (nmd) & tx_railmask & ep_xmtr_noderails(eip_tx->xmtr, ntohs(eiph->h_dhost.ip_addr)));
-+
-+      if (rnum >= 0)
-+              attr = EP_SET_PREFRAIL(attr, rnum);
-+
-+      /* add to inuse list  */
-+      spin_lock_irqsave (&eip_tx->lock, flags);
-+      list_add_tail (&tmd->chain.link, &eip_tx->inuse);
-+      spin_unlock_irqrestore (&eip_tx->lock, flags);
-+
-+      /* ENOMEM EINVAL ECONNREFUSED ESUCCESS */
-+      svc = (unlikely(eiph->h_dhost.ip_bcast)) ? 
-+              ep_multicast_message(eip_tx->xmtr, -1, -1, NULL, EIP_SVC_EP(svc), attr | EP_NOT_MYSELF, eip_txhandler, tmd, payload, nmd, 1) :
-+
-+              ep_transmit_message(eip_tx->xmtr, ntohs(eiph->h_dhost.ip_addr), EIP_SVC_EP(svc),  attr, eip_txhandler, tmd, payload, nmd, 1);
-+              
-+      if (likely(svc == EP_SUCCESS))
-+              return 0;
-+      else if (svc == ENOMEM) {
-+              EIP_ERR_PRINTF("%s", "Memory allocation error ...\n");
-+              eip_tx->errors++;
-+      }
-+      else
-+      {
-+              /* EP_EINVAL occurs when the svc has a bad value or the iovec has too many frag; */
-+              /* we don't use the latter option here                                        */
-+              __EIP_DBG_PRINTF("TMD [%p] : DROPPED skb[%p] status = %d from ep_?_message\n", tmd, tmd->skb, svc);
-+
-+              eip_tx->dropped++;
-+      }
-+
-+      eip_txhandler(NULL, tmd, -99);
-+
-+      /* Quadrics GNAT sw-elan/4397 - since we will "never" be able to send this packet to the */
-+      /* destination node, we drop it and feign success - this has the same behaviour as an    */
-+      /* ethernet where it sticks the packet on the wire, but no-one receives it.              */
-+      return 0;
-+}
-+
-+static void eip_txhandler(EP_TXD * txd, void *arg, EP_STATUS status)
-+{
-+      EIP_TMD *tmd = (EIP_TMD *) arg;
-+      struct sk_buff *skb_next;
-+      unsigned long flags;
-+      int svc = 0;
-+      
-+      if (likely(status == EP_SUCCESS)) {
-+              SIZE_TO_SVC(tmd->dma_len, svc);
-+              eip_tx->dma[svc]++;
-+              eip_tx->bytes += tmd->dma_len;
-+              
-+              if (tmd->head == &eip_tx->head[EIP_TMD_AGGREG]) {
-+                      EIP_IPFRAG *ipf = (EIP_IPFRAG *) tmd;
-+                      eip_tx->packets += ipf->frag_nr;
-+              } else
-+                      eip_tx->packets++;
-+      } else {
-+              if (tmd->head == &eip_tx->head[EIP_TMD_AGGREG]) {
-+                      EIP_IPFRAG *ipf = (EIP_IPFRAG *) tmd;
-+                      eip_tx->dropped += ipf->frag_nr;
-+                      EIP_DBG_PRINTF(EIP_DBG_TMD, "txhandler aggreg packet dropped status = %d\n", status);
-+              } else  {
-+                      eip_tx->dropped++;
-+                      EIP_DBG_PRINTF(EIP_DBG_TMD, "txhandler packet dropped status = %d\n", status);
-+              }
-+      }
-+
-+      if (tmd->head == &eip_tx->head[EIP_TMD_STD]) {
-+              eip_tmd_unload(tmd);
-+              tmd->dma_base = 0;
-+              tmd->nmd.nmd_len = -1;
-+      }
-+              
-+      tmd->dma_len = -1;
-+      
-+      svc = 0;
-+      while (tmd->skb) {
-+              svc++;
-+              
-+              if (tmd->skb->destructor)
-+                      atomic_dec(&eip_tx->destructor);
-+
-+              skb_next = tmd->skb->next;
-+              dev_kfree_skb_any(tmd->skb);
-+              tmd->skb = skb_next;
-+      }
-+      EIP_DBG_PRINTF(EIP_DBG_TMD, "IPF/TMD [%p] : %d skb RELEASE/FREED\n", tmd, svc);
-+
-+      /* remove from inuse list  */
-+      spin_lock_irqsave (&eip_tx->lock, flags);
-+      list_del (&tmd->chain.link);
-+      spin_unlock_irqrestore (&eip_tx->lock, flags);
-+
-+      eip_tmd_put(tmd);
-+}
-+
-+static void eip_tx_tasklet(unsigned long arg)
-+{
-+      struct timeval now;
-+      unsigned long flags;
-+      EIP_IPFRAG *ipf, *ipfq = NULL;
-+      EP_NMD nmd;
-+      struct list_head *list;
-+      struct list_head *tmp;
-+      char resched = 0;
-+      char poll = 1;
-+      
-+      do_gettimeofday(&now);
-+      
-+      spin_lock_irqsave(&eip_tx->ipfraglock, flags);
-+      if (eip_tx->ipfrag_count) {
-+              list_for_each_safe(list, tmp, &eip_tx->ipfrag) {
-+                      ipf = list_entry(list, EIP_IPFRAG, list);
-+                      /* delta = (((now.tv_sec - ipf->timestamp.tv_sec) * 1000000UL) + now.tv_usec) - ipf->timestamp.tv_usec; */
-+                      if (((((now.tv_sec - ipf->timestamp.tv_sec) * 1000000UL) + now.tv_usec) - 
-+                                      ipf->timestamp.tv_usec) >= (1000UL * eip_tx->sysctl_ipfrag_to)) {
-+                              list_del(&ipf->list);
-+                              eip_tx->ipfrag_count--;
-+                              ipf->chain.next = (EIP_TMD *) ipfq;
-+                              ipfq = ipf;
-+                      }
-+              }
-+      }
-+      if (eip_tx->ipfrag_count)
-+              resched = 1;
-+      spin_unlock_irqrestore(&eip_tx->ipfraglock, flags);
-+
-+      while (ipfq) {
-+              poll = 0;
-+
-+              ep_nmd_subset(&nmd, &ipfq->nmd, 0, ipfq->dma_len);
-+              
-+              ipfq->payload.Data[ipfq->frag_nr] = 0;
-+              
-+#ifdef EIP_MORE_STATS
-+              eip_tx->sent_aggreg++;
-+#endif
-+              ipf = (EIP_IPFRAG *) ipfq->chain.next;
-+              eip_do_xmit((EIP_TMD *) ipfq, &nmd, &ipfq->payload);
-+              ipfq = ipf;
-+       }
-+       
-+       if (poll)
-+               ep_poll_transmits(eip_tx->xmtr);
-+
-+       if (atomic_read(&eip_tx->destructor) || resched )
-+               tasklet_schedule(&eip_tx->tasklet);
-+}
-+void eip_start_queue()
-+{
-+      if (netif_queue_stopped(eip_tx->net_device)) {
-+              EIP_DBG_PRINTK(EIP_DBG_GEN, "Waking up %s queue\n", eip_tx->net_device->name);
-+              netif_wake_queue(eip_tx->net_device);
-+      }
-+}
-+void eip_stop_queue()
-+{
-+      EIP_DBG_PRINTK(EIP_DBG_GEN, "Stopping %s queue\n", eip_tx->net_device->name);
-+      netif_stop_queue(eip_tx->net_device);
-+}
-+
-+static int eip_open(struct net_device *devnet)
-+{
-+      if (devnet->flags & IFF_PROMISC)
-+              EIP_DBG_PRINTK(EIP_DBG_GEN, "%s entering in promiscuous mode\n", devnet->name);
-+
-+      netif_start_queue(devnet);
-+      EIP_DBG_PRINTK(EIP_DBG_GEN, "iface %s MAC %02x:%02x:%02x:%02x:%02x:%02x up\n",
-+                      devnet->name, (devnet->dev_addr[0]) & 0xff,
-+                      (devnet->dev_addr[1]) & 0xff, (devnet->dev_addr[2]) & 0xff, (devnet->dev_addr[3]) & 0xff,
-+                      (devnet->dev_addr[4]) & 0xff, (devnet->dev_addr[5]) & 0xff);
-+      return 0;
-+}
-+
-+static int eip_close(struct net_device *devnet)
-+{
-+      if (devnet->flags & IFF_PROMISC)
-+              EIP_DBG_PRINTK(EIP_DBG_GEN, "%s leaving promiscuous mode\n", devnet->name);
-+
-+      netif_stop_queue(devnet);
-+
-+      eip_rx_tasklet(0);
-+
-+      EIP_DBG_PRINTK(EIP_DBG_GEN, "iface %s MAC %02x:%02x:%02x:%02x:%02x:%02x down\n", 
-+              devnet->name, (devnet->dev_addr[0]) & 0xff,
-+              (devnet->dev_addr[1]) & 0xff, (devnet->dev_addr[2]) & 0xff, (devnet->dev_addr[3]) & 0xff,
-+              (devnet->dev_addr[4]) & 0xff, (devnet->dev_addr[5]) & 0xff);
-+      return 0;
-+}
-+
-+static struct net_device_stats *eip_get_stats(struct net_device *devnet)
-+{
-+      static struct net_device_stats stats;
-+
-+      stats.rx_packets = eip_rx->packets;
-+      stats.rx_bytes = eip_rx->bytes;
-+      stats.rx_errors = eip_rx->errors;
-+      stats.rx_dropped = eip_rx->dropped;
-+
-+      stats.tx_packets = eip_tx->packets;
-+      stats.tx_bytes = eip_tx->bytes;
-+      stats.tx_errors = eip_tx->errors;
-+      stats.tx_dropped = eip_tx->dropped;
-+      return &stats;
-+}
-+
-+static int eip_change_mtu(struct net_device *devnet, int mtu)
-+{
-+      if (mtu <= EIP_MTU_MAX) {
-+              EIP_DBG_PRINTK(EIP_DBG_GEN, "MTU size changed from %d to %d\n", devnet->mtu, mtu);
-+              devnet->mtu = mtu;
-+      }
-+      return 0;
-+}
-+
-+#ifdef MODULE
-+int eip_init(void)
-+{
-+      struct net_device *devnet;
-+      int errno = 0;
-+
-+      eip_rx_dropping = 0; 
-+      eip_rx_tasklet_locked = 1;
-+
-+      /* timer up but not started */
-+      init_timer (&eip_rx_tasklet_timer);
-+      eip_rx_tasklet_timer.function = eip_rx_tasklet_resched;
-+      eip_rx_tasklet_timer.data     = (unsigned long) 0;
-+      eip_rx_tasklet_timer.expires  = lbolt + hz;
-+
-+      devnet = alloc_etherdev(sizeof(EIP_RX) + sizeof(EIP_TX));
-+      if (!devnet) {
-+              EIP_ERR_PRINTF("Unable to ALLOCATE etherdev structure\n");
-+              return -ENOMEM;
-+      }
-+      strcpy (devnet->name, "eip0");
-+
-+      EIP_DBG_PRINTK(EIP_DBG_GEN, "Enabling aggregation code\n");
-+      devnet->change_mtu = eip_change_mtu;
-+      devnet->mtu = EIP_MTU_MAX;
-+      devnet->open = eip_open;
-+      devnet->stop = eip_close;
-+      devnet->hard_start_xmit = eip_hard_start_xmit;
-+      devnet->get_stats = eip_get_stats;
-+
-+        /* devnet->features |= (NETIF_F_DYNALLOC); */
-+        /* devnet->features = (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA); */
-+        /* devnet->features |= (NETIF_F_SG|NETIF_F_FRAGLIST|NETIF_F_HIGHDMA|NETIF_F_HW_CSUM); */
-+
-+      eip_rx = (EIP_RX *) devnet->priv;
-+      eip_tx = (EIP_TX *) (eip_rx + 1);
-+
-+      /* instance 0 */
-+      eip_tx->ep_system = ep_system();
-+      if (eip_tx->ep_system == NULL) {
-+              EIP_ERR_PRINTF("kernel comms for iface %s does not exist\n", devnet->name);
-+              errno = -ENXIO;
-+              goto out;
-+      }
-+      if (ep_waitfor_nodeid(eip_tx->ep_system) == ELAN_INVALID_NODE) {
-+              EIP_ERR_PRINTF("network position not found\n");
-+              errno = -EAGAIN;
-+              goto out;
-+      }
-+      eip_tx->xmtr = ep_alloc_xmtr(eip_tx->ep_system);
-+      if (!eip_tx->xmtr) {
-+              EIP_ERR_PRINTF("Cannot create allocated transmitter - maybe cable is disconnected\n");
-+              errno = -EAGAIN;
-+              goto out;
-+      }
-+      /* assign MAC address */
-+      *((int *) &devnet->dev_addr[4]) = htons(ep_nodeid(eip_tx->ep_system));
-+      eip_rx->net_device = devnet;
-+      eip_tx->net_device = devnet;
-+
-+      atomic_set(&eip_tx->destructor, 0);
-+
-+      if ((tmd_max >= EIP_TMD_MIN_NR) && (tmd_max <= EIP_TMD_MAX_NR)) {
-+              EIP_DBG_PRINTF(EIP_DBG_GEN, "Setting tmd_max_nr to %d\n", tmd_max);
-+              eip_tx->tmd_max_nr = tmd_max;
-+      } else {
-+              EIP_ERR_PRINTF("parameter error : %d <= tmd_max(%d) <= %d using default %d\n", 
-+                              EIP_TMD_MIN_NR, tmd_max, EIP_TMD_MAX_NR, EIP_TMD_MAX_NR);
-+              eip_tx->tmd_max_nr = EIP_TMD_MAX_NR;
-+      }
-+
-+      if ((rmd_max >= EIP_RMD_MIN_NR) && (rmd_max <= EIP_RMD_MAX_NR)) {
-+              EIP_DBG_PRINTF(EIP_DBG_GEN, "Setting rmd_max_nr to %d\n", rmd_max);
-+              eip_rx->rmd_max_nr = rmd_max;
-+      } else {
-+              EIP_ERR_PRINTF("parameter error : %d <= rmd_max(%d) <= %d using default %d\n", EIP_RMD_MIN_NR,
-+                         rmd_max, EIP_RMD_MAX_NR, EIP_RMD_MAX_NR);
-+              eip_rx->rmd_max_nr = EIP_RMD_MAX_NR;
-+      }
-+
-+      if ((rx_envelope_nr > 0) && (rx_envelope_nr <= 1024)) { /* > 1024 don't be silly */
-+              EIP_DBG_PRINTK(EIP_DBG_GEN, "Setting rx_envelope_nr to %d\n", rx_envelope_nr);
-+      } else {
-+              EIP_ERR_PRINTF("parameter error : 0 < rx_envelope_nr(%d) <= 1024 using default %d\n",
-+                         rx_envelope_nr, EIP_RX_ENVELOPE_NR);
-+              rx_envelope_nr = EIP_RX_ENVELOPE_NR;
-+      }
-+
-+      if (tx_copybreak_max <= EIP_TX_COPYBREAK_MAX) {
-+              EIP_DBG_PRINTF(EIP_DBG_GEN, "Setting tx_copybreak_max to %d\n", tx_copybreak_max);
-+      } else {
-+              EIP_ERR_PRINTF("parameter error : tx_copybreak_max > %d using default %d\n",
-+                         EIP_TX_COPYBREAK_MAX, EIP_TX_COPYBREAK_MAX);
-+              tx_copybreak_max = EIP_TX_COPYBREAK_MAX;
-+      }
-+#ifdef EIP_MORE_STATS
-+      eip_tx->sent_copybreak = 0;
-+      eip_tx->sent_std = 0;
-+      eip_tx->sent_aggreg = 0;
-+#endif
-+
-+      eip_tx->ipfrag_count = 0;
-+      eip_aggregation_set(1);
-+      eip_rx_granularity_set(rx_granularity);
-+      eip_tx_copybreak_set(EIP_TX_COPYBREAK);
-+      eip_ipfrag_to_set(EIP_IPFRAG_TO);
-+      eip_ipfrag_copybreak_set(EIP_IPFRAG_COPYBREAK);
-+
-+      spin_lock_init(&eip_tx->lock);
-+      spin_lock_init(&eip_tx->ipfraglock);
-+      spin_lock_init(&eip_rx->lock);
-+      tasklet_init(&eip_rx->tasklet, eip_rx_tasklet, 0);
-+      tasklet_init(&eip_tx->tasklet, eip_tx_tasklet, 0);
-+      INIT_LIST_HEAD(&eip_tx->ipfrag);
-+      INIT_LIST_HEAD(&eip_tx->inuse);
-+
-+      /* if we fail here cannot do much yet; waiting for rcvr remove code in ep. */
-+      errno = eip_tmds_alloc();
-+      if (errno)
-+              goto out;
-+
-+      errno = eip_rmds_alloc();
-+      if (errno)
-+              goto out;
-+
-+      errno = eip_stats_init();
-+      if (errno)
-+              goto out;
-+
-+      if (ep_svc_indicator_set(eip_tx->ep_system, EP_SVC_EIP) != EP_SUCCESS) {
-+              EIP_ERR_PRINTF("Cannot set the service indicator\n");
-+              errno = -EINVAL;
-+              goto out;
-+      }
-+
-+      eip_rx_tasklet_locked = 0;
-+      tasklet_schedule(&eip_rx->tasklet);
-+
-+      SET_MODULE_OWNER(eip_tx->net_device);
-+
-+      if (register_netdev(devnet)) {
-+              printk("eip: failed to register netdev\n");
-+              goto out;
-+      }
-+
-+      EIP_DBG_PRINTK(EIP_DBG_GEN, "iface %s MAC %02x:%02x:%02x:%02x:%02x:%02x ready\n", 
-+              devnet->name, (devnet->dev_addr[0]) & 0xff,
-+              (devnet->dev_addr[1]) & 0xff, (devnet->dev_addr[2]) & 0xff, (devnet->dev_addr[3]) & 0xff,
-+              (devnet->dev_addr[4]) & 0xff, (devnet->dev_addr[5]) & 0xff);
-+
-+      return 0;
-+      out:
-+      unregister_netdev(devnet);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 25)
-+      kfree(devnet);
-+#else
-+      free_netdev(devnet);
-+#endif
-+
-+      return errno;
-+}
-+void eip_exit(void)
-+{
-+      int i;
-+
-+      eip_rx_dropping = 1;                /* means that new messages wont be sent to tcp stack */
-+      eip_rx_tasklet_locked = 1;
-+
-+      netif_stop_queue(eip_tx->net_device);
-+
-+      if (ep_svc_indicator_clear(eip_tx->ep_system, EP_SVC_EIP) != EP_SUCCESS) {
-+              EIP_ERR_PRINTF("Cannot unset the service indicator\n");
-+      }
-+
-+      schedule_timeout(10);
-+      
-+      del_timer_sync (&eip_rx_tasklet_timer);
-+
-+      tasklet_disable(&eip_rx->tasklet);
-+      tasklet_disable(&eip_tx->tasklet);
-+
-+      tasklet_kill(&eip_tx->tasklet);
-+      tasklet_kill(&eip_rx->tasklet);
-+
-+        eip_rmds_free();
-+        eip_tmds_free();
-+
-+      /* that things freed */
-+      for (i = 0 ; i < EIP_SVC_NR ; i++) {
-+              if ( EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats) != 0 )
-+                      EIP_ERR_PRINTF("%d RMDs not FREED on SVC[%d]\n", EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats), i);
-+      }
-+      for (i = 0 ; i < 3 ; i++) {
-+              if ( EIP_STAT_ALLOC_GET(&eip_tx->head[i].stats) != 0 )
-+                      EIP_ERR_PRINTF("%d TMDs not freed on TX HEAD[%d]\n", EIP_STAT_ALLOC_GET(&eip_tx->head[i].stats), i);
-+              
-+      }
-+      unregister_netdev(eip_tx->net_device);
-+      kfree(eip_tx->net_device);
-+      
-+      eip_stats_cleanup();
-+}
-+
-+module_init(eip_init);
-+module_exit(eip_exit);
-+
-+module_param(eipdebug, uint, 0);
-+MODULE_PARM_DESC(eipdebug, "Set debug flags");
-+
-+module_param(rx_envelope_nr, uint, 0);
-+MODULE_PARM_DESC(rx_enveloppe_nr, "Number of allocated enveloppe on the rx side");
-+
-+module_param(tx_copybreak_max, uint, 0);
-+MODULE_PARM_DESC(tx_copybreak_max, "Maximum size of the tx copybreak limit (default 512)");
-+
-+module_param(tmd_max, uint, 0);
-+module_param(rmd_max, uint, 0);
-+MODULE_PARM_DESC(tmd_max, "Maximun number of transmit buffers (default 64)");
-+MODULE_PARM_DESC(rmd_max, "Maximun number of receive buffers (default 64)");
-+
-+module_param(tx_railmask, ushort, 0);
-+MODULE_PARM_DESC(tx_railmask, "Mask of which rails transmits can be queued on");
-+
-+MODULE_AUTHOR("Quadrics Ltd.");
-+MODULE_DESCRIPTION("Elan IP driver");
-+MODULE_LICENSE("GPL");
-+#endif        /* MODULE */
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/eip/eip_linux.h linux-2.6.9/drivers/net/qsnet/eip/eip_linux.h
---- clean/drivers/net/qsnet/eip/eip_linux.h    1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/eip/eip_linux.h      2004-10-01 06:49:29.000000000 -0400
-@@ -0,0 +1,399 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "$Id: eip_linux.h,v 1.47 2004/10/01 10:49:29 mike Exp $"
-+
-+#ifndef __EIP_LINUX_H
-+#define __EIP_LINUX_H
-+
-+#define EIP_WATERMARK                 (0xfab1e)
-+
-+#define EIP_PAGES(s)                  (((s - 1) >> PAGE_SHIFT) + 1)
-+#define EIP_DVMA_PAGES(s)             ((s < PAGE_SIZE) ? EIP_PAGES(s) + 1 : EIP_PAGES(s))
-+
-+#define EIP_SVC_SMALLEST_LEN          (1 << 9)        /* 512 */
-+#define EIP_SVC_BIGGEST_LEN           (1 << 16)       /* 64k */
-+
-+#define EIP_SVC_SMALLEST              (0)
-+#define EIP_SVC_BIGGEST                       (7)
-+
-+#define EIP_SVC_NR                    (8)
-+#define EIP_SVC_EP(s)                 (s + EP_MSG_SVC_EIP512)
-+
-+#define EIP_STAT_ALLOC_SHIFT          (8)
-+#define EIP_STAT_ALLOC_GET(atomicp)   ((int) atomic_read(atomicp) >> EIP_STAT_ALLOC_SHIFT)
-+#define EIP_STAT_ALLOC_ADD(atomicp, v)        (atomic_add((v << EIP_STAT_ALLOC_SHIFT), atomicp))
-+#define EIP_STAT_ALLOC_SUB(atomicp, v)        (atomic_sub((v << EIP_STAT_ALLOC_SHIFT), atomicp))
-+
-+#define EIP_STAT_QUEUED_MASK          (0xff)
-+#define EIP_STAT_QUEUED_GET(atomicp)  ((int) atomic_read(atomicp) & EIP_STAT_QUEUED_MASK)
-+
-+#define EIP_RMD_NR                    (8)
-+#define EIP_RMD_MIN_NR                        (8)
-+#define EIP_RMD_MAX_NR                        (64)    /* should be < than (1 << EIP_STAT_ALLOC_SHIFT) */
-+
-+#define EIP_RMD_ALLOC_STEP            (8)
-+#define EIP_RMD_ALLOC_THRESH          (16)
-+
-+#define EIP_RMD_ALLOC                 (1)
-+#define EIP_RMD_REPLACE                       (0)
-+
-+#define EIP_TMD_NR                    (64)
-+#define EIP_TMD_MIN_NR                        (16)
-+#define EIP_TMD_MAX_NR                        (64)    /* should be < than (1 << EIP_STAT_ALLOC_SHIFT) */
-+
-+#define EIP_TMD_TYPE_NR                       (3)
-+#define EIP_TMD_COPYBREAK             (0x0)
-+#define EIP_TMD_STD                   (0x1)
-+#define EIP_TMD_AGGREG                        (0x2)
-+
-+#define EIP_TX_COPYBREAK              (512)
-+#define EIP_TX_COPYBREAK_MAX          (1024)
-+
-+#define EIP_IPFRAG_TO                 (50)    /* time out before a frag is sent in msec */
-+#define EIP_IPFRAG_COPYBREAK          (EIP_SVC_BIGGEST_LEN - sizeof(EIP_IPFRAG) - EIP_HEADER_PAD)
-+
-+#define EIP_RX_ENVELOPE_NR            ((EIP_RMD_MAX_NR*EIP_SVC_NR)/2)
-+#define EIP_RX_GRANULARITY            (1)
-+
-+#define EIP_IP_ALIGN(X)                       (((X) + (15)) & ~(15))
-+#define EIP_EXTRA                     roundup (sizeof(EIP_RMD), 256)
-+#define EIP_RCV_DMA_LEN(s)                    (s - EIP_EXTRA - EIP_HEADER_PAD)
-+#define EIP_MTU_MAX                   (EIP_RCV_DMA_LEN(EIP_SVC_BIGGEST_LEN) - (ETH_HLEN))
-+
-+#define SIZE_TO_SVC(s, svc)                                                                   \
-+      do {                                                                                    \
-+                                      if (s <= EIP_RCV_DMA_LEN((1 << 9)))  {svc = 0;break;}   \
-+                                      if (s <= EIP_RCV_DMA_LEN((1 << 10))) {svc = 1;break;}   \
-+                                      if (s <= EIP_RCV_DMA_LEN((1 << 11))) {svc = 2;break;}   \
-+                                      if (s <= EIP_RCV_DMA_LEN((1 << 12))) {svc = 3;break;}   \
-+                                      if (s <= EIP_RCV_DMA_LEN((1 << 13))) {svc = 4;break;}   \
-+                                      if (s <= EIP_RCV_DMA_LEN((1 << 14))) {svc = 5;break;}   \
-+                                      if (s <= EIP_RCV_DMA_LEN((1 << 15))) {svc = 6;break;}   \
-+                                      if (s <= EIP_RCV_DMA_LEN((1 << 16))) {svc = 7;break;}   \
-+                                      svc = -666;                                             \
-+                                      EIP_ASSERT(1 == 0);                                     \
-+      } while (0)
-+
-+extern int eipdebug;
-+#define EIP_ASSERT_ON 
-+/* #define NO_DEBUG */
-+
-+
-+/* ######################## */
-+#ifdef NO_DEBUG
-+#define __EIP_DBG_PRINTF(fmt, args...)
-+#define EIP_DBG_PRINTF(flag, fmt, args...)
-+#else
-+
-+#define EIP_DBG_RMD           0x1
-+#define EIP_DBG_TMD           0x2
-+#define EIP_DBG_RMD_HEAD      0x4
-+#define EIP_DBG_TMD_HEAD      0x8
-+#define EIP_DBG_EIPH          0x10
-+#define EIP_DBG_IPH           0x20
-+#define EIP_DBG_RMD_EP_DVMA   0x40
-+#define EIP_DBG_TMD_EP_DVMA   0x80
-+#define EIP_DBG_EP_DVMA               (EIP_DBG_RMD_EP_DVMA|EIP_DBG_TMD_EP_DVMA)
-+#define EIP_DBG_MEMALLOC      0x100
-+#define EIP_DBG_MEMFREE               0x200
-+#define EIP_DBG_RMD_QUEUE     0x400
-+#define EIP_DBG_TMD_QUEUE     0x800
-+#define EIP_DBG_GEN           0x1000
-+#define EIP_DBG_DEBUG         0x2000
-+      
-+#define __EIP_DBG_PRINTF(fmt, args...)        (qsnet_debugf (QSNET_DEBUG_BUFFER, " CPU #%d %s: " fmt, smp_processor_id(), __func__, ## args))
-+#define EIP_DBG_PRINTF(flag, fmt, args...) (unlikely(eipdebug & flag) ? __EIP_DBG_PRINTF(fmt, ## args):(void)0)
-+
-+#define __EIP_DBG_PRINTK(fmt, args...)        (qsnet_debugf (QSNET_DEBUG_BUF_CON, " CPU #%d %s: " fmt, smp_processor_id(), __func__, ## args))
-+#define EIP_DBG_PRINTK(flag, fmt, args...) (unlikely(eipdebug & flag) ? __EIP_DBG_PRINTF(fmt, ## args):(void)0)
-+          
-+#define EIP_ERR_PRINTF(fmt, args...)  __EIP_DBG_PRINTK("!!! ERROR !!! - " fmt, ## args)
-+
-+      
-+#define EIP_DBG2(flag, fn, fn_arg, fmt, args...)                                                              \
-+    if (unlikely(eipdebug & flag)) {                                                                          \
-+          qsnet_debugf (QSNET_DEBUG_BUFFER, "+CPU #%d %s: " fmt, smp_processor_id(), __func__, ##args);       \
-+            (void)(fn)(fn_arg);                                                                               \
-+          qsnet_debugf (QSNET_DEBUG_BUFFER, "-CPU #%d %s: " fmt, smp_processor_id(), __func__, ##args);       \
-+    }
-+
-+
-+#define EIP_DBG(flag, fn, args...)                                                            \
-+    if (unlikely(eipdebug & flag)) {                                                          \
-+          qsnet_debugf (QSNET_DEBUG_BUFFER, "+CPU #%d %s\n", smp_processor_id(), __func__);   \
-+            (void)(fn)(args);                                                                 \
-+          qsnet_debugf (QSNET_DEBUG_BUFFER, "-CPU #%d %s :\n", smp_processor_id(), __func__); \
-+    }
-+#endif /* NO_DEBUG */
-+
-+
-+#ifdef EIP_ASSERT_ON
-+
-+#define __EIP_ASSERT_PRINT(exp)                               \
-+              eipdebug = 0xffff;                              \
-+              EIP_ERR_PRINTF("ASSERT : %s, %s::%d\n",         \
-+                     #exp, __BASE_FILE__, __LINE__);          
-+
-+#define EIP_ASSERT(exp)                                                       \
-+              if (!(exp)) {                                           \
-+                      __EIP_ASSERT_PRINT(exp);                        \
-+                      netif_stop_queue(eip_tx->net_device);           \
-+              }
-+
-+#define EIP_ASSERT2(exp, f, arg)                                      \
-+      do {                                                            \
-+              if (!(exp)) {                                           \
-+                      __EIP_ASSERT_PRINT(exp);                        \
-+                      f(arg);                                         \
-+              }                                                       \
-+      } while (0)
-+
-+#define EIP_ASSERT_BUG(exp)                                           \
-+      do {                                                            \
-+              if (!(exp)) {                                           \
-+                      __EIP_ASSERT_PRINT(exp);                        \
-+                      BUG();                                          \
-+              }                                                       \
-+      } while (0)
-+
-+#define EIP_ASSERT_GOTO(exp, label, f, arg)                           \
-+      do {                                                            \
-+              if (!(exp)) {                                           \
-+                      __EIP_ASSERT_PRINT(exp);                        \
-+                      f(arg);                                         \
-+                      goto label;                                     \
-+              }                                                       \
-+      } while (0)
-+
-+#define EIP_ASSERT_RET(exp, ret)                                      \
-+      do {                                                            \
-+              if (!(exp)) {                                           \
-+                      __EIP_ASSERT_PRINT(exp);                        \
-+                      return ret;                                     \
-+              }                                                       \
-+      } while (0)
-+
-+#define EIP_ASSERT_RETURN(exp, f, arg)                                        \
-+      do {                                                            \
-+              if (!(exp)) {                                           \
-+                      __EIP_ASSERT_PRINT(exp);                        \
-+                      f(arg);                                         \
-+                      return;                                         \
-+              }                                                       \
-+      } while (0)
-+
-+#define EIP_ASSERT_RETNULL(exp, f, arg)                                       \
-+      do {                                                            \
-+              if (!(exp)) {                                           \
-+                      __EIP_ASSERT_PRINT(exp);                        \
-+                      f(arg);                                         \
-+                      return NULL;                                    \
-+              }                                                       \
-+      } while (0)
-+
-+#else
-+
-+#define EIP_ASSERT(exp)               do {} while(0)
-+#define EIP_ASSERT_OUT(exp)           do {} while(0)
-+#define EIP_ASSERT_RETURN(exp)                do {} while(0)
-+#define EIP_ASSERT_RETNULL(exp)               do {} while(0)
-+#define EIP_ASSERT_BUG(exp)           do {} while(0)
-+
-+#endif /* EIP_ASSERT */
-+
-+
-+
-+typedef struct {
-+      u_short ip_bcast;
-+      u_short ip_inst;
-+      u_short ip_addr;
-+} EIP_ADDRESS;
-+
-+typedef struct {
-+      EIP_ADDRESS h_dhost;
-+      EIP_ADDRESS h_shost;
-+      u_short h_sap;
-+} EIP_HEADER;
-+#define EIP_HEADER_PAD                        (2)
-+
-+typedef struct eip_proc_fs {
-+      const char *name;
-+      struct proc_dir_entry **parent;
-+      read_proc_t *read;
-+      write_proc_t *write;
-+      unsigned char allocated;
-+      struct proc_dir_entry *entry;
-+} EIP_PROC_FS;
-+
-+#define EIP_PROC_ROOT_DIR             "eip"
-+
-+#define EIP_PROC_DEBUG_DIR            "debug"
-+#define EIP_PROC_DEBUG_RX_FLUSH               "rx_flush"
-+#define EIP_PROC_DEBUG_TX_FLUSH               "tx_flush"
-+
-+#define EIP_PROC_AGGREG_DIR           "aggregation"
-+#define EIP_PROC_AGGREG_ONOFF         "enable"
-+#define EIP_PROC_AGGREG_TO            "timeout"
-+#define EIP_PROC_AGGREG_COPYBREAK     "copybreak"
-+
-+#define EIP_PROC_TX_COPYBREAK         "tx_copybreak"
-+#define EIP_PROC_STATS                        "stats"
-+#define EIP_PROC_RX_GRAN              "rx_granularity"
-+#define EIP_PROC_TX_RAILMASK          "tx_railmask"
-+#define EIP_PROC_TMD_INUSE            "tmd_inuse"
-+#define EIP_PROC_EIPDEBUG             "eipdebug"
-+#define EIP_PROC_CHECKSUM               "checksum"
-+
-+/* RX */
-+/* dma_len is used to keep the len of a received packet */
-+/* nmd.nmd_len is the max dma that can be received      */
-+/*                                                      */
-+struct eip_rmd {
-+      struct sk_buff *skb;
-+
-+      EP_NMD nmd;
-+      u16 dvma_idx;
-+
-+      EP_RXD *rxd;
-+      struct eip_rmd_head *head;
-+      union {
-+              struct list_head link;                          /* when on "busy" list */
-+              struct eip_rmd  *next;                          /* all other lists */
-+      } chain;
-+};
-+typedef struct eip_rmd EIP_RMD;
-+struct eip_rmd_head {
-+      EP_NMH *handle;
-+
-+      EP_RCVR *rcvr;
-+      EIP_RMD *busy_list;
-+
-+      /* stats */
-+      atomic_t stats;
-+      unsigned long dma;
-+};
-+
-+typedef struct eip_rmd_head EIP_RMD_HEAD;
-+typedef struct eip_rx {
-+      struct eip_rmd_head head[EIP_SVC_NR];
-+
-+      EIP_RMD *irq_list;
-+      short    irq_list_nr;   
-+
-+      /* stats */
-+      unsigned long packets;
-+      unsigned long bytes;
-+      unsigned long errors;
-+      unsigned long dropped;
-+      unsigned long reschedule;
-+
-+      spinlock_t lock;
-+      struct tasklet_struct tasklet;
-+      unsigned char rmd_max_nr;
-+      unsigned char sysctl_granularity;
-+      struct net_device *net_device;
-+} EIP_RX;
-+
-+/* TX */
-+/* dma_len_max is the maximum len for a given DMA                      */
-+/* where mnd.nmd_len is the len of the packet to send ~> than skb->len */
-+typedef struct eip_ipfrag_handle {
-+      /* common with tmd */
-+      unsigned long dma_base;
-+      int dma_len;
-+      EP_NMD nmd;
-+      u16 dvma_idx;
-+
-+      struct sk_buff *skb;
-+      struct eip_tmd_head *head;
-+      union {
-+              struct list_head link;                          /* when on "busy" list */
-+              struct eip_tmd  *next;                          /* all other lists */
-+      } chain;
-+
-+      /* private */
-+      struct list_head list;
-+      struct timeval timestamp;
-+      unsigned int frag_nr;
-+      int datagram_len; /* Ip data */
-+      int dma_correction;
-+      EP_PAYLOAD payload;
-+} EIP_IPFRAG;
-+
-+struct eip_tmd {
-+      unsigned long dma_base;
-+      int dma_len;
-+      EP_NMD nmd;
-+      u16 dvma_idx;
-+
-+      struct sk_buff *skb;
-+      struct eip_tmd_head *head;
-+      union {
-+              struct list_head link;                          /* when on "busy" list */
-+              struct eip_tmd  *next;                          /* all other lists */
-+      } chain;
-+};
-+
-+struct eip_tmd_head {
-+      EP_NMH *handle;
-+
-+      struct eip_tmd *tmd;
-+      atomic_t stats;
-+};
-+
-+typedef struct eip_tmd EIP_TMD;
-+typedef struct eip_tmd_head EIP_TMD_HEAD;
-+
-+/* #define EIP_MORE_STATS */
-+
-+typedef struct eip_tx {
-+      struct net_device *net_device;
-+      EP_XMTR *xmtr;
-+      EP_SYS *ep_system;
-+
-+      struct eip_tmd_head head[EIP_TMD_TYPE_NR];
-+      struct list_head inuse;
-+      atomic_t destructor;
-+
-+      /* stats */
-+      unsigned long packets;
-+      unsigned long bytes;
-+      unsigned long errors;
-+      unsigned long dropped;
-+      unsigned long dma[EIP_SVC_NR];
-+      
-+#ifdef EIP_MORE_STATS
-+      unsigned long sent_copybreak;
-+      unsigned long sent_std;
-+      unsigned long sent_aggreg;
-+#endif
-+
-+      unsigned char tmd_max_nr;
-+
-+      unsigned short sysctl_copybreak;
-+      unsigned short sysctl_ipfrag_to;
-+      unsigned short sysctl_ipfrag_copybreak;
-+      unsigned short sysctl_aggregation;
-+
-+      unsigned short ipfrag_count;
-+      struct list_head ipfrag;
-+      spinlock_t ipfraglock;
-+
-+      spinlock_t lock;
-+      struct tasklet_struct tasklet;
-+} EIP_TX;
-+
-+/* =============================================== */
-+    /* unsigned long   multicast; */
-+#endif                                /* __EIP_LINUX_H */
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/eip/eip_stats.c linux-2.6.9/drivers/net/qsnet/eip/eip_stats.c
---- clean/drivers/net/qsnet/eip/eip_stats.c    1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/eip/eip_stats.c      2005-09-07 10:34:58.000000000 -0400
-@@ -0,0 +1,374 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+/*
-+ * $Id: eip_stats.c,v 1.36.2.2 2005/09/07 14:34:58 mike Exp $
-+ * $Source: /cvs/master/quadrics/eipmod/eip_stats.c,v $
-+ */
-+
-+#include <qsnet/kernel.h>
-+#include <qsnet/module.h>
-+#include <elan/epcomms.h>
-+
-+#include <linux/netdevice.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/proc_fs.h>
-+
-+#include <asm/atomic.h>
-+
-+#include <qsnet/procfs_linux.h>
-+
-+#include "eip_linux.h"
-+#include "eip_stats.h"
-+
-+extern EIP_RX *eip_rx;
-+extern EIP_TX *eip_tx;
-+extern int tx_copybreak_max;
-+extern EP_RAILMASK tx_railmask;
-+extern int  eip_checksum_state;
-+extern void eip_stop_queue(void);
-+extern void eip_start_queue(void);
-+
-+static int eip_stats_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
-+{
-+      int i, outlen = 0;
-+
-+      *buf = '\0';
-+      strcat(buf, "\n");
-+      strcat(buf, "--------------------------------------------+------------+-----------------+\n");
-+      strcat(buf, "    SKB/DMA    |               | Rx         | Tx         |  TMD TYPE       |\n");
-+      strcat(buf, "--------------------------------------------+------------|-----------------+\n");
-+
-+      i = 0;
-+      sprintf(buf + strlen(buf), " [%5d/%5d] | [%3.3d/%3.3d/%3.3d] | %10ld | %10ld | #1[%3.3d/%3.3d/%3.3d] |\n",
-+              EIP_SVC_SMALLEST_LEN << i, (int) EIP_RCV_DMA_LEN((EIP_SVC_SMALLEST_LEN << i)),
-+              EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats),
-+              eip_rx->rmd_max_nr, eip_rx->head[i].dma, eip_tx->dma[i],
-+              EIP_STAT_QUEUED_GET(&eip_tx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_tx->head[i].stats),
-+               eip_tx->tmd_max_nr);
-+
-+      i++;
-+      sprintf(buf + strlen(buf), " [%5d/%5d] | [%3.3d/%3.3d/%3.3d] | %10ld | %10ld | #2[%3.3d/%3.3d/%3.3d] |\n",
-+              EIP_SVC_SMALLEST_LEN << i, (int) EIP_RCV_DMA_LEN((EIP_SVC_SMALLEST_LEN << i)),
-+              EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats),
-+              eip_rx->rmd_max_nr, eip_rx->head[i].dma, eip_tx->dma[i],
-+              EIP_STAT_QUEUED_GET(&eip_tx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_tx->head[i].stats),
-+              eip_tx->tmd_max_nr);
-+
-+      i++;
-+      sprintf(buf + strlen(buf), " [%5d/%5d] | [%3.3d/%3.3d/%3.3d] | %10ld | %10ld | #3[%3.3d/%3.3d/%3.3d] |\n",
-+              EIP_SVC_SMALLEST_LEN << i, (int) EIP_RCV_DMA_LEN((EIP_SVC_SMALLEST_LEN << i)),
-+              EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats),
-+              eip_rx->rmd_max_nr, eip_rx->head[i].dma, eip_tx->dma[i],
-+              EIP_STAT_QUEUED_GET(&eip_tx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_tx->head[i].stats),
-+              eip_tx->tmd_max_nr);
-+
-+      i++;
-+      sprintf(buf + strlen(buf), " [%5d/%5d] | [%3.3d/%3.3d/%3.3d] | %10ld | %10ld +-----------------+\n",
-+              EIP_SVC_SMALLEST_LEN << i, (int) EIP_RCV_DMA_LEN((EIP_SVC_SMALLEST_LEN << i)),
-+              EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats),
-+              eip_rx->rmd_max_nr, eip_rx->head[i].dma, eip_tx->dma[i]);
-+
-+      i++;
-+      sprintf(buf + strlen(buf), " [%5d/%5d] | [%3.3d/%3.3d/%3.3d] | %10ld | %10ld |\n",
-+              EIP_SVC_SMALLEST_LEN << i, (int) EIP_RCV_DMA_LEN((EIP_SVC_SMALLEST_LEN << i)),
-+              EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats),
-+              eip_rx->rmd_max_nr, eip_rx->head[i].dma, eip_tx->dma[i]);
-+
-+      i++;
-+      sprintf(buf + strlen(buf), " [%5d/%5d] | [%3.3d/%3.3d/%3.3d] | %10ld | %10ld |\n",
-+              EIP_SVC_SMALLEST_LEN << i, (int) EIP_RCV_DMA_LEN((EIP_SVC_SMALLEST_LEN << i)),
-+              EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats),
-+              eip_rx->rmd_max_nr, eip_rx->head[i].dma, eip_tx->dma[i]);
-+
-+      i++;
-+      sprintf(buf + strlen(buf), " [%5d/%5d] | [%3.3d/%3.3d/%3.3d] | %10ld | %10ld |\n",
-+              EIP_SVC_SMALLEST_LEN << i, (int) EIP_RCV_DMA_LEN((EIP_SVC_SMALLEST_LEN << i)),
-+              EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats),
-+              eip_rx->rmd_max_nr, eip_rx->head[i].dma, eip_tx->dma[i]);
-+
-+      i++;
-+      sprintf(buf + strlen(buf), " [%5d/%5d] | [%3.3d/%3.3d/%3.3d] | %10ld | %10ld |\n",
-+              EIP_SVC_SMALLEST_LEN << i, (int) EIP_RCV_DMA_LEN((EIP_SVC_SMALLEST_LEN << i)),
-+              EIP_STAT_QUEUED_GET(&eip_rx->head[i].stats), EIP_STAT_ALLOC_GET(&eip_rx->head[i].stats),
-+              eip_rx->rmd_max_nr, eip_rx->head[i].dma, eip_tx->dma[i]);
-+
-+      strcat(buf, "--------------------------------------------+------------+\n");
-+      sprintf(buf + strlen(buf), " RMD IRQ %4.4d                    %10lu | %10lu |\n",
-+              eip_rx->irq_list_nr, 
-+              eip_rx->packets, eip_tx->packets);
-+      strcat(buf, "--------------------------------------------+------------+\n");
-+
-+#ifdef EIP_MORE_STATS
-+      strcat(buf, "\n");
-+      sprintf(buf + strlen(buf), " Copybreak %10ld Std %10ld Aggreg %10ld\n",
-+                      eip_tx->sent_copybreak, eip_tx->sent_std, eip_tx->sent_aggreg);
-+#endif
-+
-+
-+      strcat(buf, "\n");
-+      sprintf(buf + strlen(buf), "Rx bytes: %lu (%lu Mb) errors: %lu dropped: %lu reschedule: %lu\n",
-+              eip_rx->bytes, eip_rx->bytes / (1024 * 1024), eip_rx->errors, eip_rx->dropped, eip_rx->reschedule);
-+      sprintf(buf + strlen(buf), "Tx bytes: %lu (%lu Mb) errors: %lu dropped: %lu\n",
-+              eip_tx->bytes, eip_tx->bytes / (1024 * 1024), eip_tx->errors, eip_tx->dropped);
-+      strcat(buf, "\n");
-+
-+      outlen = strlen(buf);
-+      ASSERT(outlen < PAGE_SIZE);
-+      *eof = 1;
-+      return outlen;
-+}
-+
-+void eip_stats_dump(void)
-+{
-+    int eof;
-+
-+    char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-+
-+    if (buf == NULL)
-+    {
-+      printk("no memory to produce eip_stats\n");
-+      return;
-+    }
-+
-+    eip_stats_read(buf, NULL, 0, 0, &eof, NULL);
-+
-+    printk(buf);
-+
-+    kfree(buf);
-+}
-+
-+static int eip_stats_write(struct file *file, const char *buf, unsigned long count, void *data)
-+{
-+      int i;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&eip_rx->lock, flags);
-+      eip_rx->packets = 0;
-+      eip_rx->bytes = 0;
-+      eip_rx->errors = 0;
-+      eip_rx->dropped = 0;
-+      eip_rx->reschedule = 0;
-+      for (i = 0; i < EIP_SVC_NR; eip_rx->head[i].dma = 0, i++);
-+      spin_unlock_irqrestore(&eip_rx->lock, flags);
-+
-+      spin_lock_irqsave(&eip_tx->lock, flags);
-+      eip_tx->packets = 0;
-+      eip_tx->bytes = 0;
-+      eip_tx->errors = 0;
-+      eip_tx->dropped = 0;
-+#ifdef EIP_MORE_STATS
-+      eip_tx->sent_copybreak = 0;
-+      eip_tx->sent_std = 0;
-+      eip_tx->sent_aggreg = 0;
-+#endif
-+      for (i = 0; i < EIP_SVC_NR; eip_tx->dma[i] = 0, i++);
-+      spin_unlock_irqrestore(&eip_tx->lock, flags);
-+
-+      return count;
-+}
-+
-+#define               eip_stats_var_write(name)                                                                       \
-+static int eip_stats_##name##_write(struct file *file, const char *buf, unsigned long count, void *data)      \
-+{                                                                                                             \
-+      char * b = (char *) buf;                                                                                \
-+      *(b + count) = '\0';                                                                                    \
-+      eip_##name##_set((int) simple_strtoul(b, NULL, 10));                                                    \
-+      return count;                                                                                           \
-+}
-+
-+#define       eip_stats_var_read(name, var)                                                                   \
-+static int eip_stats_##name##_read(char *buf, char **start, off_t off, int count, int *eof, void *data)               \
-+{                                                                                                             \
-+      sprintf(buf, "%d\n", var);                                                                              \
-+      *eof = 1;                                                                                               \
-+      return strlen(buf);                                                                                     \
-+}
-+
-+
-+#define               eip_stats_var_set(name, min, max, default, var)                                                                 \
-+void eip_##name##_set(int i)                                                                                                  \
-+{                                                                                                                             \
-+      if ( (i >= min) && (i <= max)) {                                                                                        \
-+              EIP_DBG_PRINTK(EIP_DBG_GEN, "Setting " #name " to %d\n", i);                                                    \
-+              var =(unsigned short) i;                                                                                        \
-+      }                                                                                                                       \
-+      else {                                                                                                                  \
-+              EIP_ERR_PRINTF("parameter error : %d <= " #name "(%d) <= %d using default %d\n", min, i, (int) max, (int) default);     \
-+      }                                                                                                                       \
-+}
-+
-+eip_stats_var_set(tx_copybreak, 0, tx_copybreak_max, EIP_TX_COPYBREAK, eip_tx->sysctl_copybreak);
-+eip_stats_var_set(rx_granularity, 1, EIP_RMD_MIN_NR, EIP_RX_GRANULARITY, eip_rx->sysctl_granularity);
-+eip_stats_var_set(tx_railmask, 0, EP_RAILMASK_ALL, EP_RAILMASK_ALL, tx_railmask);
-+eip_stats_var_set(ipfrag_to, 0, (1 << 16), EIP_IPFRAG_TO, eip_tx->sysctl_ipfrag_to);
-+eip_stats_var_set(aggregation, 0, 1, 1, eip_tx->sysctl_aggregation);
-+eip_stats_var_set(ipfrag_copybreak, 0, EIP_IPFRAG_COPYBREAK, EIP_IPFRAG_COPYBREAK, eip_tx->sysctl_ipfrag_copybreak);
-+/* eip_stats_var_set(eipdebug, 0, , 0, eipdebug); */
-+
-+eip_stats_var_read(aggregation, eip_tx->sysctl_aggregation);
-+eip_stats_var_read(ipfrag_count, eip_tx->ipfrag_count);
-+eip_stats_var_read(ipfrag_to, eip_tx->sysctl_ipfrag_to);
-+eip_stats_var_read(ipfrag_copybreak, eip_tx->sysctl_ipfrag_copybreak);
-+eip_stats_var_read(tx_copybreak, eip_tx->sysctl_copybreak);
-+eip_stats_var_read(rx_granularity, eip_rx->sysctl_granularity);
-+eip_stats_var_read(tx_railmask, tx_railmask);
-+
-+eip_stats_var_write(aggregation);
-+eip_stats_var_write(ipfrag_to);
-+eip_stats_var_write(ipfrag_copybreak);
-+eip_stats_var_write(tx_copybreak);
-+eip_stats_var_write(rx_granularity);
-+eip_stats_var_write(tx_railmask);
-+
-+
-+static int eip_checksum_write(struct file *file, const char *buf, unsigned long count, void *data)
-+{
-+      char * b = (char *) buf;
-+      int    value;
-+
-+      *(b + count) = '\0';
-+
-+      value = (int) simple_strtoul(b, NULL, 10);
-+      if  ((value >= CHECKSUM_NONE) && (value <= CHECKSUM_UNNECESSARY)) 
-+              eip_checksum_state = value;
-+      else 
-+              EIP_ERR_PRINTF("%d <= checksum(%d) <= %d using old value %d\n", CHECKSUM_NONE, value, CHECKSUM_UNNECESSARY, eip_checksum_state);
-+
-+      return count;
-+}
-+
-+static int eip_checksum_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
-+{
-+      switch ( eip_checksum_state ) 
-+      {
-+      case 0  : sprintf(buf, "0 CHECKSUM_NONE\n");                      break;
-+      case 1  : sprintf(buf, "1 CHECKSUM_HW\n");                        break;
-+      case 2  : sprintf(buf, "2 CHECKSUM_UNNECESSARY\n");               break;
-+      default : sprintf(buf, "%d INVALID VALUE\n", eip_checksum_state); break;
-+      }
-+      *eof = 1;
-+      return strlen(buf);
-+}
-+
-+static int eip_stats_eipdebug_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
-+{
-+      *buf = '\0';
-+      sprintf(buf + strlen(buf), "0x%x\n", eipdebug);
-+      *eof = 1;
-+      return strlen(buf);
-+}
-+static int eip_stats_eipdebug_write(struct file *file, const char *buf, unsigned long count, void *data)
-+{
-+      char * p = (char *) buf;
-+      *(p + count - 1) = '\0';
-+      eipdebug = simple_strtoul(p, NULL, 0);
-+      __EIP_DBG_PRINTK("Setting eipdebug to 0x%x\n", eipdebug);
-+      return count;
-+}
-+
-+static int eip_stats_tmd_inuse_read(char *page, char **start, off_t off, int count, int *eof, void *data)
-+{
-+      struct list_head *lp;
-+      unsigned long flags;
-+      unsigned int len = 0;
-+
-+      spin_lock_irqsave(&eip_tx->lock, flags);
-+      list_for_each (lp, &eip_tx->inuse) {
-+              EIP_TMD *tmd = list_entry (lp, EIP_TMD, chain.link);
-+              EIP_HEADER *eiph = (EIP_HEADER *) tmd->dma_base;
-+              
-+                len += sprintf(page+len, "tmd=%p id=%d len=%d\n",
-+                             tmd, eiph ? ntohs(eiph->h_dhost.ip_addr) : -1,
-+                             tmd->dma_len);
-+
-+                if (len + 40 >= count)
-+                        break;
-+        }
-+        spin_unlock_irqrestore(&eip_tx->lock, flags);
-+
-+      return qsnet_proc_calc_metrics (page, start, off, count, eof, len);
-+}
-+
-+static int eip_stats_debug_rx_flush(struct file *file, const char *buf, unsigned long count, void *data)
-+{
-+      EIP_DBG_PRINTF(EIP_DBG_GEN, "Flushing rx ...\n");
-+      tasklet_schedule(&eip_rx->tasklet);
-+      return count;
-+}
-+static int eip_stats_debug_tx_flush(struct file *file, const char *buf, unsigned long count, void *data)
-+{
-+      EIP_DBG_PRINTF(EIP_DBG_GEN, "Flushing tx ... %d tmds reclaimed\n", ep_enable_txcallbacks(eip_tx->xmtr));
-+      ep_disable_txcallbacks(eip_tx->xmtr);
-+      tasklet_schedule(&eip_tx->tasklet);
-+      return count;
-+}
-+
-+#define EIP_PROC_PARENT_NR    (3)
-+/* NOTE : the parents should be declared b4 the children */
-+static EIP_PROC_FS eip_procs[] = {
-+      /* {name, parent, read fn, write fn, allocated, entry}, */
-+      {EIP_PROC_ROOT_DIR, &qsnet_procfs_root, NULL, NULL, 0, NULL},
-+      {EIP_PROC_DEBUG_DIR, &eip_procs[0].entry, NULL, NULL, 0, NULL},
-+      {EIP_PROC_AGGREG_DIR, &eip_procs[0].entry, NULL, NULL, 0, NULL},        /* end of parents */
-+      {EIP_PROC_STATS, &eip_procs[0].entry, eip_stats_read, eip_stats_write, 0, NULL},
-+      {EIP_PROC_TX_COPYBREAK, &eip_procs[0].entry, eip_stats_tx_copybreak_read, eip_stats_tx_copybreak_write, 0, NULL},
-+      {EIP_PROC_RX_GRAN, &eip_procs[0].entry, eip_stats_rx_granularity_read, eip_stats_rx_granularity_write, 0, NULL},
-+      {EIP_PROC_TX_RAILMASK, &eip_procs[0].entry, eip_stats_tx_railmask_read, eip_stats_tx_railmask_write, 0, NULL},
-+      {EIP_PROC_TMD_INUSE, &eip_procs[0].entry, eip_stats_tmd_inuse_read, NULL, 0, NULL},
-+      {EIP_PROC_EIPDEBUG, &eip_procs[0].entry, eip_stats_eipdebug_read, eip_stats_eipdebug_write, 0, NULL},
-+      {EIP_PROC_CHECKSUM, &eip_procs[0].entry, eip_checksum_read, eip_checksum_write, 0, NULL},
-+      {EIP_PROC_DEBUG_RX_FLUSH, &eip_procs[1].entry, NULL, eip_stats_debug_rx_flush, 0, NULL},
-+      {EIP_PROC_DEBUG_TX_FLUSH, &eip_procs[1].entry, NULL, eip_stats_debug_tx_flush, 0, NULL},
-+      {"ipfrag_count", &eip_procs[2].entry, eip_stats_ipfrag_count_read, NULL, 0, NULL},
-+      {EIP_PROC_AGGREG_TO, &eip_procs[2].entry, eip_stats_ipfrag_to_read, eip_stats_ipfrag_to_write, 0, NULL},
-+      {EIP_PROC_AGGREG_ONOFF, &eip_procs[2].entry, eip_stats_aggregation_read, eip_stats_aggregation_write, 0, NULL},
-+      {EIP_PROC_AGGREG_COPYBREAK, &eip_procs[2].entry, eip_stats_ipfrag_copybreak_read, eip_stats_ipfrag_copybreak_write, 0, NULL},
-+      {NULL, NULL, NULL, NULL, 1, NULL},
-+};
-+
-+int eip_stats_init(void)
-+{
-+      int p;
-+
-+      for (p = 0; !eip_procs[p].allocated; p++) {
-+              if (p < EIP_PROC_PARENT_NR)
-+                      eip_procs[p].entry = proc_mkdir(eip_procs[p].name, *eip_procs[p].parent);
-+              else
-+                      eip_procs[p].entry = create_proc_entry(eip_procs[p].name, 0, *eip_procs[p].parent);
-+
-+              if (!eip_procs[p].entry) {
-+                      EIP_ERR_PRINTF("%s\n", "Cannot allocate proc entry");
-+                      eip_stats_cleanup();
-+                      return -ENOMEM;
-+              }
-+
-+              eip_procs[p].entry->owner = THIS_MODULE;
-+              eip_procs[p].entry->write_proc = eip_procs[p].write;
-+              eip_procs[p].entry->read_proc = eip_procs[p].read;
-+              eip_procs[p].allocated = 1;
-+      }
-+      eip_procs[p].allocated = 0;
-+      return 0;
-+}
-+
-+void eip_stats_cleanup(void)
-+{
-+      int p;
-+      for (p = (sizeof (eip_procs)/sizeof (eip_procs[0]))-1; p >= 0; p--)
-+              if (eip_procs[p].allocated) {
-+                      EIP_DBG_PRINTF(EIP_DBG_GEN, "Removing %s from proc\n", eip_procs[p].name);
-+                      remove_proc_entry(eip_procs[p].name, *eip_procs[p].parent);
-+              }
-+}
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/eip/eip_stats.h linux-2.6.9/drivers/net/qsnet/eip/eip_stats.h
---- clean/drivers/net/qsnet/eip/eip_stats.h    1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/eip/eip_stats.h      2004-05-10 10:47:47.000000000 -0400
-@@ -0,0 +1,22 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "$Id: eip_stats.h,v 1.14 2004/05/10 14:47:47 daniel Exp $"
-+
-+#ifndef __EIP_STATS_H
-+#define       __EIP_STATS_H
-+
-+int eip_stats_init(void);
-+void eip_stats_cleanup(void);
-+void eip_rx_granularity_set(int);
-+void eip_tx_copybreak_set(int);
-+void eip_ipfrag_to_set(int);
-+void eip_aggregation_set(int);
-+void eip_ipfrag_copybreak_set(int);
-+void eip_stats_dump(void);
-+
-+#endif                                /* __EIP_STATS_H */
-diff -urN clean/drivers/net/qsnet/eip/Makefile linux-2.6.9/drivers/net/qsnet/eip/Makefile
---- clean/drivers/net/qsnet/eip/Makefile       1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/eip/Makefile 2005-10-10 17:47:30.000000000 -0400
-@@ -0,0 +1,15 @@
-+#
-+# Makefile for Quadrics QsNet
-+#
-+# Copyright (c) 2002-2004 Quadrics Ltd
-+#
-+# File: drivers/net/qsnet/eip/Makefile
-+#
-+
-+
-+#
-+
-+obj-$(CONFIG_EIP)     += eip.o
-+eip-objs      := eip_linux.o eip_stats.o
-+
-+EXTRA_CFLAGS          +=  -DDEBUG -DDEBUG_PRINTF -DDEBUG_ASSERT
-diff -urN clean/drivers/net/qsnet/eip/Makefile.conf linux-2.6.9/drivers/net/qsnet/eip/Makefile.conf
---- clean/drivers/net/qsnet/eip/Makefile.conf  1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/eip/Makefile.conf    2005-09-07 10:39:48.000000000 -0400
-@@ -0,0 +1,10 @@
-+# Flags for generating QsNet Linux Kernel Makefiles
-+MODNAME               =       eip.o
-+MODULENAME    =       eip
-+KOBJFILES     =       eip_linux.o eip_stats.o
-+EXPORT_KOBJS  =       
-+CONFIG_NAME   =       CONFIG_EIP
-+SGALFC                =       
-+# EXTRALINES START
-+
-+# EXTRALINES END
-diff -urN clean/drivers/net/qsnet/eip/quadrics_version.h linux-2.6.9/drivers/net/qsnet/eip/quadrics_version.h
---- clean/drivers/net/qsnet/eip/quadrics_version.h     1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/eip/quadrics_version.h       2005-09-07 10:39:49.000000000 -0400
-@@ -0,0 +1 @@
-+#define QUADRICS_VERSION "5.11.3qsnet"
-diff -urN clean/drivers/net/qsnet/elan/bitmap.c linux-2.6.9/drivers/net/qsnet/elan/bitmap.c
---- clean/drivers/net/qsnet/elan/bitmap.c      1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/bitmap.c        2004-01-20 12:32:17.000000000 -0500
-@@ -0,0 +1,287 @@
-+/*
-+ *    Copyright (c) 1996-2002 by Quadrics Supercomputers World Ltd.
-+ *
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: bitmap.c,v 1.5 2004/01/20 17:32:17 david Exp $"
-+/*      $Source: /cvs/master/quadrics/elanmod/shared/bitmap.c,v $*/
-+
-+#if defined(__KERNEL__)
-+#include <qsnet/kernel.h>
-+#endif
-+#include <qsnet/config.h>
-+#include <elan/bitmap.h>
-+
-+/*
-+ * Return the index of the first available bit in the 
-+ * bitmap , or -1 for failure
-+ */
-+int
-+bt_freebit (bitmap_t *bitmap, int nbits)
-+{
-+    int last = (--nbits) >> BT_ULSHIFT;
-+    int maxbit;
-+    int       i, j;
-+
-+    /* look for a word with a bit off */
-+    for (i = 0; i <= last; i++)
-+      if (bitmap[i] != ~((bitmap_t) 0))
-+          break;
-+
-+    if (i <= last)
-+    {
-+      /* found an word with a bit off,  now see which bit it is */
-+      maxbit = (i == last) ? (nbits & BT_ULMASK) : (BT_NBIPUL-1);
-+      for (j = 0; j <= maxbit; j++)
-+          if ((bitmap[i] & (1 << j)) == 0)
-+              return ((i << BT_ULSHIFT) | j);
-+    }
-+    return (-1);
-+    
-+}
-+
-+/*
-+ * bt_lowbit:
-+ *     Return the index of the lowest set bit in the
-+ *     bitmap, or -1 for failure.
-+ */
-+int
-+bt_lowbit (bitmap_t *bitmap, int nbits)
-+{
-+    int last = (--nbits) >> BT_ULSHIFT;
-+    int maxbit;
-+    int i, j;
-+    
-+    /* look for a word with a bit on */
-+    for (i = 0; i <= last; i++)
-+      if (bitmap[i] != 0)
-+          break;
-+    if (i <= last)
-+    {
-+      /* found a word bit a bit on, now see which bit it is */
-+      maxbit = (i == last) ? (nbits & BT_ULMASK) : (BT_NBIPUL-1);
-+      for (j = 0; j <= maxbit; j++)
-+          if (bitmap[i] & (1 << j))
-+              return ((i << BT_ULSHIFT) | j);
-+    }
-+
-+    return (-1);
-+}
-+
-+/*
-+ * Return the index of the first available bit in the 
-+ * bitmap , or -1 for failure
-+ */
-+int
-+bt_nextbit (bitmap_t *bitmap, int nbits, int last, int isset)
-+{
-+    int first = ((last+1) + BT_NBIPUL-1) >> BT_ULSHIFT;
-+    int end   = (--nbits) >> BT_ULSHIFT;
-+    int maxbit;
-+    int       i, j;
-+
-+    /* look for bits before the first whole word */
-+    if (((last+1) & BT_ULMASK) != 0)
-+    {
-+      maxbit = ((first-1) == last) ? (nbits & BT_ULMASK) : (BT_NBIPUL-1);
-+      for (j = ((last+1) & BT_ULMASK); j <= maxbit; j++)
-+          if ((bitmap[first-1] & (1 << j)) == (isset << j))
-+              return (((first-1) << BT_ULSHIFT) | j);
-+    }
-+
-+    /* look for a word with a bit off */
-+    for (i = first; i <= end; i++)
-+      if (bitmap[i] != (isset ? 0 : ~((bitmap_t) 0)))
-+          break;
-+
-+    if (i <= end)
-+    {
-+      /* found an word with a bit off,  now see which bit it is */
-+      maxbit = (i == end) ? (nbits & BT_ULMASK) : (BT_NBIPUL-1);
-+      for (j = 0; j <= maxbit; j++)
-+          if ((bitmap[i] & (1 << j)) == (isset << j))
-+              return ((i << BT_ULSHIFT) | j);
-+    }
-+    return (-1);
-+}
-+
-+void
-+bt_copy (bitmap_t *a, bitmap_t *b, int nbits)
-+{
-+    int i;
-+
-+    for (i = 0; i < (nbits>>BT_ULSHIFT); i++)
-+      b[i] = a[i];
-+
-+    for (i <<= BT_ULSHIFT; i < nbits; i++)
-+      if (BT_TEST(a, i))
-+          BT_SET(b,i);
-+      else
-+          BT_CLEAR(b,i);
-+}
-+
-+void
-+bt_zero (bitmap_t *bitmap, int nbits)
-+{
-+    int i;
-+
-+    for (i = 0; i < (nbits>>BT_ULSHIFT); i++)
-+      bitmap[i] = 0;
-+
-+    for (i <<= BT_ULSHIFT; i < nbits; i++)
-+      BT_CLEAR(bitmap,i);
-+}
-+
-+void
-+bt_fill (bitmap_t *bitmap, int nbits)
-+{
-+    int i;
-+
-+    for (i = 0; i < (nbits>>BT_ULSHIFT); i++)
-+      bitmap[i] = ~((bitmap_t) 0);
-+
-+    for (i <<= BT_ULSHIFT; i < nbits; i++)
-+      BT_SET(bitmap,i);
-+}
-+
-+int
-+bt_cmp (bitmap_t *a, bitmap_t *b, int nbits)
-+{
-+    int i;
-+
-+    for (i = 0; i < (nbits>>BT_ULSHIFT); i++)
-+      if (a[i] != b[i])
-+          return (1);
-+
-+    for (i <<= BT_ULSHIFT; i < nbits; i++)
-+      if (BT_TEST (a, i) != BT_TEST(b, i))
-+          return (1);
-+    return (0);
-+}
-+
-+void
-+bt_intersect (bitmap_t *a, bitmap_t *b, int nbits)
-+{
-+    int i;
-+    
-+    for (i = 0; i < (nbits>>BT_ULSHIFT); i++)
-+      a[i] &= b[i];
-+
-+    for (i <<= BT_ULSHIFT; i < nbits; i++)
-+      if (BT_TEST (a, i) && BT_TEST (b, i))
-+          BT_SET (a, i);
-+      else
-+          BT_CLEAR (a, i);
-+}
-+
-+void
-+bt_remove (bitmap_t *a, bitmap_t *b, int nbits)
-+{
-+    int i;
-+
-+    for (i = 0; i < (nbits>>BT_ULSHIFT); i++)
-+      a[i] &= ~b[i];
-+
-+    for (i <<= BT_ULSHIFT; i < nbits; i++)
-+      if (BT_TEST (b, i))
-+          BT_CLEAR (a, i);
-+}
-+
-+void
-+bt_add (bitmap_t *a, bitmap_t *b, int nbits)
-+{
-+    int i;
-+
-+    for (i = 0; i < (nbits>>BT_ULSHIFT); i++)
-+      a[i] |= b[i];
-+
-+    for (i <<= BT_ULSHIFT; i < nbits; i++)
-+      if (BT_TEST(b, i))
-+          BT_SET (a, i);
-+}
-+
-+/*
-+ * bt_spans : partition a spans partition b
-+ *    == all bits set in 'b' are set in 'a'
-+ */
-+int
-+bt_spans (bitmap_t *a, bitmap_t *b, int nbits)
-+{
-+    int i;
-+    
-+    for (i = 0; i < nbits; i++)
-+      if (BT_TEST (b, i) && !BT_TEST (a, i))
-+          return (0);
-+    return (1);
-+}
-+
-+/*
-+ * bt_subset: copy [base,base+nbits-1] from 'a' to 'b'
-+ */
-+void
-+bt_subset (bitmap_t *a, bitmap_t *b, int base, int nbits)
-+{
-+    int i;
-+
-+    for (i = 0; i < nbits; i++)
-+    {
-+      if (BT_TEST (a, base+i))
-+          BT_SET(b,i);
-+      else
-+          BT_CLEAR (b,i);
-+    }
-+}
-+
-+void 
-+bt_up (bitmap_t *a, bitmap_t *b, bitmap_t *c, int nbits)
-+{
-+    int i;
-+    
-+    for (i = 0; i < nbits; i++)
-+    {
-+      if (!BT_TEST (a, i) && BT_TEST (b, i))
-+      {
-+          BT_SET (c, i);
-+        }
-+      else
-+      {
-+          BT_CLEAR (c, i);
-+        }
-+    }
-+}
-+
-+void 
-+bt_down (bitmap_t *a, bitmap_t *b, bitmap_t *c, int nbits)
-+{
-+    int i;
-+    
-+    for (i = 0; i < nbits; i++)
-+    {
-+      if (BT_TEST (a, i) && !BT_TEST (b, i))
-+      {
-+          BT_SET (c, i);
-+        }
-+      else
-+      {
-+          BT_CLEAR (c, i);
-+        }
-+    }
-+}
-+
-+int
-+bt_nbits (bitmap_t *a, int nbits)
-+{
-+    int i, c;
-+    for (i = 0, c = 0; i < nbits; i++)
-+      if (BT_TEST (a, i))
-+          c++;
-+    return (c);
-+}
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "stroustrup"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan/capability.c linux-2.6.9/drivers/net/qsnet/elan/capability.c
---- clean/drivers/net/qsnet/elan/capability.c  1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/capability.c    2005-07-21 06:42:36.000000000 -0400
-@@ -0,0 +1,796 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: capability.c,v 1.19.2.2 2005/07/21 10:42:36 addy Exp $"
-+/*      $Source: /cvs/master/quadrics/elanmod/modsrc/capability.c,v $ */
-+
-+
-+#include <qsnet/kernel.h>
-+#include <elan/elanmod.h>
-+
-+static LIST_HEAD(elan_cap_list); 
-+
-+typedef struct elan_vp_struct
-+{
-+      struct list_head list;
-+      ELAN_CAPABILITY  vp;
-+} ELAN_VP_NODE_STRUCT;
-+
-+/* There is an array of these structs for each process/context in the CAP 
-+ * This is then replicated for each rail. The usercopy handle stuff is 
-+ * only maintained in rail 0 though
-+ */
-+typedef struct elan_attached_struct
-+{
-+      void               *cb_args;
-+      ELAN_DESTROY_CB  cb_func;
-+      struct task_struct *handle;             /* usercopy: attached task handle */
-+      struct task_struct *owner;              /* usercopy: attached task handle owner */
-+} ELAN_ATTACHED_STRUCT;
-+
-+typedef struct elan_cap_node_struct
-+{
-+      struct list_head list;
-+      ELAN_CAP_STRUCT     node;
-+      ELAN_ATTACHED_STRUCT *attached[ELAN_MAX_RAILS];
-+      struct list_head vp_list;
-+} ELAN_CAP_NODE_STRUCT;
-+
-+
-+ELAN_CAP_NODE_STRUCT *
-+find_cap_node(ELAN_CAPABILITY *cap)
-+{
-+      struct list_head        *tmp;
-+      ELAN_CAP_NODE_STRUCT *ptr=NULL;
-+
-+      list_for_each(tmp, &elan_cap_list) {
-+              ptr = list_entry(tmp, ELAN_CAP_NODE_STRUCT , list);
-+              /* is it an exact match (key not checked) */
-+              if ( ELAN_CAP_TYPE_MATCH(&ptr->node.cap,cap) 
-+                   && ELAN_CAP_GEOM_MATCH(&ptr->node.cap,cap)) {
-+                      return ptr;
-+              }
-+      }
-+      return ptr;
-+}
-+
-+ELAN_VP_NODE_STRUCT *
-+find_vp_node( ELAN_CAP_NODE_STRUCT *cap_node,ELAN_CAPABILITY *map)
-+{
-+      struct list_head       * tmp;
-+      ELAN_VP_NODE_STRUCT * ptr = NULL;
-+
-+      list_for_each(tmp, &cap_node->vp_list) {
-+              ptr = list_entry(tmp, ELAN_VP_NODE_STRUCT , list);
-+              /* is it an exact match (key not checked) */
-+              if ( ELAN_CAP_TYPE_MATCH(&ptr->vp,map) 
-+                   && ELAN_CAP_GEOM_MATCH(&ptr->vp,map)){
-+                      return ptr;
-+              }
-+      }
-+      return ptr;
-+}
-+
-+int 
-+elan_validate_cap(ELAN_CAPABILITY *cap)
-+{
-+      char                      space[127];
-+
-+      ELAN_DEBUG1 (ELAN_DBG_VP,"elan_validate_cap %s\n",elan_capability_string(cap,space));
-+
-+      /* check versions */
-+      if (cap->cap_version != ELAN_CAP_VERSION_NUMBER)
-+      {
-+              ELAN_DEBUG2 (ELAN_DBG_VP,"elan_validate_cap: (cap->Version != ELAN_CAP_VERSION) %d %d\n", cap->cap_version, ELAN_CAP_VERSION_NUMBER);
-+              return (EINVAL);
-+      }
-+
-+      /* check its not HWTEST */
-+      if ( cap->cap_type & ELAN_CAP_TYPE_HWTEST )
-+      {
-+              ELAN_DEBUG0 (ELAN_DBG_VP,"elan_validate_cap: failed type = ELAN_CAP_TYPE_HWTEST \n");   
-+              return (EINVAL);
-+      }
-+      
-+      /* check its type */
-+      switch (cap->cap_type & ELAN_CAP_TYPE_MASK)
-+      {
-+      case ELAN_CAP_TYPE_KERNEL :     
-+              ELAN_DEBUG0 (ELAN_DBG_VP,"elan_validate_cap: failed type = ELAN_CAP_TYPE_KERNEL \n");   
-+              return (EINVAL);
-+
-+              /* check it has a valid type */
-+      case ELAN_CAP_TYPE_BLOCK:
-+      case ELAN_CAP_TYPE_CYCLIC:
-+              break;
-+
-+              /* all others are failed as well */
-+      default:
-+              ELAN_DEBUG1 (ELAN_DBG_VP,"elan_validate_cap: failed unknown type = %x \n", (cap->cap_type & ELAN_CAP_TYPE_MASK));       
-+              return (EINVAL);
-+      }
-+      
-+      if ((cap->cap_lowcontext == ELAN_CAP_UNINITIALISED) || (cap->cap_highcontext == ELAN_CAP_UNINITIALISED)
-+          || (cap->cap_lownode == ELAN_CAP_UNINITIALISED) || (cap->cap_highnode    == ELAN_CAP_UNINITIALISED))
-+      {
-+              
-+              ELAN_DEBUG4 (ELAN_DBG_VP,"elan_validate_cap: ELAN_CAP_UNINITIALISED   LowNode %d   HighNode %d   LowContext %d   highContext %d\n",
-+                           cap->cap_lownode , cap->cap_highnode,
-+                           cap->cap_lowcontext , cap->cap_highcontext);
-+              return (EINVAL);
-+      }       
-+
-+      if (cap->cap_lowcontext > cap->cap_highcontext)
-+      {
-+              ELAN_DEBUG2 (ELAN_DBG_VP,"elan_validate_cap: (cap->cap_lowcontext > cap->cap_highcontext) %d %d\n",cap->cap_lowcontext , cap->cap_highcontext);
-+              return (EINVAL);
-+      }
-+      
-+      if (cap->cap_lownode > cap->cap_highnode)
-+      {
-+              ELAN_DEBUG2 (ELAN_DBG_VP,"elan_validate_cap: (cap->cap_lownode > cap->cap_highnode) %d %d\n",cap->cap_lownode, cap->cap_highnode);
-+              return (EINVAL);
-+      }
-+
-+      if (cap->cap_mycontext != ELAN_CAP_UNINITIALISED) 
-+      {
-+              ELAN_DEBUG1 (ELAN_DBG_VP,"elan_validate_cap: failed cap->cap_mycontext is set %d  \n", cap->cap_mycontext);
-+              return (EINVAL);
-+      }
-+
-+
-+      if ((ELAN_CAP_NUM_NODES(cap) * ELAN_CAP_NUM_CONTEXTS(cap)) > ELAN_MAX_VPS)
-+      {
-+              ELAN_DEBUG6 (ELAN_DBG_VP,"elan_validate_cap: too many vps  LowNode %d   HighNode %d   LowContext %d   highContext %d,  %d >% d\n",
-+                           cap->cap_lownode , cap->cap_highnode,
-+                           cap->cap_lowcontext , cap->cap_highcontext,
-+                           (ELAN_CAP_NUM_NODES(cap) * ELAN_CAP_NUM_CONTEXTS(cap)),
-+                           ELAN_MAX_VPS);
-+              
-+              return (EINVAL);
-+      }
-+
-+      return (ESUCCESS);
-+}
-+
-+int
-+elan_validate_map(ELAN_CAPABILITY *cap, ELAN_CAPABILITY *map)
-+{
-+      ELAN_CAP_NODE_STRUCT * ptr  = NULL;
-+      ELAN_VP_NODE_STRUCT  * vptr = NULL;
-+      char space[256];
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      ELAN_DEBUG0 (ELAN_DBG_VP,"elan_validate_map \n");
-+      ELAN_DEBUG1 (ELAN_DBG_VP,"elan_validate_map cap = %s \n",elan_capability_string(cap,space));
-+      ELAN_DEBUG1 (ELAN_DBG_VP,"elan_validate_map map = %s \n",elan_capability_string(map,space));
-+
-+      /* does cap exist    */
-+      ptr = find_cap_node(cap);
-+      if ( ptr == NULL ) 
-+      {
-+              ELAN_DEBUG0 (ELAN_DBG_VP,"elan_validate_map: cap not found \n");
-+              ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+              return EINVAL;
-+      }
-+      /* is it active */
-+      if ( ! ptr->node.active ) 
-+      {
-+              ELAN_DEBUG0 (ELAN_DBG_VP,"elan_validate_map: cap not active \n");
-+              ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+              return EINVAL;
-+      }
-+
-+      /* are they the same */
-+      if ( ELAN_CAP_TYPE_MATCH(cap,map) 
-+           && ELAN_CAP_GEOM_MATCH(cap,map)) 
-+      {
-+              ELAN_DEBUG0 (ELAN_DBG_VP,"elan_validate_map: cap == map  passed\n");
-+              ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+              return ESUCCESS;
-+      }
-+
-+      /* is map in map list */
-+      vptr = find_vp_node(ptr, map);
-+      if ( vptr == NULL ) 
-+      {
-+              ELAN_DEBUG0 (ELAN_DBG_VP,"elan_validate_map:  map not found\n");
-+              ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+              return EINVAL;
-+      }
-+      
-+      ELAN_DEBUG0 (ELAN_DBG_VP,"elan_validate_map:  map passed\n");
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return ESUCCESS;
-+}
-+
-+int
-+elan_create_cap(ELAN_CAP_OWNER owner, ELAN_CAPABILITY *cap)
-+{
-+      char                      space[127];
-+      struct list_head        * tmp;
-+      ELAN_CAP_NODE_STRUCT * ptr = NULL;
-+      int                       i, rail;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      ELAN_DEBUG1 (ELAN_DBG_VP,"elan_create_cap %s\n",elan_capability_string(cap,space));     
-+
-+      /* need to check that the cap does not over lap another one 
-+         or is an exact match with only the userkey changing */
-+      list_for_each(tmp, &elan_cap_list) {
-+              ptr = list_entry(tmp, ELAN_CAP_NODE_STRUCT , list);
-+
-+              /* is it an exact match (key not checked) */
-+              if ( ELAN_CAP_TYPE_MATCH(&ptr->node.cap,cap) 
-+                   && ELAN_CAP_GEOM_MATCH(&ptr->node.cap,cap)
-+                   && (ptr->node.owner == owner)) {
-+                      if ( ptr->node.active ) {
-+                              /* dont inc attached count as its like a create */
-+                              ptr->node.cap.cap_userkey = cap->cap_userkey;
-+                              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                              return ESUCCESS;
-+                      }
-+                      else
-+                      {
-+                              ELAN_DEBUG (ELAN_DBG_VP,"elan_create_cap failed %s\n",
-+                                          elan_capability_string(&ptr->node.cap,space));
-+                              ELAN_DEBUG (ELAN_DBG_VP,"elan_create_cap failed ptr %p owner %p attached %d\n",
-+                                          ptr, owner, ptr->node.attached);
-+                                           
-+                              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                              return EINVAL;
-+                      }
-+              }
-+              
-+              /* does it overlap, even with ones being destroyed */
-+              if (elan_cap_overlap(&ptr->node.cap,cap))
-+              {
-+                      ELAN_DEBUG (ELAN_DBG_VP,"elan_create_cap failed overlap %s\n",
-+                                  elan_capability_string(&ptr->node.cap,space));
-+                      ELAN_DEBUG (ELAN_DBG_VP,"elan_create_cap failed overlap ptr %p owner %p attached %d active %d\n",
-+                                  ptr, owner, ptr->node.attached, ptr->node.active);
-+
-+                      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                      return  EACCES;
-+              }
-+      }
-+
-+      /* create it */
-+      KMEM_ALLOC(ptr, ELAN_CAP_NODE_STRUCT *, sizeof(ELAN_CAP_NODE_STRUCT), 1);
-+      if (ptr == NULL)
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return  ENOMEM;
-+      }
-+
-+      /* create per rail space for the attached array */
-+      for(rail=0;rail<ELAN_MAX_RAILS;rail++)
-+      {
-+              ptr->attached[rail]=NULL;
-+              /* GNAT 7685: Always need to allocate an attached structure in rail 0 for the usercopy device */
-+              if ( ELAN_CAP_IS_RAIL_SET(cap,rail) || rail == 0 ) 
-+              {
-+                      KMEM_ALLOC(ptr->attached[rail], ELAN_ATTACHED_STRUCT *, sizeof(ELAN_ATTACHED_STRUCT) *  ELAN_CAP_NUM_CONTEXTS(cap), 1);
-+                      if (ptr->attached[rail] == NULL) 
-+                      {
-+                              for(;rail>=0;rail--)
-+                                      if ( ptr->attached[rail] )
-+                                              KMEM_FREE(ptr->attached[rail], sizeof(ELAN_ATTACHED_STRUCT) *  ELAN_CAP_NUM_CONTEXTS(cap));
-+
-+                              KMEM_FREE(ptr, sizeof(ELAN_CAP_NODE_STRUCT));
-+                              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                              return  ENOMEM;
-+                      }
-+                      /* blank the per context attached array */
-+                      for(i=0;i<ELAN_CAP_NUM_CONTEXTS(cap);i++)
-+                      {
-+                              ptr->attached[rail][i].cb_func = NULL;
-+                              /* user-to-user copy */
-+                              ptr->attached[rail][i].handle  = NULL;
-+                              ptr->attached[rail][i].owner   = NULL;
-+                      }
-+              }
-+      }       
-+      
-+      ptr->node.owner     = owner;
-+      ptr->node.cap       = *cap;
-+      ptr->node.attached  = 1;    /* creator counts as attached */
-+      ptr->node.active    = 1;
-+      ptr->vp_list.next   = &(ptr->vp_list);
-+      ptr->vp_list.prev   = &(ptr->vp_list);
-+
-+      list_add_tail(&ptr->list, &elan_cap_list);      
-+
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return  ESUCCESS;
-+}
-+
-+void
-+elan_destroy_cap_test(ELAN_CAP_NODE_STRUCT *cap_ptr)
-+{
-+      /* called by someone holding the mutex   */
-+      struct list_head       * vp_tmp;
-+      ELAN_VP_NODE_STRUCT * vp_ptr = NULL;
-+      int                      rail;
-+
-+      ASSERT(cap_ptr->node.attached >= 0);
-+
-+      /* check to see if it can be deleted now */
-+      if ( cap_ptr->node.attached == 0 ) {
-+              
-+              ELAN_DEBUG1(ELAN_DBG_CAP,"elan_destroy_cap_test: %p attached == 0\n", cap_ptr); 
-+              
-+              /* delete the vp list */
-+              list_for_each(vp_tmp, &(cap_ptr->vp_list)) {
-+                      vp_ptr = list_entry(vp_tmp, ELAN_VP_NODE_STRUCT , list);
-+                      list_del(&vp_ptr->list);
-+                      KMEM_FREE( vp_ptr, sizeof(ELAN_VP_NODE_STRUCT));
-+              }
-+              
-+              list_del(&cap_ptr->list);
-+
-+              /* delete space for the attached array */
-+              for(rail=0;rail<ELAN_MAX_RAILS;rail++)
-+                      if (cap_ptr->attached[rail]) 
-+                              KMEM_FREE(cap_ptr->attached[rail], sizeof(ELAN_ATTACHED_STRUCT) * ELAN_CAP_NUM_CONTEXTS(&(cap_ptr->node.cap)));
-+                      
-+              KMEM_FREE(cap_ptr, sizeof(ELAN_CAP_NODE_STRUCT));               
-+      }
-+      else
-+              ELAN_DEBUG2(ELAN_DBG_CAP,"elan_destroy_cap_test: %p attached = %d\n",
-+                          cap_ptr, cap_ptr->node.attached);   
-+
-+}
-+
-+int
-+elan_destroy_cap(ELAN_CAP_OWNER owner, ELAN_CAPABILITY *cap)
-+{
-+      char                      space[127];
-+      struct list_head        * el;
-+      struct list_head        * nel;
-+      ELAN_CAP_NODE_STRUCT * ptr = NULL;
-+      int                       i, rail;
-+      int                       found = 0;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      ELAN_DEBUG1 (ELAN_DBG_CAP,"elan_destroy_cap %s\n",elan_capability_string(cap,space));   
-+
-+      list_for_each_safe (el, nel, &elan_cap_list) {
-+              ptr = list_entry(el, ELAN_CAP_NODE_STRUCT , list);
-+              
-+              /* is it an exact match */
-+              if ( (ptr->node.owner == owner )
-+                   && (  (cap == NULL) 
-+                         || (ELAN_CAP_TYPE_MATCH(&ptr->node.cap,cap) && ELAN_CAP_GEOM_MATCH(&ptr->node.cap,cap)))) {
-+
-+                      if ( ptr->node.active ) {
-+
-+                              /* mark as in active and dec attached count */
-+                              ptr->node.active = 0;
-+                              ptr->node.attached--;
-+                              ptr->node.owner  = 0; /* no one own's it now */
-+
-+                              ASSERT(ptr->node.attached >= 0);
-+                              
-+                              /* need to tell any one who was attached that this has been destroy'd */
-+                              for(rail=0;rail<ELAN_MAX_RAILS;rail++)
-+                                      if (ELAN_CAP_IS_RAIL_SET( &(ptr->node.cap), rail)) {
-+                                              for(i=0;i< ELAN_CAP_NUM_CONTEXTS(&(ptr->node.cap));i++)
-+                                                      if ( ptr->attached[rail][i].cb_func != NULL) 
-+                                                              ptr->attached[rail][i].cb_func(ptr->attached[rail][i].cb_args, cap, NULL);
-+                                      }
-+                              
-+                              /* now try to destroy it */
-+                              elan_destroy_cap_test(ptr);
-+                              
-+                              /* found it */
-+                              found = 1;
-+                      }
-+              }
-+      }
-+      
-+      if ( found )
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return ESUCCESS;
-+      }
-+
-+      /* failed */
-+      ELAN_DEBUG1(ELAN_DBG_CAP,"elan_destroy_cap: %p didnt find it \n", cap); 
-+
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return EINVAL;
-+}
-+
-+int 
-+elan_get_caps(uint *number_of_results, uint array_size, ELAN_CAP_STRUCT *caps)
-+{
-+      uint                      results = 0;
-+      struct list_head        * tmp;
-+      ELAN_CAP_NODE_STRUCT * ptr = NULL;
-+      
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      ELAN_DEBUG0(ELAN_DBG_CAP,"elan_get_caps\n");    
-+
-+      list_for_each(tmp, &elan_cap_list) {
-+              ptr = list_entry(tmp, ELAN_CAP_NODE_STRUCT , list);
-+              
-+              copyout(&ptr->node, &caps[results], sizeof (ELAN_CAP_STRUCT));
-+              
-+              results++;
-+              
-+              if ( results >= array_size )
-+              {
-+                      copyout(&results, number_of_results, sizeof(uint));     
-+                      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+                      return ESUCCESS;
-+              }
-+      }
-+
-+      copyout(&results, number_of_results, sizeof(uint));     
-+
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return ESUCCESS;
-+}
-+
-+int
-+elan_create_vp(ELAN_CAP_OWNER owner, ELAN_CAPABILITY *cap, ELAN_CAPABILITY *map)
-+{
-+      ELAN_CAP_NODE_STRUCT * cap_ptr = NULL;
-+      ELAN_VP_NODE_STRUCT  * vp_ptr  = NULL;
-+      
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+
-+      ELAN_DEBUG0(ELAN_DBG_CAP,"elan_create_vp\n");
-+
-+      /* the railmasks must match */
-+      if ( cap->cap_railmask != map->cap_railmask)
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return  EINVAL;
-+      }
-+
-+      /* does the cap exist */
-+      cap_ptr = find_cap_node(cap);
-+      if ((cap_ptr == NULL) || ( cap_ptr->node.owner != owner ) || (! cap_ptr->node.active) )
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return  EINVAL;
-+      }
-+      
-+      /* is there already a mapping */
-+      vp_ptr = find_vp_node(cap_ptr,map);
-+      if ( vp_ptr != NULL) 
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return  EINVAL;
-+      }
-+
-+      /* create space for mapping */
-+      KMEM_ALLOC(vp_ptr, ELAN_VP_NODE_STRUCT *, sizeof(ELAN_VP_NODE_STRUCT), 1);
-+      if (vp_ptr == NULL)
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return  ENOMEM;
-+      }
-+                      
-+      /* copy map */
-+      vp_ptr->vp = *map;
-+      list_add_tail(&vp_ptr->list, &(cap_ptr->vp_list));      
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return  ESUCCESS;
-+}
-+
-+int
-+elan_destroy_vp(ELAN_CAP_OWNER owner, ELAN_CAPABILITY *cap, ELAN_CAPABILITY *map)
-+{
-+      ELAN_CAP_NODE_STRUCT * cap_ptr = NULL;
-+      ELAN_VP_NODE_STRUCT  * vp_ptr  = NULL;
-+      int                       i, rail;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      ELAN_DEBUG0(ELAN_DBG_CAP,"elan_destroy_vp\n");  
-+
-+      cap_ptr = find_cap_node(cap);
-+      if ((cap_ptr!=NULL) && (cap_ptr->node.owner == owner) && ( cap_ptr->node.active))
-+      {               
-+              vp_ptr = find_vp_node( cap_ptr, map );
-+              if ( vp_ptr != NULL ) 
-+              {
-+                      list_del(&vp_ptr->list);
-+                      KMEM_FREE(vp_ptr, sizeof(ELAN_VP_NODE_STRUCT));
-+            
-+                      /* need to tell those who are attached that map is nolonger in use */
-+                      for(rail=0;rail<ELAN_MAX_RAILS;rail++)
-+                              if (ELAN_CAP_IS_RAIL_SET(cap, rail))
-+                              {
-+                                      for(i=0;i< ELAN_CAP_NUM_CONTEXTS(&(cap_ptr->node.cap));i++)
-+                                              if ( cap_ptr->attached[rail][i].cb_func != NULL) 
-+                                                      cap_ptr->attached[rail][i].cb_func( cap_ptr->attached[rail][i].cb_args, cap, map);
-+                              }
-+
-+                      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                      return  ESUCCESS;
-+              }
-+      }       
-+      
-+      /* didnt find it */
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return  EINVAL;
-+}
-+
-+int 
-+elan_attach_cap(ELAN_CAPABILITY *cap, unsigned int rail, void *args, ELAN_DESTROY_CB func)
-+{
-+      char                  space[127];
-+      struct list_head     *el;
-+
-+      ELAN_DEBUG1 (ELAN_DBG_CAP,"elan_attach_cap %s\n",elan_capability_string(cap,space));
-+
-+      /* currently must provide a call back, as null mean something */
-+      if ( func == NULL)
-+              return (EINVAL);
-+
-+      /* mycontext must be set and correct */
-+      if ( ! ELAN_CAP_VALID_MYCONTEXT(cap))
-+              return (EINVAL);
-+
-+      /* rail must be one of the rails in railmask */
-+      if (((1 << rail) & cap->cap_railmask) == 0)
-+              return (EINVAL);
-+      
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      list_for_each(el, &elan_cap_list) {
-+              ELAN_CAP_NODE_STRUCT *cap_ptr = list_entry(el, ELAN_CAP_NODE_STRUCT , list);
-+              
-+              /* is it an exact match */
-+              if (ELAN_CAP_MATCH(&cap_ptr->node.cap,cap) && cap_ptr->node.active) {
-+                      unsigned int attached_index = cap->cap_mycontext - cap->cap_lowcontext;
-+                      
-+                      if ( cap_ptr->attached[rail][attached_index].cb_func != NULL ) /* only one per ctx per rail */
-+                      {
-+                              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                              return   EBUSY;
-+                      }
-+
-+                      /* keep track of who attached as we might need to tell them when */
-+                      /* cap or maps get destroyed                                     */
-+                      cap_ptr->attached[rail][ attached_index ].cb_func = func;
-+                      cap_ptr->attached[rail][ attached_index ].cb_args = args;
-+                      cap_ptr->node.attached++;
-+
-+                      ELAN_DEBUG0(ELAN_DBG_CAP,"elan_attach_cap: passed\n");
-+                      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                      return ESUCCESS;
-+              }
-+      }
-+      
-+      ELAN_DEBUG0(ELAN_DBG_CAP,"elan_attach_cap: failed to find \n");
-+
-+      /* didnt find one */
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return EINVAL;
-+}
-+
-+int 
-+elan_detach_cap(ELAN_CAPABILITY *cap, unsigned int rail)
-+{
-+      struct list_head *el, *nel;
-+      char              space[256];
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      ELAN_DEBUG1(ELAN_DBG_CAP,"elan_detach_cap %s\n",elan_capability_string(cap,space));
-+      list_for_each_safe (el, nel, &elan_cap_list) {
-+              ELAN_CAP_NODE_STRUCT *ptr = list_entry (el, ELAN_CAP_NODE_STRUCT, list);
-+
-+              /* is it an exact match (key not checked) */
-+              if (ELAN_CAP_TYPE_MATCH(&ptr->node.cap,cap) &&
-+                  ELAN_CAP_GEOM_MATCH(&ptr->node.cap,cap) &&
-+                  (ptr->node.cap.cap_railmask & cap->cap_railmask) == cap->cap_railmask) {
-+              
-+                      unsigned int attached_index = cap->cap_mycontext - cap->cap_lowcontext;
-+
-+                      if ( ptr->attached[rail][ attached_index ].cb_func == NULL ) {
-+                              ELAN_DEBUG0(ELAN_DBG_CAP,"elanmod_detach_cap already removed \n");
-+                              
-+                              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                              return  ESUCCESS;
-+                      }
-+
-+                      ptr->attached[rail][ attached_index ].cb_func = NULL;
-+                      ptr->attached[rail][ attached_index ].cb_args = (void *)0;
-+
-+                      ptr->node.attached--;
-+                      
-+                      ASSERT(ptr->node.attached >= 0);
-+
-+                      ELAN_DEBUG1(ELAN_DBG_CAP,"elanmod_detach_cap new attach count %d \n", ptr->node.attached);
-+
-+                      elan_destroy_cap_test(ptr);
-+
-+                      ELAN_DEBUG0(ELAN_DBG_CAP,"elan_detach_cap: success\n"); 
-+
-+                      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                      return  ESUCCESS;
-+              }
-+      }
-+
-+      ELAN_DEBUG0(ELAN_DBG_CAP,"elan_detach_cap: failed to find\n");
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return  EINVAL;
-+}
-+
-+int
-+elan_cap_dump()
-+{
-+      struct list_head        * tmp;
-+      ELAN_CAP_NODE_STRUCT * ptr = NULL;
-+      
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+      
-+      list_for_each(tmp, &elan_cap_list) {
-+              ptr = list_entry(tmp, ELAN_CAP_NODE_STRUCT , list);
-+
-+              ELAN_DEBUG2 (ELAN_DBG_ALL, "cap dump: owner %p type %x\n", ptr->node.owner, ptr->node.cap.cap_type);
-+                      
-+              ELAN_DEBUG5 (ELAN_DBG_ALL, "cap dump: LowNode %d   HighNode %d   LowContext %d   mycontext %d   highContext %d\n",
-+                           ptr->node.cap.cap_lownode , ptr->node.cap.cap_highnode,
-+                           ptr->node.cap.cap_lowcontext , ptr->node.cap.cap_mycontext, ptr->node.cap.cap_highcontext);
-+
-+      }
-+
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return  ESUCCESS;
-+}
-+
-+int
-+elan_usercopy_attach(ELAN_CAPABILITY *cap, ELAN_CAP_NODE_STRUCT **node_ptr, void *handle, void *owner)
-+{
-+      struct list_head     *el;
-+
-+      /* mycontext must be set and correct */
-+      if ( ! ELAN_CAP_VALID_MYCONTEXT(cap))
-+              return -EINVAL;
-+      
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      /* Search all cap node structs looking for an exact match (including key) */
-+      list_for_each(el, &elan_cap_list) {
-+              ELAN_CAP_NODE_STRUCT *cap_ptr = list_entry(el, ELAN_CAP_NODE_STRUCT , list);
-+              
-+              /* is it an exact match */
-+              if (ELAN_CAP_MATCH(&cap_ptr->node.cap,cap) && cap_ptr->node.active) {
-+                      char space[127];
-+                      /* Work out which local process index we are */
-+                      unsigned int attached_index = cap->cap_mycontext - cap->cap_lowcontext;
-+
-+                      ELAN_DEBUG(ELAN_DBG_CAP, "usercopy_attach: %s\n",
-+                                 elan_capability_string(cap,space));
-+
-+                      ELAN_DEBUG(ELAN_DBG_CAP, 
-+                                 "usercopy_attach: cap_ptr %p handle %p owner %p idx %d\n", 
-+                                 cap_ptr, handle, owner, attached_index);
-+                      
-+                      /* Check we're not being called multiple times for the same local process */
-+                      if (cap_ptr->attached[0][attached_index].handle)
-+                      {
-+                              ELAN_DEBUG(ELAN_DBG_CAP, 
-+                                         "usercopy_attach: cap_ptr %p idx %d already attached handle %p owner %p\n",
-+                                         cap_ptr, attached_index, 
-+                                         cap_ptr->attached[0][attached_index].handle,
-+                                         cap_ptr->attached[0][attached_index].owner);
-+                                          
-+                              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                              return -EAGAIN;
-+                      }
-+
-+                      /* Reference count node struct */
-+                      cap_ptr->node.attached++;
-+                      
-+                      /* Stash our task handle/owner off the cap node array */
-+                      cap_ptr->attached[0][attached_index].handle = handle;
-+                      cap_ptr->attached[0][attached_index].owner = owner;
-+                      
-+                      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+
-+                      /* Return node pointer to caller */
-+                      *node_ptr = cap_ptr;
-+
-+                      return ESUCCESS;
-+              }
-+      }
-+
-+      /* failed to match a cap */
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return -EINVAL;
-+}
-+
-+int
-+elan_usercopy_detach(ELAN_CAP_NODE_STRUCT *cap_ptr, void *owner)
-+{
-+      int i;
-+
-+      /* NB: The usercopy code holds a read lock on this rwlock and
-+       * hence we will block here if exit_fs() gets called during a
-+       * copy to this process
-+       */
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      /* Find this process in the attached task handle/owner array */
-+      for(i=0; i< ELAN_CAP_NUM_CONTEXTS((&cap_ptr->node.cap)); i++)
-+      {
-+              if (cap_ptr->attached[0][i].owner == owner)
-+              {
-+                      ELAN_DEBUG(ELAN_DBG_CAP,
-+                                 "usercopy_detach: cap_ptr %p handle %p owner %p id %d\n",
-+                                 cap_ptr, cap_ptr->attached[0][i].handle, owner, i);
-+
-+                      /* Clear our task handle/owner off the cap node array */
-+                      cap_ptr->attached[0][i].handle = NULL;
-+                      cap_ptr->attached[0][i].owner  = NULL;
-+                      
-+                      /* Reference count node struct */
-+                      cap_ptr->node.attached--;
-+
-+                      ASSERT(cap_ptr->node.attached >= 0);
-+                      
-+                      /* May need to destroy cap if reference count has hit zero */
-+                      elan_destroy_cap_test(cap_ptr);
-+
-+                      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+
-+                      return ESUCCESS;
-+              }
-+      }
-+
-+      ELAN_DEBUG(ELAN_DBG_CAP, "usercopy_detach: cap_ptr %p[%d] failed owner %p\n", 
-+                 cap_ptr, cap_ptr->node.attached, owner);
-+
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+
-+      return -EINVAL;
-+}
-+
-+/* Returns the associated handle for the supplied ctxId process in the cap node */
-+/* Should be called holding a read lock on the elan_rwlock */
-+int
-+elan_usercopy_handle(ELAN_CAP_NODE_STRUCT *cap_ptr, int ctxId, void **handlep)
-+{
-+      int res = ESUCCESS;
-+      void *handle;
-+
-+      /* Sanity check argument */
-+      if (ctxId < 0 || ctxId >= ELAN_CAP_NUM_CONTEXTS(&(cap_ptr->node.cap)))
-+              return -EINVAL;
-+      
-+//    ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      /* Get the task handle for the remote process */
-+      if ((handle = cap_ptr->attached[0][ctxId].handle) == NULL)
-+              res = -EAGAIN;
-+      
-+//    ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+
-+      *handlep = handle;
-+
-+      return res;
-+}
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan/capability_general.c linux-2.6.9/drivers/net/qsnet/elan/capability_general.c
---- clean/drivers/net/qsnet/elan/capability_general.c  1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/capability_general.c    2004-02-25 08:47:59.000000000 -0500
-@@ -0,0 +1,446 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: capability_general.c,v 1.10 2004/02/25 13:47:59 daniel Exp $"
-+/*      $Source: /cvs/master/quadrics/elanmod/shared/capability_general.c,v $ */
-+
-+#if defined(__KERNEL__)
-+
-+#include <qsnet/kernel.h>
-+
-+#else
-+
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <sys/param.h>
-+
-+#endif
-+
-+#include <elan/elanmod.h>
-+
-+
-+void
-+elan_nullcap (ELAN_CAPABILITY *cap)
-+{
-+      register int i;
-+
-+      for (i = 0; i < sizeof (cap->cap_userkey)/sizeof(cap->cap_userkey.key_values[0]); i++)
-+              cap->cap_userkey.key_values[i] = ELAN_CAP_UNINITIALISED;
-+    
-+      cap->cap_lowcontext  = ELAN_CAP_UNINITIALISED;
-+      cap->cap_highcontext = ELAN_CAP_UNINITIALISED;
-+      cap->cap_mycontext   = ELAN_CAP_UNINITIALISED;
-+      cap->cap_lownode     = ELAN_CAP_UNINITIALISED;
-+      cap->cap_highnode    = ELAN_CAP_UNINITIALISED;
-+      cap->cap_railmask    = ELAN_CAP_UNINITIALISED;
-+      cap->cap_type        = ELAN_CAP_UNINITIALISED;
-+      cap->cap_spare       = 0;
-+      cap->cap_version     = ELAN_CAP_VERSION_NUMBER;
-+      
-+      for (i = 0; i < sizeof (cap->cap_bitmap)/sizeof (cap->cap_bitmap[0]); i++)
-+              cap->cap_bitmap[i] = 0;
-+}
-+
-+char *
-+elan_capability_string (ELAN_CAPABILITY *cap, char *str)
-+{
-+      if (cap == NULL) 
-+              sprintf (str, "[-.-.-.-] cap = NULL\n");
-+      else
-+              sprintf (str, "[%x.%x.%x.%x] Version %x Type %x \n"
-+                       "Context %x.%x.%x Node %x.%x\n",
-+                       cap->cap_userkey.key_values[0], cap->cap_userkey.key_values[1],
-+                       cap->cap_userkey.key_values[2], cap->cap_userkey.key_values[3],
-+                       cap->cap_version, cap->cap_type, 
-+                       cap->cap_lowcontext, cap->cap_mycontext, cap->cap_highcontext,
-+                       cap->cap_lownode, cap->cap_highnode);
-+      
-+      return (str);
-+}
-+
-+ELAN_LOCATION
-+elan_vp2location (u_int process, ELAN_CAPABILITY *cap)
-+{
-+      ELAN_LOCATION location;
-+      int i, vp, node, context, nnodes, nctxs;
-+
-+      vp = 0;
-+
-+      location.loc_node    = ELAN_INVALID_NODE;
-+      location.loc_context = -1;
-+       
-+      nnodes = cap->cap_highnode - cap->cap_lownode + 1;
-+      nctxs  = cap->cap_highcontext - cap->cap_lowcontext + 1;
-+       
-+      switch (cap->cap_type & ELAN_CAP_TYPE_MASK)
-+      {
-+      case ELAN_CAP_TYPE_BLOCK:
-+              for (node = 0, i = 0; node < nnodes; node++)
-+              {
-+                      for (context = 0; context < nctxs; context++)
-+                      {
-+                              if ((cap->cap_type & ELAN_CAP_TYPE_NO_BITMAP) || BT_TEST (cap->cap_bitmap, context + (node * nctxs)))
-+                              {
-+                                      if (vp == process)
-+                                      {
-+                                              /* Return relative indices within the capability box */
-+                                              location.loc_node    = node;
-+                                              location.loc_context = context;
-+
-+                                              return (location);
-+                                      }
-+                     
-+                                      vp++;
-+                              }
-+                      }
-+              }
-+              break;
-+      
-+      case ELAN_CAP_TYPE_CYCLIC:
-+              for (context = 0, i = 0; context < nctxs; context++)
-+              {
-+                      for (node = 0; node < nnodes; node++)
-+                      {
-+                              if ((cap->cap_type & ELAN_CAP_TYPE_NO_BITMAP) || BT_TEST (cap->cap_bitmap, node + (context * nnodes)))
-+                              {
-+                                      if (vp == process)
-+                                      {
-+                                              location.loc_node    = node;
-+                                              location.loc_context = context;
-+
-+                                              return (location);
-+                                      }
-+                  
-+                                      vp++;
-+                              }
-+                      }
-+              }
-+              break;
-+      }
-+    
-+      return( location );
-+}
-+
-+int
-+elan_location2vp (ELAN_LOCATION location, ELAN_CAPABILITY *cap)
-+{
-+    int  vp, node, context, nnodes, nctxs;
-+
-+    nnodes = cap->cap_highnode - cap->cap_lownode + 1;
-+    nctxs  = cap->cap_highcontext - cap->cap_lowcontext + 1;
-+
-+    vp = 0;
-+    
-+    switch (cap->cap_type & ELAN_CAP_TYPE_MASK)
-+    {
-+    case ELAN_CAP_TYPE_BLOCK:
-+      for (node = 0 ; node < nnodes ; node++)
-+      {
-+          for (context = 0; context < nctxs; context++)
-+          {
-+              if ((cap->cap_type & ELAN_CAP_TYPE_NO_BITMAP) || BT_TEST (cap->cap_bitmap, context + (node * nctxs)))
-+              {
-+                  if ((location.loc_node == node) && (location.loc_context == context))
-+                  {
-+                      /* Found it ! */
-+                      return( vp );
-+                  }
-+                  
-+                  vp++;
-+              }
-+          }
-+      }
-+      break;
-+      
-+    case ELAN_CAP_TYPE_CYCLIC:
-+      for (context = 0; context < nctxs; context++)
-+      {
-+          for (node = 0; node < nnodes; node++)
-+          {
-+              if ((cap->cap_type & ELAN_CAP_TYPE_NO_BITMAP) || BT_TEST (cap->cap_bitmap, node + (context * nnodes)))
-+              {
-+                  if ((location.loc_node == node) && (location.loc_context == context))
-+                  {
-+                      /* Found it ! */
-+                      return( vp );
-+                  }
-+                  
-+                  vp++;
-+              }
-+          }
-+      }
-+      break;
-+    }
-+    
-+    /* Failed to find it */
-+    return( -1 );
-+}
-+
-+/* Return the number of processes as described by a capability */
-+int
-+elan_nvps (ELAN_CAPABILITY *cap)
-+{
-+      int i, c, nbits = ELAN_CAP_BITMAPSIZE(cap);
-+
-+      if (cap->cap_type & ELAN_CAP_TYPE_NO_BITMAP)
-+              return (nbits);
-+
-+      for (i = 0, c = 0; i < nbits; i++)
-+              if (BT_TEST (cap->cap_bitmap, i))
-+                      c++;
-+
-+      return (c);
-+}
-+
-+/* Return the number of local processes on a given node as described by a capability */
-+int
-+elan_nlocal (int node, ELAN_CAPABILITY *cap)
-+{
-+      int vp;
-+      ELAN_LOCATION loc;
-+      int nLocal = 0;
-+
-+      for (vp = 0; vp < elan_nvps(cap); vp++)
-+      {
-+              loc = elan_vp2location(vp, cap);
-+              if (loc.loc_node == node)
-+                      nLocal++;
-+      }
-+
-+      return (nLocal);
-+}
-+
-+/* Return the maximum number of local processes on any node as described by a capability */
-+int
-+elan_maxlocal (ELAN_CAPABILITY *cap)
-+{
-+      return(cap->cap_highcontext - cap->cap_lowcontext + 1);
-+}
-+
-+/* Return the vps of the local processes on a given node as described by a capability */
-+int
-+elan_localvps (int node, ELAN_CAPABILITY *cap, int *vps, int size)
-+{
-+      int context;
-+      ELAN_LOCATION loc;
-+      int nLocal = 0;
-+    
-+      loc.loc_node = node;
-+
-+      for (context = 0; context < MIN(size, elan_maxlocal(cap)); context++)
-+      {
-+              loc.loc_context = context;
-+      
-+              /* Should return -1 if none found */
-+              if ( (vps[context] = elan_location2vp( loc, cap )) != -1)
-+                      nLocal++;
-+      }
-+
-+      return (nLocal);
-+}
-+
-+/* Return the number of rails that this capability utilises */
-+int
-+elan_nrails (ELAN_CAPABILITY *cap)
-+{
-+      int nrails = 0;
-+      unsigned int railmask;
-+
-+      /* Test for a multi-rail capability */
-+      if (cap->cap_type & ELAN_CAP_TYPE_MULTI_RAIL)
-+      {
-+              /* Grab rail bitmask from capability */
-+              railmask = cap->cap_railmask;
-+      
-+              while (railmask)
-+              {
-+                      if (railmask & 1)
-+                              nrails++;
-+          
-+                      railmask >>= 1;
-+              }
-+      }
-+      else 
-+              /* Default to just one rail */
-+              nrails = 1;
-+      
-+      return (nrails);
-+}
-+
-+/* Fill out an array giving the physical rail numbers utilised by a capability */
-+int
-+elan_rails (ELAN_CAPABILITY *cap, int *rails)
-+{
-+      int nrails, rail;
-+      unsigned int railmask;
-+
-+      /* Test for a multi-rail capability */
-+      if (cap->cap_type & ELAN_CAP_TYPE_MULTI_RAIL)
-+      {
-+              /* Grab rail bitmask from capability */
-+              railmask = cap->cap_railmask;
-+      
-+              nrails = rail = 0;
-+              while (railmask)
-+              {
-+                      if (railmask & 1)
-+                              rails[nrails++] = rail;
-+          
-+                      rail++;
-+                      railmask >>= 1;
-+              }
-+      }
-+      else
-+      {
-+              /* Default to just one rail */
-+              rails[0] = 0;
-+              nrails = 1;
-+      }
-+
-+      return( nrails );
-+}
-+
-+int 
-+elan_cap_overlap(ELAN_CAPABILITY *cap1, ELAN_CAPABILITY *cap2)
-+{
-+      /* by context */
-+      if ( cap1->cap_highcontext < cap2->cap_lowcontext ) return (0);
-+      if ( cap1->cap_lowcontext  > cap2->cap_highcontext) return (0);
-+      
-+      /* by node */
-+      if ( cap1->cap_highnode < cap2->cap_lownode ) return (0);
-+      if ( cap1->cap_lownode  > cap2->cap_highnode) return (0);
-+
-+      /* by rail */
-+      /* they overlap if they have a rail in common */
-+      return (cap1->cap_railmask & cap2->cap_railmask);
-+}
-+
-+#if !defined(__KERNEL__)
-+
-+/* Fill out an array that hints at the best use of the rails on a
-+ * per process basis. The library user can then decide whether or not
-+ * to take this into account (e.g. TPORTs)
-+ * All processes calling this fn will be returned the same information.
-+ */
-+int
-+elan_prefrails(ELAN_CAPABILITY *cap, int *pref, int nvp)
-+{
-+      int i;
-+      int nrails = elan_nrails(cap);
-+      int maxlocal = elan_maxlocal(cap);
-+
-+      /* Test for a multi-rail capability */
-+      if (! (cap->cap_type & ELAN_CAP_TYPE_MULTI_RAIL))
-+      {
-+              /* Default to just one rail */
-+              for (i = 0; i < nvp; i++)
-+                      pref[i] = 0;
-+
-+              return( 0 );
-+      }
-+
-+      /*
-+       * We allocate rails on a per node basis sharing our the rails
-+       * equally amongst the local processes. However, if there is only
-+       * one process per node and multiple rails, then we use a different
-+       * algorithm where rails are allocated across all the processes in 
-+       * a round-robin fashion
-+       */
-+    
-+      if (maxlocal == 1)
-+      {
-+              /* Allocate rails in a round-robin manner */
-+              for (i = 0; i < nvp; i++)
-+                      *pref++ = i % nrails;
-+      }
-+      else
-+      {
-+              int node;
-+              int *vps;
-+              int nnodes = cap->cap_highnode - cap->cap_lownode + 1;
-+
-+              vps = (int *) malloc(sizeof(int)*maxlocal);
-+
-+              /* Grab the local process info for each node and allocate
-+               * rails to those vps on an equal basis
-+               */
-+              for (node = 0; node < nnodes; node++)
-+              {
-+                      int nlocal;
-+                      int pprail;
-+
-+                      /* Grab an array of local vps */
-+                      nlocal = elan_localvps(node, cap, vps, maxlocal);
-+          
-+                      /* Calculate the number processes per rail */
-+                      if ((pprail = nlocal/nrails) == 0)
-+                              pprail = 1;
-+
-+                      /* Allocate processes to rails */
-+                      for (i = 0; i < nlocal; i++)
-+                      {
-+                              pref[vps[i]] = (i / pprail) % nrails;
-+                      }
-+              }
-+      
-+              free(vps);
-+      }
-+
-+      return( 0 );
-+}
-+
-+void 
-+elan_get_random_key(ELAN_USERKEY *key)
-+{
-+    int i;
-+    for (i = 0; i < sizeof(key->key_values) / sizeof(key->key_values[0]); i++)
-+      key->key_values[i] = lrand48();
-+}
-+
-+int elan_lowcontext(ELAN_CAPABILITY *cap)
-+{
-+    return(cap->cap_lowcontext);
-+}
-+
-+int elan_mycontext(ELAN_CAPABILITY *cap)
-+{
-+    return(cap->cap_mycontext);
-+}
-+
-+int elan_highcontext(ELAN_CAPABILITY *cap)
-+{
-+    return(cap->cap_highcontext);
-+}
-+
-+int elan_lownode(ELAN_CAPABILITY *cap)
-+{
-+    return(cap->cap_lownode);
-+}
-+
-+int elan_highnode(ELAN_CAPABILITY *cap)
-+{
-+    return(cap->cap_highnode);
-+}
-+
-+int elan_captype(ELAN_CAPABILITY *cap)
-+{
-+    return(cap->cap_type);
-+}
-+
-+int elan_railmask(ELAN_CAPABILITY *cap)
-+{
-+    return(cap->cap_railmask);
-+}
-+
-+#endif
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan/device.c linux-2.6.9/drivers/net/qsnet/elan/device.c
---- clean/drivers/net/qsnet/elan/device.c      1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/device.c        2005-04-13 05:31:47.000000000 -0400
-@@ -0,0 +1,147 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: device.c,v 1.6 2005/04/13 09:31:47 addy Exp $"
-+/*      $Source: /cvs/master/quadrics/elanmod/modsrc/device.c,v $*/
-+
-+#include <qsnet/kernel.h>
-+#include <elan/elanmod.h>
-+
-+static LIST_HEAD(elan_dev_list);
-+
-+ELAN_DEV_STRUCT *
-+elan_dev_find (ELAN_DEV_IDX devidx)
-+{
-+      struct list_head   *tmp;
-+      ELAN_DEV_STRUCT *ptr=NULL;
-+
-+      list_for_each(tmp, &elan_dev_list) {
-+              ptr = list_entry(tmp, ELAN_DEV_STRUCT , node);
-+              if (ptr->devidx == devidx) 
-+                      return ptr;
-+              if (ptr->devidx > devidx)
-+                      return ERR_PTR(-ENXIO);
-+      }
-+      
-+      return ERR_PTR(-EINVAL);
-+}
-+
-+ELAN_DEV_STRUCT *
-+elan_dev_find_byrail (unsigned short deviceid, unsigned rail)
-+{
-+      struct list_head   *tmp;
-+      ELAN_DEV_STRUCT *ptr=NULL;
-+
-+      list_for_each(tmp, &elan_dev_list) {
-+              ptr = list_entry(tmp, ELAN_DEV_STRUCT , node);
-+
-+              ELAN_DEBUG5 (ELAN_DBG_ALL,"elan_dev_find_byrail devidx %d - %04x %04x,  %d %d \n", ptr->devidx, 
-+                           ptr->devinfo->dev_device_id, deviceid, ptr->devinfo->dev_rail, rail);
-+
-+              if (ptr->devinfo->dev_device_id == deviceid && ptr->devinfo->dev_rail == rail)
-+                      return ptr;
-+      }
-+      
-+      return NULL;
-+}
-+
-+ELAN_DEV_IDX
-+elan_dev_register (ELAN_DEVINFO *devinfo, ELAN_DEV_OPS *ops, void * user_data)
-+{
-+      ELAN_DEV_STRUCT *ptr;
-+      ELAN_DEV_IDX        devidx = 0;
-+      struct list_head   *tmp;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      /* is it already registered */
-+      if ((ptr = elan_dev_find_byrail(devinfo->dev_device_id, devinfo->dev_rail)) != NULL) 
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return EINVAL;
-+      }
-+
-+      /* find a free device idx */
-+      list_for_each (tmp, &elan_dev_list) {
-+              if (list_entry (tmp, ELAN_DEV_STRUCT, node)->devidx != devidx)
-+                      break;
-+              devidx++;
-+      }
-+
-+      /* create it and add */
-+      KMEM_ALLOC(ptr, ELAN_DEV_STRUCT *, sizeof(ELAN_DEV_STRUCT), 1);
-+      if (ptr == NULL)
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return ENOMEM;
-+      }
-+
-+      ptr->devidx    = devidx;
-+      ptr->ops       = ops;
-+      ptr->devinfo   = devinfo;
-+      ptr->user_data = user_data;
-+
-+      /* insert this entry *before* the last entry we've found */
-+      list_add_tail(&ptr->node, tmp);
-+
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return  ESUCCESS;
-+}
-+
-+int
-+elan_dev_deregister (ELAN_DEVINFO *devinfo)
-+{
-+      ELAN_DEV_STRUCT *target;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      if ((target = elan_dev_find_byrail (devinfo->dev_device_id, devinfo->dev_rail)) == NULL)
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return  EINVAL;
-+      }
-+
-+      list_del(&target->node);
-+
-+      /* delete target entry */
-+      KMEM_FREE(target, sizeof(ELAN_DEV_STRUCT));
-+
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return  ESUCCESS;
-+}
-+
-+int
-+elan_dev_dump ()
-+{
-+      struct list_head   *tmp;
-+      ELAN_DEV_STRUCT *ptr=NULL;
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      list_for_each(tmp, &elan_dev_list) {
-+              ptr = list_entry(tmp, ELAN_DEV_STRUCT , node);
-+
-+              ELAN_DEBUG3 (ELAN_DBG_ALL,"dev dump: index %u rail %u elan%c\n", 
-+                           ptr->devidx, ptr->devinfo->dev_rail, '3' + ptr->devinfo->dev_device_id);
-+              ELAN_DEBUG5 (ELAN_DBG_ALL,"dev dump: Vid %x   Did %x  Rid %x  DR %d  DVal %x\n",
-+                           ptr->devinfo->dev_vendor_id,
-+                           ptr->devinfo->dev_device_id,
-+                           ptr->devinfo->dev_revision_id,
-+                           ptr->devinfo->dev_driver_version,
-+                           ptr->devinfo->dev_num_down_links_value);
-+
-+      }
-+
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return ESUCCESS;
-+}
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan/devinfo.c linux-2.6.9/drivers/net/qsnet/elan/devinfo.c
---- clean/drivers/net/qsnet/elan/devinfo.c     1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/devinfo.c       2005-04-13 05:31:47.000000000 -0400
-@@ -0,0 +1,78 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: devinfo.c,v 1.6 2005/04/13 09:31:47 addy Exp $"
-+/*      $Source: /cvs/master/quadrics/elanmod/modsrc/devinfo.c,v $*/
-+
-+#include <qsnet/kernel.h>
-+#include <elan/elanmod.h>
-+
-+int 
-+elan_get_devinfo(ELAN_DEV_IDX devidx, ELAN_DEVINFO *devinfo)
-+{
-+      ELAN_DEV_STRUCT *target;
-+      int                 res;
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      target = elan_dev_find (devidx);
-+
-+      if (IS_ERR (target))
-+              res = PTR_ERR(target);
-+      else
-+      {
-+              copyout(target->devinfo, devinfo, sizeof(ELAN_DEVINFO));
-+              res = ESUCCESS;
-+      }
-+      
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return res;
-+}
-+
-+int 
-+elan_get_position(ELAN_DEV_IDX devidx, ELAN_POSITION *position)
-+{
-+      ELAN_DEV_STRUCT *target;
-+      int                 res;
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      target = elan_dev_find(devidx);
-+
-+      if (IS_ERR (target))
-+              res = PTR_ERR(target);
-+      else
-+              res = target->ops->get_position(target->user_data, position);
-+      
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return res;
-+}
-+
-+int 
-+elan_set_position(ELAN_DEV_IDX devidx, unsigned short nodeId, unsigned short numNodes)
-+{
-+      ELAN_DEV_STRUCT *target;
-+      int                 res;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      target = elan_dev_find(devidx);
-+
-+      if (IS_ERR (target))
-+              res = PTR_ERR (target);
-+      else
-+              res = target->ops->set_position(target->user_data, nodeId, numNodes);
-+      
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return res;
-+}
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan/elanmod.c linux-2.6.9/drivers/net/qsnet/elan/elanmod.c
---- clean/drivers/net/qsnet/elan/elanmod.c     1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/elanmod.c       2005-04-13 05:31:47.000000000 -0400
-@@ -0,0 +1,149 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+#ident "@(#)$Id: elanmod.c,v 1.12 2005/04/13 09:31:47 addy Exp $"
-+/*      $Source: /cvs/master/quadrics/elanmod/modsrc/elanmod.c,v $*/
-+
-+#include <qsnet/kernel.h>
-+#include <elan/elanmod.h>
-+
-+ELANMOD_RWLOCK elan_rwlock;
-+
-+int 
-+elan_init()
-+{
-+      ELANMOD_RWLOCK_INIT(&elan_rwlock);
-+      return (ESUCCESS);
-+}
-+
-+int 
-+elan_fini()
-+{
-+      ELANMOD_RWLOCK_DESTROY(&elan_rwlock);
-+      return (ESUCCESS);
-+}
-+
-+int 
-+elanmod_classify_cap (ELAN_POSITION *position, ELAN_CAPABILITY *cap, unsigned use)
-+{
-+      if (cap->cap_version != ELAN_CAP_VERSION_NUMBER)
-+      {
-+              ELAN_DEBUG2 (ELAN_DBG_VP, "elanmod_classify_cap: (cap->Version != ELAN_CAP_VERSION) %d %d\n", cap->cap_version, ELAN_CAP_VERSION_NUMBER);
-+              return (-EINVAL);
-+      }
-+      
-+      if (cap->cap_lowcontext == ELAN_CAP_UNINITIALISED || cap->cap_highcontext == ELAN_CAP_UNINITIALISED)
-+      {
-+              ELAN_DEBUG3 (ELAN_DBG_VP, "elanmod_classify_cap: LowContext %d    HighContext %d MyContext %d\n",
-+                           cap->cap_lowcontext , cap->cap_highcontext, cap->cap_mycontext);
-+              return (-EINVAL);
-+      }
-+      
-+      if (cap->cap_lowcontext > cap->cap_highcontext)
-+      {
-+              ELAN_DEBUG2 (ELAN_DBG_VP, "elanmod_classify_cap: (cap->cap_lowcontext > cap->cap_highcontext) %d %d\n",cap->cap_lowcontext , cap->cap_highcontext);
-+              return (-EINVAL);
-+      }
-+      
-+      
-+      switch (cap->cap_type & ELAN_CAP_TYPE_MASK)
-+      {
-+      case ELAN_CAP_TYPE_BLOCK:
-+      case ELAN_CAP_TYPE_CYCLIC:
-+              if (position->pos_mode == ELAN_POS_UNKNOWN)
-+              {
-+                      ELAN_DEBUG0 (ELAN_DBG_VP, "elanmod_classify_cap: Position Unknown \n");
-+                      return (-EAGAIN);
-+              }
-+              
-+              if ( ! ( ELAN_USER_CONTEXT(cap->cap_lowcontext) && ELAN_USER_CONTEXT(cap->cap_highcontext)))
-+              {
-+                      ELAN_DEBUG4 (ELAN_DBG_VP, "elanmod_classify_cap:  USER_BASE_CONTEXT %d %d %d %d \n" ,  ELAN_USER_BASE_CONTEXT_NUM,cap->cap_lowcontext, cap->cap_highcontext ,ELAN_USER_TOP_CONTEXT_NUM);
-+                      return (-EINVAL);
-+              }
-+              if (cap->cap_lownode == ELAN_CAP_UNINITIALISED)
-+                      cap->cap_lownode = position->pos_nodeid;
-+              if (cap->cap_highnode == ELAN_CAP_UNINITIALISED)
-+                      cap->cap_highnode = position->pos_nodeid;
-+              
-+              if (cap->cap_lownode < 0 || cap->cap_highnode >= position->pos_nodes || cap->cap_lownode > cap->cap_highnode)
-+              {
-+                      ELAN_DEBUG3 ( ELAN_DBG_VP,"elanmod_classify_cap: low %d high %d pos %d \n" , cap->cap_lownode  ,cap->cap_highnode, position->pos_nodes);
-+                      
-+                      return (-EINVAL);
-+              }
-+              
-+              if ((cap->cap_highnode < position->pos_nodeid) || (cap->cap_lownode > position->pos_nodeid))
-+              {
-+                      ELAN_DEBUG3 (ELAN_DBG_VP, "elanmod_classify_cap: node not i range low %d high %d this %d\n",
-+                                   cap->cap_lownode, cap->cap_highnode, position->pos_nodeid);
-+                      return (-EINVAL);
-+              }
-+
-+              break;
-+      default:
-+              ELAN_DEBUG1 (ELAN_DBG_VP, "elanmod_classify_cap: cant decode type %x \n", cap->cap_type & ELAN_CAP_TYPE_MASK);
-+              return (-EINVAL);
-+
-+      }
-+
-+      switch (use)
-+      {
-+      case ELAN_USER_ATTACH:
-+      case ELAN_USER_DETACH:
-+              if (cap->cap_mycontext == ELAN_CAP_UNINITIALISED)
-+              {
-+                      ELAN_DEBUG0 (ELAN_DBG_VP, "elanmod_classify_cap: cap->cap_mycontext == ELAN_CAP_UNINITIALISED");
-+                      return (-EINVAL);
-+              }
-+      
-+              if ((cap->cap_mycontext != ELAN_CAP_UNINITIALISED) && 
-+                  (cap->cap_mycontext < cap->cap_lowcontext || cap->cap_mycontext > cap->cap_highcontext))
-+              {
-+                      ELAN_DEBUG3 (ELAN_DBG_VP, "elanmod_classify_cap: cap->cap_mycontext out of range %d %d %d \n", cap->cap_lowcontext,cap->cap_mycontext,cap->cap_highcontext);
-+                      return (-EINVAL);
-+              }   
-+              break;
-+
-+      case ELAN_USER_P2P:
-+              break;
-+
-+      case ELAN_USER_BROADCAST:
-+              if (! (cap->cap_type & ELAN_CAP_TYPE_BROADCASTABLE)) {
-+                      ELAN_DEBUG0 (ELAN_DBG_VP, "elanmod_classify_cap: use ELAN_USER_BROADCAST but cap not ELAN_CAP_TYPE_BROADCASTABLE\n");
-+                      return (-EINVAL);
-+              }
-+              break;
-+
-+      default:
-+              ELAN_DEBUG1 (ELAN_DBG_VP, "elanmod_classify_cap: unknown use (%d)\n",use);
-+              return (-EINVAL);
-+      }
-+
-+
-+
-+      /* is any ctxt an rms one ?? */
-+      if (ELAN_RMS_CONTEXT(cap->cap_lowcontext) || ELAN_RMS_CONTEXT(cap->cap_highcontext))
-+      {
-+              /* so both low and high must be */
-+              if (!(ELAN_RMS_CONTEXT(cap->cap_lowcontext) && ELAN_RMS_CONTEXT(cap->cap_highcontext))) 
-+              {
-+                      ELAN_DEBUG2 (ELAN_DBG_VP, "elanmod_classify_cap: not rms ctxt %x %x\n",cap->cap_lowcontext,cap->cap_highcontext );
-+                      return (-EINVAL);
-+              }
-+              ELAN_DEBUG0 (ELAN_DBG_VP, "elanmod_classify_cap: returning ELAN_CAP_RMS\n");
-+              return (ELAN_CAP_RMS);
-+      }
-+
-+      ELAN_DEBUG0 (ELAN_DBG_VP, "elanmod_classify_cap: returning ELAN_CAP_OK\n");
-+      return (ELAN_CAP_OK);
-+}
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan/elanmod_linux.c linux-2.6.9/drivers/net/qsnet/elan/elanmod_linux.c
---- clean/drivers/net/qsnet/elan/elanmod_linux.c       1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/elanmod_linux.c 2005-09-07 10:35:03.000000000 -0400
-@@ -0,0 +1,544 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: elanmod_linux.c,v 1.23.2.6 2005/09/07 14:35:03 mike Exp $"
-+/*      $Source: /cvs/master/quadrics/elanmod/modsrc/elanmod_linux.c,v $*/
-+
-+#include <qsnet/kernel.h>
-+
-+#include <elan/elanmod.h>
-+#include <elan/elanmod_linux.h>
-+
-+#include <qsnet/module.h>
-+#include <linux/sysctl.h>
-+#include <linux/init.h>
-+
-+#include <qsnet/procfs_linux.h>
-+
-+MODULE_AUTHOR("Quadrics Ltd.");
-+MODULE_DESCRIPTION("Elan support module");
-+
-+MODULE_LICENSE("GPL");
-+
-+/* elanmod.c */
-+EXPORT_SYMBOL(elanmod_classify_cap);
-+
-+/* bitmap.c */
-+#include <elan/bitmap.h>
-+
-+EXPORT_SYMBOL(bt_freebit);
-+EXPORT_SYMBOL(bt_lowbit); 
-+EXPORT_SYMBOL(bt_nextbit);
-+EXPORT_SYMBOL(bt_copy);
-+EXPORT_SYMBOL(bt_zero); 
-+EXPORT_SYMBOL(bt_fill); 
-+EXPORT_SYMBOL(bt_cmp); 
-+EXPORT_SYMBOL(bt_intersect);
-+EXPORT_SYMBOL(bt_remove); 
-+EXPORT_SYMBOL(bt_add); 
-+EXPORT_SYMBOL(bt_spans);
-+EXPORT_SYMBOL(bt_subset);  
-+EXPORT_SYMBOL(bt_up);
-+EXPORT_SYMBOL(bt_down);
-+EXPORT_SYMBOL(bt_nbits);
-+
-+/* capability.c */
-+EXPORT_SYMBOL(elan_nullcap);
-+EXPORT_SYMBOL(elan_detach_cap);
-+EXPORT_SYMBOL(elan_attach_cap);
-+EXPORT_SYMBOL(elan_validate_map);
-+
-+/* stats.c */
-+EXPORT_SYMBOL(elan_stats_register);
-+EXPORT_SYMBOL(elan_stats_deregister);
-+
-+/* device.c */
-+EXPORT_SYMBOL(elan_dev_deregister);
-+EXPORT_SYMBOL(elan_dev_register);
-+
-+/* debug */
-+int  elan_debug_mode = QSNET_DEBUG_BUFFER; 
-+int  elan_debug_mask;
-+
-+static struct proc_dir_entry *elan_procfs_root;
-+
-+extern void elan_procfs_init(void);
-+extern void elan_procfs_fini(void);
-+
-+static int elan_open    (struct inode *ino, struct file *fp);
-+static int elan_release (struct inode *ino, struct file *fp);
-+static int elan_ioctl   (struct inode *ino, struct file *fp, unsigned int cmd, unsigned long arg);
-+
-+static int elan_user_open    (struct inode *ino, struct file *fp);
-+static int elan_user_release (struct inode *ino, struct file *fp);
-+static int elan_user_ioctl (struct inode *ino, struct file *fp, unsigned int cmd, unsigned long arg);
-+
-+static struct file_operations elan_fops = 
-+{
-+      ioctl:   elan_ioctl,
-+      open:    elan_open,
-+      release: elan_release,
-+};
-+
-+static struct file_operations elan_user_fops = 
-+{
-+      ioctl:   elan_user_ioctl,
-+      open:    elan_user_open,
-+      release: elan_user_release,
-+};
-+
-+static int __init elan_start(void)
-+{
-+      int res;
-+
-+      elan_procfs_init(); 
-+
-+      if ((res = elan_init()) != ESUCCESS)
-+      {
-+              elan_procfs_fini();
-+              return (-res);
-+      }
-+
-+      return (0);
-+}
-+
-+static void __exit elan_exit(void)
-+{
-+      elan_fini();
-+      elan_procfs_fini();
-+}
-+
-+
-+/* Declare the module init and exit functions */
-+void
-+elan_procfs_init()
-+{
-+      struct proc_dir_entry  *p;
-+      
-+      elan_procfs_root = proc_mkdir("elan",   qsnet_procfs_root);
-+
-+      if (elan_procfs_root == NULL)
-+              return;
-+      
-+      qsnet_proc_register_hex(elan_procfs_root, "debug_mask", &elan_debug_mask, 0);
-+      qsnet_proc_register_hex(elan_procfs_root, "debug_mode", &elan_debug_mode, 0);
-+
-+      if ((p = create_proc_entry ("ioctl", 0, elan_procfs_root)) != NULL)
-+      {
-+              p->proc_fops = &elan_fops;
-+              p->data      = 0;
-+              p->owner     = THIS_MODULE;
-+      }   
-+
-+      /* user entry point */
-+      if ((p = create_proc_entry ("user", 0, elan_procfs_root)) != NULL)
-+      {
-+              p->proc_fops = &elan_user_fops;
-+              p->data      = 0;
-+              p->owner     = THIS_MODULE;
-+      }   
-+}
-+
-+void
-+elan_procfs_fini()
-+{
-+      if (elan_procfs_root == NULL)
-+              return;
-+
-+      remove_proc_entry ("debug_mask", elan_procfs_root);
-+      remove_proc_entry ("debug_mode", elan_procfs_root);
-+      
-+      remove_proc_entry ("ioctl",   elan_procfs_root); 
-+
-+      /* remove user entry point */
-+      remove_proc_entry ("user",   elan_procfs_root); 
-+      
-+      remove_proc_entry ("elan",   qsnet_procfs_root);
-+}
-+
-+module_init(elan_start);
-+module_exit(elan_exit);
-+
-+static int
-+elan_open (struct inode *inode, struct file *fp)
-+{
-+      MOD_INC_USE_COUNT;
-+      fp->private_data = NULL;
-+      return (0);
-+}
-+
-+static int
-+elan_release (struct inode *inode, struct file *fp)
-+{
-+      /* mark all caps owned by fp to be destroyed */
-+      elan_destroy_cap(fp,NULL);
-+
-+      MOD_DEC_USE_COUNT;
-+      return (0);
-+}
-+
-+static int 
-+elan_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg)
-+{
-+      int rep = 0;
-+
-+      switch (cmd) 
-+      {
-+      case ELANCTRL_STATS_GET_NEXT :
-+      {
-+              ELANCTRL_STATS_GET_NEXT_STRUCT args;
-+
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_STATS_GET_NEXT_STRUCT)))
-+                      return (-EFAULT); 
-+
-+              /* uses copyin/copyout */
-+              if (elan_stats_get_next_index(args.statidx, args.next_statidx) != 0 ) 
-+                      return (-EINVAL);       
-+
-+              break;
-+      }
-+      case ELANCTRL_STATS_FIND_INDEX :
-+      {
-+              ELANCTRL_STATS_FIND_INDEX_STRUCT args;
-+              char block_name[ELAN_STATS_NAME_MAX_LEN+1];
-+              int res;
-+
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_STATS_FIND_INDEX_STRUCT)))
-+                      return (-EFAULT); 
-+
-+              res = strncpy_from_user (block_name, args.block_name, sizeof (block_name));
-+
-+              if (res == 0 || res  == sizeof (block_name))
-+                      return -ERANGE;
-+              if (res < 0)
-+                      return res;
-+
-+              /* uses copyin/copyout */
-+              if (elan_stats_find_index(block_name, args.statidx, args.num_entries) != 0 ) 
-+                      return (-EINVAL);       
-+
-+              break;
-+      }
-+      case ELANCTRL_STATS_GET_BLOCK_INFO :
-+      {
-+              ELANCTRL_STATS_GET_BLOCK_INFO_STRUCT args;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_STATS_GET_BLOCK_INFO_STRUCT)))
-+                      return (-EFAULT);
-+
-+              /* uses copyin/copyout */
-+              if (elan_stats_get_block_info(args.statidx, args.block_name, args.num_entries) != 0 ) 
-+                      return (-EINVAL);
-+              break;          
-+      }
-+      case ELANCTRL_STATS_GET_INDEX_NAME :
-+      {
-+              ELANCTRL_STATS_GET_INDEX_NAME_STRUCT args;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_STATS_GET_INDEX_NAME_STRUCT)))
-+                      return (-EFAULT);
-+
-+              /* uses copyin/copyout */
-+              if (elan_stats_get_index_name(args.statidx, args.index, args.name) != 0 )
-+                      return (-EINVAL);
-+              break;
-+      }
-+      case ELANCTRL_STATS_CLEAR_BLOCK :
-+      {
-+              ELANCTRL_STATS_CLEAR_BLOCK_STRUCT args;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_STATS_CLEAR_BLOCK_STRUCT)))
-+                      return (-EFAULT);
-+
-+              /* statidx is not a pointer */
-+              if (elan_stats_clear_block(args.statidx) != 0 )
-+                      return (-EINVAL);
-+              break;
-+      }
-+      case ELANCTRL_STATS_GET_BLOCK :
-+      {
-+              ELANCTRL_STATS_GET_BLOCK_STRUCT args;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_STATS_GET_BLOCK_STRUCT)))
-+                      return (-EFAULT);
-+
-+              /* uses copyin/copyout */
-+              if (elan_stats_get_block(args.statidx, args.entries, args.values) != 0 )
-+                      return (-EINVAL);
-+              break;
-+      }
-+      case ELANCTRL_GET_DEVINFO :
-+      {
-+              ELANCTRL_GET_DEVINFO_STRUCT args;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_GET_DEVINFO_STRUCT)))
-+                      return (-EFAULT);
-+
-+              /* uses copyin/copyout */
-+              if (elan_get_devinfo(args.devidx, args.devinfo) != 0 )
-+                      return (-EINVAL);
-+              break;          
-+      }
-+      case ELANCTRL_GET_POSITION :
-+      {
-+              ELANCTRL_GET_POSITION_STRUCT args;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_GET_POSITION_STRUCT)))
-+                      return (-EFAULT); 
-+
-+              /* uses copyin/copyout */
-+              if (elan_get_position(args.devidx, args.position) != 0 )
-+                      return (-EINVAL);
-+              break;          
-+      }
-+      case ELANCTRL_SET_POSITION :
-+      {
-+              ELANCTRL_SET_POSITION_STRUCT args;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_SET_POSITION_STRUCT)))
-+                      return (-EFAULT);
-+
-+              /* uses copyin/copyout */
-+              if (elan_set_position(args.devidx, args.nodeId, args.numNodes) != 0 )
-+                      return (-EINVAL);       
-+              break;          
-+      }
-+      case ELANCTRL_CREATE_CAP  :
-+      {
-+              ELANCTRL_CREATE_CAP_STRUCT *args;
-+
-+              /* get space for args */
-+              KMEM_ALLOC(args, ELANCTRL_CREATE_CAP_STRUCT *, sizeof(ELANCTRL_CREATE_CAP_STRUCT), 1);
-+              if (args == NULL)
-+                      return(-ENOMEM);        
-+
-+              /* copy them */
-+              if (copy_from_user (args, (void *) arg, sizeof (ELANCTRL_CREATE_CAP_STRUCT)))
-+                      return (-EFAULT);
-+              else 
-+              {
-+                      if (((rep = elan_validate_cap(&args->cap)) != 0) || ((rep = elan_create_cap(fp,&args->cap)) != 0)) 
-+                              rep = (-rep);
-+              }
-+
-+              /* free the space */
-+              KMEM_FREE(args, sizeof(ELANCTRL_CREATE_CAP_STRUCT));
-+
-+              break;          
-+      }
-+      case ELANCTRL_DESTROY_CAP  :
-+      {
-+              ELANCTRL_DESTROY_CAP_STRUCT *args;
-+
-+              /* get space for args */
-+              KMEM_ALLOC(args, ELANCTRL_DESTROY_CAP_STRUCT *, sizeof(ELANCTRL_DESTROY_CAP_STRUCT), 1);
-+              if (args == NULL)
-+                      return(-ENOMEM);        
-+
-+              /* copy them */
-+              if (copy_from_user (args, (void *) arg, sizeof (ELANCTRL_DESTROY_CAP_STRUCT)))
-+                      rep = (-EFAULT);
-+              else 
-+              {
-+                      if (elan_destroy_cap(fp, &args->cap) != 0 )
-+                              rep = (-EINVAL);
-+              }
-+
-+              /* free the space */
-+              KMEM_FREE(args, sizeof(ELANCTRL_DESTROY_CAP_STRUCT));
-+
-+              break;          
-+      }
-+      case ELANCTRL_CREATE_VP  :
-+      {
-+              ELANCTRL_CREATE_VP_STRUCT *args;
-+
-+              /* get space for args */
-+              KMEM_ALLOC(args, ELANCTRL_CREATE_VP_STRUCT *, sizeof(ELANCTRL_CREATE_VP_STRUCT), 1);
-+              if (args == NULL)
-+                      return(-ENOMEM);        
-+
-+              /* copy them */
-+              if (copy_from_user (args, (void *) arg, sizeof (ELANCTRL_CREATE_VP_STRUCT)))
-+                      return (-EFAULT);
-+              else
-+              {
-+                      if ((elan_validate_cap( &args->map) != 0) || (elan_create_vp(fp, &args->cap, &args->map) != 0 ))
-+                              rep = (-EINVAL);        
-+              }
-+
-+              KMEM_FREE(args, sizeof(ELANCTRL_CREATE_VP_STRUCT ));
-+
-+              break;          
-+      }
-+      case ELANCTRL_DESTROY_VP  :
-+      {
-+              ELANCTRL_DESTROY_VP_STRUCT *args;
-+
-+              /* get space for args */
-+              KMEM_ALLOC(args, ELANCTRL_DESTROY_VP_STRUCT *, sizeof(ELANCTRL_DESTROY_VP_STRUCT), 1);
-+              if (args == NULL)
-+                      return(-ENOMEM);        
-+              
-+              /* copy them */
-+              if (copy_from_user (args, (void *) arg, sizeof (ELANCTRL_DESTROY_VP_STRUCT)))
-+                      rep = (-EFAULT);
-+              else 
-+              {
-+                      if (elan_destroy_vp(fp, &args->cap, &args->map) != 0 )
-+                              rep = (-EINVAL);        
-+              }
-+
-+              KMEM_FREE(args, sizeof(ELANCTRL_DESTROY_VP_STRUCT ));
-+
-+              break;          
-+      }
-+
-+      case ELANCTRL_GET_CAPS  :
-+      {
-+              ELANCTRL_GET_CAPS_STRUCT args;
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_GET_CAPS_STRUCT)))
-+                      return (-EFAULT);
-+
-+              /* uses copyin/copyout */
-+              if (elan_get_caps(args.number_of_results, args.array_size, args.caps) != 0 )
-+                      return (-EINVAL);
-+              break;          
-+      }
-+      case ELANCTRL_DEBUG_DUMP :
-+      {
-+              elan_cap_dump();
-+              elan_dev_dump();
-+
-+              break;
-+      }
-+      case ELANCTRL_DEBUG_BUFFER :
-+      {
-+              ELANCTRL_DEBUG_BUFFER_STRUCT args;
-+
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_DEBUG_BUFFER_STRUCT)))
-+                      return (-EFAULT);
-+
-+              /* uses copyin/copyout */
-+              if ((args.size = qsnet_debug_buffer (args.buffer, args.size)) != -1 &&
-+                  copy_to_user ((void *) arg, &args, sizeof (ELANCTRL_DEBUG_BUFFER_STRUCT)))
-+                      return (-EFAULT);
-+              break;
-+      }
-+      default:
-+              return (-EINVAL);
-+              break;
-+      }
-+
-+      return (rep);
-+}
-+
-+
-+static int
-+elan_user_open (struct inode *inode, struct file *fp)
-+{
-+      MOD_INC_USE_COUNT;
-+      fp->private_data = NULL;
-+      return (0);
-+}
-+
-+static int
-+elan_user_release (struct inode *inode, struct file *fp)
-+{
-+      struct elan_cap_node_struct *cap_ptr = (struct elan_cap_node_struct *)fp->private_data;
-+
-+      if (cap_ptr) {
-+              /* Remove this process from usercopy system */
-+              /* GNAT 7498: New to pass in a common owner pointer */
-+              if (elan_usercopy_detach (cap_ptr, fp) == 0)
-+                      fp->private_data = NULL;
-+      }
-+      
-+      MOD_DEC_USE_COUNT;
-+      return (0);
-+}
-+
-+static int 
-+elan_user_ioctl (struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg)
-+{
-+      int rep = 0;
-+#if !defined(NO_MMPUT) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
-+      struct elan_cap_node_struct *cap_ptr = (struct elan_cap_node_struct *)fp->private_data;
-+#endif
-+
-+      switch (cmd) 
-+      {
-+#if !defined(NO_MMPUT) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
-+      case ELANCTRL_USERCOPY_ATTACH:
-+      {
-+              ELANCTRL_USERCOPY_ATTACH_STRUCT args;
-+              
-+              /* Are we already attached ? */
-+              if (cap_ptr != NULL)
-+                      return -EAGAIN;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_USERCOPY_ATTACH_STRUCT)))
-+                      return -EFAULT; 
-+      
-+              /* Lookup the associated cap node and can check we are allowed to
-+               * access it using the supplied capability. If allowed, then associate 
-+               * our task with that cap node
-+               * We also reference count it as we then hang it off the file pointer
-+               */
-+              /* GNAT 7498: New to pass in a common owner pointer */
-+              if ((rep = elan_usercopy_attach(&args.cap, &cap_ptr, current, fp)) < 0)
-+                      return -EAGAIN;
-+              
-+              /* Hang cap node off file pointer for future usercopy ioctls */
-+              fp->private_data = (void *) cap_ptr;
-+
-+              break;  
-+      }
-+      case ELANCTRL_USERCOPY_DETACH:
-+      {
-+              /* Detach process */
-+              if (cap_ptr) {
-+                      /* Remove this process from usercopy system */
-+                      /* GNAT 7498: New to pass in a common owner pointer */
-+                      if ((rep = elan_usercopy_detach (cap_ptr, fp)) == 0)
-+                              fp->private_data = NULL;
-+              }
-+              else
-+                      rep = -EINVAL;
-+              
-+              break;  
-+      }
-+      case ELANCTRL_USERCOPY:
-+      {
-+              ELANCTRL_USERCOPY_STRUCT args;
-+              
-+              /* Check that we have previously successfully attached */
-+              if (cap_ptr == NULL)
-+                      return -EAGAIN;
-+              
-+              if (copy_from_user (&args, (void *) arg, sizeof (ELANCTRL_USERCOPY_STRUCT)))
-+                      return (-EFAULT); 
-+              
-+              /* Perform user-to-user copy */
-+              rep = elan_usercopy(args.remote, args.local, args.len, args.write, args.ctxId, cap_ptr);
-+
-+              break;
-+      }
-+#endif /* !defined(NO_MMPUT) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) */
-+      default:
-+              return (-EINVAL);
-+              break;
-+      }
-+
-+      return (rep);
-+}
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan/Makefile linux-2.6.9/drivers/net/qsnet/elan/Makefile
---- clean/drivers/net/qsnet/elan/Makefile      1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/Makefile        2005-10-10 17:47:30.000000000 -0400
-@@ -0,0 +1,15 @@
-+#
-+# Makefile for Quadrics QsNet
-+#
-+# Copyright (c) 2002-2004 Quadrics Ltd
-+#
-+# File: drivers/net/qsnet/elan/Makefile
-+#
-+
-+
-+#
-+
-+obj-$(CONFIG_QSNET)   += elan.o
-+elan-objs     := elanmod.o device.o stats.o devinfo.o capability.o usercopy.o elanmod_linux.o capability_general.o bitmap.o
-+
-+EXTRA_CFLAGS          +=  -DDEBUG -DDEBUG_PRINTF -DDEBUG_ASSERT
-diff -urN clean/drivers/net/qsnet/elan/Makefile.conf linux-2.6.9/drivers/net/qsnet/elan/Makefile.conf
---- clean/drivers/net/qsnet/elan/Makefile.conf 1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/Makefile.conf   2005-09-07 10:39:36.000000000 -0400
-@@ -0,0 +1,10 @@
-+# Flags for generating QsNet Linux Kernel Makefiles
-+MODNAME               =       elan.o
-+MODULENAME    =       elan
-+KOBJFILES     =       elanmod.o device.o stats.o devinfo.o capability.o usercopy.o elanmod_linux.o capability_general.o bitmap.o
-+EXPORT_KOBJS  =       elanmod_linux.o 
-+CONFIG_NAME   =       CONFIG_QSNET
-+SGALFC                =       
-+# EXTRALINES START
-+
-+# EXTRALINES END
-diff -urN clean/drivers/net/qsnet/elan/quadrics_version.h linux-2.6.9/drivers/net/qsnet/elan/quadrics_version.h
---- clean/drivers/net/qsnet/elan/quadrics_version.h    1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/quadrics_version.h      2005-09-07 10:39:49.000000000 -0400
-@@ -0,0 +1 @@
-+#define QUADRICS_VERSION "5.11.3qsnet"
-diff -urN clean/drivers/net/qsnet/elan/stats.c linux-2.6.9/drivers/net/qsnet/elan/stats.c
---- clean/drivers/net/qsnet/elan/stats.c       1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/stats.c 2005-04-13 05:31:47.000000000 -0400
-@@ -0,0 +1,277 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: stats.c,v 1.7 2005/04/13 09:31:47 addy Exp $"
-+/*      $Source: /cvs/master/quadrics/elanmod/modsrc/stats.c,v $*/
-+
-+#include <qsnet/kernel.h>
-+#include <elan/elanmod.h>
-+
-+static LIST_HEAD(elan_stats_list);
-+static ELAN_STATS_IDX elan_next_statidx=0;
-+
-+ELAN_STATS_STRUCT *
-+elan_stats_find(ELAN_STATS_IDX statidx)
-+{
-+      struct list_head     *tmp;
-+      ELAN_STATS_STRUCT *ptr=NULL;
-+
-+      list_for_each(tmp, &elan_stats_list) {
-+              ptr = list_entry(tmp, ELAN_STATS_STRUCT , node);
-+              if ( ptr->statidx == statidx ) 
-+                      return ptr;
-+      }
-+
-+      ELAN_DEBUG1 (ELAN_DBG_CTRL, "elan_stats_find failed %d\n", statidx);    
-+      return NULL;
-+}
-+
-+ELAN_STATS_STRUCT *
-+elan_stats_find_by_name(caddr_t block_name)
-+{
-+      struct list_head     *tmp;
-+      ELAN_STATS_STRUCT *ptr=NULL;
-+
-+      list_for_each(tmp, &elan_stats_list)    {
-+              ptr = list_entry(tmp, ELAN_STATS_STRUCT , node);
-+              if (!strcmp(ptr->block_name, block_name)) 
-+              {
-+                      ELAN_DEBUG3 (ELAN_DBG_CTRL, "elan_stats_find_by_name found %s (%d,%d)\n", block_name, ptr->statidx, ptr->num_entries);  
-+                      return ptr;
-+              }
-+      }
-+
-+      ELAN_DEBUG1 (ELAN_DBG_CTRL, "elan_stats_find_by_name failed %s\n", block_name);
-+      return NULL;
-+}
-+
-+ELAN_STATS_STRUCT *
-+elan_stats_find_next(ELAN_STATS_IDX statidx)
-+{
-+      struct list_head     *tmp;
-+      ELAN_STATS_STRUCT *ptr=NULL;
-+
-+      list_for_each(tmp, &elan_stats_list) {
-+              ptr = list_entry(tmp, ELAN_STATS_STRUCT , node);
-+        
-+              if ( ptr->statidx > statidx ) 
-+                      return ptr;       
-+      }       
-+
-+      return NULL;
-+}
-+
-+int 
-+elan_stats_get_next_index (ELAN_STATS_IDX statidx, ELAN_STATS_IDX *next_block)
-+{
-+      ELAN_STATS_STRUCT *target;
-+      ELAN_STATS_IDX        next = 0;
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      if ((target = elan_stats_find_next(statidx)) != NULL)
-+              next = target->statidx;
-+
-+      copyout(&next, next_block, sizeof(ELAN_STATS_IDX) );
-+
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return 0;
-+}
-+
-+int 
-+elan_stats_find_index  (caddr_t  block_name, ELAN_STATS_IDX *statidx,  uint *num_entries)
-+
-+{
-+      ELAN_STATS_STRUCT *target;
-+      ELAN_STATS_IDX        index   = 0;
-+      uint                  entries = 0;
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      ELAN_DEBUG1(ELAN_DBG_CTRL, "elan_stats_find_index %s \n", block_name);
-+
-+      if ((target = elan_stats_find_by_name(block_name)) != NULL)
-+      {
-+              index   = target->statidx;
-+              entries = target->num_entries;
-+      }
-+
-+      ELAN_DEBUG3(ELAN_DBG_CTRL, "elan_stats_find_index found %d %d (target=%p)\n", index, entries, target);
-+
-+      copyout(&index,   statidx,     sizeof(ELAN_STATS_IDX));
-+      copyout(&entries, num_entries, sizeof(uint));
-+
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return  ESUCCESS;
-+}
-+
-+int 
-+elan_stats_get_block_info (ELAN_STATS_IDX statidx, caddr_t  block_name, uint *num_entries)
-+{
-+      ELAN_STATS_STRUCT *target;
-+      int                   res=EINVAL;
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      ELAN_DEBUG1(ELAN_DBG_CTRL, "elan_stats_get_block_info statidx %d\n",statidx);
-+
-+      if ((target = elan_stats_find(statidx)) != NULL)
-+      {
-+              ELAN_DEBUG2(ELAN_DBG_CTRL, "elan_stats_get_block_info name %s entries %d\n",block_name, *num_entries);
-+              
-+              copyout( target->block_name,  block_name,  ELAN_STATS_NAME_MAX_LEN);
-+              copyout(&target->num_entries, num_entries, sizeof(uint));
-+
-+              res = ESUCCESS;
-+      }
-+
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return res;
-+}
-+
-+int 
-+elan_stats_get_index_name (ELAN_STATS_IDX statidx, uint index, caddr_t name)
-+{
-+      ELAN_STATS_STRUCT *target;
-+      int                   res=EINVAL;
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      ELAN_DEBUG2(ELAN_DBG_CTRL, "elan_stats_get_index_name statidx %d index %d\n",statidx, index);
-+
-+      if ((target = elan_stats_find(statidx)) != NULL)
-+      {
-+              if ( target->ops->elan_stats_get_name== NULL) 
-+              {
-+                      ELAN_DEBUG0(ELAN_DBG_CTRL, "elan_stats_get_index_name no callback\n");  
-+                      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+                      return  res;
-+              }
-+
-+              if ((res = target->ops->elan_stats_get_name(target->arg, index, name)) == 0)
-+                      ELAN_DEBUG1(ELAN_DBG_CTRL, "elan_stats_get_index_name name %s\n",name); 
-+
-+      }
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return  res;
-+}
-+
-+int 
-+elan_stats_get_block (ELAN_STATS_IDX statidx, uint entries, ulong *values)
-+{
-+      ELAN_STATS_STRUCT *target;
-+      int                   res=EINVAL;
-+
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      
-+      if ((target = elan_stats_find(statidx)) != NULL)
-+      {
-+              if ( target->ops->elan_stats_get_block == NULL) 
-+              {
-+                      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+                      return  res;
-+              }
-+
-+              res = target->ops->elan_stats_get_block(target->arg, entries, values);
-+      }
-+
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      return  res;
-+}
-+
-+int 
-+elan_stats_clear_block (ELAN_STATS_IDX statidx)
-+{
-+      ELAN_STATS_STRUCT *target;
-+      int                   res=EINVAL;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      if ((target = elan_stats_find(statidx)) != NULL)
-+      {
-+              if ( target->ops->elan_stats_clear_block == NULL) 
-+              {
-+                      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+                      return  res;
-+              }
-+      
-+              res = target->ops->elan_stats_clear_block(target->arg);
-+      }
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return  res;
-+}
-+
-+void
-+elan_stats_next_statidx(void)
-+{
-+      /* XXXXX need to put not in use check here incase we loop MRH */
-+      /* tho its a bigish loop :)                                   */
-+      elan_next_statidx++;
-+      if (!elan_next_statidx)
-+              elan_next_statidx++;
-+}
-+
-+int 
-+elan_stats_register (ELAN_STATS_IDX    *statidx, 
-+                      char              *block_name, 
-+                      uint               num_entries,
-+                      ELAN_STATS_OPS *ops,
-+                      void              *arg)
-+{
-+      ELAN_STATS_STRUCT *target;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+
-+      /* create it and add */
-+      KMEM_ALLOC(target, ELAN_STATS_STRUCT *, sizeof(ELAN_STATS_STRUCT), 1);
-+      if (target == NULL)
-+      {
-+              ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+              return  ENOMEM;
-+      }
-+
-+      elan_stats_next_statidx();
-+
-+      *statidx = elan_next_statidx;
-+
-+      target->statidx     = elan_next_statidx;
-+      target->num_entries = num_entries;
-+      target->ops         = ops;
-+      target->arg         = arg;
-+      strcpy(target->block_name, block_name);
-+      
-+      list_add_tail(&target->node, &elan_stats_list);
-+
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+      return  0;
-+}
-+
-+int
-+elan_stats_deregister (ELAN_STATS_IDX statidx)
-+{
-+      ELAN_STATS_STRUCT *target;
-+
-+      ELANMOD_RWLOCK_WRITE(&elan_rwlock);
-+      if ((target = elan_stats_find(statidx)) != NULL)
-+      {
-+
-+              list_del(&target->node);
-+              
-+              /* delete target entry */
-+              KMEM_FREE(target, sizeof(ELAN_STATS_STRUCT));
-+      }
-+      ELANMOD_RWLOCK_WRITE_UNLOCK(&elan_rwlock);
-+
-+      return  target == NULL ? EINVAL : 0;
-+}
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan/usercopy.c linux-2.6.9/drivers/net/qsnet/elan/usercopy.c
---- clean/drivers/net/qsnet/elan/usercopy.c    1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan/usercopy.c      2005-09-06 05:06:58.000000000 -0400
-@@ -0,0 +1,198 @@
-+/*
-+ *    Copyright (c) 2005 by Quadrics Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: usercopy.c,v 1.10.2.6 2005/09/06 09:06:58 addy Exp $"
-+/*$Source: /cvs/master/quadrics/elanmod/modsrc/usercopy.c,v $*/
-+
-+#include <qsnet/kernel.h>
-+#include <qsnet/autoconf.h>
-+
-+#include <elan/elanmod.h>
-+#include <elan/elanmod_linux.h>
-+
-+#include <linux/sched.h>
-+#include <linux/mm.h>
-+#include <linux/highmem.h>
-+#include <linux/pagemap.h>
-+
-+/*
-+ * Access another process' address space copying directly to/from user space (current)
-+ *
-+ * Remote is the non-local process memory address, which we access using get_user_pages() and kmap()
-+ * For the local memory (i.e. owned by current task) we use the standard copy_[to|from]_user interfaces
-+ *
-+ * Code based on linux/kernel/ptrace.c
-+ */
-+
-+#if defined(NO_MMPUT) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-+static size_t 
-+rw_process_vm (struct task_struct *tsk, unsigned long remote, void *local, size_t len, int write)
-+{
-+#warning "NO EXPORTED MMPUT - usercopy not possible"
-+
-+      /* Without an exported mmput() function we cannot make this
-+       * safe as the remote process may be torn down during the copy
-+       * I experimented with taking a write lock on the remote mmap_sem
-+       * but this seemed to lead to deadlocks when pagefaulting
-+       */
-+      /* GNAT 7768: We have also found that some older versions of the get_task_mm() code
-+       * in linux/sched.h call mmgrab() which is not exported in any 2.6.X kernel
-+       */
-+      return 0;
-+}
-+
-+#else
-+static size_t 
-+rw_process_vm (struct task_struct *tsk, unsigned long remote, void *local, size_t len, int write)
-+{
-+        struct mm_struct *mm;
-+        struct vm_area_struct *vma;
-+        struct page *page;
-+        void *old_buf = local;
-+
-+      if (write)
-+              ELAN_DEBUG5(ELAN_DBG_USERCOPY, "%p remote write from %p to %lx len %ld tsk %p\n",
-+                          current, local, remote, (long)len, tsk);
-+      else
-+              ELAN_DEBUG5(ELAN_DBG_USERCOPY, "%p remote read from %lx to %p len %ld tsk %p\n",
-+                          current, remote, local, (long)len, tsk);
-+
-+      /* This locks the task, grabs a reference to the mm and then unlocks the task */
-+      mm = get_task_mm(tsk);
-+
-+      if (!mm)
-+      {
-+              /* GNAT 7777: Must drop lock before returning */
-+              ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+              return 0;
-+      }
-+
-+      /* Do not try and copy from ourselves! */
-+      if (mm == current->mm)
-+      {
-+              /* GNAT 7777: Must now drop the elanmod lock as otherwise we can create a deadlock
-+               * during the mmput() due it it calling exit_mmap() for the remote process
-+               */
-+              ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+              mmput(mm);
-+              return 0;
-+      }
-+      
-+        down_read(&mm->mmap_sem);
-+
-+        /* ignore errors, just check how much was sucessfully transfered */
-+        while (len) {
-+                size_t bytes, ret, offset;
-+                void *maddr;
-+
-+                ret = get_user_pages(tsk, mm, remote, 1, write, 1, &page, &vma);
-+                if (ret <= 0)
-+                        break;
-+
-+                bytes = len;
-+                offset = remote & (PAGE_SIZE-1);
-+                if (bytes > PAGE_SIZE-offset)
-+                        bytes = PAGE_SIZE-offset;
-+
-+                maddr = kmap(page);
-+                if (write) {
-+                        if (copy_from_user(/* remote to */maddr + offset, /* user from */local, bytes))       {
-+                              kunmap(page);
-+                              page_cache_release(page);       
-+                              break;
-+                      }
-+                      set_page_dirty_lock(page);
-+                } else {
-+                        if (copy_to_user(/* user to */local, /* remote from */maddr + offset, bytes)) {
-+                              kunmap(page);
-+                              page_cache_release(page);
-+                              break;
-+                      }
-+                }
-+                kunmap(page);
-+              page_cache_release(page);
-+                len -= bytes;
-+                local += bytes;
-+                remote += bytes;
-+        }
-+
-+        up_read(&mm->mmap_sem);
-+
-+      /* GNAT 7777: Must now drop the elanmod lock as otherwise can we create a deadlock
-+       * during the mmput() due it it calling exit_mmap() in the remote process
-+       */
-+      ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+      mmput(mm);
-+
-+      /* Return num bytes copied */
-+        return local - old_buf;
-+}
-+#endif /* !defined(NO_MMPUT) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) */
-+
-+int
-+elan_usercopy (void *remote, void *local, size_t len, int write, int ctxId, struct elan_cap_node_struct *cap_ptr)
-+{
-+      int ret = 0;
-+      size_t bytes;
-+      
-+      struct task_struct *tsk;
-+
-+      /* Grab a read lock on elanmod lock 
-+       *
-+       * This prevents any process from exiting whilst the copy is in progress
-+       * as it will need to take a write lock on the elanmod lock in order to do so
-+       * As exit_fs() is called before the task is destroyed this should prevent
-+       * the remote tsk from being torn down during the copy
-+       *
-+       * It would be much easier if we could just use get_task_struct()/put_task_struct()
-+       * but __put_task_struct() is not exported by the 2.6.X kernels - sigh.
-+       */
-+      ELANMOD_RWLOCK_READ(&elan_rwlock);
-+
-+      /* Get the task handle from the cap node for the supplied ctxId */
-+      if ((ret = elan_usercopy_handle(cap_ptr, ctxId, (void **)&tsk)) < 0)
-+      {
-+              ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+              return ret;
-+      }
-+      
-+      ELAN_DEBUG6(ELAN_DBG_USERCOPY,
-+                  "elan_usercopy: remote %p local %p len %ld write %d ctxId %d tsk %p\n",
-+                  remote, local, (long) len, write, ctxId, tsk);
-+      
-+      ASSERT(tsk);
-+
-+      /* The BKL - why ??? (arch/[i386|ia64]/kernel/ptrace.c seems to hold it) */
-+//    lock_kernel();
-+
-+      bytes = rw_process_vm(tsk, (unsigned long)remote, local, len, write);
-+      
-+      if (bytes != len)
-+      {
-+              ELAN_DEBUG2(ELAN_DBG_USERCOPY, "elan_usercopy: Failed to read %ld bytes (%ld copied)\n",
-+                          (long)len, (long)bytes);
-+              ret = -EPERM;
-+      }
-+
-+      /* The BKL - why ??? (arch/[i386|ia64]/kernel/ptrace.c seems to hold it) */
-+//    unlock_kernel();
-+
-+      /* GNAT 7777: rw_process_vm() now drops the elanmod lock 
-+       *
-+       * ELANMOD_RWLOCK_READ_UNLOCK(&elan_rwlock);
-+       */
-+
-+      return ret;
-+}
-+
-+
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "linux"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan3/context.c linux-2.6.9/drivers/net/qsnet/elan3/context.c
---- clean/drivers/net/qsnet/elan3/context.c    1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan3/context.c      2005-07-20 07:35:36.000000000 -0400
-@@ -0,0 +1,2101 @@
-+/*
-+ *    Copyright (c) 1996-2002 by Quadrics Supercomputers World Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: context.c,v 1.117.2.1 2005/07/20 11:35:36 mike Exp $"
-+/*      $Source: /cvs/master/quadrics/elan3mod/elan3/os/context.c,v $ */
-+
-+#include <qsnet/kernel.h>
-+#include <qsnet/autoconf.h>
-+#include <elan/elanmod.h>
-+#include <elan3/elanregs.h>
-+#include <elan3/elandev.h>
-+#include <elan3/elanvp.h>
-+#include <elan3/elan3mmu.h>
-+#include <elan3/elanctxt.h>
-+#include <elan3/elan3mmu.h>
-+#include <elan3/elandebug.h>
-+#include <elan3/urom_addrs.h>
-+#include <elan3/thread.h>
-+#include <elan3/vmseg.h>
-+#include <elan3/elan3ops.h>
-+#include <elan3/elansyscall.h>
-+/*
-+ * Global variables configurable from /etc/system file
-+ *     (OR /etc/sysconfigtab on Digital UNIX)
-+ */
-+int ntrapped_threads   = 64;
-+int ntrapped_dmas      = 64;
-+int ntrapped_events    = E3_NonSysCntxQueueSize + 128;
-+int ntrapped_commands  = 64;
-+int noverflow_commands = 1024;
-+int nswapped_threads   = 64;
-+int nswapped_dmas      = 64;
-+
-+#define NUM_HALTOPS   8
-+
-+void *SwapListsLockInfo;
-+void *CmdLockInfo;
-+
-+static void HaltSwapContext (ELAN3_DEV *dev, void *arg);
-+
-+static char *OthersStateStrings[]  = {"others_running", "others_halting", "others_swapping", 
-+                                    "others_halting_more", "others_swapping_more", "others_swapped"};
-+
-+ELAN3_CTXT *
-+elan3_alloc (ELAN3_DEV *dev, int  kernel)
-+{
-+    ELAN3_CTXT    *ctxt;
-+    int           i;
-+    unsigned long flags;
-+
-+    PRINTF1 (DBG_DEVICE, DBG_FN, "elan3_alloc: %s\n", kernel ? "kernel" : "user");
-+
-+    KMEM_ZALLOC (ctxt, ELAN3_CTXT *, sizeof (ELAN3_CTXT), TRUE);
-+    
-+    if (ctxt == NULL)
-+      return (NULL);
-+
-+    elan_nullcap (&ctxt->Capability);
-+
-+    ctxt->Device      = dev;
-+    ctxt->OthersState = CTXT_OTHERS_SWAPPED;
-+    ctxt->RefCnt      = 1;
-+    ctxt->Position    = dev->Position;
-+
-+    if (kernel)
-+      ctxt->Status = CTXT_DETACHED | CTXT_SWAPPED_OUT | CTXT_KERNEL;
-+    else
-+      ctxt->Status = CTXT_DETACHED | CTXT_SWAPPED_OUT | CTXT_NO_LWPS;
-+
-+    ctxt->Elan3mmu = elan3mmu_alloc (ctxt);
-+
-+    kcondvar_init (&ctxt->Wait);
-+    kcondvar_init (&ctxt->CommandPortWait);
-+    kcondvar_init (&ctxt->LwpWait);
-+    kcondvar_init (&ctxt->HaltWait);
-+
-+    spin_lock_init (&ctxt->InputFaultLock);
-+
-+    kmutex_init (&ctxt->SwapListsLock);
-+    kmutex_init (&ctxt->CmdPortLock);
-+    kmutex_init (&ctxt->NetworkErrorLock);
-+    kmutex_init (&ctxt->CmdLock);
-+
-+    krwlock_init (&ctxt->VpLock);
-+
-+    KMEM_GETPAGES (ctxt->FlagPage, ELAN3_FLAGSTATS *, 1, TRUE);
-+    if (!ctxt->FlagPage)
-+      goto error;
-+    bzero ((char *) ctxt->FlagPage, PAGESIZE);
-+
-+    KMEM_ZALLOC (ctxt->CommandTraps, COMMAND_TRAP *,    sizeof (COMMAND_TRAP)    * ntrapped_commands, TRUE);
-+    if (!ctxt->CommandTraps)
-+      goto error;
-+
-+    KMEM_ZALLOC (ctxt->ThreadTraps,  THREAD_TRAP *,     sizeof (THREAD_TRAP)     * ntrapped_threads,  TRUE);
-+    if (!ctxt->ThreadTraps)
-+      goto error;
-+
-+    KMEM_ZALLOC (ctxt->DmaTraps,     DMA_TRAP *,        sizeof (DMA_TRAP)        * ntrapped_dmas,     TRUE);
-+    if (!ctxt->DmaTraps)
-+      goto error;
-+
-+    KMEM_ZALLOC (ctxt->EventCookies, EVENT_COOKIE *,    sizeof (EVENT_COOKIE)    * ntrapped_events,   TRUE);
-+    if (!ctxt->EventCookies)
-+      goto error;
-+
-+    KMEM_ZALLOC (ctxt->Commands,     CProcTrapBuf_BE *, sizeof (CProcTrapBuf_BE) * noverflow_commands,TRUE);
-+    if (!ctxt->Commands)
-+      goto error;
-+
-+    KMEM_ZALLOC (ctxt->SwapThreads,  E3_Addr *,         sizeof (E3_Addr)         * nswapped_threads,  TRUE);
-+    if (!ctxt->SwapThreads)
-+      goto error;
-+
-+    KMEM_ZALLOC (ctxt->SwapDmas,     E3_DMA_BE *,       sizeof (E3_DMA_BE)       * nswapped_dmas,     TRUE);
-+    if (!ctxt->SwapDmas)
-+      goto error;
-+
-+    /*
-+     * "slop" is defined as follows :
-+     *     number of entries REQUIRED to be left spare to consume all other traps
-+     *     up until the time that the context can be swapped out.
-+     *  
-+     * CommandTrapQ : 1 command issued by main + 1 issued by the thread processor per elan
-+     * ThreadTrapQ  : 2 from command + 2 input
-+     * DmaTrapQ     : 2 from command + 2 input
-+     * EventTrapQ   : 2 from command + 1 thread + 1 dma + 2 input + E3_NonSysCntxQueueSize
-+     */
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+    ELAN3_QUEUE_INIT (ctxt->CommandTrapQ, ntrapped_commands,  2);
-+    ELAN3_QUEUE_INIT (ctxt->ThreadTrapQ,  ntrapped_threads,   4);
-+    ELAN3_QUEUE_INIT (ctxt->DmaTrapQ,     ntrapped_dmas,      4);
-+    ELAN3_QUEUE_INIT (ctxt->EventCookieQ, ntrapped_events,    MIN(E3_NonSysCntxQueueSize + 6, ntrapped_events - 6));
-+    ELAN3_QUEUE_INIT (ctxt->CommandQ,     noverflow_commands, 0);
-+    ELAN3_QUEUE_INIT (ctxt->SwapThreadQ,  nswapped_threads,   0);
-+    ELAN3_QUEUE_INIT (ctxt->SwapDmaQ,     nswapped_dmas,      0);
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+
-+#if defined(DIGITAL_UNIX)
-+    /* Allocate the segelan for the command port */
-+    if (! kernel && elan3_segelan3_create (ctxt) == NULL)
-+    {
-+      elan3_detach(ctxt);
-+      elan3_free (ctxt);
-+      return ((ELAN3_CTXT *) NULL);
-+    }
-+#endif
-+
-+    /*
-+     * Initialise the Input Fault list 
-+     */
-+    spin_lock (&ctxt->InputFaultLock);
-+    for (i = 0; i < NUM_INPUT_FAULT_SAVE; i++)
-+      ctxt->InputFaults[i].Next = (i == (NUM_INPUT_FAULT_SAVE-1)) ? NULL : &ctxt->InputFaults[i+1];
-+    ctxt->InputFaultList = &ctxt->InputFaults[0];
-+    spin_unlock (&ctxt->InputFaultLock);
-+
-+    ReserveHaltOperations (dev, NUM_HALTOPS, TRUE);
-+    
-+    if ((ctxt->RouteTable = AllocateRouteTable (ctxt->Device, ELAN3_MAX_VPS)) == NULL)
-+    {
-+      PRINTF0 (DBG_DEVICE, DBG_FN, "elan3_alloc: cannot map route table\n");
-+      elan3_detach(ctxt);
-+      elan3_free (ctxt);
-+      return ((ELAN3_CTXT *) NULL);
-+    }  
-+
-+    return (ctxt);
-+
-+
-+ error:
-+
-+    elan3_detach(ctxt);
-+    elan3_free (ctxt);
-+    if (ctxt->FlagPage)
-+      KMEM_FREEPAGES ((void *) ctxt->FlagPage, 1);
-+    if (ctxt->CommandTraps)
-+      KMEM_FREE ((void *) ctxt->CommandTraps, sizeof (COMMAND_TRAP)    * ntrapped_commands);
-+    if (ctxt->ThreadTraps)
-+      KMEM_FREE ((void *) ctxt->ThreadTraps,  sizeof (THREAD_TRAP)     * ntrapped_threads);
-+    if (ctxt->DmaTraps)
-+      KMEM_FREE ((void *) ctxt->DmaTraps,     sizeof (DMA_TRAP)        * ntrapped_dmas);
-+    if (ctxt->EventCookies)
-+      KMEM_FREE ((void *) ctxt->EventCookies, sizeof (EVENT_COOKIE)    * ntrapped_events);
-+    if (ctxt->Commands)
-+      KMEM_FREE ((void *) ctxt->Commands,     sizeof (CProcTrapBuf_BE) * noverflow_commands);
-+    if (ctxt->SwapThreads)
-+      KMEM_FREE ((void *) ctxt->SwapThreads,  sizeof (E3_Addr)         * nswapped_threads);
-+    if (ctxt->SwapDmas)
-+      KMEM_FREE ((void *) ctxt->SwapDmas,     sizeof (E3_DMA_BE)       * nswapped_dmas);
-+
-+    kcondvar_destroy (&ctxt->Wait);
-+    kcondvar_destroy (&ctxt->CommandPortWait);
-+    kcondvar_destroy (&ctxt->LwpWait);
-+    kcondvar_destroy (&ctxt->HaltWait);
-+
-+    kmutex_destroy (&ctxt->SwapListsLock);
-+    kmutex_destroy (&ctxt->CmdLock);
-+    kmutex_destroy (&ctxt->NetworkErrorLock);
-+    spin_lock_destroy  (&ctxt->InputFaultLock);
-+
-+    krwlock_destroy (&ctxt->VpLock);
-+
-+    KMEM_FREE (ctxt, sizeof (ELAN3_CTXT));
-+
-+    return (NULL);
-+}
-+
-+void
-+elan3_free (ELAN3_CTXT *ctxt)
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    NETERR_FIXUP *nef;
-+    
-+    PRINTF1 (ctxt, DBG_FN, "elan3_free: %p \n", ctxt);
-+   
-+    elan3_removevp (ctxt, ELAN3_INVALID_PROCESS);                     /* Remove any virtual process mappings */
-+
-+#if defined(DIGITAL_UNIX)
-+    WaitForContext (ctxt);                                    /* wait for all references to this context to go away */
-+#endif
-+
-+    if (ctxt->RouteTable)
-+      FreeRouteTable (dev, ctxt->RouteTable);
-+    ctxt->RouteTable = NULL;
-+
-+    elan3mmu_free (ctxt->Elan3mmu);                           /* free of our Elan3mmu  */
-+
-+    if (ctxt->Private)                                                /* Call back to "user" to free off  */
-+      ELAN3_OP_FREE_PRIVATE (ctxt);                           /* private data */
-+
-+#if defined(DIGITAL_UNIX)
-+    if (! CTXT_IS_KERNEL(ctxt))
-+      elan3_segelan3_destroy (ctxt);                          /* Unmap the command port from the users address space. */
-+#endif
-+   
-+    ReleaseHaltOperations (dev, NUM_HALTOPS);
-+
-+    if (ctxt->Input0Resolver)
-+      CancelNetworkErrorResolver (ctxt->Input0Resolver);
-+
-+    if (ctxt->Input1Resolver)
-+      CancelNetworkErrorResolver (ctxt->Input1Resolver);
-+
-+    while ((nef = ctxt->NetworkErrorFixups) != NULL)
-+    {
-+      ctxt->NetworkErrorFixups = nef->Next;
-+
-+      CompleteNetworkErrorFixup (ctxt, nef, ESRCH);
-+    }
-+
-+    KMEM_FREEPAGES ((void *) ctxt->FlagPage, 1);
-+
-+    KMEM_FREE ((void *) ctxt->CommandTraps, sizeof (COMMAND_TRAP)    * ntrapped_commands);
-+    KMEM_FREE ((void *) ctxt->ThreadTraps,  sizeof (THREAD_TRAP)     * ntrapped_threads);
-+    KMEM_FREE ((void *) ctxt->DmaTraps,     sizeof (DMA_TRAP)        * ntrapped_dmas);
-+    KMEM_FREE ((void *) ctxt->EventCookies, sizeof (EVENT_COOKIE)    * ntrapped_events);
-+    KMEM_FREE ((void *) ctxt->Commands,     sizeof (CProcTrapBuf_BE) * noverflow_commands);
-+    KMEM_FREE ((void *) ctxt->SwapThreads,  sizeof (E3_Addr)         * nswapped_threads);
-+    KMEM_FREE ((void *) ctxt->SwapDmas,     sizeof (E3_DMA_BE)       * nswapped_dmas);
-+
-+    kcondvar_destroy (&ctxt->Wait);
-+    kcondvar_destroy (&ctxt->CommandPortWait);
-+    kcondvar_destroy (&ctxt->LwpWait);
-+    kcondvar_destroy (&ctxt->HaltWait);
-+
-+    kmutex_destroy (&ctxt->SwapListsLock);
-+    kmutex_destroy (&ctxt->CmdLock);
-+    kmutex_destroy (&ctxt->NetworkErrorLock);
-+    spin_lock_destroy  (&ctxt->InputFaultLock);
-+
-+    krwlock_destroy (&ctxt->VpLock);
-+
-+    KMEM_FREE (ctxt, sizeof (ELAN3_CTXT));
-+}
-+
-+int 
-+elan3_doattach(ELAN3_CTXT *ctxt, ELAN_CAPABILITY *cap)
-+{
-+    unsigned long pgnum = ((cap->cap_mycontext & MAX_ROOT_CONTEXT_MASK) * sizeof (E3_CommandPort)) / PAGE_SIZE;
-+    unsigned long pgoff = ((cap->cap_mycontext & MAX_ROOT_CONTEXT_MASK) * sizeof (E3_CommandPort)) & (PAGE_SIZE-1);
-+    ELAN3_DEV     *dev   = ctxt->Device;
-+    int           res   = ESUCCESS;
-+    unsigned long flags;
-+
-+    /* Map in the command port for this context */
-+    if (MapDeviceRegister (dev, ELAN3_BAR_COMMAND_PORT, &ctxt->CommandPage, pgnum * PAGE_SIZE, PAGE_SIZE, &ctxt->CommandPageHandle) != ESUCCESS)
-+    {
-+      PRINTF0 (ctxt, DBG_FN, "elan3_doattach: MapDeviceRegister failed");
-+      return (EINVAL);
-+    }
-+
-+    ctxt->CommandPort = ctxt->CommandPage + pgoff;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    res = 0;
-+    if (ELAN3_DEV_CTX_TABLE(dev,cap->cap_mycontext) != NULL)
-+      res = EBUSY;
-+    else
-+    {
-+      if ((res = elan3mmu_attach (ctxt->Device, cap->cap_mycontext, ctxt->Elan3mmu, 
-+                                  ctxt->RouteTable->Table, ctxt->RouteTable->Size-1)) == 0)
-+      {
-+          ELAN3_DEV_CTX_TABLE(dev,cap->cap_mycontext) = ctxt;
-+          ctxt->Capability                            = *cap;
-+      }
-+    }
-+
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+
-+    if (res == ESUCCESS)
-+      elan3_swapin (ctxt, CTXT_DETACHED);
-+    else 
-+    {
-+      UnmapDeviceRegister (dev, &ctxt->CommandPageHandle);
-+      ctxt->CommandPage = (ioaddr_t) 0; 
-+      ctxt->CommandPort = (ioaddr_t) 0;
-+    }
-+
-+    return (res);
-+}
-+
-+void
-+elan3_destroy_callback( void * args, ELAN_CAPABILITY *cap, ELAN_CAPABILITY *map)
-+{
-+    if (map == NULL) 
-+    {
-+      /* the cap is being destroyed */
-+      PRINTF0 (NULL, DBG_VP, "elan3_destroy_callback: the cap is being destroyed \n");
-+    }
-+    else
-+    {
-+      /* the map is being destroyed */
-+      PRINTF0 (NULL, DBG_VP, "elan3_destroy_callback: the map is being destroyed \n");
-+    }
-+}
-+
-+int
-+elan3_attach (ELAN3_CTXT *ctxt, ELAN_CAPABILITY *cap)
-+{
-+    ELAN3_DEV *dev = ctxt->Device;
-+    int type;
-+    int res;
-+
-+    switch (type = elan3_validate_cap (dev, cap, ELAN_USER_ATTACH))
-+    {
-+    case ELAN_CAP_OK:
-+      /* nothing */
-+      break;
-+
-+    case ELAN_CAP_RMS:
-+      if ((res = elan_attach_cap(cap, dev->Devinfo.dev_rail, ctxt, elan3_destroy_callback)) != 0)
-+          return res;
-+      break;
-+
-+    default:
-+      return (EINVAL);
-+    }
-+
-+    if (((res = elan3_doattach(ctxt,cap)) != ESUCCESS) && (type == ELAN_CAP_RMS))
-+      elan_detach_cap(cap, dev->Devinfo.dev_rail);
-+
-+    return res;
-+}
-+
-+void
-+elan3_detach ( ELAN3_CTXT *ctxt )
-+{
-+    ELAN3_DEV   *dev                 = ctxt->Device;
-+    int need_to_call_elanmod_detach = 0;
-+    unsigned long flags;
-+
-+    PRINTF1 (ctxt, DBG_FN, "elan3_detach: %p \n", ctxt );
-+    
-+    if (ctxt->Capability.cap_mycontext == ELAN_CAP_UNINITIALISED)
-+    {
-+      PRINTF0 (ctxt, DBG_FN, "elan3_detach: context not attached \n");
-+      return ;
-+    }
-+
-+    /* must you be in the ctx_table ?? */
-+    
-+    switch (ctxt->Capability.cap_type & ELAN_CAP_TYPE_MASK)
-+    {
-+    case ELAN_CAP_TYPE_BLOCK:
-+    case ELAN_CAP_TYPE_CYCLIC:
-+    {
-+      if (ELAN3_SYSTEM_CONTEXT (ctxt->Capability.cap_mycontext))
-+          return ;
-+
-+      if (! (ctxt->Capability.cap_type & ELAN_CAP_TYPE_HWTEST))
-+          need_to_call_elanmod_detach = 1;
-+
-+      break;
-+    } 
-+    default:
-+      return ;
-+    }
-+
-+    elan3_swapout (ctxt, CTXT_DETACHED);
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    elan3mmu_detach (dev, ctxt->Capability.cap_mycontext);
-+    ELAN3_DEV_CTX_TABLE(dev,ctxt->Capability.cap_mycontext) = NULL;
-+
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+
-+    if (ctxt->CommandPage)
-+    {
-+      UnmapDeviceRegister (dev, &ctxt->CommandPageHandle);
-+      ctxt->CommandPage = (ioaddr_t) 0;
-+    }
-+    
-+    if (need_to_call_elanmod_detach) 
-+      elan_detach_cap(&ctxt->Capability, dev->Devinfo.dev_rail);
-+
-+    elan_nullcap (&ctxt->Capability);
-+
-+}
-+
-+void
-+elan3_dodetach ( ELAN3_CTXT *ctxt )
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    unsigned long flags;
-+
-+    PRINTF1 (ctxt, DBG_FN, "elan3_dodetach: %p \n", ctxt );
-+    
-+    if (ctxt->Capability.cap_mycontext == ELAN_CAP_UNINITIALISED)
-+    {
-+      PRINTF0 (ctxt, DBG_FN, "elan3_dodetach: context not attached \n");
-+      return ;
-+    }
-+
-+    elan3_swapout (ctxt, CTXT_DETACHED);
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    elan3mmu_detach (dev, ctxt->Capability.cap_mycontext);
-+    ELAN3_DEV_CTX_TABLE(dev,ctxt->Capability.cap_mycontext) = NULL;
-+
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+
-+    if (ctxt->CommandPage)
-+    {
-+      UnmapDeviceRegister (dev, &ctxt->CommandPageHandle);
-+      ctxt->CommandPage = (ioaddr_t) 0;
-+    }
-+    
-+    elan_nullcap (&ctxt->Capability);
-+}
-+
-+void
-+elan3_swapin (ELAN3_CTXT *ctxt, int reason)
-+{
-+    ELAN3_DEV *dev = ctxt->Device;
-+    unsigned long flags;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    ASSERT (ctxt->Status & CTXT_SWAPPED_REASONS);
-+
-+    PRINTF3 (ctxt, DBG_SWAP, "elan3_swapin: status %x State %s reason %x\n", 
-+           ctxt->Status, OthersStateStrings[ctxt->OthersState], reason);
-+
-+    while (ctxt->Status & CTXT_SWAPPING_OUT)                  /* In transition */
-+      kcondvar_wait (&ctxt->LwpWait, &dev->IntrLock, &flags);
-+
-+    if (reason == CTXT_NO_LWPS && ctxt->LwpCount++ != 0)      /* Added another LWP */
-+    {
-+      spin_unlock_irqrestore (&dev->IntrLock, flags);
-+      return;
-+    }
-+
-+    if ((ctxt->Status & ~reason) & CTXT_SWAPPED_REASONS)
-+      ctxt->Status &= ~reason;
-+    else
-+    {
-+      ASSERT (ctxt->Status & CTXT_SWAPPED_OUT);
-+      ASSERT (ctxt->OthersState == CTXT_OTHERS_SWAPPED);
-+      
-+      /*
-+       * Will not be swapped out anymore, so ask the "user" to perform 
-+       * any swapping in he needs before letting the context run again.
-+       */
-+      
-+      ctxt->Status &= ~(CTXT_SWAPPED_OUT | CTXT_QUEUES_EMPTY | reason);
-+      ctxt->OthersState = CTXT_OTHERS_RUNNING;
-+
-+      if (ctxt->Input0Trap.State == CTXT_STATE_OK && ctxt->Input1Trap.State == CTXT_STATE_OK)
-+          SetInputterStateForContext (ctxt, 0, NULL);
-+      
-+      kcondvar_wakeupall (&ctxt->Wait, &dev->IntrLock);
-+    }
-+
-+    PRINTF2 (ctxt, DBG_SWAP, "elan3_swapin: all done - status %x state %s\n",
-+           ctxt->Status, OthersStateStrings[ctxt->OthersState]);
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+}
-+
-+
-+void
-+elan3_swapout (ELAN3_CTXT *ctxt, int reason)
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    int           cansleep;
-+    unsigned long flags;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    PRINTF3 (ctxt, DBG_SWAP, "elan3_swapout: status %x state %s reason %x\n", 
-+           ctxt->Status, OthersStateStrings[ctxt->OthersState], reason);
-+
-+    if (reason == CTXT_NO_LWPS)
-+    {
-+      if (--ctxt->LwpCount != 0)                              /* Still other LWPs running */
-+      {
-+          spin_unlock_irqrestore (&dev->IntrLock, flags);
-+          return;
-+      }
-+
-+      kcondvar_wakeupall (&ctxt->LwpWait, &dev->IntrLock);            /* Wakeup anyone waiting on LwpCount */
-+    }
-+    
-+    ctxt->Status |= reason;
-+    
-+    while (ctxt->Status & CTXT_SWAPPING_OUT)                  /* wait for someone else to finish swapping */
-+      kcondvar_wait (&ctxt->LwpWait, &dev->IntrLock, &flags);         /* out */
-+
-+    if (ctxt->Status & CTXT_SWAPPED_OUT)
-+    {
-+      if (reason == CTXT_NO_LWPS)                             /* Wakeup other thread waiting on LWP exit */
-+          kcondvar_wakeupall (&ctxt->LwpWait, &dev->IntrLock);
-+      
-+      spin_unlock_irqrestore (&dev->IntrLock, flags);
-+      return;
-+    }
-+    
-+    /*
-+     * mark the context as swapping out.
-+     */
-+    ctxt->Status |= CTXT_SWAPPING_OUT;
-+    
-+    if (reason != CTXT_FIXUP_NETERR)
-+    {
-+      /*
-+       * Stop all of the lwps.
-+       */
-+      while (ctxt->LwpCount)
-+      {
-+          kcondvar_wakeupall (&ctxt->Wait, &dev->IntrLock);           /* Wake up any lwps */
-+          kcondvar_wait (&ctxt->LwpWait, &dev->IntrLock, &flags);             /* then wait for them to enter elan3_swapout */
-+      }
-+    }
-+    
-+    StartSwapoutContext (ctxt, 0, NULL);
-+    for (;;)
-+    {
-+      PRINTF0 (ctxt, DBG_SWAP, "elan3_swapout: HandleExceptions\n");
-+
-+      cansleep = (HandleExceptions(ctxt, &flags) == ESUCCESS);
-+
-+      PRINTF2 (ctxt, DBG_SWAP, "elan3_swapout: OthersState=%d cansleep=%d\n", ctxt->OthersState, cansleep);
-+
-+      if (ctxt->OthersState == CTXT_OTHERS_SWAPPED)
-+          break;
-+
-+      if (cansleep)
-+          kcondvar_wait (&ctxt->Wait, &dev->IntrLock, &flags);
-+    }
-+    PRINTF0 (ctxt, DBG_SWAP, "elan3_swapout: swapped out\n");
-+    
-+    ASSERT (ELAN3_QUEUE_EMPTY (ctxt->DmaTrapQ));
-+    ASSERT (ELAN3_QUEUE_EMPTY (ctxt->ThreadTrapQ));
-+
-+    ctxt->Status |=  CTXT_SWAPPED_OUT;
-+    ctxt->Status &= ~CTXT_SWAPPING_OUT;
-+
-+    kcondvar_wakeupall (&ctxt->LwpWait, &dev->IntrLock);
-+
-+    PRINTF2 (ctxt, DBG_SWAP, "elan3_swapout: all done - status %x state %s\n",
-+           ctxt->Status, OthersStateStrings[ctxt->OthersState]);
-+
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+}
-+
-+int
-+elan3_pagefault (ELAN3_CTXT *ctxt, E3_FaultSave_BE *FaultSave, int npages)
-+{
-+    E3_Addr     elanAddr = FaultSave->s.FaultAddress;
-+    int               writeable;
-+    int               res;
-+
-+    PRINTF3 (ctxt, DBG_FAULT, "elan3_pagefault: elanAddr %08x FSR %08x : %s\n", elanAddr, FaultSave->s.FSR.Status,
-+           FaultSave->s.FSR.s.ProtFault ? "protection fault" : "pte invalid");
-+    
-+    /* Look at the FSR to determine the fault type etc */
-+    
-+    if (FaultSave->s.FSR.Status == 0)                         /* this is a target abort/parity error, so look */
-+    {                                                         /* at the PCI config space registers to determine  */
-+      ElanBusError (ctxt->Device);
-+      return (EFAULT);                                        
-+    }
-+    
-+    if (FaultSave->s.FSR.s.AlignmentErr)                      /* Alignment errors are always fatal. */
-+    {
-+      PRINTF0 (ctxt, DBG_FAULT, "elan3_pagefault: Alignment error\n");
-+      return (EFAULT);
-+    }
-+
-+    if (FaultSave->s.FSR.s.WalkBadData)                               /* Memory ECC error during a walk */
-+    {
-+      PRINTF0 (ctxt, DBG_FAULT, "elan3_pagefault: Memory ECC error during walk\n");
-+      return (EFAULT);
-+    }
-+
-+    if (!FaultSave->s.FSR.s.ProtFault &&                      /* DMA memory type changed */
-+      !FaultSave->s.FSR.s.Walking)
-+    {
-+      PRINTF0 (ctxt, DBG_FAULT, "elan3_pagefault: DMA memory type changed\n");
-+      return (EFAULT);
-+    }
-+
-+    ASSERT (FaultSave->s.FSR.s.ProtFault ?                    /* protection errors, should always have a valid pte */
-+          (!FaultSave->s.FSR.s.Walking || !(FaultSave->s.FSR.s.Level==3) ||  FaultSave->s.FSR.s.FaultPte == ELAN3_ET_PTE) : 
-+          FaultSave->s.FSR.s.FaultPte == ELAN3_ET_INVALID);   /* otherwise it must be an invalid pte */
-+
-+    /*
-+     * Determine whether to fault for a 'write' from the access permissions we need, and not
-+     * from the access type (WrAcc).
-+     */
-+    writeable = (FaultSave->s.FSR.s.AccTypePerm & (1 << FSR_WritePermBit));
-+
-+    /* Check that we have the right permissions for this access type. */
-+    if ((res = elan3mmu_checkperm (ctxt->Elan3mmu, (elanAddr&PAGEMASK), npages*PAGESIZE, FaultSave->s.FSR.s.AccTypePerm)) != 0)
-+    {
-+      PRINTF1 (ctxt, DBG_FAULT, "elan3_pagefault: %s\n", (res == ENOMEM) ? "no protection mapping" : "protection error");
-+      
-+      return (res);
-+    }
-+
-+    res = LoadElanTranslation (ctxt, (elanAddr&PAGEMASK), npages*PAGESIZE, FaultSave->s.FSR.s.ProtFault, writeable);
-+
-+    if (res == ESUCCESS)
-+    {
-+      BumpStat (ctxt->Device, PageFaults);
-+      BumpUserStat (ctxt, PageFaults);
-+    }
-+
-+    PRINTF1 (ctxt, DBG_FAULT, "elan3_pagefault: -> %d\n", res);
-+
-+    return (res);
-+}
-+
-+void
-+elan3_block_inputter (ELAN3_CTXT *ctxt, int block)
-+{
-+    ELAN3_DEV *dev = ctxt->Device;
-+    unsigned long flags;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+    
-+    if (block)
-+      ctxt->Status |= CTXT_USER_FILTERING;
-+    else
-+      ctxt->Status &= ~CTXT_USER_FILTERING;
-+
-+    if (ctxt->Capability.cap_mycontext != ELAN_CAP_UNINITIALISED)
-+      SetInputterStateForContext (ctxt, 0, NULL);
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+}
-+
-+int
-+FixupNetworkErrors (ELAN3_CTXT *ctxt, unsigned long *flags)
-+{
-+    ELAN3_DEV          *dev = ctxt->Device;
-+    NETERR_FIXUP *nef;
-+
-+    ASSERT (SPINLOCK_HELD (&dev->IntrLock));
-+    
-+    if (ctxt->NetworkErrorFixups == NULL)
-+      return (ESUCCESS);
-+
-+    spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+    
-+    kmutex_lock (&ctxt->NetworkErrorLock);                    /* single thread while fixing up errors */
-+    elan3_swapout (ctxt, CTXT_FIXUP_NETERR);
-+
-+    spin_lock_irqsave (&dev->IntrLock, *flags);
-+    while ((nef = ctxt->NetworkErrorFixups) != NULL)
-+    {
-+      ctxt->NetworkErrorFixups = nef->Next;
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+
-+      if (ELAN3_OP_FIXUP_NETWORK_ERROR (ctxt, nef) == OP_FAILED)
-+          CompleteNetworkErrorFixup (ctxt, nef, EINVAL);
-+
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+    }
-+    spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+
-+    elan3_swapin (ctxt, CTXT_FIXUP_NETERR);
-+
-+    kmutex_unlock (&ctxt->NetworkErrorLock);
-+    spin_lock_irqsave (&dev->IntrLock, *flags);
-+    return (EAGAIN);
-+}
-+
-+int
-+CompleteNetworkErrorResolver (ELAN3_CTXT *ctxt, INPUT_TRAP *trap, NETERR_RESOLVER *rvp)
-+{
-+    int state;
-+
-+    switch (rvp->Status)
-+    {
-+    case ESUCCESS:
-+      /*
-+       * the item still existed at the source - if it's a wait for EOP transaction
-+       * then the source will retry - otherwise the remote event will have been
-+       * cleared and we should execute it
-+       */
-+      PRINTF1 (ctxt, DBG_NETERR, "CompleteNetworkErrorResolver: ESUCCESS zero WaitForEopTransaction %p\n", trap->WaitForEopTransaction);
-+
-+      state = trap->WaitForEopTransaction ? CTXT_STATE_OK : CTXT_STATE_NEEDS_RESTART;
-+
-+      break;
-+
-+    case ESRCH:       
-+      /*
-+       * the item was not found at the source - we should always execute the transaction
-+       * since it will never be resent
-+       */
-+      PRINTF1 (ctxt, DBG_NETERR, "CompleteNetworkErrorResolver: ESRCH execute WaitForEopTransaction %p\n", trap->WaitForEopTransaction);
-+      state = CTXT_STATE_NEEDS_RESTART;
-+      break;
-+
-+    default:                                                  /* other errors */
-+      PRINTF1 (ctxt, DBG_NETERR, "CompleteNetworkErrorResolver: %d\n", rvp->Status);
-+      if (ElanException (ctxt, EXCEPTION_NETWORK_ERROR, INPUT_PROC, trap, &rvp) == OP_HANDLED)
-+          state = CTXT_STATE_NEEDS_RESTART;
-+      else
-+          state = CTXT_STATE_OK;
-+      break;
-+    }
-+
-+    FreeNetworkErrorResolver (rvp);
-+
-+    return (state);
-+}
-+
-+int
-+HandleExceptions (ELAN3_CTXT *ctxt, unsigned long *flags)
-+{
-+    ELAN3_DEV        *dev    = ctxt->Device;
-+    THREAD_TRAP      tproc;
-+    DMA_TRAP         dproc;
-+    NETERR_RESOLVER *rvp;
-+    int                    state;
-+
-+    if (ctxt->Status & CTXT_COMMAND_OVERFLOW_ERROR)
-+    {
-+      ctxt->Status &= ~CTXT_COMMAND_OVERFLOW_ERROR;
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+      ElanException (ctxt, EXCEPTION_COMMAND_OVERFLOW, COMMAND_PROC, NULL);
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+      return (EAGAIN);
-+    }
-+    
-+    if (! ELAN3_QUEUE_BACK_EMPTY (ctxt->CommandTrapQ))
-+    {
-+      /* XXXX: unmap translations to the command port */
-+
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+      ResolveCProcTrap (ctxt);
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+      return (EAGAIN);
-+    }
-+    
-+    if (ctxt->Input0Trap.State == CTXT_STATE_TRAPPED)
-+    {
-+      ctxt->Input0Trap.State = CTXT_STATE_RESOLVING;
-+
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+      ResolveIProcTrap (ctxt, &ctxt->Input0Trap, &ctxt->Input0Resolver);
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+      return (EAGAIN);
-+    }
-+
-+    if (ctxt->Input1Trap.State == CTXT_STATE_TRAPPED)
-+    {
-+      ctxt->Input1Trap.State = CTXT_STATE_RESOLVING;
-+
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+      ResolveIProcTrap (ctxt, &ctxt->Input1Trap, &ctxt->Input1Resolver);
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+      return (EAGAIN);
-+    }
-+
-+    if ((rvp = ctxt->Input0Resolver) != NULL && rvp->Completed)
-+    {
-+      ASSERT (ctxt->Input0Trap.State == CTXT_STATE_NETWORK_ERROR);
-+
-+      ctxt->Input0Resolver = NULL;
-+      
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+      state = CompleteNetworkErrorResolver (ctxt, &ctxt->Input0Trap, rvp);
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+      ctxt->Input0Trap.State = state;
-+      return (EAGAIN);
-+    }
-+
-+    if ((rvp = ctxt->Input1Resolver) != NULL && rvp->Completed)
-+    {
-+      ASSERT (ctxt->Input1Trap.State == CTXT_STATE_NETWORK_ERROR);
-+
-+      ctxt->Input1Resolver = NULL;
-+      
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+      state = CompleteNetworkErrorResolver (ctxt,&ctxt->Input1Trap, rvp);
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+      ctxt->Input1Trap.State = state;
-+      return (EAGAIN);
-+    }
-+
-+    if (NextTProcTrap (ctxt, &tproc))
-+    {
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+      ResolveTProcTrap (ctxt, &tproc);
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+      return (EAGAIN);
-+    }
-+    ctxt->Status &= ~CTXT_THREAD_QUEUE_FULL;
-+
-+    if (NextDProcTrap (ctxt, &dproc))
-+    {
-+      spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+      ResolveDProcTrap (ctxt, &dproc);
-+      spin_lock_irqsave (&dev->IntrLock, *flags);
-+      return (EAGAIN);
-+    }
-+    ctxt->Status &= ~CTXT_DMA_QUEUE_FULL;
-+
-+    /* Handle all event interrupts. */
-+    if (! ELAN3_QUEUE_EMPTY (ctxt->EventCookieQ))
-+    {
-+      while (! ELAN3_QUEUE_EMPTY (ctxt->EventCookieQ))
-+      {
-+          E3_uint32 cookie = *ELAN3_QUEUE_FRONT (ctxt->EventCookieQ, ctxt->EventCookies);
-+
-+          ELAN3_QUEUE_REMOVE (ctxt->EventCookieQ);
-+
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+          if (ELAN3_OP_EVENT (ctxt, cookie, OP_LWP) != OP_DEFER)
-+              spin_lock_irqsave (&dev->IntrLock, *flags);
-+          else
-+          {
-+              spin_lock_irqsave (&dev->IntrLock, *flags);     /* place the cookie back on the queue. */
-+                                                              /* note we place it on the front to ensure  */
-+              ELAN3_QUEUE_ADD_FRONT (ctxt->EventCookieQ);     /* event ordering. */
-+              *ELAN3_QUEUE_FRONT (ctxt->EventCookieQ, ctxt->EventCookies) = cookie;
-+          }
-+      }
-+      return (EAGAIN);
-+    }
-+    ctxt->Status &= ~CTXT_EVENT_QUEUE_FULL;
-+
-+    if (! ELAN3_QUEUE_EMPTY (ctxt->SwapDmaQ))
-+    {
-+      while (! ELAN3_QUEUE_EMPTY (ctxt->SwapDmaQ))
-+      {
-+          E3_DMA_BE DmaDesc = *ELAN3_QUEUE_FRONT (ctxt->SwapDmaQ, ctxt->SwapDmas);
-+
-+          ELAN3_QUEUE_REMOVE (ctxt->SwapDmaQ);
-+
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+          RestartDmaDesc (ctxt, &DmaDesc);
-+          spin_lock_irqsave (&dev->IntrLock, *flags);
-+      }
-+      return (EAGAIN);
-+    }
-+    
-+    if (! ELAN3_QUEUE_EMPTY (ctxt->SwapThreadQ))
-+    {
-+      while (! ELAN3_QUEUE_EMPTY (ctxt->SwapThreadQ))
-+      {
-+          E3_Addr StackPointer = *ELAN3_QUEUE_FRONT (ctxt->SwapThreadQ, ctxt->SwapThreads);
-+
-+          ELAN3_QUEUE_REMOVE (ctxt->SwapThreadQ);
-+
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+          ReissueStackPointer (ctxt, StackPointer);
-+          spin_lock_irqsave (&dev->IntrLock, *flags);
-+      }
-+      return (EAGAIN);
-+    }
-+    
-+    switch (ctxt->OthersState)
-+    {
-+    case CTXT_OTHERS_SWAPPING:
-+      if (! (ctxt->Status & CTXT_OTHERS_REASONS))
-+          ctxt->OthersState = CTXT_OTHERS_RUNNING;
-+      else
-+          ctxt->OthersState = CTXT_OTHERS_SWAPPED;
-+
-+      PRINTF1 (ctxt, DBG_LWP, "HandleExceptions: OthersState : swapping -> %s\n", OthersStateStrings[ctxt->OthersState]);
-+          
-+      break;
-+
-+    case CTXT_OTHERS_SWAPPING_MORE:
-+      ctxt->OthersState = CTXT_OTHERS_HALTING_MORE;
-+      QueueHaltOperation (dev, 0, NULL, INT_DProcHalted | INT_TProcHalted, HaltSwapContext, ctxt);
-+
-+      PRINTF1 (ctxt, DBG_LWP, "HandleExceptions: OthersState : swapping_more -> %s\n", OthersStateStrings[ctxt->OthersState]);
-+      break;
-+    }
-+    return (ESUCCESS);
-+}
-+
-+int
-+RestartContext (ELAN3_CTXT *ctxt, unsigned long *flags)
-+{
-+    ELAN3_DEV *dev = ctxt->Device;
-+    int       res;
-+
-+    ASSERT (SPINLOCK_HELD (&dev->IntrLock));
-+
-+    PRINTF1 (ctxt, DBG_LWP, "RestartContext: status %x\n", ctxt->Status);
-+
-+    if (! (ctxt->Status & CTXT_OTHERS_REASONS))
-+    {
-+      if (! ELAN3_QUEUE_FRONT_EMPTY (ctxt->CommandTrapQ) || ! ELAN3_QUEUE_EMPTY(ctxt->CommandQ))
-+      {
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+          RestartCProcTrap (ctxt);
-+          spin_lock_irqsave (&dev->IntrLock, *flags);
-+          return (EAGAIN);
-+      }
-+
-+      if (ctxt->Input0Trap.State == CTXT_STATE_NEEDS_RESTART)
-+      {
-+          ctxt->Input0Trap.State = CTXT_STATE_EXECUTING;
-+
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+          res = RestartIProcTrap (ctxt, &ctxt->Input0Trap);
-+          spin_lock_irqsave (&dev->IntrLock, *flags);
-+          
-+          if (res == ESUCCESS)
-+              ctxt->Input0Trap.State = CTXT_STATE_OK;
-+          else
-+              ctxt->Input0Trap.State = CTXT_STATE_NEEDS_RESTART;
-+          return (EAGAIN);
-+      }
-+
-+      if (ctxt->Input1Trap.State == CTXT_STATE_NEEDS_RESTART)
-+      {
-+          ctxt->Input1Trap.State = CTXT_STATE_EXECUTING;
-+
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+          res = RestartIProcTrap (ctxt, &ctxt->Input1Trap);
-+          spin_lock_irqsave (&dev->IntrLock, *flags);
-+
-+          if (res == ESUCCESS)
-+              ctxt->Input1Trap.State = CTXT_STATE_OK;
-+          else
-+              ctxt->Input1Trap.State = CTXT_STATE_NEEDS_RESTART;
-+          return (EAGAIN);
-+      }
-+
-+      if (SetEventsNeedRestart (ctxt))
-+      {
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+          RestartSetEvents (ctxt);
-+          spin_lock_irqsave (&dev->IntrLock, *flags);
-+          return (EAGAIN);
-+      }
-+
-+      SetInputterStateForContext (ctxt, 0, NULL);
-+
-+      if (TProcNeedsRestart (ctxt))
-+      {
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+
-+          LoadCommandPortTranslation (ctxt);
-+          RestartTProcItems (ctxt);
-+          spin_lock_irqsave (&dev->IntrLock, *flags);
-+          return (EAGAIN);
-+      }
-+
-+      if (DProcNeedsRestart (ctxt))
-+      {
-+          spin_unlock_irqrestore (&dev->IntrLock, *flags);
-+          RestartDProcItems (ctxt);
-+          spin_lock_irqsave (&dev->IntrLock, *flags);
-+          return (EAGAIN);
-+      }
-+
-+      if (ELAN3_QUEUE_EMPTY (ctxt->CommandTrapQ))
-+      {
-+          PRINTF1 (ctxt, DBG_LWP, "RestartContext: setting Command Flag at %p to 0\n", &ctxt->FlagPage->CommandFlag);
-+
-+          ctxt->FlagPage->CommandFlag = 0;
-+
-+          if (ctxt->Status & CTXT_WAITING_COMMAND)
-+          {
-+              PRINTF0 (ctxt, DBG_LWP, "RestartContext: waking up threads waiting for commandport\n");
-+              
-+              ctxt->Status &= ~CTXT_WAITING_COMMAND;
-+              
-+              kcondvar_wakeupall (&ctxt->CommandPortWait, &dev->IntrLock);
-+          }
-+      }
-+    }
-+
-+    return (ESUCCESS);
-+}
-+
-+static void
-+HaltSwapContext (ELAN3_DEV *dev, void *arg)
-+{
-+    ELAN3_CTXT        *ctxt    = (ELAN3_CTXT *) arg;
-+    int                     SysCntx = (ctxt->Capability.cap_mycontext & SYS_CONTEXT_BIT);
-+    E3_ThreadQueue_BE thread;
-+    E3_DMA_BE         dma;
-+    sdramaddr_t       FPtr, BPtr;
-+    sdramaddr_t             Base, Top;
-+    u_int          *runCount;
-+    unsigned long     flags;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    ASSERT (ctxt->OthersState == CTXT_OTHERS_HALTING || ctxt->OthersState == CTXT_OTHERS_HALTING_MORE);
-+
-+    PRINTF2 (ctxt, DBG_SWAP, "HaltSwapContext: status %x state %s\n", ctxt->Status, OthersStateStrings[ctxt->OthersState]);
-+
-+    if (! (ctxt->Status & CTXT_OTHERS_REASONS))
-+    {
-+      if (ctxt->OthersState == CTXT_OTHERS_HALTING_MORE)
-+      {
-+          runCount = SysCntx ? &dev->HaltAllCount : &dev->HaltNonContext0Count;
-+
-+          if (--(*runCount) == 0)
-+              SetSchedStatusRegister (dev, 0, NULL);
-+      }
-+      ctxt->OthersState = CTXT_OTHERS_RUNNING;
-+      
-+      PRINTF0 (ctxt, DBG_SWAP, "HaltSwapContext: no more reason to swap -> others_running\n");
-+
-+      kcondvar_wakeupall (&ctxt->Wait, &dev->IntrLock);
-+      spin_unlock_irqrestore (&dev->IntrLock, flags);
-+      return;
-+    }
-+
-+    /*
-+     * Capture all other processors since we're not being responsive to 
-+     * the command processor interrupt.
-+     */
-+    CAPTURE_CPUS();
-+
-+    if (SysCntx)
-+    {
-+      FPtr = read_reg32 (dev, TProc_SysCntx_FPtr);
-+      BPtr = read_reg32 (dev, TProc_SysCntx_BPtr);
-+      Base = dev->TAndQBase + offsetof (E3_TrapAndQueue, SysCntxThreadQueue[0]);
-+      Top  = dev->TAndQBase + offsetof (E3_TrapAndQueue, SysCntxThreadQueue[E3_SysCntxQueueSize-1]);
-+    }
-+    else
-+    {
-+      FPtr  = read_reg32 (dev, TProc_NonSysCntx_FPtr);
-+      BPtr  = read_reg32 (dev, TProc_NonSysCntx_BPtr);
-+      Base  = dev->TAndQBase + offsetof (E3_TrapAndQueue, NonSysCntxThreadQueue[0]);
-+      Top   = dev->TAndQBase + offsetof (E3_TrapAndQueue, NonSysCntxThreadQueue[E3_NonSysCntxQueueSize-1]);
-+    }
-+
-+    while (FPtr != BPtr)
-+    {
-+      elan3_sdram_copyq_from_sdram (dev, FPtr, (void *) &thread, sizeof (E3_ThreadQueue_BE));
-+      
-+      if (thread.s.Context == ctxt->Capability.cap_mycontext)
-+      {
-+          if (ELAN3_QUEUE_FULL (ctxt->SwapThreadQ))
-+              break;
-+          
-+          *ELAN3_QUEUE_BACK(ctxt->SwapThreadQ, ctxt->SwapThreads) = thread.s.Thread;
-+          ELAN3_QUEUE_ADD (ctxt->SwapThreadQ);
-+          
-+          /*
-+           * Remove this entry from the queue by replacing it with 
-+           * the "magic" thread value.
-+           *
-+           * NOTE: we must preserve the SYS_CONTEXT_BIT since the Elan uses this
-+           * to mark the approriate run queue as empty.
-+           */
-+          thread.s.Context = SysCntx ? SYS_CONTEXT_BIT : 0;
-+          thread.s.Thread  = VanishingStackPointer;
-+
-+          elan3_sdram_copyq_to_sdram (dev, (void *) &thread, FPtr, sizeof (E3_ThreadQueue_BE));
-+      }
-+      
-+      FPtr = (FPtr == Top) ? Base : FPtr + sizeof (E3_ThreadQueue);
-+    }
-+
-+    ASSERT (elan3_sdram_readl (dev, dev->TAndQBase + offsetof (E3_TrapAndQueue, DProc.s.FSR)) == 0);
-+    ASSERT (elan3_sdram_readl (dev, dev->TAndQBase + offsetof (E3_TrapAndQueue, DProcData0.s.FSR.Status)) == 0);
-+    ASSERT (elan3_sdram_readl (dev, dev->TAndQBase + offsetof (E3_TrapAndQueue, DProcData1.s.FSR.Status)) == 0);
-+    ASSERT (elan3_sdram_readl (dev, dev->TAndQBase + offsetof (E3_TrapAndQueue, DProcData2.s.FSR.Status)) == 0);
-+    ASSERT (elan3_sdram_readl (dev, dev->TAndQBase + offsetof (E3_TrapAndQueue, DProcData3.s.FSR.Status)) == 0);
-+
-+    if (SysCntx)
-+    {
-+      FPtr  = read_reg32 (dev, DProc_SysCntx_FPtr);
-+      BPtr  = read_reg32 (dev, DProc_SysCntx_BPtr);
-+      Base  = dev->TAndQBase + offsetof (E3_TrapAndQueue, SysCntxDmaQueue[0]);
-+      Top   = dev->TAndQBase + offsetof (E3_TrapAndQueue, SysCntxDmaQueue[E3_SysCntxQueueSize-1]);
-+    }
-+    else
-+    {
-+      FPtr  = read_reg32 (dev, DProc_NonSysCntx_FPtr);
-+      BPtr  = read_reg32 (dev, DProc_NonSysCntx_BPtr);
-+      Base  = dev->TAndQBase + offsetof (E3_TrapAndQueue, NonSysCntxDmaQueue[0]);
-+      Top   = dev->TAndQBase + offsetof (E3_TrapAndQueue, NonSysCntxDmaQueue[E3_NonSysCntxQueueSize-1]);
-+    }
-+
-+    while (FPtr != BPtr)
-+    {
-+      elan3_sdram_copyq_from_sdram (dev, FPtr, &dma, sizeof (E3_DMA_BE));
-+          
-+      if (dma.s.dma_u.s.Context == ctxt->Capability.cap_mycontext)
-+      {
-+          if (ELAN3_QUEUE_FULL (ctxt->SwapDmaQ))
-+              break;
-+          
-+          *ELAN3_QUEUE_BACK (ctxt->SwapDmaQ, ctxt->SwapDmas) = dma;
-+          ELAN3_QUEUE_ADD (ctxt->SwapDmaQ);
-+
-+          /*
-+           * Remove the DMA from the queue by replacing it with one with
-+           * zero size and no events.
-+           *
-+           * NOTE: we must preserve the SYS_CONTEXT_BIT since the Elan uses this
-+           * to mark the approriate run queue as empty.
-+           */
-+          dma.s.dma_type            = ((SysCntx ? SYS_CONTEXT_BIT : 0) << 16);
-+          dma.s.dma_size            = 0;
-+          dma.s.dma_source          = (E3_Addr) 0;
-+          dma.s.dma_dest            = (E3_Addr) 0;
-+          dma.s.dma_destCookieVProc = (E3_Addr) 0;
-+          dma.s.dma_srcEvent        = (E3_Addr) 0;
-+          dma.s.dma_srcCookieVProc  = (E3_Addr) 0;
-+
-+          elan3_sdram_copyq_to_sdram (dev, &dma, FPtr, sizeof (E3_DMA_BE));
-+      }
-+
-+      FPtr = (FPtr == Top) ? Base : FPtr + sizeof (E3_DMA);
-+    }
-+
-+    /*
-+     * Release the other processors now before signalling the LWP.
-+     */
-+    RELEASE_CPUS();
-+
-+    if (! ELAN3_QUEUE_FULL (ctxt->SwapDmaQ) && !ELAN3_QUEUE_FULL (ctxt->SwapThreadQ))
-+    {
-+      /*
-+       * We've compleletly emptied the elan queues of items in this
-+       * context, so we now mark it as fully swapped out.
-+       */
-+      if (ctxt->OthersState == CTXT_OTHERS_HALTING_MORE)
-+      {
-+          runCount = SysCntx ? &dev->HaltAllCount : &dev->HaltNonContext0Count;
-+          
-+          if (--(*runCount) == 0)
-+              SetSchedStatusRegister (dev, 0, NULL);
-+          
-+      }
-+      PRINTF0 (ctxt, DBG_SWAP, "HaltSwapContext: queues emptied -> others_swapping\n");
-+
-+      ctxt->OthersState = CTXT_OTHERS_SWAPPING;
-+      kcondvar_wakeupall (&ctxt->Wait, &dev->IntrLock);
-+    }
-+    else
-+    {
-+      if (ctxt->OthersState == CTXT_OTHERS_HALTING)
-+      {
-+          runCount = SysCntx ? &dev->HaltAllCount : &dev->HaltNonContext0Count;
-+          
-+          if ((*runCount)++ == 0)
-+              SetSchedStatusRegister (dev, 0, NULL);
-+      }
-+      PRINTF0 (ctxt, DBG_SWAP, "HaltSwapContext: queues not emptied -> others_swapping_more\n");
-+
-+      ctxt->OthersState = CTXT_OTHERS_SWAPPING_MORE;
-+      kcondvar_wakeupone (&ctxt->Wait, &dev->IntrLock);
-+    }
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+}
-+
-+void
-+UnloadCommandPageMapping (ELAN3_CTXT *ctxt)
-+{
-+    /*
-+     * Unload the Elan translations,  and flag the main processor to stall after 
-+     * issueing its next command.
-+     */
-+    if (ctxt->CommandPageMapping != NULL && (ctxt->Status & CTXT_COMMAND_MAPPED_ELAN))
-+    {
-+      ELAN3MMU_RGN *rgn = elan3mmu_rgnat_main (ctxt->Elan3mmu, ctxt->CommandPageMapping);
-+      
-+      if (rgn != NULL)
-+      {
-+          E3_Addr eaddr = rgn->rgn_ebase + (ctxt->CommandPageMapping - rgn->rgn_mbase);
-+          
-+          PRINTF1 (ctxt, DBG_INTR, "UnloadCommandPageMapping: unmapping command port at addr %08x\n", eaddr);
-+          
-+          elan3mmu_unload (ctxt->Elan3mmu, eaddr, PAGESIZE, PTE_UNLOAD);
-+      }
-+      
-+      ctxt->Status &= ~CTXT_COMMAND_MAPPED_ELAN;
-+    }
-+}
-+
-+void
-+StartSwapoutContext (ELAN3_CTXT *ctxt, E3_uint32 Pend, E3_uint32 *Maskp)
-+{
-+    ELAN3_DEV   *dev     = ctxt->Device;
-+    int               SysCntx = (ctxt->Capability.cap_mycontext & SYS_CONTEXT_BIT);
-+    u_int      *runCount;
-+
-+    ASSERT (SPINLOCK_HELD (&dev->IntrLock));
-+
-+    PRINTF2 (ctxt, DBG_SWAP, "StartSwapoutContext: Status %x OthersState %s\n",
-+           ctxt->Status, OthersStateStrings [ctxt->OthersState]);
-+    /*
-+     * Disable the inputters,  we should already have a reason for it.
-+     */
-+    SetInputterStateForContext (ctxt, Pend, Maskp);
-+
-+    UnloadCommandPageMapping (ctxt);
-+
-+    /* 
-+     * Flag main processor to stall after issueing next command
-+     */
-+    PRINTF1 (ctxt, DBG_SWAP, "StartSwapoutContext: setting Command Flag at %p to 1\n", &ctxt->FlagPage->CommandFlag);
-+
-+    ctxt->FlagPage->CommandFlag = 1;
-+
-+    PRINTF1 (ctxt, DBG_SWAP, "StartSwapoutContext: OthersState=%d\n", ctxt->OthersState);
-+
-+    /*
-+     * And queue a haltop to stop the queues and clear it out.
-+     */
-+    switch (ctxt->OthersState)
-+    {
-+    case CTXT_OTHERS_RUNNING:
-+      PRINTF0 (ctxt, DBG_SWAP, "StartSwapoutContext: -> others_halting\n");
-+
-+      ctxt->OthersState = CTXT_OTHERS_HALTING;
-+
-+      QueueHaltOperation (dev, Pend, Maskp, INT_DProcHalted | INT_TProcHalted, HaltSwapContext, ctxt);
-+      break;
-+      
-+    case CTXT_OTHERS_SWAPPING:
-+      PRINTF0 (ctxt, DBG_SWAP, "StartSwapoutContext: -> others_swapping_more\n");
-+      ctxt->OthersState = CTXT_OTHERS_SWAPPING_MORE;
-+
-+      runCount = SysCntx ? &dev->HaltAllCount : &dev->HaltNonContext0Count;
-+          
-+      if ((*runCount)++ == 0)
-+          SetSchedStatusRegister (dev, Pend, Maskp);
-+      break;
-+    default:
-+      PRINTF1 (ctxt, DBG_SWAP, "StartSwapoutContext: OthersState=%d\n", ctxt->OthersState);
-+      break;
-+    }
-+}
-+
-+#if defined(DIGITAL_UNIX)
-+/* temporary tweaks to priority bump */
-+int lwp_do_prio = 1;
-+int lwp_do_nxm = 1;
-+int lwp_prio = BASEPRI_USER-1;
-+#elif defined(LINUX)
-+/* This is the default nice level for the helper LWP */
-+int LwpNice = -1;
-+#endif
-+
-+int
-+elan3_lwp (ELAN3_CTXT *ctxt)
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    int                 res;
-+    unsigned long flags;
-+
-+    PRINTF1 (ctxt, DBG_LWP, "elan3_lwp: started, context 0x%x\n", ctxt->Capability.cap_mycontext);
-+
-+#if defined(DIGITAL_UNIX)
-+    {
-+        thread_t mythread = current_thread();
-+        if (lwp_do_prio && (lwp_do_nxm || !IS_NXM_TASK(mythread->task)))
-+        {
-+            mythread->priority = mythread->sched_pri = lwp_prio;
-+            mythread->max_priority = BASEPRI_HIGHEST;
-+            (void) thread_priority(mythread, lwp_prio, 0, 1);
-+        }
-+    }
-+#elif defined(LINUX)
-+    {
-+      /* Do the priority trick for the helper LWP so that it
-+       * runs in preferance to the user threads which may be
-+       * burning CPU waiting for a trap to be fixed up
-+       */
-+#ifdef NO_O1_SCHED
-+      if (LwpNice >= -20 && LwpNice < 20)
-+          current->nice = LwpNice;
-+#else
-+      set_user_nice(current, LwpNice);
-+#endif
-+    }
-+#endif
-+
-+    elan3_swapin (ctxt, CTXT_NO_LWPS);
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    /* If we're swapped out, and not detached (or exiting) then wait until we're swapped back in */
-+    /* since otherwise we could "spin" forever continually calling elan3_lwp() */
-+    if ((ctxt->Status & CTXT_SWAPPED_REASONS) && ! (ctxt->Status & (CTXT_DETACHED|CTXT_EXITING)))
-+      kcondvar_waitsig (&ctxt->Wait, &dev->IntrLock, &flags);
-+
-+    for (;;)
-+    {
-+#if defined(DIGITAL_UNIX)
-+        if (thread_should_halt(current_thread()) || 
-+            CURSIG_CHECK(task_to_proc(current_thread()->task), u.np_uthread))
-+      {
-+          PRINTF1 (ctxt, DBG_LWP, "elan3_lwp: exiting on %s\n", 
-+                   thread_should_halt(current_thread()) ? "halt" : "signal");
-+            break;
-+      }
-+#endif
-+
-+      if (ctxt->Status & CTXT_SWAPPED_REASONS)
-+      {
-+          PRINTF0 (ctxt, DBG_LWP, "elan3_lwp: exiting on swapped reasons\n");
-+          break;
-+      }
-+
-+      if (! (ctxt->inhibit))
-+      {
-+          if (FixupNetworkErrors (ctxt, &flags) == ESUCCESS &&
-+              HandleExceptions (ctxt, &flags) == ESUCCESS &&
-+              RestartContext (ctxt, &flags) == ESUCCESS)
-+              {
-+                  if (kcondvar_waitsig (&ctxt->Wait, &dev->IntrLock, &flags) == 0)
-+                  {
-+                      PRINTF0 (ctxt, DBG_LWP, "elan3_lwp: exiting by kcondvar_wait_sig()\n");
-+                      break;
-+                  }
-+              }
-+      }
-+      else
-+      {
-+          printk("elan3_lwp :: skipping as inhibited\n");
-+          if (kcondvar_waitsig (&ctxt->Wait, &dev->IntrLock, &flags) == 0)
-+          {
-+              PRINTF0 (ctxt, DBG_LWP, "elan3_lwp: exiting by kcondvar_wait_sig()\n");
-+              break;
-+          }
-+      }
-+
-+    }
-+
-+    /* Return EINVAL to elan3_syscall_lwp() when we want it to exit */
-+    res = (ctxt->Status & (CTXT_DETACHED|CTXT_EXITING)) ? EINVAL : 0;
-+
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+    
-+    elan3_swapout (ctxt, CTXT_NO_LWPS);
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+    FixupNetworkErrors (ctxt, &flags);
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+
-+    return (res);
-+}
-+
-+void
-+SetInputterStateForContext (ELAN3_CTXT *ctxt, E3_uint32 Pend, E3_uint32 *Maskp)
-+{
-+    ELAN3_DEV  *dev          = NULL;
-+    int        new_disabled = 0;
-+    int              ctxnum;
-+
-+    ASSERT (ctxt != NULL);
-+    dev  = ctxt->Device;
-+    ASSERT (SPINLOCK_HELD (&dev->IntrLock));
-+
-+    new_disabled = (ctxt->Input0Trap.State != CTXT_STATE_OK ||
-+                  ctxt->Input1Trap.State != CTXT_STATE_OK ||
-+                  (ctxt->Status & CTXT_INPUTTER_REASONS) != 0);
-+    
-+
-+    ctxnum   = ctxt->Capability.cap_mycontext;
-+
-+#ifndef __lock_lint  
-+    PRINTF2 (ctxt , DBG_IPROC, "SetInputterState: ctxnum %x %s attached\n", ctxnum, ctxt->Disabled ? "disabled " : "");
-+#endif /* __lock_lint */
-+        
-+    if (ctxt->Disabled != new_disabled)
-+    {
-+      PRINTF2 (ctxt, DBG_IPROC, "SetInputterState: ctxnum %x change %s\n", ctxnum, new_disabled ? "enabled to disabled" : "disabled to enabled");
-+      
-+      ctxt->Disabled = new_disabled;
-+
-+      /* synchronize the context filter for this context */
-+      elan3mmu_set_context_filter (dev, ctxnum, new_disabled, Pend, Maskp);
-+    }
-+}
-+
-+int
-+CheckCommandQueueFlushed (ELAN3_CTXT *ctxt, E3_uint32 cflags, int how, unsigned long *flags)
-+{
-+    ELAN3_DEV *dev    = ctxt->Device;
-+    int       delay  = 1;
-+    int i, SeenComQueueEmpty;
-+
-+    ASSERT (SPINLOCK_HELD (&dev->IntrLock));
-+    ASSERT (cflags != DmaComQueueNotEmpty || dev->HaltDmaDequeueCount != 0);
-+
-+    /*
-+     * Flush the command processor queues and poll the queue to see it it empties.
-+     */
-+    if (dev->FlushCommandCount++ == 0)
-+      SetSchedStatusRegister (dev, 0, NULL);
-+
-+    /* 
-+     * Ensure previous writes have been flushed through the write buffers
-+     */
-+    wmb(); mmiob();
-+
-+    /*
-+     * If the command processor traps,  or it's taking too long to observe
-+     * the queue as emtpy,  then we need to force the interrupt handler to 
-+     * run for us.  So queue a halt operation for the dma processor.
-+     */
-+    SeenComQueueEmpty = !(read_reg32 (dev, ComQueueStatus) & cflags);
-+    for (i = 20; i > 0 || (how & ISSUE_COMMAND_CANT_WAIT); i--)
-+    {
-+      if (SeenComQueueEmpty || (read_reg32 (dev, Exts.InterruptReg) & (INT_CProc | INT_ComQueue)))
-+          break;
-+      
-+      mb();
-+      DELAY (delay);
-+
-+      if ((delay <<= 1) == 0) delay = 1;
-+
-+      SeenComQueueEmpty = !(read_reg32 (dev, ComQueueStatus) & cflags);
-+    }
-+
-+    if (--dev->FlushCommandCount == 0)
-+      SetSchedStatusRegister (dev, 0, NULL);
-+
-+    /*
-+     * If we've seen the command queue that we're interested in with nothing in it
-+     * and the command processor has not trapped then the commands we've
-+     * issued have been successfully processed.
-+     */
-+    if (SeenComQueueEmpty && ! (read_reg32 (dev, Exts.InterruptReg) & (INT_CProc | INT_ComQueue)))
-+    {
-+      PRINTF0 (ctxt, DBG_CMD, "CheckCommandQueueFlushed: observed dma queue empty and command proc not trapped\n");
-+
-+      if (cflags == DmaComQueueNotEmpty && --dev->HaltDmaDequeueCount == 0)
-+          SetSchedStatusRegister (dev, 0, NULL);
-+
-+      return (ISSUE_COMMAND_OK);
-+    }
-+
-+    if ((how & ISSUE_COMMAND_CANT_WAIT) != 0)
-+      return (ISSUE_COMMAND_WAIT);
-+    
-+    /*
-+     * Halt the dma processor and wait for it to halt,  if the command we've issued has
-+     * trapped then the interrupt handler will have moved it to the context structure.
-+     */
-+    PRINTF0 (ctxt, DBG_CMD, "CheckCommandQueueFlushed: waiting for dproc to halt\n");
-+    QueueHaltOperation (dev, 0, NULL, INT_DProcHalted, WakeupLwp, ctxt);
-+    while (! ctxt->Halted)
-+    {
-+      PRINTF1 (ctxt, DBG_CMD, "CheckCommandQueueFlushed: waiting for Halted - %d\n", ctxt->Halted);
-+
-+      kcondvar_wait (&ctxt->HaltWait, &dev->IntrLock, flags);
-+
-+      PRINTF1 (ctxt, DBG_CMD, "CheckCommandQueueFlushed: woken for Halted - %d\n", ctxt->Halted);
-+    }
-+    ctxt->Halted = 0;
-+    
-+    PRINTF0 (ctxt, DBG_CMD, "CheckCommandQueueFlushed: dproc halted, checking for trap\n");
-+    
-+    if (cflags == DmaComQueueNotEmpty && --dev->HaltDmaDequeueCount == 0)
-+      SetSchedStatusRegister (dev, 0, NULL);
-+
-+    return (ELAN3_QUEUE_BACK_EMPTY (ctxt->CommandTrapQ) ? ISSUE_COMMAND_OK : ISSUE_COMMAND_TRAPPED);
-+}
-+
-+int
-+WaitForCommandPort (ELAN3_CTXT *ctxt)
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    int                 res;
-+    unsigned long flags;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    if (ctxt->Status & CTXT_DETACHED)
-+      res = EINVAL;
-+    else 
-+    {
-+      if (! ELAN3_QUEUE_EMPTY (ctxt->CommandTrapQ) || (ctxt->Status & CTXT_OTHERS_REASONS))
-+      {
-+          ctxt->Status |= CTXT_WAITING_COMMAND;
-+          if (CTXT_IS_KERNEL(ctxt))
-+              kcondvar_wait (&ctxt->CommandPortWait, &dev->IntrLock, &flags);
-+          else 
-+              kcondvar_waitsig (&ctxt->CommandPortWait, &dev->IntrLock, &flags);
-+      }
-+      
-+      res = (!ELAN3_QUEUE_EMPTY(ctxt->CommandTrapQ) || (ctxt->Status & CTXT_OTHERS_REASONS)) ? EAGAIN : 0;
-+    }
-+      
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+
-+    return (res);
-+}
-+
-+static char *
-+CommandName (int offset)
-+{
-+    switch (offset)
-+    {
-+    case offsetof (E3_CommandPort, PutDma):   return ("PutDma");
-+    case offsetof (E3_CommandPort, GetDma):   return ("GetDma");
-+    case offsetof (E3_CommandPort, RunThread):        return ("RunThread");
-+    case offsetof (E3_CommandPort, WaitEvent0):       return ("WaitEvent0");
-+    case offsetof (E3_CommandPort, WaitEvent1):       return ("WaitEvent1");
-+    case offsetof (E3_CommandPort, SetEvent): return ("SetEvent");
-+    default:                                  return ("Bad Command");
-+    }
-+}
-+
-+int
-+IssueCommand (ELAN3_CTXT *ctxt, unsigned cmdoff, E3_Addr value, int cflags)
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    int                 res;
-+    unsigned long flags;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    if ((! (cflags & ISSUE_COMMAND_FOR_CPROC) && !ELAN3_QUEUE_EMPTY (ctxt->CommandTrapQ)) || (ctxt->Status & CTXT_OTHERS_REASONS))
-+    {
-+      /*
-+       * Cannot issue commands for non-cproc traps if command port is trapped, 
-+       * nor if the dma/thread trap queues are full, or we're swapping out
-+       */
-+      PRINTF2 (ctxt, DBG_CMD, "IssueCommand: %s %08x -> ISSUE_COMMAND_RETRY\n",
-+               CommandName (cmdoff), value);
-+
-+      res = ISSUE_COMMAND_RETRY;
-+    }
-+    else
-+    {
-+      PRINTF2 (ctxt, DBG_CMD, "IssueCommand: %s %08x -> ISSUE_COMMAND_OK\n",
-+               CommandName (cmdoff), value);
-+
-+      mb();                                                   /* ensure writes to main memory completed */
-+      writel (value, (void *)(ctxt->CommandPort + cmdoff));           /* issue command */
-+      mmiob();                                                /* and flush through IO writes */
-+
-+      res = ISSUE_COMMAND_OK;
-+    }
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+    
-+    return (res);
-+}
-+
-+int
-+IssueDmaCommand (ELAN3_CTXT *ctxt, E3_Addr value, void *item, int how)
-+{
-+    ELAN3_DEV     *dev    = ctxt->Device;
-+    int                 res;
-+    unsigned long flags;
-+
-+    /*
-+     * Since we may be issuing a command that could trap, and we're interested in
-+     * the outcome, the command port trap resolving code must be locked out.
-+     */
-+    kmutex_lock (&ctxt->CmdLock);
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    if ((! (how & ISSUE_COMMAND_FOR_CPROC) && !ELAN3_QUEUE_EMPTY (ctxt->CommandTrapQ)) || (ctxt->Status & CTXT_OTHERS_REASONS))
-+    {
-+      PRINTF2 (ctxt, DBG_CMD, "IssueDmaCommand: PutDma %08x [%p] -> ISSUE_COMMAND_RETRY\n", value, item);
-+
-+      /*
-+       * Cannot issue commands for non-cproc traps if command port is trapped, 
-+       * nor if the dma/thread trap queues are full, or we're swapping out
-+       */
-+      spin_unlock_irqrestore (&dev->IntrLock, flags);
-+      kmutex_unlock (&ctxt->CmdLock);
-+      return (ISSUE_COMMAND_RETRY);
-+    }
-+    
-+    ASSERT (item == NULL || ctxt->CommandPortItem == NULL);
-+
-+    /*
-+     * Stop the DMA processor from removing entries from the 
-+     * command port, and force the command processor to do this.
-+     * This means that if a trap occurs then it will be the command
-+     * processor that traps.
-+     */
-+    if (dev->HaltDmaDequeueCount++ == 0)
-+      SetSchedStatusRegister (dev, 0, NULL);
-+
-+    PRINTF2 (ctxt, DBG_CMD, "IssueDmaCommand: PutDma %08x [%p]\n", value, item);
-+
-+    /*
-+     * Always issue the DMA to the 'write' command,  since we've asserted HaltDmaDequeue
-+     * the command processor will read the descriptor and transfer it to the run queue. 
-+     * The command processor looks at the dma_direction field to determine whether it is
-+     * a read or a write and whether to alter the dma_souce of the descriptr on the run 
-+     * queue
-+     */
-+    mb();                                                     /* ensure writes to main memory ccompleted */
-+    writel (value, (void *) (ctxt->CommandPort + offsetof (E3_CommandPort, PutDma)));
-+    mmiob();                                                  /* and flush through IO writes */
-+    
-+    res = CheckCommandQueueFlushed (ctxt, DmaComQueueNotEmpty, how, &flags);
-+
-+    if (res == ISSUE_COMMAND_TRAPPED)
-+    {
-+      PRINTF2 (ctxt, DBG_CMD, "IssueDmaCommand: PutDma %08x [%p] -> ISSUE_COMMAND_TRAPPED\n", value, item);
-+      /*
-+       * Remember the item we're issueing so that if the command port traps the item will not
-+       * get freed off until the descriptor has been read after the command trap has been fixed
-+       * up.
-+       */
-+      if (item != NULL)
-+          ctxt->CommandPortItem = item;
-+    }
-+
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+    kmutex_unlock (&ctxt->CmdLock);
-+
-+    return (res);
-+}
-+
-+int
-+WaitForDmaCommand (ELAN3_CTXT *ctxt, void *item, int how)
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    int           res;
-+    unsigned long flags;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    res = CheckCommandQueueFlushed (ctxt, DmaComQueueNotEmpty, how, &flags);
-+
-+    if (res == ISSUE_COMMAND_TRAPPED && item != NULL)
-+      ctxt->CommandPortItem = item;
-+
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+    
-+    return (res);
-+}
-+
-+void
-+FixupEventTrap (ELAN3_CTXT *ctxt, int proc, void *trap, E3_uint32 TrapType, E3_FaultSave_BE *FaultSaveArea, int flags)
-+{
-+    ASSERT (! CTXT_IS_KERNEL (ctxt));
-+
-+    /*
-+     * This code re-issues the part of the set event that trapped.
-+     */
-+    switch (TrapType)
-+    {
-+    case MI_ChainedEventError:
-+      ElanException (ctxt, EXCEPTION_CHAINED_EVENT, proc, trap, FaultSaveArea->s.EventAddress);
-+      break;
-+      
-+
-+    case MI_SetEventReadWait:
-+      /*
-+       * Fault occured on the read for the event location. Just re-issue
-+       * setevent using EventAddress in E3_FaultSave
-+       */
-+      PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_SetEventReadWait: re-issuing setevent %08x\n", 
-+               FaultSaveArea->s.EventAddress);
-+      
-+      ReissueEvent (ctxt, (E3_Addr) FaultSaveArea->s.EventAddress, flags);
-+      break;
-+
-+    case MI_DoSetEvent:
-+    {
-+      /*
-+       * Fault occured because the block write of a block copy event trapped.
-+       * Must grab the event type, source and dest then simulate the block copy and then
-+       * perform the set. Once the block copy is started the event location cannot be read
-+       * again.
-+       */
-+      E3_Event *EventPtr  = (E3_Event *) elan3mmu_mainaddr (ctxt->Elan3mmu, FaultSaveArea->s.EventAddress);
-+      E3_uint32 EventType = fuword (&EventPtr->ev_Type);
-+      
-+      /*
-+       * Check that the event has the block copy bit
-+       * set in it,  since we couldn't trap here if it
-+       * didn't
-+       */
-+      if ((EventType & EV_TYPE_BCOPY) != EV_TYPE_BCOPY)
-+      {
-+          PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_DoSetEvent: Unexpected type=%x\n", EventType);
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+          break;
-+      }
-+      
-+      PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_DoSetEvent: RunEventType %x\n", EventType);
-+
-+      if (RunEventType (ctxt, FaultSaveArea, EventType))
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+
-+      break;
-+    }
-+    
-+    case MI_ThreadUpdateNonSysCntxBack:
-+    case MI_ThreadUpdateSysCntxBack:
-+    {
-+      /*
-+       * Fault occured because the block write of a block copy event trapped.
-+       * Must grab the event type, source and dest then simulate the block copy and then
-+       * run the thread. Once the block copy is started the event location cannot be read
-+       * again.
-+       */
-+      E3_Event *EventPtr = (E3_Event *) elan3mmu_mainaddr (ctxt->Elan3mmu, FaultSaveArea->s.EventAddress);
-+      E3_uint32 EventType = fuword (&EventPtr->ev_Type);
-+
-+      /*
-+       * Check for the correct EventPtr type
-+       */
-+      if ((EventType & (EV_TYPE_MASK_THREAD|EV_TYPE_MASK_BCOPY)) != (EV_TYPE_BCOPY | EV_TYPE_THREAD))
-+      {
-+          PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_ThreadUpdateCntx0Back: Unexpected type=%x for setevent trap. Should be thread\n", EventType);
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+          break;
-+      }
-+      
-+      PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_ThreadUpdateCntx0Back: RunEventType %x\n", EventType);
-+      if (RunEventType (ctxt, FaultSaveArea, EventType))
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+      break;
-+    }
-+    
-+    case MI_EventIntUpdateBPtr:
-+    {
-+      /*
-+       * Fault occured because the block write of a block copy event trapped.
-+       * Must grab the event type, source and dest then simulate the block copy and then
-+       * run the dma. Once the block copy is started the event location cannot be read
-+       * again.
-+       */
-+      E3_Event *EventPtr = (E3_Event *) elan3mmu_mainaddr (ctxt->Elan3mmu, FaultSaveArea->s.EventAddress);
-+      E3_uint32 EventType = fuword (&EventPtr->ev_Type);
-+
-+      /*
-+       * Check for the correct EventPtr type
-+       */
-+      if ((EventType & (EV_TYPE_MASK_EVIRQ|EV_TYPE_MASK_BCOPY)) != (EV_TYPE_BCOPY | EV_TYPE_EVIRQ))
-+      {
-+          PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_EventIntUpdateBPtr: Unexpected type=%x\n", EventType);
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+          break;
-+      }
-+
-+      PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_EventIntUpdateBPtr: RunEventType %x\n", EventType);
-+      if (RunEventType(ctxt, FaultSaveArea, EventType))
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+      break;
-+    }
-+    
-+    case MI_RunDmaDesc:
-+    {
-+      /*
-+       * Fault occured because the block write of a block copy event trapped.
-+       * Must grab the event type, source and dest then simulate the block copy and then
-+       * run the dma. Once the block copy is started the event location cannot be read
-+       * again.
-+       */
-+      E3_Event *EventPtr = (E3_Event *) elan3mmu_mainaddr (ctxt->Elan3mmu, FaultSaveArea->s.EventAddress);
-+      E3_uint32 EventType = fuword (&EventPtr->ev_Type);
-+
-+      /*
-+       * Check for the correct EventPtr type
-+       */
-+      if ((EventType & (EV_TYPE_MASK_DMA|EV_TYPE_MASK_BCOPY)) != (EV_TYPE_BCOPY | EV_TYPE_DMA))
-+      {
-+          PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_RunDmaDesc: Unexpected type=%x\n", EventType);
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+          break;
-+      }
-+
-+      PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_RunDmaDesc: RunEventType %x\n", EventType);
-+      if (RunEventType(ctxt, FaultSaveArea, EventType))
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+      break;
-+    }
-+    
-+    case MI_WaitForCntxDmaDescRead:
-+    case MI_WaitForNonCntxDmaDescRead:
-+      /*
-+       * Fault occured on the read of the dma descriptor. Run dma using the
-+       * Fault Address in FaultSave.
-+       */
-+      PRINTF1 (ctxt, DBG_EVENT, "FixupEventTrap: MI_WaitForCntxDmaDescRead: re-issue dma at %08x\n", FaultSaveArea->s.FaultAddress);
-+      
-+      RestartDmaPtr (ctxt, FaultSaveArea->s.FaultAddress);
-+      break;
-+    
-+    case MI_FinishedSetEvent:
-+      /*
-+       * Fault occured because the block write of a block copy event trapped.
-+       * Simulate the block copy.
-+       */
-+      if (SimulateBlockCopy (ctxt, FaultSaveArea->s.EventAddress))
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+      break;
-+      
-+    case MI_BlockCopyEvent:
-+    case MI_BlockCopyWaitForReadData:
-+    {
-+      /*
-+       * Fault occured on the read or write of the data for a block copy
-+       * event. Simulate the block copy using EventAddress in E3_FaultSave. Must also sample
-+       * the event type and then perform a run.
-+       */
-+      E3_Event *EventPtr = (E3_Event *) elan3mmu_mainaddr (ctxt->Elan3mmu, FaultSaveArea->s.EventAddress);
-+      E3_uint32 EventType = fuword (&EventPtr->ev_Type);
-+
-+      PRINTF0 (ctxt, DBG_EVENT, "FixupEventTrap: MI_BlockCopyWaitForReadData: BCopy read fault in BCopy event. Simulating BCopy.\n");
-+      
-+      if (RunEventType(ctxt, FaultSaveArea, EventType))
-+          ElanException (ctxt, EXCEPTION_BAD_EVENT, proc, trap, FaultSaveArea, TrapType);
-+      break;
-+    }
-+    
-+    case MI_EventQueueOverflow:
-+    case MI_ThreadQueueOverflow:
-+    case MI_DmaQueueOverflow:
-+      /* XXXX: should handle queue overflow */
-+      PRINTF0 (ctxt, DBG_EVENT, "FixupEventTrap: Queue overflow\n");
-+
-+      ElanException (ctxt, EXCEPTION_QUEUE_OVERFLOW, proc, trap, FaultSaveArea, TrapType);
-+      break;
-+
-+    default:
-+      ElanException (ctxt, EXCEPTION_BUS_ERROR, proc, trap, FaultSaveArea, TrapType);
-+      break;
-+    }
-+}
-+
-+int
-+SimulateBlockCopy (ELAN3_CTXT *ctxt, E3_Addr EventAddress)
-+{
-+    E3_Addr  SourcePtrElan;
-+    E3_Addr  DestPtrElan;
-+    unsigned DataType;
-+    int      i;
-+
-+    if (ELAN3_OP_START_FAULT_CHECK (ctxt))
-+    {
-+      ELAN3_OP_END_FAULT_CHECK (ctxt);
-+
-+      ElanException (ctxt, EXCEPTION_FAULTED, EVENT_PROC, NULL, EventAddress);
-+      return (TRUE);
-+    }
-+
-+    SourcePtrElan = ELAN3_OP_LOAD32 (ctxt, EventAddress + offsetof (E3_BlockCopyEvent, ev_Source));
-+    DestPtrElan   = ELAN3_OP_LOAD32 (ctxt, EventAddress + offsetof (E3_BlockCopyEvent, ev_Dest));
-+    DataType      = DestPtrElan & EV_BCOPY_DTYPE_MASK;
-+    DestPtrElan  &= ~EV_BCOPY_DTYPE_MASK;
-+
-+
-+    PRINTF3 (ctxt, DBG_EVENT, "SimulateBlockCopy: Event %08x SourcePtr %08x DestPtr %08x\n",
-+           EventAddress, SourcePtrElan, DestPtrElan);
-+
-+    if (SourcePtrElan & EV_WCOPY)
-+      ELAN3_OP_STORE32 (ctxt, DestPtrElan, SourcePtrElan);
-+    else
-+    {
-+      /*
-+       * NOTE: since the block copy could be to sdram, we issue the writes backwards,
-+       *       except we MUST ensure that the last item in the block is written last.
-+       */
-+#if defined(__LITTLE_ENDIAN__)
-+      /*
-+       * For little endian cpu's we don't need to worry about the data type.
-+       */
-+      for (i = E3_BLK_SIZE-(2*sizeof (E3_uint64)); i >= 0; i -= sizeof (E3_uint64))
-+          ELAN3_OP_STORE64 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD64 (ctxt, SourcePtrElan + i));
-+
-+      i = E3_BLK_SIZE - sizeof (E3_uint64);
-+      ELAN3_OP_STORE64 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD64 (ctxt, SourcePtrElan + i));
-+#else
-+      switch (DataType)
-+      {
-+      case EV_TYPE_BCOPY_BYTE:
-+          for (i = E3_BLK_SIZE-(2*sizeof (E3_uint8)); i >= 0; i -= sizeof (E3_uint8))
-+              ELAN3_OP_STORE8 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD8 (ctxt, SourcePtrElan + i));
-+          
-+          i = E3_BLK_SIZE - sizeof (E3_uint8);
-+          ELAN3_OP_STORE8 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD8 (ctxt, SourcePtrElan + i));
-+          break;
-+
-+      case EV_TYPE_BCOPY_HWORD: 
-+          for (i = E3_BLK_SIZE-(2*sizeof (E3_uint16)); i >= 0; i -= sizeof (E3_uint16))
-+              ELAN3_OP_STORE16 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD16 (ctxt, SourcePtrElan + i));
-+          
-+          i = E3_BLK_SIZE - sizeof (E3_uint16);
-+          ELAN3_OP_STORE16 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD16 (ctxt, SourcePtrElan + i));
-+          break;
-+          
-+      case EV_TYPE_BCOPY_WORD:  
-+          for (i = E3_BLK_SIZE-(2*sizeof (E3_uint32)); i >= 0; i -= sizeof (E3_uint32))
-+              ELAN3_OP_STORE32 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD32 (ctxt, SourcePtrElan + i));
-+          
-+          i = E3_BLK_SIZE - sizeof (E3_uint32);
-+          ELAN3_OP_STORE32 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD32 (ctxt, SourcePtrElan + i));
-+          break;
-+          
-+      case EV_TYPE_BCOPY_DWORD: 
-+          for (i = E3_BLK_SIZE-(2*sizeof (E3_uint64)); i >= 0; i -= sizeof (E3_uint64))
-+              ELAN3_OP_STORE64 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD64 (ctxt, SourcePtrElan + i));
-+          
-+          i = E3_BLK_SIZE - sizeof (E3_uint64);
-+          ELAN3_OP_STORE64 (ctxt, DestPtrElan + i, ELAN3_OP_LOAD64 (ctxt, SourcePtrElan + i));
-+          break;
-+      }
-+#endif
-+    }
-+    ELAN3_OP_END_FAULT_CHECK (ctxt);
-+
-+    return (FALSE);
-+}
-+
-+void
-+ReissueEvent (ELAN3_CTXT *ctxt, E3_Addr addr, int flags)
-+{
-+    PRINTF1 (ctxt, DBG_CMD, "ReissueEvent : Event=%08x\n", addr);
-+
-+    if (IssueCommand (ctxt, offsetof (E3_CommandPort, SetEvent), addr, flags) == ISSUE_COMMAND_RETRY)
-+    {
-+      PRINTF1 (ctxt, DBG_CMD, "ReissueEvent: queue event %08x\n", addr);
-+
-+      kmutex_lock (&ctxt->SwapListsLock);
-+      ctxt->ItemCount[LIST_SETEVENT]++;
-+      ELAN3_OP_PUT_WORD_ITEM (ctxt, LIST_SETEVENT, addr);
-+      kmutex_unlock (&ctxt->SwapListsLock);
-+    }
-+}
-+
-+int
-+SetEventsNeedRestart (ELAN3_CTXT *ctxt)
-+{
-+    return (ctxt->ItemCount[LIST_SETEVENT] != 0);
-+}
-+
-+void
-+RestartSetEvents (ELAN3_CTXT *ctxt)
-+{
-+    void     *item;
-+    E3_uint32 EventPointer;
-+
-+    kmutex_lock (&ctxt->SwapListsLock);
-+    
-+    while (ctxt->ItemCount[LIST_SETEVENT])
-+    {
-+      if (! ELAN3_OP_GET_WORD_ITEM (ctxt, LIST_SETEVENT, &item, &EventPointer))
-+          ctxt->ItemCount[LIST_SETEVENT] = 0;
-+      else
-+      {
-+          if (IssueCommand (ctxt, offsetof (E3_CommandPort, SetEvent), EventPointer, FALSE) == ISSUE_COMMAND_RETRY)
-+          {
-+              ELAN3_OP_PUTBACK_ITEM (ctxt, LIST_SETEVENT, item);
-+              kmutex_unlock (&ctxt->SwapListsLock);
-+              return;
-+          }
-+          
-+          ctxt->ItemCount[LIST_SETEVENT]--;
-+          ELAN3_OP_FREE_WORD_ITEM (ctxt, item);
-+      }
-+    }
-+    kmutex_unlock (&ctxt->SwapListsLock);
-+}
-+
-+int
-+RunEventType(ELAN3_CTXT *ctxt, E3_FaultSave_BE *FaultSaveArea, E3_uint32 EventType)
-+{
-+    int failed = FALSE;
-+
-+    if ((EventType & EV_TYPE_BCOPY) != 0)
-+      failed = SimulateBlockCopy(ctxt, FaultSaveArea->s.EventAddress);
-+    
-+    if ((EventType & EV_TYPE_MASK) == EV_TYPE_THREAD)
-+      ReissueStackPointer (ctxt, EventType & ~(EV_TYPE_MASK_THREAD|EV_TYPE_MASK_BCOPY));
-+    else if ((EventType & EV_TYPE_MASK) == EV_TYPE_DMA)
-+      RestartDmaPtr (ctxt, EventType & ~(EV_TYPE_MASK_DMA|EV_TYPE_MASK_BCOPY));
-+    else if ((EventType & EV_TYPE_EVIRQ) != 0)
-+      QueueEventInterrupt (ctxt, EventType & ~(EV_TYPE_MASK_EVIRQ|EV_TYPE_MASK_BCOPY));
-+    else /* Chained event */
-+    {
-+      if ((EventType & ~EV_TYPE_BCOPY) != 0) /* not null setevent */
-+          ReissueEvent (ctxt, EventType & ~(EV_TYPE_MASK_CHAIN|EV_TYPE_MASK_BCOPY), FALSE);
-+    }
-+
-+    return (failed);
-+}
-+
-+void
-+WakeupLwp (ELAN3_DEV *dev, void *arg)
-+{
-+    ELAN3_CTXT    *ctxt = (ELAN3_CTXT *) arg;
-+    unsigned long flags;
-+
-+    PRINTF1 (ctxt, DBG_INTR, "WakeupLwp: %d\n", SPINLOCK_HELD (&dev->IntrLock));
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+    ctxt->Halted = 1;
-+    kcondvar_wakeupone (&ctxt->HaltWait, &dev->IntrLock);
-+
-+    PRINTF0 (ctxt, DBG_INTR, "WakeupLwp: woken up context\n");
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+}
-+
-+void
-+QueueEventInterrupt (ELAN3_CTXT *ctxt, E3_uint32 cookie)
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    unsigned long flags;
-+
-+    PRINTF1 (ctxt, DBG_EVENT, "QueueEventInterrupt: cookie %08x\n", cookie);
-+
-+    if (ELAN3_OP_EVENT (ctxt, cookie, OP_INTR) == OP_DEFER)
-+    {
-+      spin_lock_irqsave (&ctxt->Device->IntrLock, flags);
-+
-+      if (ELAN3_QUEUE_REALLY_FULL (ctxt->EventCookieQ))
-+      {
-+          ctxt->Status |= CTXT_COMMAND_OVERFLOW_ERROR;
-+          StartSwapoutContext (ctxt, 0, NULL);
-+      }
-+      else
-+      {
-+          *(ELAN3_QUEUE_BACK (ctxt->EventCookieQ, ctxt->EventCookies)) = cookie;
-+          
-+          ELAN3_QUEUE_ADD (ctxt->EventCookieQ);
-+          kcondvar_wakeupone (&ctxt->Wait, &dev->IntrLock);
-+          if (ELAN3_QUEUE_FULL (ctxt->EventCookieQ))
-+          {
-+              ctxt->Status |= CTXT_EVENT_QUEUE_FULL;
-+              StartSwapoutContext (ctxt, 0, NULL);
-+          }
-+      }
-+      spin_unlock_irqrestore (&ctxt->Device->IntrLock, flags);
-+    }
-+}
-+
-+int
-+ElanException (ELAN3_CTXT *ctxt, int type, int proc, void *trap, ...)
-+{
-+    int     res;
-+    va_list ap;
-+
-+    va_start (ap, trap);
-+
-+    PRINTF2 (ctxt, DBG_FN, "ElanException: proc %d type %d\n", proc, type);
-+
-+    res = ELAN3_OP_EXCEPTION (ctxt, type, proc, trap, ap);
-+
-+    va_end (ap);
-+    
-+    return (res);
-+}
-+
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "stroustrup"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan3/context_linux.c linux-2.6.9/drivers/net/qsnet/elan3/context_linux.c
---- clean/drivers/net/qsnet/elan3/context_linux.c      1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan3/context_linux.c        2004-10-28 07:51:00.000000000 -0400
-@@ -0,0 +1,229 @@
-+/*
-+ *    Copyright (c) 2003 by Quadrics Limited.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: context_linux.c,v 1.32 2004/10/28 11:51:00 david Exp $"
-+/*      $Source: /cvs/master/quadrics/elan3mod/elan3/os/context_linux.c,v $*/
-+
-+#include <qsnet/kernel.h>
-+#include <qsnet/kpte.h>
-+
-+#include <elan3/elanregs.h>
-+#include <elan3/elandev.h>
-+#include <elan3/elanvp.h>
-+#include <elan3/elan3mmu.h>
-+#include <elan3/elanctxt.h>
-+#include <elan3/elandebug.h>
-+#include <elan3/urom_addrs.h>
-+#include <elan3/thread.h>
-+
-+int
-+LoadElanTranslation (ELAN3_CTXT *ctxt, E3_Addr addr, int len, int protFault, int writeable)
-+{
-+    ELAN3MMU          *elan3mmu = ctxt->Elan3mmu;
-+    ELAN3MMU_RGN      *rgn;
-+    caddr_t           mainAddr;
-+    int                       perm;
-+    unsigned int        off;
-+    unsigned long       flags;
-+
-+    ASSERT (PAGE_ALIGNED (addr) && PAGE_ALIGNED (len));
-+
-+    PRINTF (ctxt, DBG_FAULT, "LoadElanTranslation: addr %08x len %08x%s%s\n", 
-+        addr, len, protFault ? " prot fault" : "", writeable ? " writeable" : "");
-+
-+    /* Ensure there's enough elan mmu tables for us to use */
-+    elan3mmu_expand (elan3mmu, addr, len, PTBL_LEVEL_3, 0);
-+
-+    while (len > 0) 
-+    {
-+      /*
-+       * Retrieve permission region and calculate main address
-+       */
-+      spin_lock (&elan3mmu->elan3mmu_lock);
-+
-+      rgn = elan3mmu_rgnat_elan (elan3mmu, addr);
-+      if (rgn == NULL) {
-+          PRINTF (ctxt, DBG_FAULT, "LoadElanTranslation: no permission region at %lx %p\n", 
-+              (u_long) addr, rgn);
-+          spin_unlock (&elan3mmu->elan3mmu_lock);
-+          return (EFAULT);
-+      }
-+      mainAddr = rgn->rgn_mbase + (addr - rgn->rgn_ebase);
-+
-+      ASSERT (PAGE_ALIGNED ((unsigned long)mainAddr));
-+
-+      spin_unlock (&elan3mmu->elan3mmu_lock);
-+
-+      /*
-+       * If we're tying to load a translation to the elan command port, 
-+       * then don't do it now, but mark the context to have it reloaded
-+       * just before we restart any threads. We do this because we don't
-+       * want to call into the segment driver since we could then block
-+       * waiting for the command port to become available.
-+       */
-+      if (mainAddr == ctxt->CommandPageMapping)
-+      {
-+          PRINTF (ctxt, DBG_FAULT, "LoadElanTranslation: addr=%08x maps command port\n", addr);
-+
-+          spin_lock_irqsave (&ctxt->Device->IntrLock, flags);
-+          UnloadCommandPageMapping (ctxt);
-+          spin_unlock_irqrestore (&ctxt->Device->IntrLock, flags);
-+      }
-+      else 
-+      {
-+          struct vm_area_struct *area;
-+          struct mm_struct *mm = current->mm;
-+          pte_t *ptep_ptr;
-+          pte_t  ptep_value;
-+
-+          down_read (&current->mm->mmap_sem);
-+
-+          if ((area = find_vma_intersection(mm, (unsigned long)mainAddr, (unsigned long)mainAddr + PAGESIZE)) == NULL)
-+          {
-+              PRINTF (ctxt, DBG_FAULT, "LoadElanTranslation: %p no vma\n", mainAddr);
-+              up_read (&current->mm->mmap_sem);
-+              return EFAULT;
-+          }
-+
-+          if (writeable && !(area->vm_flags & VM_WRITE)) 
-+          {
-+              PRINTF (ctxt, DBG_FAULT, "LoadElanTranslation: %p not writeable\n", mainAddr);
-+              up_read (&current->mm->mmap_sem);
-+              return EFAULT;
-+          }
-+          
-+          spin_lock (&mm->page_table_lock);
-+
-+          /* dont deference the pointer after the unmap */
-+          ptep_ptr = find_pte_map (mm, (unsigned long)mainAddr);  
-+          if (ptep_ptr) {
-+              ptep_value = *ptep_ptr;
-+              pte_unmap(ptep_ptr);
-+          }
-+
-+          PRINTF (ctxt, DBG_FAULT, "LoadElanTranslation: %p %s %s\n", 
-+                  mainAddr, writeable ? "writeable" : "readonly", 
-+                  !ptep_ptr ? "invalid" : pte_none(ptep_value) ? "none " : !pte_present(ptep_value) ? "swapped " : 
-+                  writeable && !pte_write(ptep_value) ? "COW" : "OK");
-+          
-+          if (!ptep_ptr || pte_none(ptep_value) || !pte_present(ptep_value) || (writeable && !pte_write(ptep_value))) 
-+          {  
-+              spin_unlock (&mm->page_table_lock);
-+
-+              get_user_pages (current, current->mm, (unsigned long) mainAddr, PAGE_SIZE, 
-+                              (area->vm_flags & VM_WRITE), 0, NULL, NULL);
-+
-+              spin_lock (&mm->page_table_lock);
-+
-+              /* dont deference the pointer after the unmap */
-+              ptep_ptr = find_pte_map (mm, (unsigned long)mainAddr);  
-+              if (ptep_ptr) {
-+                  ptep_value = *ptep_ptr;
-+                  pte_unmap(ptep_ptr);
-+              }
-+
-+              if (!ptep_ptr || pte_none(ptep_value) || !pte_present(ptep_value) || (writeable && !pte_write(ptep_value))) 
-+              {
-+                  spin_unlock (&mm->page_table_lock);
-+                  up_read (&current->mm->mmap_sem);
-+                  return EFAULT;
-+              }
-+          } 
-+
-+          /* don't allow user write access to kernel pages if not kernel */
-+          if (!pte_read(ptep_value))
-+          {
-+              spin_unlock (&mm->page_table_lock);
-+              up_read (&current->mm->mmap_sem);
-+              return EFAULT;
-+          }
-+
-+          if (writeable)
-+              pte_mkdirty(ptep_value);
-+          pte_mkyoung (ptep_value);
-+
-+          /* now load the elan pte */
-+          if (writeable)
-+              perm  = rgn->rgn_perm;
-+          else
-+              perm = ELAN3_PERM_READONLY(rgn->rgn_perm & ELAN3_PTE_PERM_MASK) | (rgn->rgn_perm & ~ELAN3_PTE_PERM_MASK);
-+
-+          for (off = 0; off < PAGE_SIZE; off += ELAN3_PAGE_SIZE)
-+              elan3mmu_pteload (elan3mmu, PTBL_LEVEL_3, addr + off, pte_phys(ptep_value) + off, perm, PTE_LOAD | PTE_NO_SLEEP);
-+
-+          spin_unlock (&mm->page_table_lock);
-+          up_read (&current->mm->mmap_sem);
-+      }
-+
-+      len -= PAGESIZE;
-+      addr += PAGESIZE;
-+    }
-+    return (ESUCCESS);
-+}
-+
-+
-+/*
-+ * LoadCommandPortTranslation:
-+ *    explicitly load an elan translation to the command port.
-+ *    but only do it if the command port is accessible.
-+ *
-+ *    we call this function just after we have restarted
-+ *    and trapped commands,  since when a command traps
-+ *    the elan translation to the command port is unloaded.
-+ */
-+void
-+LoadCommandPortTranslation (ELAN3_CTXT *ctxt)
-+{
-+    ELAN3MMU     *elan3mmu = ctxt->Elan3mmu;
-+    ELAN3MMU_RGN *rgn;
-+    E3_Addr       addr;
-+    int                 perm;
-+    physaddr_t    phys;
-+    unsigned int  off;
-+    unsigned long flags;
-+
-+    PRINTF (ctxt, DBG_FAULT, "LoadCommandPortTranslation: SegAddr=%p Status=%x\n", ctxt->CommandPageMapping, ctxt->Status);
-+
-+    if (ctxt->CommandPageMapping != NULL  && !(ctxt->Status & CTXT_COMMAND_MAPPED_ELAN))
-+    {
-+      spin_lock (&elan3mmu->elan3mmu_lock);
-+      
-+      rgn = elan3mmu_rgnat_main (elan3mmu, ctxt->CommandPageMapping);
-+      if (rgn == (ELAN3MMU_RGN *) NULL) 
-+      {
-+          PRINTF(ctxt, DBG_FAULT, "LoadCommandPortTranslation: no permission for command port\n");
-+          spin_unlock (&elan3mmu->elan3mmu_lock);
-+          return;
-+      }
-+      
-+      addr = rgn->rgn_ebase + (ctxt->CommandPageMapping - rgn->rgn_mbase);
-+      perm = rgn->rgn_perm;
-+      phys = kmem_to_phys((caddr_t) ctxt->CommandPage);
-+
-+      spin_lock_irqsave (&ctxt->Device->IntrLock, flags);
-+      if (ELAN3_QUEUE_EMPTY(ctxt->CommandTrapQ) && !(ctxt->Status & CTXT_OTHERS_REASONS))
-+      {
-+          PRINTF(ctxt, DBG_FAULT, "LoadCommandPortTranslation: load xlation addr=%08x phys=%llx perm=%d\n", 
-+                 addr, (unsigned long long)phys, perm);
-+
-+          ctxt->Status |= CTXT_COMMAND_MAPPED_ELAN;
-+
-+          for (off = 0; off < PAGESIZE; off += ELAN3_PAGE_SIZE)
-+              elan3mmu_pteload (elan3mmu, PTBL_LEVEL_3, addr + off, phys + off, perm, PTE_LOAD | PTE_NO_SLEEP);
-+      }
-+      spin_unlock_irqrestore (&ctxt->Device->IntrLock, flags);
-+      
-+      spin_unlock (&elan3mmu->elan3mmu_lock);
-+    }
-+}
-+
-+
-+/*
-+ * Local variables:
-+ * c-file-style: "stroustrup"
-+ * End:
-+ */
-diff -urN clean/drivers/net/qsnet/elan3/cproc.c linux-2.6.9/drivers/net/qsnet/elan3/cproc.c
---- clean/drivers/net/qsnet/elan3/cproc.c      1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.9/drivers/net/qsnet/elan3/cproc.c        2004-02-10 10:05:10.000000000 -0500
-@@ -0,0 +1,539 @@
-+/*
-+ *    Copyright (c) 1996-2002 by Quadrics Supercomputers World Ltd.
-+ * 
-+ *    For licensing information please see the supplied COPYING file
-+ *
-+ */
-+
-+#ident "@(#)$Id: cproc.c,v 1.46 2004/02/10 15:05:10 david Exp $"
-+/*      $Source: /cvs/master/quadrics/elan3mod/elan3/os/cproc.c,v $ */
-+
-+
-+#include <qsnet/kernel.h>
-+
-+#include <elan3/elanregs.h>
-+#include <elan3/elandev.h>
-+#include <elan3/elanvp.h>
-+#include <elan3/elan3mmu.h>
-+#include <elan3/elanctxt.h>
-+#include <elan3/elandebug.h>
-+#include <elan3/urom_addrs.h>
-+#include <elan3/vmseg.h>
-+
-+void
-+HandleCProcTrap (ELAN3_DEV *dev, E3_uint32 Pend, E3_uint32 *Maskp)
-+{
-+    E3_FaultSave_BE     FaultSave;
-+    CProcTrapBuf_BE   TrapBuf;
-+    COMMAND_TRAP       *trap;
-+    ELAN3_CTXT               *ctxt;
-+    sdramaddr_t         CurrTrap;
-+    sdramaddr_t         LastTrapAddr;
-+    int               NTrapEntries;
-+    int                       NewPend;
-+    unsigned long       flags;
-+
-+    /* 
-+     * Temporarily mask out the command processor interrupt, since
-+     * we may cause it be re-asserted when we re-issue the commands
-+     * from the overflow queue area.
-+     */
-+    DISABLE_INT_MASK (dev, INT_CProc | INT_ComQueue);
-+
-+    NewPend = read_reg32 (dev, Exts.InterruptReg);
-+
-+    do {
-+      if (NewPend & INT_ComQueue)
-+      {
-+          if ((read_reg32 (dev, ComQueueStatus) & ComQueueError) != 0)
-+          {
-+              printk ("elan%d: InterruptReg=%x ComQueueStatus=%x\n", dev->Instance,
-+                      read_reg32 (dev, Exts.InterruptReg), read_reg32 (dev, ComQueueStatus));
-+              panic ("elan: command queue has overflowed !!");
-+              /* NOTREACHED */
-+          }
-+
-+          BumpStat (dev, ComQueueHalfFull);
-+
-+          /*
-+           * Capture the other cpus and stop the threads processor then
-+           * allow the command processor to eagerly flush the command queue.
-+           */
-+          dev->FlushCommandCount++; dev->HaltThreadCount++;
-+          SetSchedStatusRegister (dev, Pend, Maskp);
-+
-+          CAPTURE_CPUS();
-+
-+          while ((read_reg32 (dev, ComQueueStatus) & ComQueueNotEmpty) != 0)
-+              mb();
-+          
-+          /*
-+           * Let the threads processor run again, and release the cross call.
-+           */
-+          RELEASE_CPUS();
-+
-+          dev->FlushCommandCount--; dev->HaltThreadCount--;
-+          SetSchedStatusRegister (dev, Pend, Maskp);
-+
-+          /*
-+           * Re-sample the interrupt register to see if the command processor
-+           * has trapped while flushing the queue.  Preserve the INT_ComQueue
-+           * bit, so we can clear the ComQueueStatus register later.
-+           */
-+          NewPend = (read_reg32 (dev, Exts.InterruptReg) | INT_ComQueue);
-+      }
-+      
-+      CurrTrap = dev->CommandPortTraps[dev->CurrentCommandPortTrap];
-+      
-+      if (NewPend & INT_CProc)
-+      {
-+          BumpStat (dev, CProcTraps);
-+
-+          /*
-+           * Copy the MMU Fault Save area and zero it out for future traps.
-+           */
-+          elan3_sdram_copyq_from_sdram (dev, dev->TAndQBase + offsetof (E3_TrapAndQueue, CProc), &FaultSave, sizeof (E3_FaultSave));
-+          elan3_sdram_zeroq_sdram      (dev, dev->TAndQBase + offsetof (E3_TrapAndQueue, CProc), sizeof (E3_FaultSave));
-+
-+          /*
-+           * First entry in the cproc trap save area is the value of Areg and Breg for the
-+           * uWord before the address fault.
-+           */
-+          TrapBuf.Align64 = elan3_sdram_readq (dev, CurrTrap); CurrTrap += sizeof (TrapBuf.Align64);
-+
-+          ctxt = ELAN3_DEV_CTX_TABLE(dev, (TrapBuf.r.Breg >> 16));
-+          if (ctxt == NULL)
-+          {
-+              PRINTF2 (DBG_DEVICE, DBG_INTR, "HandleCProcTrap: context invalid [%08x.%08x]\n", TrapBuf.r.Areg, TrapBuf.r.Breg);
-+              BumpStat (dev, InvalidContext);
-+          }
-+          else
-+          {
-+              if (ELAN3_QUEUE_REALLY_FULL (ctxt->CommandTrapQ))
-+              {
-+                  if ((ctxt->Status & CTXT_COMMAND_OVERFLOW_ERROR) == 0)
-+                  {
-+                      ctxt->Status |= CTXT_COMMAND_OVERFLOW_ERROR;
-+                      StartSwapoutContext (ctxt, Pend, Maskp);
-+                  }
-+              }
-+              else
-+              {
-+                  trap = ELAN3_QUEUE_BACK (ctxt->CommandTrapQ, ctxt->CommandTraps);
-+                  
-+                  trap->FaultSave     = FaultSave;
-+                  trap->Status.Status = read_reg32 (dev, Exts.CProcStatus.Status);
-+                  trap->TrapBuf       = TrapBuf;
-+                  
-+                  /*
-+                   * The command processor does not stop after it has trapped. It will continue
-+                   * to save commands for other contexts into the commands port save area.
-+                   * The valid context for the trap is held in FaultSave. As some of this
-+                   * trap code uses the context in the status register the local copy must be
-+                   * updated with the trap context.
-+                   */
-+                  trap->Status.s.Context = (TrapBuf.r.Breg >> 16);
-+                  
-+                  PRINTF4 (ctxt, DBG_INTR, "HandleCProcTrap: WakeupFnt=%x Cntx=%x SuspAddr=%x TrapType=%s\n",
-+                           trap->Status.s.WakeupFunction, trap->Status.s.Context,
-+                           trap->Status.s.SuspendAddr, MiToName(trap->Status.s.TrapType));
-+                  PRINTF2 (ctxt, DBG_INTR, "HandleCProcTrap: Areg=%08x Breg=%08x\n", 
-+                           trap->TrapBuf.r.Areg, trap->TrapBuf.r.Breg);
-+                  
-+                  if (ELAN3_OP_CPROC_TRAP (ctxt, trap) == OP_DEFER)
-+                  {
-+                      ELAN3_QUEUE_ADD (ctxt->CommandTrapQ);
-+                      
-+                      PRINTF1 (ctxt, DBG_INTR, "HandleCProcTrap: setting Command Flag at %p to 1\n", &ctxt->FlagPage->CommandFlag);
-+                      
-+                      ctxt->FlagPage->CommandFlag = 1;
-+                      
-+                      kcondvar_wakeupone (&ctxt->Wait, &dev->IntrLock);
-+                  }
-+              }
-+
-+              UnloadCommandPageMapping (ctxt);
-+          }
-+      }
-+      
-+      /*
-+       * Now change the CommandPortTrap queue.
-+       * Must stop the command processor, wait for it to stop, find the final
-+       * entry in the current cproc trap save area, reset the comm port
-+       * trap save address to the other queue, clear the command port interrupt and
-+       * set it running normally again, and then let it go again. This is not very
-+       * time critical but it would be a good idea to prevent a higher priority
-+       * interrupt from slowing down the process to prevent to fifos filling.
-+       */
-+      spin_lock_irqsave (&dev->CProcLock, flags);
-+
-+      SET_SCHED_STATUS (dev, CProcStop);
-+
-+      while ((read_reg32 (dev, Exts.SchCntReg) & CProcStopped) == 0)
-+      {
-+          PRINTF0 (DBG_DEVICE, DBG_INTR, "HandleCProcTrap: waiting for command processor to stop\n");
-+          mb();
-+      }
-+      
-+      /*
-+       * Remember how many entries are in the saved command queue,  and 
-+       * re-initialise it, before restarting the command processor.
-+       */
-+      NTrapEntries = (read_reg32 (dev, CProc_TrapSave_Addr) - dev->CommandPortTraps[dev->CurrentCommandPortTrap])/sizeof (E3_uint64);
-+      LastTrapAddr = dev->CommandPortTraps[dev->CurrentCommandPortTrap] + NTrapEntries*sizeof (TrapBuf);
-+
-+      dev->CurrentCommandPortTrap ^= 1;
-+      write_reg32 (dev, CProc_TrapSave_Addr, dev->CommandPortTraps[dev->CurrentCommandPortTrap]);
-+
-+      PRINTF1 (DBG_DEVICE, DBG_INTR, "HandleCProcTrap: command trap queue has %d entries\n", NTrapEntries);
-+
-+      if (NTrapEntries > ELAN3_COMMAND_TRAP_SIZE/sizeof (E3_uint64))
-+          panic ("HandleCProcTrap: command trap queue has overflowed\n");
-+      
-+      if (NewPend & INT_CProc)
-+      {
-+          /*
-+           * Clear the CProc interrupt and set it running normally again. Nothing should
-+           * be running now that could issue commands apart from this trap handler.
-+           */
-+          PULSE_SCHED_STATUS (dev, RestartCProc);
-+      }
-+      
-+      if (NewPend & INT_ComQueue)
-+      {
-+          /*
-+           * Write any value here to clear out the half full and error bits of the command
-+           * overflow queues. This will also remove the overflow interrupt.
-+           */
-+          write_reg32 (dev, ComQueueStatus, 0);
-+      }
-+      
-+      /*
-+       * And let the command processor start again
-+       */
-+      CLEAR_SCHED_STATUS (dev, CProcStop);
-+      
-+      /*
-+       * Now re-issue all the commands that were issued after the command port trapped.
-+       * Should halt the dma processor and force command sto be put onto the run queues
-+       * to ensure that a remote re-issued command is handled correctly. NOTE it is
-+       * not necessary to wait for the dma processor to stop and this will reduce the
-+       * performance impact. As CProcHalt is asserted all commands will be flushed
-+       * to the queues.
-+       */
-+      dev->HaltDmaDequeueCount++; dev->FlushCommandCount++;
-+      SetSchedStatusRegister (dev, Pend, Maskp);
-+      
-+      /*
-+       * XXXX: should we do a capture/release if the trap overflow
-+       *       area has a "large" number of commands in it,  since
-+       *       we will just stuff them all back in, together with 
-+       *       all those issued by the other cpus/thread processors.
-+       */
-+      while (CurrTrap != LastTrapAddr)
-+      {
-+          /* Read the next saved (but not trapped) command */
-+          TrapBuf.Align64 = elan3_sdram_readq (dev, CurrTrap); CurrTrap += sizeof (TrapBuf);
-+          
-+
-+          ctxt = ELAN3_DEV_CTX_TABLE(dev, (TrapBuf.s.ContextType >> 16));
-+          
-+          if (ctxt == NULL)
-+          {
-+              PRINTF1 (DBG_DEVICE, DBG_INTR, "HandleCProcTrap: context %x invalid\n", TrapBuf.s.ContextType >> 16);
-+              BumpStat (dev, InvalidContext);
-+          }
-+          else
-+          {
-+              if (!ELAN3_QUEUE_EMPTY (ctxt->CommandTrapQ) || (ctxt->Status & CTXT_OTHERS_REASONS))
-+              {
-+                  PRINTF3 (ctxt, DBG_INTR, "HandleCProcTrap: save command %x context %x - %08x\n",
-+                           (TrapBuf.s.ContextType>>3) & 0x3ff, TrapBuf.s.ContextType >> 17, TrapBuf.s.Addr);
-+                  
-+                  if (ELAN3_QUEUE_REALLY_FULL (ctxt->CommandQ))
-+                  {
-+                      ctxt->Status |= CTXT_COMMAND_OVERFLOW_ERROR;
-+                      StartSwapoutContext (ctxt, Pend, Maskp);
-+                  }
-+                  else
-+                  {
-+                      *ELAN3_QUEUE_BACK(ctxt->CommandQ, ctxt->Commands) = TrapBuf;
-+
-+                      ELAN3_QUEUE_ADD (ctxt->CommandQ);
-+                  }
-+                  continue;
-+              }
-+              
-+              /* Reissue the command to the command port for this context */
-+              PRINTF2 (ctxt, DBG_INTR, "HandleCProcTrap: re-issue command %x - %08x\n",
-+                       (TrapBuf.s.ContextType>>5) & 0xff, TrapBuf.s.Addr);
-+              
-+              mb();
-+              if (ELAN3_OP_CPROC_REISSUE(ctxt, &TrapBuf) != OP_HANDLED)
-+                  ((E3_uint32 *) ctxt->CommandPort)[(TrapBuf.s.ContextType>>5) & 0xff] = TrapBuf.s.Addr;
-+              mmiob();
-+          }
-+      }
-+      
-+      while ((read_reg32 (dev, ComQueueStatus) & ComQueueNotEmpty) != 0)
-+      {
-+          PRINTF0 (DBG_DEVICE, DBG_INTR, "HandleCProcTrap: waiting for queues to empty after reissueing commands\n");
-+          mb();
-+      }
-+      
-+      dev->HaltDmaDequeueCount--; dev->FlushCommandCount--;
-+      SetSchedStatusRegister (dev, Pend, Maskp);
-+      
-+      spin_unlock_irqrestore (&dev->CProcLock, flags);
-+
-+      /*
-+       * Re-read the interrupt register and see if we've got another command
-+       * port interrupt
-+       */
-+      NewPend = read_reg32 (dev, Exts.InterruptReg);
-+    } while ((NewPend & (INT_CProc | INT_ComQueue)) != 0);
-+
-+
-+    /*
-+     * Re-enable the command processor interrupt as we've finished 
-+     * polling it.
-+     */
-+    ENABLE_INT_MASK (dev, INT_CProc | INT_ComQueue);
-+}
-+
-+void
-+ResolveCProcTrap (ELAN3_CTXT *ctxt)
-+{
-+    ELAN3_DEV     *dev = ctxt->Device;
-+    COMMAND_TRAP *trap;
-+    int                 res;
-+    unsigned long flags;
-+
-+    kmutex_lock (&ctxt->CmdLock);
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    while (! ELAN3_QUEUE_BACK_EMPTY (ctxt->CommandTrapQ))
-+    {
-+      trap = ELAN3_QUEUE_MIDDLE(ctxt->CommandTrapQ, ctxt->CommandTraps);
-+      spin_unlock_irqrestore (&dev->IntrLock, flags);
-+
-+      switch (trap->Status.s.TrapType)
-+      {
-+      case MI_EventIntUpdateBPtr:
-+      case MI_ChainedEventError:
-+      case MI_EventQueueOverflow:
-+      case MI_ThreadQueueOverflow:
-+      case MI_DmaQueueOverflow:
-+          PRINTF1 (ctxt, DBG_CPROC, "ResolveCProcTrap: %s\n", MiToName (trap->Status.s.TrapType));
-+          break;
-+          
-+      default:
-+          /* All other traps are MMU related, we should have a fault address and FSR */
-+          if ((res = elan3_pagefault (ctxt, &trap->FaultSave, 1)) != ESUCCESS)
-+          {
-+              PRINTF1 (ctxt, DBG_CPROC, "ResolveCProcTrap: elan3_pagefault failed for address %08x\n", 
-+                       trap->FaultSave.s.FaultAddress);
-+              ElanException (ctxt, EXCEPTION_INVALID_ADDR, COMMAND_PROC, trap, &trap->FaultSave, res);
-+              
-+              /* Set the trap type to 0 so the command does not get re-issued */
-+              trap->Status.s.TrapType = 0;
-+          }
-+          break;
-+      }
-+      
-+      spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+      ELAN3_QUEUE_CONSUME (ctxt->CommandTrapQ);
-+    }
-+    spin_unlock_irqrestore (&dev->IntrLock, flags);
-+    kmutex_unlock (&ctxt->CmdLock);
-+}
-+
-+int
-+RestartCProcTrap (ELAN3_CTXT *ctxt)
-+{
-+    ELAN3_DEV     *dev      = ctxt->Device;
-+    COMMAND_TRAP  trap;
-+    void       *item;
-+    int                 res;
-+    unsigned long flags;
-+
-+    spin_lock_irqsave (&dev->IntrLock, flags);
-+
-+    while (! ELAN3_QUEUE_FRONT_EMPTY (ctxt->CommandTrapQ))
-+    {
-+      trap = (*ELAN3_QUEUE_FRONT (ctxt->CommandTrapQ, ctxt->CommandTraps));
-+      ELAN3_QUEUE_REMOVE (ctxt->CommandTrapQ);
-+      spin_unlock_irqrestore (&dev->IntrLock, flags);
-+      
-+      BumpUserStat (ctxt, CProcTraps);
-+
-+      switch (trap.Status.s.TrapType)
-+      {
-+      case 0:
-+          res = ISSUE_COMMAND_OK;
-+          break;
-+          
-+      case MI_WaitForWaitEventDesc:
-+          /*
-+           * Fault occured on the read of wait event descriptor for wait event type 0.
-+           * Fault already fixed. Just re-issue the wait command. Wait event descriptor addr
-+           * is in the Areg save value.
-+           */
-+          PRINTF1 (ctxt, DBG_CPROC, "RestartCProcTrap: WaitEvent type0 desc read fault %08x\n", 
-+                   trap.TrapBuf.r.Areg);
-+          
-+          res = IssueCommand (ctxt, offsetof (E3_CommandPort, WaitEvent0), trap.TrapBuf.r.Areg, ISSUE_COMMAND_FOR_CPROC);
-+          break;
-+
-+      case MI_WaitForEventReadTy0:
-+          /*
-+           * Fault occured on the read of event location for wait event type 0.
-+           * Fault already fixed. Just re-issue the wait command. Wait event descriptor addr
-+           * is in the Areg save value.
-+           */
-+          PRINTF1 (ctxt, DBG_CPROC, "RestartCProcTrap: WaitEvent type0 event loc fault %08x\n",
-+                   trap.TrapBuf.r.Areg);
-+          
-+          res = IssueCommand (ctxt, offsetof (E3_CommandPort, WaitEvent0), trap.TrapBuf.r.Areg, ISSUE_COMMAND_FOR_CPROC);
-+          break;
-+          
-+      case MI_WaitForEventReadTy1:
-+          /*
-+           * Fault occured on the read of the event location for wait event type 1.
-+           * Areg has the original ptr and count.
-+           * Fault already fixed. Just re-issue the wait command using Areg and context.
-+           */
-+          PRINTF1 (ctxt, DBG_CPROC, "RestartCProcTrap: WaitEvent type1 event location read fault %08x\n",
-+                   trap.TrapBuf.r.Areg);
-+          res = IssueCommand (ctxt, offsetof (E3_CommandPort, WaitEvent1), trap.TrapBuf.r.Areg, ISSUE_COMMAND_FOR_CPROC);
-+          break;
-+          
-+      case MI_WaitForCntxDmaDescRead:
-+      case MI_WaitForNonCntxDmaDescRead:
-+          /*
-+           * Fault occured on the read of the dma descriptor. Run dma using the
-+           * Fault Address in FaultSave.
-+           */
-+          PRINTF1 (ctxt, DBG_CPROC, "RestartCProcTrap: MI_WaitForCntxDmaDescRead: re-issue dma at %08x\n", 
-+                   trap.FaultSave.s.FaultAddress);
-+          
-+    &nbs